Skip to main content

copc_streaming/
types.rs

1/// Octree node key: (level, x, y, z).
2#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3pub struct VoxelKey {
4    /// Octree depth (0 = root).
5    pub level: i32,
6    /// X coordinate at this level.
7    pub x: i32,
8    /// Y coordinate at this level.
9    pub y: i32,
10    /// Z coordinate at this level.
11    pub z: i32,
12}
13
14impl VoxelKey {
15    /// The root octree node.
16    pub const ROOT: VoxelKey = VoxelKey {
17        level: 0,
18        x: 0,
19        y: 0,
20        z: 0,
21    };
22
23    /// Return the parent key, or `None` for the root node.
24    pub fn parent(&self) -> Option<VoxelKey> {
25        if self.level == 0 {
26            return None;
27        }
28        Some(VoxelKey {
29            level: self.level - 1,
30            x: self.x >> 1,
31            y: self.y >> 1,
32            z: self.z >> 1,
33        })
34    }
35
36    /// Return the child key in the given octant direction (0–7).
37    pub fn child(&self, dir: i32) -> VoxelKey {
38        VoxelKey {
39            level: self.level + 1,
40            x: (self.x << 1) | (dir & 0x1),
41            y: (self.y << 1) | ((dir >> 1) & 0x1),
42            z: (self.z << 1) | ((dir >> 2) & 0x1),
43        }
44    }
45
46    /// Return all eight child keys.
47    pub fn children(&self) -> [VoxelKey; 8] {
48        [
49            self.child(0),
50            self.child(1),
51            self.child(2),
52            self.child(3),
53            self.child(4),
54            self.child(5),
55            self.child(6),
56            self.child(7),
57        ]
58    }
59
60    /// Compute the spatial bounding box of this node given the root octree bounds.
61    pub fn bounds(&self, root_bounds: &Aabb) -> Aabb {
62        let side = (root_bounds.max[0] - root_bounds.min[0]) / 2_u32.pow(self.level as u32) as f64;
63        Aabb {
64            min: [
65                root_bounds.min[0] + self.x as f64 * side,
66                root_bounds.min[1] + self.y as f64 * side,
67                root_bounds.min[2] + self.z as f64 * side,
68            ],
69            max: [
70                root_bounds.min[0] + (self.x + 1) as f64 * side,
71                root_bounds.min[1] + (self.y + 1) as f64 * side,
72                root_bounds.min[2] + (self.z + 1) as f64 * side,
73            ],
74        }
75    }
76}
77
78/// Axis-aligned bounding box.
79#[derive(Debug, Clone, Copy, PartialEq)]
80pub struct Aabb {
81    /// Minimum corner `[x, y, z]`.
82    pub min: [f64; 3],
83    /// Maximum corner `[x, y, z]`.
84    pub max: [f64; 3],
85}
86
87impl Aabb {
88    /// Test whether two bounding boxes overlap.
89    pub fn intersects(&self, other: &Aabb) -> bool {
90        self.min[0] <= other.max[0]
91            && self.max[0] >= other.min[0]
92            && self.min[1] <= other.max[1]
93            && self.max[1] >= other.min[1]
94            && self.min[2] <= other.max[2]
95            && self.max[2] >= other.min[2]
96    }
97}