pub mod partition;
pub use partition::*;
use crate::compute_method::math::Float;
pub type NodeID = u32;
#[derive(Clone, Debug)]
pub struct Tree<Node, Data> {
pub nodes: Vec<Node>,
pub data: Vec<Data>,
}
impl<Node, Data> Tree<Node, Data> {
#[inline]
pub fn new() -> Self {
Self {
nodes: Vec::new(),
data: Vec::new(),
}
}
#[inline]
pub fn with_capacity(capacity: usize) -> Self {
Self {
nodes: Vec::with_capacity(capacity),
data: Vec::with_capacity(capacity),
}
}
}
impl<Node, Data> Default for Tree<Node, Data> {
#[inline]
fn default() -> Self {
Self::new()
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Node<N> {
Internal(N),
External,
}
pub type Orthtree<const X: usize, const D: usize, S, Data> =
Tree<Node<SizedOrthant<X, D, NodeID, S>>, Data>;
impl<const X: usize, const D: usize, S, Data> Orthtree<X, D, S, Data> {
#[inline]
pub fn build_node<I, P, C>(&mut self, input: &[I], position: P, compute: C) -> Option<NodeID>
where
I: Copy,
P: Fn(I) -> [S; D] + Copy,
C: Fn(&[I]) -> Data + Copy,
S: Copy + Float + PartialOrd,
BoundingBox<[S; D]>: SubDivide<Division = [BoundingBox<[S; D]>; X]>,
{
self.build_node_with(
BoundingBox::square_with(input.iter().copied().map(position)),
input,
position,
compute,
)
}
pub fn build_node_with<I, P, C>(
&mut self,
bbox: BoundingBox<[S; D]>,
input: &[I],
pos: P,
compute: C,
) -> Option<NodeID>
where
I: Copy,
P: Fn(I) -> [S; D] + Copy,
C: Fn(&[I]) -> Data + Copy,
S: Copy + Float + PartialOrd,
BoundingBox<[S; D]>: SubDivide<Division = [BoundingBox<[S; D]>; X]>,
{
if input.is_empty() {
return None;
}
let id = self.nodes.len();
self.nodes.push(Node::External);
self.data.push(compute(input));
if input.windows(2).any(|d| pos(d[0]) != pos(d[1])) {
let center = bbox.center();
let mut result = bbox.subdivide().map(|bbox| (Vec::new(), bbox));
for &d in input {
let position = pos(d);
let index = (0..D).fold(0, |index, i| {
index + (usize::from(position[i] < center[i]) << i)
});
result[index].0.push(d);
}
self.nodes[id] = Node::Internal(SizedOrthant {
orthant: result.map(|(data, bbox)| self.build_node_with(bbox, &data, pos, compute)),
bbox,
});
}
Some(id as NodeID)
}
}