use {
crate::geometry::{Aabb, Point, Real},
anyhow::Result,
nalgebra::Scalar,
std::num::NonZeroU32,
};
pub struct Dim<const DIMS: usize>;
pub trait Branching {
const CHILDREN: usize;
type Children<T>: IntoIterator<Item = T>;
fn children_from_fn<T>(f: impl FnMut(usize) -> T) -> Self::Children<T>;
}
macro_rules! impl_branching {($($dims:literal)*) => {$(
impl Branching for Dim<$dims> {
const CHILDREN: usize = 1 << $dims;
type Children<T> = [T; 1 << $dims];
#[inline]
fn children_from_fn<T>(f: impl FnMut(usize) -> T) -> Self::Children<T> {
std::array::from_fn(f)
}
}
)*}}
impl_branching!(1 2 3 4 5 6);
pub type Children<T, const DIMS: usize> = <Dim<DIMS> as Branching>::Children<T>;
#[inline]
pub fn child_rect<F: Real, const DIMS: usize>(
rect: Aabb<F, DIMS>,
i: usize,
) -> Aabb<F, DIMS> {
let c = rect.center();
let mut min = rect.min;
let mut max = rect.max;
for a in 0..DIMS {
if i & (1 << a) != 0 { min[a] = c[a]; } else { max[a] = c[a]; }
}
Aabb { min, max }
}
#[inline]
pub fn child_rects<F: Real, const DIMS: usize>(
rect: Aabb<F, DIMS>,
) -> Children<Aabb<F, DIMS>, DIMS>
where
Dim<DIMS>: Branching,
{
<Dim<DIMS> as Branching>::children_from_fn(|i| child_rect(rect, i))
}
#[derive(Clone)]
pub struct Node<Data, Float: Scalar, const DIMS: usize> {
pub rect: Aabb<Float, DIMS>,
pub depth: u8,
pub data: Data,
children: Option<NonZeroU32>,
}
impl<Data, Float: Scalar, const DIMS: usize> Node<Data, Float, DIMS> {
#[inline]
pub fn is_leaf(&self) -> bool {
self.children.is_none()
}
}
#[derive(Clone)]
pub struct Quadtree<Data, Float: Scalar, const DIMS: usize> {
nodes: Vec<Node<Data, Float, DIMS>>,
pub max_depth: u8,
}
pub enum Refine<Data, const DIMS: usize>
where
Dim<DIMS>: Branching,
{
None,
SetData(Data),
Subdivide(Children<Data, DIMS>),
}
impl<Data, _Float: Real, const DIMS: usize> Quadtree<Data, _Float, DIMS>
where
Dim<DIMS>: Branching,
{
pub fn new(max_depth: u8, init: Data) -> Self {
let root = Node {
rect: Aabb::unit(),
depth: 0,
data: init,
children: None,
};
Quadtree { nodes: vec![root], max_depth }
}
#[inline]
pub fn root(&self) -> &Node<Data, _Float, DIMS> {
&self.nodes[0]
}
#[inline]
pub fn node_count(&self) -> usize {
self.nodes.len()
}
pub fn traverse(&self, f: &mut dyn FnMut(&Node<Data, _Float, DIMS>) -> Result<()>) -> Result<()> {
for node in &self.nodes {
f(node)?;
}
Ok(())
}
pub fn visit_leaves(
&self,
mut prune: impl FnMut(&Node<Data, _Float, DIMS>) -> bool,
mut visit: impl FnMut(&Node<Data, _Float, DIMS>),
) {
let mut stack = vec![0usize];
while let Some(idx) = stack.pop() {
let node = &self.nodes[idx];
if prune(node) {
continue;
}
match node.children {
Some(first) => stack.extend(
first.get() as usize..first.get() as usize + <Dim<DIMS> as Branching>::CHILDREN),
None => visit(node),
}
}
}
pub fn pt_to_node(&self, pt: Point<_Float, DIMS>) -> Option<&Node<Data, _Float, DIMS>> {
let mut node = &self.nodes[0];
if !node.rect.contains(&pt) {
return None;
}
while let Some(first) = node.children {
let center = node.rect.center();
let mut child = 0usize;
for a in 0..DIMS {
child |= ((pt[a] >= center[a]) as usize) << a;
}
node = &self.nodes[first.get() as usize + child];
}
Some(node)
}
pub fn refine_leaves<K, F>(&mut self, keep: K, decide: F) -> bool
where
K: Fn(&Node<Data, _Float, DIMS>) -> bool + Sync,
F: Fn(&Node<Data, _Float, DIMS>) -> Refine<Data, DIMS> + Send + Sync,
Data: Send + Sync,
Children<Data, DIMS>: Send,
_Float: Sync,
{
let actions = self.collect_actions(0, &keep, &decide);
let mut changed = false;
for (i, action) in actions {
match action {
Refine::None => {}
Refine::SetData(data) => {
self.nodes[i].data = data;
changed = true;
}
Refine::Subdivide(data) => {
self.subdivide(i, data);
changed = true;
}
}
}
changed
}
fn collect_actions<K, F>(
&self,
idx: usize,
keep: &K,
decide: &F,
) -> Vec<(usize, Refine<Data, DIMS>)>
where
K: Fn(&Node<Data, _Float, DIMS>) -> bool + Sync,
F: Fn(&Node<Data, _Float, DIMS>) -> Refine<Data, DIMS> + Sync,
Data: Send + Sync,
Children<Data, DIMS>: Send,
_Float: Sync,
{
use rayon::prelude::*;
let node = &self.nodes[idx];
if !keep(node) {
return Vec::new();
}
match node.children {
None => match decide(node) {
Refine::None => Vec::new(),
action => vec![(idx, action)],
},
Some(first) => {
let first = first.get() as usize;
(first..first + <Dim<DIMS> as Branching>::CHILDREN).into_par_iter()
.flat_map_iter(|child| self.collect_actions(child, keep, decide))
.collect()
}
}
}
fn subdivide(&mut self, parent: usize, data: Children<Data, DIMS>) {
let rects = child_rects(self.nodes[parent].rect);
let child_depth = self.nodes[parent].depth + 1;
let first = NonZeroU32::new(self.nodes.len() as u32).expect("root occupies index 0");
for (rect, data) in rects.into_iter().zip(data) {
self.nodes.push(Node { rect, depth: child_depth, data, children: None });
}
self.nodes[parent].children = Some(first);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test] fn layout_2d() {
use std::mem::size_of;
assert_eq!(size_of::<Aabb<f64, 2>>(), 32);
assert_eq!(size_of::<Node<Vec<u64>, f64, 2>>(), 64);
let quads = child_rects(Aabb::<f64, 2>::unit());
assert_eq!(quads.map(|q| [q.min.x, q.min.y]),
[[0.0, 0.0], [0.5, 0.0], [0.0, 0.5], [0.5, 0.5]]);
}
#[test] fn octree_descent() {
let mut tree = Quadtree::<u32, f64, 3>::new(2, 0);
tree.refine_leaves(
|_| true,
|node| if node.depth == 0 {
Refine::Subdivide(std::array::from_fn(|i| i as u32))
} else {
Refine::None
});
assert_eq!(tree.node_count(), 9);
let node = tree.pt_to_node(Point::from([0.75, 0.25, 0.75])).unwrap();
assert_eq!(node.data, 0b101);
assert_eq!(node.rect.min, Point::from([0.5, 0.0, 0.5]));
assert!(tree.pt_to_node(Point::from([0.5, 1.0, 0.5])).is_none()); }
}