#[derive(Debug, Clone)]
pub enum OctreeNode {
Leaf {
value: f64,
centre: [f64; 3],
half_size: f64,
},
Internal {
centre: [f64; 3],
half_size: f64,
children: Box<[OctreeNode; 8]>,
},
}
impl OctreeNode {
pub fn evaluate(&self, p: [f64; 3]) -> f64 {
match self {
OctreeNode::Leaf { value, .. } => *value,
OctreeNode::Internal {
centre,
children,
half_size: _,
} => {
let ix = if p[0] >= centre[0] { 1 } else { 0 };
let iy = if p[1] >= centre[1] { 1 } else { 0 };
let iz = if p[2] >= centre[2] { 1 } else { 0 };
let child_idx = ix + 2 * iy + 4 * iz;
children[child_idx].evaluate(p)
}
}
}
pub fn half_size(&self) -> f64 {
match self {
OctreeNode::Leaf { half_size, .. } => *half_size,
OctreeNode::Internal { half_size, .. } => *half_size,
}
}
}
#[derive(Debug, Clone)]
pub struct OctreeSdf {
pub root: OctreeNode,
pub max_depth: usize,
pub refine_threshold: f64,
}
impl OctreeSdf {
pub fn build<F>(
f: &F,
centre: [f64; 3],
half_size: f64,
max_depth: usize,
refine_threshold: f64,
) -> Self
where
F: Fn([f64; 3]) -> f64,
{
let root = Self::build_node(f, centre, half_size, 0, max_depth, refine_threshold);
Self {
root,
max_depth,
refine_threshold,
}
}
fn build_node<F>(
f: &F,
centre: [f64; 3],
half_size: f64,
depth: usize,
max_depth: usize,
threshold: f64,
) -> OctreeNode
where
F: Fn([f64; 3]) -> f64,
{
let value = f(centre);
if depth >= max_depth || value.abs() > threshold {
return OctreeNode::Leaf {
value,
centre,
half_size,
};
}
let hs = half_size * 0.5;
let children: [OctreeNode; 8] = std::array::from_fn(|k| {
let cx = centre[0] + if k & 1 != 0 { hs } else { -hs };
let cy = centre[1] + if k & 2 != 0 { hs } else { -hs };
let cz = centre[2] + if k & 4 != 0 { hs } else { -hs };
Self::build_node(f, [cx, cy, cz], hs, depth + 1, max_depth, threshold)
});
OctreeNode::Internal {
centre,
half_size,
children: Box::new(children),
}
}
pub fn evaluate(&self, p: [f64; 3]) -> f64 {
self.root.evaluate(p)
}
pub fn count_leaves(&self) -> usize {
Self::count_leaves_node(&self.root)
}
fn count_leaves_node(node: &OctreeNode) -> usize {
match node {
OctreeNode::Leaf { .. } => 1,
OctreeNode::Internal { children, .. } => {
children.iter().map(Self::count_leaves_node).sum()
}
}
}
}