1#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
6pub struct VoxelKey {
7 pub level: i32,
9 pub x: i32,
11 pub y: i32,
13 pub z: i32,
15}
16
17impl VoxelKey {
18 pub const ROOT: VoxelKey = VoxelKey {
20 level: 0,
21 x: 0,
22 y: 0,
23 z: 0,
24 };
25
26 pub fn parent(&self) -> Option<VoxelKey> {
28 if self.level == 0 {
29 return None;
30 }
31 Some(VoxelKey {
32 level: self.level - 1,
33 x: self.x >> 1,
34 y: self.y >> 1,
35 z: self.z >> 1,
36 })
37 }
38
39 pub fn child(&self, dir: u8) -> VoxelKey {
41 debug_assert!(dir < 8, "octant direction must be 0–7");
42 VoxelKey {
43 level: self.level + 1,
44 x: (self.x << 1) | i32::from(dir & 0x1),
45 y: (self.y << 1) | i32::from((dir >> 1) & 0x1),
46 z: (self.z << 1) | i32::from((dir >> 2) & 0x1),
47 }
48 }
49
50 pub fn children(&self) -> [VoxelKey; 8] {
52 std::array::from_fn(|i| self.child(i as u8))
53 }
54
55 pub fn bounds(&self, root_bounds: &Aabb) -> Aabb {
57 let side = (root_bounds.max[0] - root_bounds.min[0]) / 2_u32.pow(self.level as u32) as f64;
58 Aabb {
59 min: [
60 root_bounds.min[0] + self.x as f64 * side,
61 root_bounds.min[1] + self.y as f64 * side,
62 root_bounds.min[2] + self.z as f64 * side,
63 ],
64 max: [
65 root_bounds.min[0] + (self.x + 1) as f64 * side,
66 root_bounds.min[1] + (self.y + 1) as f64 * side,
67 root_bounds.min[2] + (self.z + 1) as f64 * side,
68 ],
69 }
70 }
71}
72
73#[derive(Debug, Clone, Copy, PartialEq)]
75pub struct Aabb {
76 pub min: [f64; 3],
78 pub max: [f64; 3],
80}
81
82impl Aabb {
83 pub fn intersects(&self, other: &Aabb) -> bool {
85 self.min[0] <= other.max[0]
86 && self.max[0] >= other.min[0]
87 && self.min[1] <= other.max[1]
88 && self.max[1] >= other.min[1]
89 && self.min[2] <= other.max[2]
90 && self.max[2] >= other.min[2]
91 }
92}