earths 0.0.1

High-fidelity Earth simulation engine — orbit, atmosphere, geology, hydrology, biosphere, terrain, lighting, rendering, satellites, and temporal systems with full scientific coupling
Documentation
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Face {
    PosX,
    NegX,
    PosY,
    NegY,
    PosZ,
    NegZ,
}
pub struct QuadTreeNode {
    pub face: Face,
    pub level: u32,
    pub x: u32,
    pub y: u32,
    pub children: Option<Box<[QuadTreeNode; 4]>>,
}
pub struct LodConfig {
    pub max_level: u32,
    pub split_distance_factor: f64,
    pub base_resolution: u32,
}
impl Default for LodConfig {
    fn default() -> Self {
        Self {
            max_level: 15,
            split_distance_factor: 2.0,
            base_resolution: 64,
        }
    }
}
impl QuadTreeNode {
    pub fn new(face: Face, level: u32, x: u32, y: u32) -> Self {
        Self {
            face,
            level,
            x,
            y,
            children: None,
        }
    }
    pub fn should_split(&self, camera_distance: f64, config: &LodConfig) -> bool {
        if self.level >= config.max_level {
            return false;
        }
        let node_size = 1.0 / (1u64 << self.level) as f64;
        camera_distance < node_size * config.split_distance_factor
    }
    pub fn split(&mut self) {
        let nl = self.level + 1;
        let nx = self.x * 2;
        let ny = self.y * 2;
        self.children = Some(Box::new([
            QuadTreeNode::new(self.face, nl, nx, ny),
            QuadTreeNode::new(self.face, nl, nx + 1, ny),
            QuadTreeNode::new(self.face, nl, nx, ny + 1),
            QuadTreeNode::new(self.face, nl, nx + 1, ny + 1),
        ]));
    }
    pub fn is_leaf(&self) -> bool {
        self.children.is_none()
    }
}
pub struct LodTerrain {
    pub roots: Vec<QuadTreeNode>,
    pub config: LodConfig,
}
impl LodTerrain {
    pub fn new(config: LodConfig) -> Self {
        let faces = [
            Face::PosX,
            Face::NegX,
            Face::PosY,
            Face::NegY,
            Face::PosZ,
            Face::NegZ,
        ];
        let roots = faces
            .iter()
            .map(|&f| QuadTreeNode::new(f, 0, 0, 0))
            .collect();
        Self { roots, config }
    }
    pub fn update(&mut self, camera_pos: [f64; 3]) {
        let cam_dist =
            (camera_pos[0].powi(2) + camera_pos[1].powi(2) + camera_pos[2].powi(2)).sqrt();
        for root in &mut self.roots {
            Self::update_node(root, cam_dist, &self.config);
        }
    }
    fn update_node(node: &mut QuadTreeNode, camera_distance: f64, config: &LodConfig) {
        if node.should_split(camera_distance, config) {
            if node.is_leaf() {
                node.split();
            }
            if let Some(ref mut children) = node.children {
                for child in children.iter_mut() {
                    Self::update_node(child, camera_distance, config);
                }
            }
        }
    }
}