├── .gitignore ├── noun_partition_591721_100x100.png ├── src ├── errors.rs ├── tpntree_dynamic │ ├── nalgebra.rs │ ├── iterators.rs │ └── mod.rs ├── tpntree │ ├── nalgebra.rs │ ├── iterators.rs │ ├── spatial.rs │ └── mod.rs ├── lib.rs └── iterators.rs ├── Cargo.toml └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /noun_partition_591721_100x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SilvanCodes/tpntree/main/noun_partition_591721_100x100.png -------------------------------------------------------------------------------- /src/errors.rs: -------------------------------------------------------------------------------- 1 | use std::{error::Error, fmt::Display}; 2 | 3 | #[derive(Debug, Eq, PartialEq)] 4 | pub enum TpnTreeError { 5 | DoesNotSpan, 6 | CanNotDivide, 7 | } 8 | 9 | impl Display for TpnTreeError { 10 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 11 | match &self { 12 | TpnTreeError::DoesNotSpan => write!( 13 | f, 14 | "The tree does not span over the provided data coordinates." 15 | ), 16 | TpnTreeError::CanNotDivide => write!(f, "The tree has been divided before."), 17 | } 18 | } 19 | } 20 | 21 | impl Error for TpnTreeError {} 22 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tpntree" 3 | version = "0.5.2" 4 | edition = "2018" 5 | license = "MIT" 6 | description = "A N-dimensional generalization of region quad/oc-trees." 7 | homepage = "https://github.com/SilvanCodes/tpntree" 8 | documentation = "https://docs.rs/tpntree" 9 | repository = "https://github.com/SilvanCodes/tpntree" 10 | readme = "README.md" 11 | keywords = ["quadtree", "octree"] 12 | categories = ["data-structures"] 13 | 14 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 15 | 16 | [dependencies] 17 | bitvec = "1.0.1" 18 | nalgebra = { version = "0.28", optional = true } 19 | 20 | [features] 21 | default = ["nalgebra"] 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Welcome to tpntree! 2 | 3 | ![space partition](./noun_partition_591721_100x100.png) 4 | 5 | The N-dimensional generalization of region quad/oc-trees. 6 | 7 | ## What are tpntrees? 8 | 9 | Tpntrees are [quadtrees], [octrees] and the same thing at any other dimension. 10 | 11 | [quadtrees]: https://en.wikipedia.org/wiki/Quadtree 12 | [octrees]: https://en.wikipedia.org/wiki/Octree 13 | 14 | ## Why is it called tpntree? 15 | 16 | `tpn` is an acronym for `two power n` or written as math `2^N` which indicates the number of regions a tree has as children. 17 | In 2D its 2^2 = 4, a.k.a. quadtree, in 3D its 2^3 = 8 a.k.a. octree. 18 | 19 | ## How do I use tpntrees? 20 | 21 | For usage information please head over to [the docs]. 22 | 23 | [the docs]: https://docs.rs/tpntree 24 | -------------------------------------------------------------------------------- /src/tpntree_dynamic/nalgebra.rs: -------------------------------------------------------------------------------- 1 | use nalgebra::DVector; 2 | 3 | use super::TpnTree; 4 | 5 | #[cfg(feature = "nalgebra")] 6 | impl TpnTree { 7 | /// Calculate the variance of TpnTrees with f64 data. 8 | pub fn variance(&self) -> f64 { 9 | DVector::from_iterator( 10 | self.children.len(), 11 | self.children.iter().map(|c| c.data.unwrap_or(0.0)), 12 | ) 13 | .variance() 14 | } 15 | } 16 | 17 | #[cfg(test)] 18 | mod tests { 19 | use super::TpnTree; 20 | 21 | #[test] 22 | fn calculate_variance_alone() { 23 | let tree = TpnTree::::root(1.0, 2); 24 | 25 | assert!(tree.variance() < f64::EPSILON); 26 | } 27 | 28 | #[test] 29 | fn calculate_variance_with_children() { 30 | let mut tree = TpnTree::::root(1.0, 2); 31 | 32 | tree.divide(); 33 | 34 | for (i, c) in tree.iter_children_mut().enumerate() { 35 | c.data = Some(i as f64) 36 | } 37 | 38 | // population variance of 0,1,2,3 39 | assert!((tree.variance() - 1.25).abs() < f64::EPSILON); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/tpntree/nalgebra.rs: -------------------------------------------------------------------------------- 1 | use nalgebra::DVector; 2 | 3 | use super::TpnTree; 4 | 5 | #[cfg(feature = "nalgebra")] 6 | impl TpnTree { 7 | /// Calculate the variance of TpnTrees with f64 data. 8 | pub fn variance(&self) -> f64 { 9 | DVector::from_iterator( 10 | self.children.len(), 11 | self.children.iter().map(|c| c.data.unwrap_or(0.0)), 12 | ) 13 | .variance() 14 | } 15 | } 16 | 17 | #[cfg(test)] 18 | mod tests { 19 | use crate::tpntree::TpnTree; 20 | 21 | #[test] 22 | fn calculate_variance_alone() { 23 | let tree = TpnTree::::root(1.0); 24 | 25 | assert!(tree.variance() < f64::EPSILON); 26 | } 27 | 28 | #[test] 29 | fn calculate_variance_with_children() { 30 | let mut tree = TpnTree::::root(1.0); 31 | 32 | assert!(tree.divide().is_ok()); 33 | 34 | for (i, c) in tree.iter_children_mut().enumerate() { 35 | c.data = Some(i as f64) 36 | } 37 | 38 | // population variance of 0,1,2,3 39 | assert!((tree.variance() - 1.25).abs() < f64::EPSILON); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! This crate contains an N-dimensional generalization of a region quadtree called **T**wo-**p**ower-__n__-tree or tpntree, 2 | //! as there exist 2^N children per node, where N is the number of dimensions. 3 | //! A quadtree is the two-dimensional case, an octtree is the three-dimensional case of the tpntree. 4 | 5 | mod errors; 6 | mod iterators; 7 | pub mod tpntree; 8 | pub mod tpntree_dynamic; 9 | 10 | pub use errors::TpnTreeError; 11 | 12 | /// [`Coordinates`] is required for a type to be used inside a [`tpntree::SpatialTree`]. 13 | /// 14 | /// Be sure to return a slice of a length equal to const generic type parameter N. 15 | pub trait Coordinates { 16 | fn coordinates(&self) -> &[f64]; 17 | } 18 | 19 | impl Coordinates for [f64; N] { 20 | /// Blanket implementation for arrays of length N. 21 | fn coordinates(&self) -> &[f64] { 22 | self 23 | } 24 | } 25 | 26 | impl Coordinates for Vec { 27 | /// Blanket implementation for vectors. 28 | /// 29 | /// Panics if the length of the vec is different from N. 30 | fn coordinates(&self) -> &[f64] { 31 | assert_eq!( 32 | self.len(), 33 | N, 34 | "Expected vec of length {}, got vec of length {}.", 35 | N, 36 | self.len() 37 | ); 38 | self 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/tpntree_dynamic/iterators.rs: -------------------------------------------------------------------------------- 1 | use crate::{impl_breadth_first_iterator, impl_depth_first_iterator}; 2 | 3 | impl_breadth_first_iterator!(); 4 | impl_depth_first_iterator!(); 5 | 6 | #[cfg(test)] 7 | mod tests { 8 | use crate::tpntree_dynamic::TpnTree; 9 | 10 | #[test] 11 | fn iterate_depth_first() { 12 | let mut tree = TpnTree::::root(1.0, 2); 13 | 14 | tree.data = Some(1.0); 15 | tree.divide(); 16 | 17 | tree.get_child_mut(3).and_then::<(), _>(|child| { 18 | child.data = Some(2.0); 19 | child.divide(); 20 | child.get_child_mut(3).and_then::<(), _>(|childchild| { 21 | childchild.data = Some(3.0); 22 | None 23 | }); 24 | None 25 | }); 26 | 27 | let mut iter = tree.iter_depth_first(); 28 | 29 | assert_eq!(iter.next().and_then(|t| t.data), Some(1.0)); 30 | assert_eq!(iter.next().and_then(|t| t.data), Some(2.0)); 31 | assert_eq!(iter.next().and_then(|t| t.data), Some(3.0)); 32 | } 33 | 34 | #[test] 35 | fn iterate_breadth_first() { 36 | let mut tree = TpnTree::::root(1.0, 2); 37 | 38 | tree.data = Some(1.0); 39 | tree.divide(); 40 | 41 | tree.get_child_mut(0).and_then::<(), _>(|child| { 42 | *child.data_mut() = Some(2.0); 43 | child.divide(); 44 | None 45 | }); 46 | tree.get_child_mut(1).and_then::<(), _>(|child| { 47 | *child.data_mut() = Some(3.0); 48 | child.divide(); 49 | None 50 | }); 51 | 52 | let mut iter = tree.iter_breadth_first(); 53 | 54 | assert_eq!(iter.next().and_then(|t| t.data().as_ref()), Some(&1.0)); 55 | assert_eq!(iter.next().and_then(|t| t.data().as_ref()), Some(&2.0)); 56 | assert_eq!(iter.next().and_then(|t| t.data().as_ref()), Some(&3.0)); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/tpntree/iterators.rs: -------------------------------------------------------------------------------- 1 | use crate::{impl_breadth_first_iterator, impl_depth_first_iterator}; 2 | 3 | impl_breadth_first_iterator!(N); 4 | impl_depth_first_iterator!(N); 5 | 6 | #[cfg(test)] 7 | mod tests { 8 | use crate::tpntree::TpnTree; 9 | 10 | #[test] 11 | fn iterate_depth_first() { 12 | let mut tree = TpnTree::::root(1.0); 13 | 14 | tree.data = Some(1.0); 15 | assert!(tree.divide().is_ok()); 16 | 17 | tree.get_child_mut(3).and_then::<(), _>(|child| { 18 | child.data = Some(2.0); 19 | assert!(child.divide().is_ok()); 20 | child.get_child_mut(3).and_then::<(), _>(|childchild| { 21 | childchild.data = Some(3.0); 22 | None 23 | }); 24 | None 25 | }); 26 | 27 | let mut iter = tree.iter_depth_first(); 28 | 29 | assert_eq!(iter.next().and_then(|t| t.data()), Some(&1.0)); 30 | assert_eq!(iter.next().and_then(|t| t.data()), Some(&2.0)); 31 | assert_eq!(iter.next().and_then(|t| t.data()), Some(&3.0)); 32 | } 33 | 34 | #[test] 35 | fn iterate_breadth_first() { 36 | let mut tree = TpnTree::::root(1.0); 37 | 38 | tree.data = Some(1.0); 39 | assert!(tree.divide().is_ok()); 40 | 41 | tree.get_child_mut(0).and_then::<(), _>(|child| { 42 | child.data_mut().insert(2.0); 43 | assert!(child.divide().is_ok()); 44 | None 45 | }); 46 | tree.get_child_mut(1).and_then::<(), _>(|child| { 47 | child.data_mut().insert(3.0); 48 | assert!(child.divide().is_ok()); 49 | None 50 | }); 51 | 52 | let mut iter = tree.iter_breadth_first(); 53 | 54 | assert_eq!(iter.next().and_then(|t| t.data()), Some(&1.0)); 55 | assert_eq!(iter.next().and_then(|t| t.data()), Some(&2.0)); 56 | assert_eq!(iter.next().and_then(|t| t.data()), Some(&3.0)); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/iterators.rs: -------------------------------------------------------------------------------- 1 | #[macro_export] 2 | macro_rules! get_tree_type { 3 | ( $n:ident ) => { 4 | crate::tpntree::TpnTree 5 | }; 6 | ( ) => { 7 | crate::tpntree_dynamic::TpnTree 8 | }; 9 | } 10 | 11 | #[macro_export] 12 | macro_rules! impl_depth_first_iterator { 13 | ( $( $n:ident )? ) => { 14 | impl $crate::get_tree_type!( $( $n )?) { 17 | /// Iterate the tree depth first, starting with the root. 18 | pub fn iter_depth_first(&self) -> DepthFirstIterator { 21 | DepthFirstIterator::new(self) 22 | } 23 | } 24 | 25 | pub struct DepthFirstIterator<'a, T $(, 26 | const $n: usize 27 | )?> { 28 | stack: Vec<&'a $crate::get_tree_type!( $( $n )?)>, 29 | } 30 | 31 | impl<'a, T $(, 32 | const $n: usize 33 | )?> DepthFirstIterator<'a, T $(, 34 | $n 35 | )?> { 36 | fn new(root: &'a $crate::get_tree_type!( $( $n )?)) -> Self { 37 | Self { stack: vec![root] } 38 | } 39 | } 40 | 41 | impl<'a, T $(, 42 | const $n: usize 43 | )?> Iterator for DepthFirstIterator<'a, T $(, 44 | $n 45 | )?> { 46 | type Item = &'a $crate::get_tree_type!( $( $n )?); 47 | 48 | fn next(&mut self) -> Option { 49 | self.stack.pop().map(|tree| { 50 | for child in tree.iter_children() { 51 | self.stack.push(child); 52 | } 53 | tree 54 | }) 55 | } 56 | } 57 | }; 58 | } 59 | 60 | #[macro_export] 61 | macro_rules! impl_breadth_first_iterator { 62 | ( $( $n:ident )? ) => { 63 | impl $crate::get_tree_type!( $( $n )?) { 66 | /// Iterate the tree breadth first, starting with the root. 67 | pub fn iter_breadth_first(&self) -> BreadthFirstIterator { 70 | BreadthFirstIterator::new(self) 71 | } 72 | } 73 | 74 | pub struct BreadthFirstIterator<'a, T $(, 75 | const $n: usize 76 | )?> { 77 | queue: std::collections::VecDeque<&'a $crate::get_tree_type!( $( $n )?)>, 78 | } 79 | 80 | impl<'a, T $(, 81 | const $n: usize 82 | )?> BreadthFirstIterator<'a, T $(, 83 | $n 84 | )?> { 85 | fn new(root: &'a $crate::get_tree_type!( $( $n )?)) -> Self { 86 | Self { 87 | queue: vec![root].into_iter().collect(), 88 | } 89 | } 90 | } 91 | 92 | impl<'a, T $(, 93 | const $n: usize 94 | )?> Iterator for BreadthFirstIterator<'a, T $(, 95 | $n 96 | )?> { 97 | type Item = &'a $crate::get_tree_type!( $( $n )?); 98 | 99 | fn next(&mut self) -> Option { 100 | self.queue.pop_front().map(|tree| { 101 | for child in tree.iter_children() { 102 | self.queue.push_back(child); 103 | } 104 | tree 105 | }) 106 | } 107 | } 108 | }; 109 | } 110 | -------------------------------------------------------------------------------- /src/tpntree/spatial.rs: -------------------------------------------------------------------------------- 1 | use std::iter::once; 2 | 3 | use super::TpnTree; 4 | use crate::{errors::TpnTreeError, Coordinates}; 5 | 6 | /// A helper type to work with spatial data bins. 7 | pub type SpatialTree = TpnTree, N>; 8 | 9 | /// A helper type to specify a tree working with 3D data. 10 | pub type Tree3D = SpatialTree; 11 | 12 | impl, const N: usize> SpatialTree { 13 | /// Checks if the tree spans over the coordinates of the provided data. 14 | /// 15 | /// ``` 16 | /// # use tpntree::tpntree::Tree3D; 17 | /// # use tpntree::TpnTreeError; 18 | /// let tree = Tree3D::root(1.0); 19 | /// 20 | /// assert_eq!(tree.spans(&[0.5,0.5,0.5]), true); 21 | /// assert_eq!(tree.spans(&[1.5,0.5,0.5]), false); 22 | /// ``` 23 | pub fn spans(&self, data: &T) -> bool { 24 | let data_coordinates = data.coordinates(); 25 | 26 | // checks if tpn tree contains the data coordinates 27 | // children overlap on their edges 28 | self.coordinates 29 | .iter() 30 | .enumerate() 31 | .all(|(dimension, &coordinate)| { 32 | data_coordinates[dimension] <= coordinate + self.span()[dimension] 33 | && data_coordinates[dimension] >= coordinate - self.span()[dimension] 34 | }) 35 | } 36 | 37 | /// Inserts data in the tree with its center closest to the data given the constrains of the `division_condition`. 38 | /// 39 | /// The `division condition` determines when a tree divides and inserts its data into its children. 40 | /// Errors if the tree does not span the data. 41 | /// 42 | /// ``` 43 | /// # use tpntree::tpntree::Tree3D; 44 | /// let mut tree = Tree3D::root(1.0); 45 | /// 46 | /// assert!(tree.insert_by_coordinates([1.0, 0.0, -1.0], &|_| false).is_ok()); 47 | /// ``` 48 | pub fn insert_by_coordinates( 49 | &mut self, 50 | data: T, 51 | division_condition: &dyn Fn(&Self) -> bool, 52 | ) -> Result<(), TpnTreeError> { 53 | // if the root tree does not span over the data, it can not be inserted 54 | if self.is_root() && !self.spans(&data) { 55 | return Err(TpnTreeError::DoesNotSpan); 56 | } 57 | 58 | if self.is_leaf() { 59 | if division_condition(self) { 60 | self.divide()?; 61 | 62 | for data in self 63 | .data 64 | .take() 65 | .unwrap_or_default() 66 | .into_iter() 67 | .chain(once(data)) 68 | { 69 | self.insert_into_children(data, division_condition)? 70 | } 71 | Ok(()) 72 | } else { 73 | self.data.get_or_insert(Vec::new()).push(data); 74 | Ok(()) 75 | } 76 | } else { 77 | self.insert_into_children(data, division_condition) 78 | } 79 | } 80 | 81 | fn insert_into_children( 82 | &mut self, 83 | data: T, 84 | division_condition: &dyn Fn(&Self) -> bool, 85 | ) -> Result<(), TpnTreeError> { 86 | self.children 87 | .iter_mut() 88 | // we can savely unwrap here as dimn=ensions are checked before 89 | .find(|child| child.spans(&data)) 90 | .map(|child| child.insert_by_coordinates(data, division_condition)) 91 | .unwrap() 92 | } 93 | 94 | /// Return the tree closest to the given data coordinates. 95 | /// 96 | /// Errors if the tree does not span the data. 97 | /// 98 | /// ``` 99 | /// # use tpntree::tpntree::Tree3D; 100 | /// let mut tree = Tree3D::root(1.0); 101 | /// 102 | /// tree.insert_by_coordinates([1.0, 0.0, -1.0], &|_| false).expect("Couldn't insert."); 103 | /// assert!(tree 104 | /// .find_by_coordinates(&[0.0, 0.0, 0.0]) 105 | /// .ok() 106 | /// .and_then(|tree| tree.data().map(|vec| vec.contains(&[1.0, 0.0, -1.0]))) 107 | /// .unwrap()); 108 | /// ``` 109 | pub fn find_by_coordinates(&self, data: &T) -> Result<&Self, TpnTreeError> { 110 | if self.is_root() && !self.spans(data) { 111 | return Err(TpnTreeError::DoesNotSpan); 112 | } 113 | 114 | for child in &self.children { 115 | if child.spans(data) { 116 | return child.find_by_coordinates(data); 117 | } 118 | } 119 | Ok(self) 120 | } 121 | } 122 | 123 | #[cfg(test)] 124 | mod tests { 125 | use crate::tpntree::Tree3D; 126 | 127 | #[test] 128 | fn tree_contains_coordinates() { 129 | let tree = Tree3D::root(1.0); 130 | 131 | let data_inside = [1.0, 1.0, 1.0]; 132 | 133 | assert!(tree.spans(&data_inside)); 134 | } 135 | 136 | #[test] 137 | fn tree_does_not_contain_coordinates() { 138 | let tree = Tree3D::root(1.0); 139 | 140 | let data_outside = [1.0, 1.5, 1.0]; 141 | 142 | assert!(!tree.spans(&data_outside)); 143 | } 144 | 145 | #[test] 146 | fn insert_into_root() { 147 | let mut tree = Tree3D::root(1.0); 148 | 149 | let data = [1.0, 1.0, 1.0]; 150 | 151 | assert!(tree.insert_by_coordinates(data, &|_| false).is_ok()); 152 | assert!(tree 153 | .find_by_coordinates(&[0.0, 0.0, 0.0]) 154 | .map(|tree| tree.data().as_ref().map(|vec| vec.contains(&data))) 155 | .unwrap() 156 | .unwrap()); 157 | assert!(tree.is_leaf()); 158 | } 159 | 160 | #[test] 161 | fn insert_and_split() { 162 | let mut tree = Tree3D::root(1.0); 163 | 164 | let data_one = [1.0, 1.0, 1.0]; 165 | let data_two = [-1.0, -1.0, -1.0]; 166 | 167 | let division_condition = |tree: &Tree3D| tree.data().is_some(); 168 | 169 | assert!(tree 170 | .insert_by_coordinates(data_one, &division_condition) 171 | .is_ok()); 172 | assert!(tree 173 | .insert_by_coordinates(data_two, &division_condition) 174 | .is_ok()); 175 | assert!(tree 176 | .find_by_coordinates(&[0.5, 0.5, 0.5]) 177 | .ok() 178 | .and_then(|tree| tree.data().map(|vec| vec.contains(&data_one))) 179 | .unwrap()); 180 | assert!(tree 181 | .find_by_coordinates(&[-0.5, -0.5, -0.5]) 182 | .ok() 183 | .and_then(|tree| tree.data().map(|vec| vec.contains(&data_two))) 184 | .unwrap()); 185 | assert!(tree.data().is_none()); 186 | assert!(tree.child_count() == 8); 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /src/tpntree/mod.rs: -------------------------------------------------------------------------------- 1 | mod iterators; 2 | mod nalgebra; 3 | mod spatial; 4 | 5 | use bitvec::bitvec; 6 | 7 | use crate::errors::TpnTreeError; 8 | pub use spatial::SpatialTree; 9 | pub use spatial::Tree3D; 10 | 11 | #[derive(Debug, Clone)] 12 | pub struct TpnTree { 13 | /// Coordinates of the N-dimensional hyperrectangle center. 14 | coordinates: [f64; N], 15 | /// Length of the normals from center of N-dimensional hyperrectangle to its faces. 16 | span: [f64; N], 17 | /// Height in tree. 18 | level: usize, 19 | /// There are zero or 2^N children, one times two per axis. 20 | children: Vec, 21 | /// Any potential data the tree might hold. 22 | data: Option, 23 | } 24 | 25 | impl TpnTree { 26 | /// Creates a new TpnTree. 27 | /// 28 | /// Use this function if you need explicit control over the initial coordinates or a span with various length along different axis. 29 | /// Usually the [`TpnTree::root`] function should suffice and is simpler to use. 30 | /// 31 | /// # Examples 32 | /// 33 | /// Here we create a one dimensional tree, i.e. with one axis sitting on the center `[0.0]` with a span of 1.0 in each direction `[1.0]`. 34 | /// This is equal to a line segment spanning from -1.0 to 1.0 with its midpoint at 0.0. 35 | /// The `level` of the root is usually zero. 36 | /// ``` 37 | /// # use tpntree::tpntree::TpnTree; 38 | /// 39 | /// let root = TpnTree::<(), 1>::new([0.0], [1.0], 0); 40 | /// ``` 41 | /// 42 | /// Now lets create a two dimensional tree. 43 | /// The tree root corresponds to a square with its center sitting at the coordinates (1.0/1.0) with edges one edge being 4.0 the other being 1.0 units long. 44 | /// The edges equate to twice the span as it originates from the midpoint. 45 | /// ``` 46 | /// # use tpntree::tpntree::TpnTree; 47 | /// let root = TpnTree::<(), 2>::new([1.0, 1.0], [2.0, 0.5], 0); 48 | /// ``` 49 | pub fn new(coordinates: [f64; N], span: [f64; N], level: usize) -> Self { 50 | Self { 51 | coordinates, 52 | span, 53 | level, 54 | children: Vec::new(), 55 | data: None, 56 | } 57 | } 58 | 59 | /// Creates a new TpnTree with equal span in all dimension at the center of the space at level zero. 60 | /// 61 | /// Use this function if you want your TpnTree to represenst a centered N-dimensional hypercube. 62 | /// 63 | /// # Examples 64 | /// 65 | /// Here we create a three dimensional TpnTree with a span of 1.0 in ervery dimension. 66 | /// That is equal to a cube with edges of length 2.0. 67 | /// ``` 68 | /// # use tpntree::tpntree::TpnTree; 69 | /// let root = TpnTree::<(), 3>::root(1.0); 70 | /// ``` 71 | pub fn root(span: f64) -> Self { 72 | Self::new([0.0; N], [span; N], 0) 73 | } 74 | 75 | /// Divides the TpnTree into subregions creating new TpnTrees as children. 76 | /// 77 | /// Returns true if division happened, returns false when already divided. 78 | /// 79 | /// Each created child has its center moved by half the parents span up or down along the axis. 80 | /// Every child is equal to one unique combination of such half span moves. 81 | /// 82 | /// # Examples 83 | /// 84 | /// Dividing in the 2D case is creating four smaller squares. 85 | /// 86 | /// ``` 87 | /// // +---+ +-+-+ 88 | /// // | | => +-+-+ 89 | /// // +---+ +-+-+ 90 | /// # use tpntree::tpntree::TpnTree; 91 | /// let mut root = TpnTree::<(), 2>::root(1.0); 92 | /// 93 | /// assert!(root.divide().is_ok()); 94 | /// assert_eq!(root.child_count(), 4); 95 | /// ``` 96 | pub fn divide(&mut self) -> Result<(), TpnTreeError> { 97 | if self.is_leaf() { 98 | let mut children = Vec::::new(); 99 | let mut pattern = bitvec![0; self.coordinates.len()]; 100 | 101 | // iterate for 2^N to generate all children 102 | for _ in 0..2usize.pow(self.coordinates.len() as u32) { 103 | let mut coordinates = self.coordinates; 104 | let mut span = self.span; 105 | // generate sign pattern from bits 106 | for i in 0..self.coordinates.len() { 107 | span[i] = self.span[i] / 2.0; 108 | coordinates[i] += span[i] - self.span[i] * pattern[i] as usize as f64; 109 | } 110 | 111 | children.push(Self::new(coordinates, span, self.level + 1)); 112 | 113 | let mut carry = pattern.clone(); 114 | carry.set_elements(0); 115 | let mut one = carry.clone(); 116 | one.set(0, true); 117 | 118 | // "add one" to the pattern, loop to accomodate for carry 119 | while one.any() { 120 | carry = pattern.clone() & one.clone(); 121 | pattern ^= one; 122 | one = carry.clone(); 123 | // push so we can shift 124 | one.push(false); 125 | one.shift_right(1); 126 | // pop to have an overflowing shift 127 | one.pop(); 128 | } 129 | } 130 | self.children = children; 131 | Ok(()) 132 | } else { 133 | Err(TpnTreeError::CanNotDivide) 134 | } 135 | } 136 | 137 | /// Get a reference to a child TpnTree if it exists. 138 | pub fn get_child(&self, index: usize) -> Option<&Self> { 139 | self.children.get(index) 140 | } 141 | /// Get a mutable reference to a child TpnTree if it exists. 142 | pub fn get_child_mut(&mut self, index: usize) -> Option<&mut Self> { 143 | self.children.get_mut(index) 144 | } 145 | 146 | /// Returns the count of direct children. 147 | pub fn child_count(&self) -> usize { 148 | self.children.len() 149 | } 150 | 151 | /// Iterates all direct children by reference. 152 | pub fn iter_children(&self) -> impl Iterator { 153 | self.children.iter() 154 | } 155 | 156 | /// Iterates all direct children by mutable reference. 157 | pub fn iter_children_mut(&mut self) -> impl Iterator { 158 | self.children.iter_mut() 159 | } 160 | 161 | /// Returns the coordinates of the center of the TpnTree. 162 | pub fn coordinates(&self) -> [f64; N] { 163 | self.coordinates 164 | } 165 | 166 | /// Returns the span of the TpnTree. 167 | pub fn span(&self) -> [f64; N] { 168 | self.span 169 | } 170 | 171 | /// Returns the data by reference of the TpnTree. 172 | pub fn data(&self) -> Option<&T> { 173 | self.data.as_ref() 174 | } 175 | 176 | /// Returns the data by mutable reference of the TpnTree. 177 | pub fn data_mut(&mut self) -> &mut Option { 178 | &mut self.data 179 | } 180 | 181 | /// Returns the level of the TpnTree. 182 | pub fn level(&self) -> usize { 183 | self.level 184 | } 185 | 186 | /// Returns wheter the tree is a root. 187 | pub fn is_root(&self) -> bool { 188 | self.level == 0 189 | } 190 | 191 | /// Returns wheter the tree is a leaf. 192 | pub fn is_leaf(&self) -> bool { 193 | self.children.is_empty() 194 | } 195 | 196 | /// Returns a list of adjacent trees along each dimension. 197 | /// 198 | /// The trees appear in order of dimension and that first the tree above self, then the one below. 199 | /// Thereby there will be dimension times two TpnTrees returned. 200 | pub fn adjacent_trees(&self) -> Vec { 201 | let mut adjacent_trees = Vec::new(); 202 | for i in 0..self.coordinates.len() { 203 | let mut coordinates_above = self.coordinates; 204 | coordinates_above[i] += self.span[i] * 2.0; 205 | let tree_above = Self::new(coordinates_above, self.span, 0); 206 | 207 | let mut coordinates_below = self.coordinates; 208 | coordinates_below[i] -= self.span[i] * 2.0; 209 | let tree_below = Self::new(coordinates_below, self.span, 0); 210 | 211 | adjacent_trees.push(tree_above); 212 | adjacent_trees.push(tree_below); 213 | } 214 | adjacent_trees 215 | } 216 | } 217 | 218 | #[cfg(test)] 219 | #[allow(clippy::float_cmp)] 220 | mod tests { 221 | use super::TpnTree; 222 | 223 | #[test] 224 | pub fn divide_into_subregions_dim_1() { 225 | let mut root = TpnTree::<(), 1>::root(2.0); 226 | 227 | assert!(root.divide().is_ok()); 228 | assert_eq!(root.child_count(), 2); 229 | 230 | assert_eq!(root.get_child(0).map(|c| c.coordinates()), Some([1.0])); 231 | assert_eq!(root.get_child(1).map(|c| c.coordinates()), Some([-1.0])); 232 | 233 | assert!(root.divide().is_err()); 234 | } 235 | 236 | #[test] 237 | pub fn divide_into_subregions_dim_2() { 238 | let mut root = TpnTree::<(), 2>::root(1.0); 239 | 240 | assert!(root.divide().is_ok()); 241 | assert_eq!(root.child_count(), 4); 242 | 243 | assert!(root.iter_children().any(|c| c.coordinates() == [0.5, 0.5])); 244 | assert!(root.iter_children().any(|c| c.coordinates() == [0.5, -0.5])); 245 | assert!(root.iter_children().any(|c| c.coordinates() == [-0.5, 0.5])); 246 | assert!(root 247 | .iter_children() 248 | .any(|c| c.coordinates() == [-0.5, -0.5])); 249 | 250 | assert!(root.divide().is_err()); 251 | } 252 | 253 | #[test] 254 | pub fn divide_into_subregions_dim_3() { 255 | let mut root = TpnTree::<(), 3>::root(1.0); 256 | 257 | assert!(root.divide().is_ok()); 258 | assert_eq!(root.child_count(), 8); 259 | 260 | assert!(root 261 | .iter_children() 262 | .any(|c| c.coordinates() == [0.5, 0.5, 0.5])); 263 | assert!(root 264 | .iter_children() 265 | .any(|c| c.coordinates() == [0.5, 0.5, -0.5])); 266 | assert!(root 267 | .iter_children() 268 | .any(|c| c.coordinates() == [0.5, -0.5, 0.5])); 269 | assert!(root 270 | .iter_children() 271 | .any(|c| c.coordinates() == [0.5, -0.5, -0.5])); 272 | assert!(root 273 | .iter_children() 274 | .any(|c| c.coordinates() == [-0.5, 0.5, 0.5])); 275 | assert!(root 276 | .iter_children() 277 | .any(|c| c.coordinates() == [-0.5, 0.5, -0.5])); 278 | assert!(root 279 | .iter_children() 280 | .any(|c| c.coordinates() == [-0.5, -0.5, 0.5])); 281 | assert!(root 282 | .iter_children() 283 | .any(|c| c.coordinates() == [-0.5, -0.5, -0.5])); 284 | 285 | assert!(root.divide().is_err()); 286 | } 287 | 288 | #[test] 289 | pub fn get_adjacent_trees_dimension_one() { 290 | let root = TpnTree::<(), 1>::root(1.0); 291 | 292 | let adjacent_trees = root.adjacent_trees(); 293 | 294 | assert!(adjacent_trees.iter().any(|c| c.coordinates() == [2.0])); 295 | assert!(adjacent_trees.iter().any(|c| c.coordinates() == [-2.0])); 296 | } 297 | 298 | #[test] 299 | pub fn get_adjacent_trees_dimension_two() { 300 | let root = TpnTree::<(), 2>::root(1.0); 301 | 302 | let adjacent_trees = root.adjacent_trees(); 303 | 304 | assert!(adjacent_trees.iter().any(|c| c.coordinates() == [0.0, 2.0])); 305 | assert!(adjacent_trees 306 | .iter() 307 | .any(|c| c.coordinates() == [0.0, -2.0])); 308 | 309 | assert!(adjacent_trees.iter().any(|c| c.coordinates() == [2.0, 0.0])); 310 | assert!(adjacent_trees 311 | .iter() 312 | .any(|c| c.coordinates() == [-2.0, 0.0])); 313 | } 314 | } 315 | -------------------------------------------------------------------------------- /src/tpntree_dynamic/mod.rs: -------------------------------------------------------------------------------- 1 | mod iterators; 2 | mod nalgebra; 3 | 4 | use bitvec::bitvec; 5 | 6 | #[derive(Debug, Clone)] 7 | pub struct TpnTree { 8 | /// Coordinates of the N-dimensional hyperrectangle center. 9 | coordinates: Vec, 10 | /// Length of the normals from center of N-dimensional hyperrectangle to its faces. 11 | span: Vec, 12 | /// Height in tree. 13 | level: usize, 14 | /// There are zero or 2^N children, one times two per axis. 15 | children: Vec, 16 | /// Any potential data the tree might hold. 17 | data: Option, 18 | } 19 | 20 | impl TpnTree { 21 | /// Creates a new TpnTree. 22 | /// 23 | /// Use this function if you need explicit control over the initial coordinates or a span with various length along different axis. 24 | /// Usually the [`TpnTree::root`] function should suffice and is simpler to use. 25 | /// 26 | /// # Examples 27 | /// 28 | /// Here we create a one dimensional tree, i.e. with one axis sitting on the center `[0.0]` with a span of 1.0 in each direction `[1.0]`. 29 | /// This is equal to a line segment spanning from -1.0 to 1.0 with its midpoint at 0.0. 30 | /// The `level` of the root is usually zero. 31 | /// The length of the vectors must match. 32 | /// ``` 33 | /// # use tpntree::tpntree_dynamic::TpnTree; 34 | /// 35 | /// let root = TpnTree::<()>::new(vec![0.0], vec![1.0], 0); 36 | /// ``` 37 | /// 38 | /// Now lets create a two dimensional tree. 39 | /// The tree root corresponds to a square with its center sitting at the coordinates (1.0/1.0) with edges one edge being 4.0 the other being 1.0 units long. 40 | /// The edges equate to twice the span as it originates from the midpoint. 41 | /// ``` 42 | /// # use tpntree::tpntree_dynamic::TpnTree; 43 | /// let root = TpnTree::<()>::new(vec![1.0, 1.0], vec![2.0, 0.5], 0); 44 | /// ``` 45 | pub fn new(coordinates: Vec, span: Vec, level: usize) -> Self { 46 | assert!( 47 | coordinates.len() == span.len(), 48 | "coordinates must match span dimensions" 49 | ); 50 | Self { 51 | coordinates, 52 | span, 53 | level, 54 | children: Vec::new(), 55 | data: None, 56 | } 57 | } 58 | 59 | /// Creates a new TpnTree with equal span in all dimension at the center of the space at level zero. 60 | /// 61 | /// Use this function if you want your TpnTree to represenst a centered N-dimensional hypercube. 62 | /// 63 | /// # Examples 64 | /// 65 | /// Here we create a three dimensional TpnTree with a span of 1.0 in ervery dimension. 66 | /// That is equal to a cube with edges of length 2.0. 67 | /// ``` 68 | /// # use tpntree::tpntree_dynamic::TpnTree; 69 | /// let root = TpnTree::<()>::root(1.0, 3); 70 | /// ``` 71 | pub fn root(span: f64, dimensions: usize) -> Self { 72 | Self::new(vec![0.0; dimensions], vec![span; dimensions], 0) 73 | } 74 | 75 | /// Divides the TpnTree into subregions creating new TpnTrees as children. 76 | /// 77 | /// Returns true if division happened, returns false when already divided. 78 | /// 79 | /// Each created child has its center moved by half the parents span up or down along the axis. 80 | /// Every child is equal to one unique combination of such half span moves. 81 | /// 82 | /// # Examples 83 | /// 84 | /// Dividing in the 2D case is creating four smaller squares. 85 | /// 86 | /// +---+ +-+-+ 87 | /// | | => +-+-+ 88 | /// +---+ +-+-+ 89 | /// ``` 90 | /// # use tpntree::tpntree_dynamic::TpnTree; 91 | /// let mut root = TpnTree::<()>::root(1.0, 2); 92 | /// 93 | /// assert!(root.divide()); 94 | /// assert_eq!(root.child_count(), 4); 95 | /// ``` 96 | pub fn divide(&mut self) -> bool { 97 | if self.children.is_empty() { 98 | let mut children = Vec::::new(); 99 | let mut pattern = bitvec![0; self.coordinates.len()]; 100 | 101 | // iterate for 2^N to generate all children 102 | for _ in 0..2usize.pow(self.coordinates.len() as u32) { 103 | let mut coordinates = self.coordinates.clone(); 104 | let mut span = self.span.clone(); 105 | // generate sign pattern from bits 106 | for i in 0..self.coordinates.len() { 107 | span[i] = self.span[i] / 2.0; 108 | coordinates[i] += span[i] - self.span[i] * pattern[i] as usize as f64; 109 | } 110 | 111 | children.push(Self::new(coordinates, span, self.level + 1)); 112 | 113 | let mut carry = pattern.clone(); 114 | carry.set_elements(0); 115 | let mut one = carry.clone(); 116 | one.set(0, true); 117 | 118 | // "add one" to the pattern, loop to accomodate for carry 119 | while one.any() { 120 | carry = pattern.clone() & one.clone(); 121 | pattern ^= one; 122 | one = carry.clone(); 123 | // push so we can shift 124 | one.push(false); 125 | one.shift_right(1); 126 | // pop to have an overflowing shift 127 | one.pop(); 128 | } 129 | } 130 | self.children = children; 131 | true 132 | } else { 133 | false 134 | } 135 | } 136 | 137 | /// Get a reference to a child TpnTree if it exists. 138 | pub fn get_child(&self, index: usize) -> Option<&Self> { 139 | self.children.get(index) 140 | } 141 | /// Get a mutable reference to a child TpnTree if it exists. 142 | pub fn get_child_mut(&mut self, index: usize) -> Option<&mut Self> { 143 | self.children.get_mut(index) 144 | } 145 | 146 | /// Returns the count of direct children. 147 | pub fn child_count(&self) -> usize { 148 | self.children.len() 149 | } 150 | 151 | /// Iterates all direct children by reference. 152 | pub fn iter_children(&self) -> impl Iterator { 153 | self.children.iter() 154 | } 155 | 156 | /// Iterates all direct children by mutable reference. 157 | pub fn iter_children_mut(&mut self) -> impl Iterator { 158 | self.children.iter_mut() 159 | } 160 | 161 | /// Returns the coordinates of the center of the TpnTree. 162 | pub fn coordinates(&self) -> &Vec { 163 | &self.coordinates 164 | } 165 | 166 | /// Returns the span of the TpnTree. 167 | pub fn span(&self) -> &Vec { 168 | &self.span 169 | } 170 | 171 | /// Returns the data by reference of the TpnTree. 172 | pub fn data(&self) -> &Option { 173 | &self.data 174 | } 175 | 176 | /// Returns the data by mutable reference of the TpnTree. 177 | pub fn data_mut(&mut self) -> &mut Option { 178 | &mut self.data 179 | } 180 | 181 | /// Returns the level of the TpnTree. 182 | pub fn level(&self) -> usize { 183 | self.level 184 | } 185 | 186 | /// Returns a list of adjacent trees along each dimension. 187 | /// 188 | /// The trees appear in order of dimension and that first the tree above self, then the one below. 189 | /// Thereby there will be dimension times two TpnTrees returned. 190 | pub fn adjacent_trees(&self) -> Vec { 191 | let mut adjacent_trees = Vec::new(); 192 | for i in 0..self.coordinates.len() { 193 | let mut coordinates_above = self.coordinates.clone(); 194 | coordinates_above[i] += self.span[i] * 2.0; 195 | let tree_above = Self::new(coordinates_above, self.span.clone(), 0); 196 | 197 | let mut coordinates_below = self.coordinates.clone(); 198 | coordinates_below[i] -= self.span[i] * 2.0; 199 | let tree_below = Self::new(coordinates_below, self.span.clone(), 0); 200 | 201 | adjacent_trees.push(tree_above); 202 | adjacent_trees.push(tree_below); 203 | } 204 | adjacent_trees 205 | } 206 | } 207 | 208 | #[cfg(test)] 209 | #[allow(clippy::float_cmp)] 210 | mod tests { 211 | use super::TpnTree; 212 | 213 | #[test] 214 | pub fn divide_into_subregions_dim_1() { 215 | let mut root = TpnTree::<()>::root(2.0, 1); 216 | 217 | assert!(root.divide()); 218 | assert_eq!(root.child_count(), 2); 219 | 220 | assert_eq!(root.get_child(0).map(|c| c.coordinates()), Some(&vec![1.0])); 221 | assert_eq!( 222 | root.get_child(1).map(|c| c.coordinates()), 223 | Some(&vec![-1.0]) 224 | ); 225 | 226 | assert!(!root.divide()); 227 | } 228 | 229 | #[test] 230 | pub fn divide_into_subregions_dim_2() { 231 | let mut root = TpnTree::<()>::root(1.0, 2); 232 | 233 | assert!(root.divide()); 234 | assert_eq!(root.child_count(), 4); 235 | 236 | assert!(root 237 | .iter_children() 238 | .any(|c| c.coordinates() == &vec![0.5, 0.5])); 239 | assert!(root 240 | .iter_children() 241 | .any(|c| c.coordinates() == &vec![0.5, -0.5])); 242 | assert!(root 243 | .iter_children() 244 | .any(|c| c.coordinates() == &vec![-0.5, 0.5])); 245 | assert!(root 246 | .iter_children() 247 | .any(|c| c.coordinates() == &vec![-0.5, -0.5])); 248 | 249 | assert!(!root.divide()); 250 | } 251 | 252 | #[test] 253 | pub fn divide_into_subregions_dim_3() { 254 | let mut root = TpnTree::<()>::root(1.0, 3); 255 | 256 | assert!(root.divide()); 257 | assert_eq!(root.child_count(), 8); 258 | 259 | assert!(root 260 | .iter_children() 261 | .any(|c| c.coordinates() == &vec![0.5, 0.5, 0.5])); 262 | assert!(root 263 | .iter_children() 264 | .any(|c| c.coordinates() == &vec![0.5, 0.5, -0.5])); 265 | assert!(root 266 | .iter_children() 267 | .any(|c| c.coordinates() == &vec![0.5, -0.5, 0.5])); 268 | assert!(root 269 | .iter_children() 270 | .any(|c| c.coordinates() == &vec![0.5, -0.5, -0.5])); 271 | assert!(root 272 | .iter_children() 273 | .any(|c| c.coordinates() == &vec![-0.5, 0.5, 0.5])); 274 | assert!(root 275 | .iter_children() 276 | .any(|c| c.coordinates() == &vec![-0.5, 0.5, -0.5])); 277 | assert!(root 278 | .iter_children() 279 | .any(|c| c.coordinates() == &vec![-0.5, -0.5, 0.5])); 280 | assert!(root 281 | .iter_children() 282 | .any(|c| c.coordinates() == &vec![-0.5, -0.5, -0.5])); 283 | 284 | assert!(!root.divide()); 285 | } 286 | 287 | #[test] 288 | pub fn get_adjacent_trees_dimension_one() { 289 | let root = TpnTree::<()>::root(1.0, 1); 290 | 291 | let adjacent_trees = root.adjacent_trees(); 292 | 293 | assert!(adjacent_trees.iter().any(|c| c.coordinates() == &vec![2.0])); 294 | assert!(adjacent_trees 295 | .iter() 296 | .any(|c| c.coordinates() == &vec![-2.0])); 297 | } 298 | 299 | #[test] 300 | pub fn get_adjacent_trees_dimension_two() { 301 | let root = TpnTree::<()>::root(1.0, 2); 302 | 303 | let adjacent_trees = root.adjacent_trees(); 304 | 305 | assert!(adjacent_trees 306 | .iter() 307 | .any(|c| c.coordinates() == &vec![0.0, 2.0])); 308 | assert!(adjacent_trees 309 | .iter() 310 | .any(|c| c.coordinates() == &vec![0.0, -2.0])); 311 | 312 | assert!(adjacent_trees 313 | .iter() 314 | .any(|c| c.coordinates() == &vec![2.0, 0.0])); 315 | assert!(adjacent_trees 316 | .iter() 317 | .any(|c| c.coordinates() == &vec![-2.0, 0.0])); 318 | } 319 | } 320 | --------------------------------------------------------------------------------