oxiphysics_geometry/signed_distance_field/
octree.rs1#[derive(Debug, Clone)]
12pub enum OctreeNode {
13 Leaf {
15 value: f64,
17 centre: [f64; 3],
19 half_size: f64,
21 },
22 Internal {
24 centre: [f64; 3],
26 half_size: f64,
28 children: Box<[OctreeNode; 8]>,
30 },
31}
32
33impl OctreeNode {
34 pub fn evaluate(&self, p: [f64; 3]) -> f64 {
36 match self {
37 OctreeNode::Leaf { value, .. } => *value,
38 OctreeNode::Internal {
39 centre,
40 children,
41 half_size: _,
42 } => {
43 let ix = if p[0] >= centre[0] { 1 } else { 0 };
44 let iy = if p[1] >= centre[1] { 1 } else { 0 };
45 let iz = if p[2] >= centre[2] { 1 } else { 0 };
46 let child_idx = ix + 2 * iy + 4 * iz;
47 children[child_idx].evaluate(p)
48 }
49 }
50 }
51
52 pub fn half_size(&self) -> f64 {
54 match self {
55 OctreeNode::Leaf { half_size, .. } => *half_size,
56 OctreeNode::Internal { half_size, .. } => *half_size,
57 }
58 }
59}
60
61#[derive(Debug, Clone)]
63pub struct OctreeSdf {
64 pub root: OctreeNode,
66 pub max_depth: usize,
68 pub refine_threshold: f64,
70}
71
72impl OctreeSdf {
73 pub fn build<F>(
75 f: &F,
76 centre: [f64; 3],
77 half_size: f64,
78 max_depth: usize,
79 refine_threshold: f64,
80 ) -> Self
81 where
82 F: Fn([f64; 3]) -> f64,
83 {
84 let root = Self::build_node(f, centre, half_size, 0, max_depth, refine_threshold);
85 Self {
86 root,
87 max_depth,
88 refine_threshold,
89 }
90 }
91
92 fn build_node<F>(
93 f: &F,
94 centre: [f64; 3],
95 half_size: f64,
96 depth: usize,
97 max_depth: usize,
98 threshold: f64,
99 ) -> OctreeNode
100 where
101 F: Fn([f64; 3]) -> f64,
102 {
103 let value = f(centre);
104 if depth >= max_depth || value.abs() > threshold {
105 return OctreeNode::Leaf {
106 value,
107 centre,
108 half_size,
109 };
110 }
111 let hs = half_size * 0.5;
112 let children: [OctreeNode; 8] = std::array::from_fn(|k| {
113 let cx = centre[0] + if k & 1 != 0 { hs } else { -hs };
114 let cy = centre[1] + if k & 2 != 0 { hs } else { -hs };
115 let cz = centre[2] + if k & 4 != 0 { hs } else { -hs };
116 Self::build_node(f, [cx, cy, cz], hs, depth + 1, max_depth, threshold)
117 });
118 OctreeNode::Internal {
119 centre,
120 half_size,
121 children: Box::new(children),
122 }
123 }
124
125 pub fn evaluate(&self, p: [f64; 3]) -> f64 {
127 self.root.evaluate(p)
128 }
129
130 pub fn count_leaves(&self) -> usize {
132 Self::count_leaves_node(&self.root)
133 }
134
135 fn count_leaves_node(node: &OctreeNode) -> usize {
136 match node {
137 OctreeNode::Leaf { .. } => 1,
138 OctreeNode::Internal { children, .. } => {
139 children.iter().map(Self::count_leaves_node).sum()
140 }
141 }
142 }
143}