kdtree/src/lib.rs

217 lines
5.9 KiB
Rust
Raw Normal View History

2018-03-05 14:10:50 +01:00
use std::cmp::Ordering;
2022-08-16 15:40:46 +02:00
use std::fmt;
2018-03-05 10:37:48 +01:00
2018-03-08 16:33:03 +01:00
pub enum Side {
Left,
Right,
}
2018-03-05 11:17:50 +01:00
/// A k-dimension kd tree
2018-03-05 11:44:43 +01:00
pub enum KdTree<T> {
2018-03-05 14:10:50 +01:00
Node {
location: T,
left: Box<KdTree<T>>,
right: Box<KdTree<T>>,
},
2018-03-05 11:44:43 +01:00
Leaf(Vec<T>),
2018-03-05 11:17:50 +01:00
}
2018-03-05 10:37:48 +01:00
2022-08-16 15:40:46 +02:00
impl<T: Clone> KdTree<T> {
pub fn min_leaf_size<F: Fn(usize, &T, &T) -> Ordering>(
2018-03-05 14:10:50 +01:00
points: &mut [T],
dimension: usize,
comparator: F,
leaf_size: usize,
) -> KdTree<T> {
2018-03-08 16:33:03 +01:00
// Compute bounding box of points
2022-08-16 15:40:46 +02:00
KdTree::min_leaf_size_with_depth(points, dimension, &comparator, leaf_size, 0)
2018-03-05 11:17:50 +01:00
}
2018-03-05 10:37:48 +01:00
2022-08-16 15:40:46 +02:00
fn min_leaf_size_with_depth<F: Fn(usize, &T, &T) -> Ordering>(
2018-03-05 14:10:50 +01:00
points: &mut [T],
dimension: usize,
comparator: &F,
leaf_size: usize,
depth: usize,
) -> KdTree<T> {
2018-03-05 11:17:50 +01:00
// Select axis to work on
let axis = depth % dimension;
2018-03-05 10:37:48 +01:00
2018-03-05 11:17:50 +01:00
// Sort the points by axis
2018-03-05 14:10:50 +01:00
points.sort_by(|a, b| comparator(axis, a, b));
2018-03-05 10:37:48 +01:00
2018-03-05 11:17:50 +01:00
// Find the median
let len = points.len();
2018-03-05 11:44:43 +01:00
// If there are not enough elements for a leaf, make a leaf
if len <= leaf_size {
2018-03-05 14:10:50 +01:00
let mut contained = vec![];
for p in points {
contained.push(p.clone());
}
2018-03-05 11:44:43 +01:00
return KdTree::Leaf(contained);
}
// Else split what's remaining
2018-03-05 11:17:50 +01:00
let delimiter = points.len() / 2;
2018-03-05 14:10:50 +01:00
let median = points[delimiter].clone();
2018-03-05 10:37:48 +01:00
2018-03-05 11:44:43 +01:00
// Build the left and right branches
2018-03-05 14:10:50 +01:00
let mut left = vec![];
2018-03-20 16:01:01 +01:00
for i in &points[0..delimiter + 1] {
2018-03-05 14:10:50 +01:00
left.push(i.clone());
}
2018-03-05 10:37:48 +01:00
2018-03-05 14:10:50 +01:00
let right = &mut points[delimiter + 1..len];
2018-03-05 10:37:48 +01:00
2018-03-05 11:44:43 +01:00
// Recursive call
KdTree::Node {
location: median,
2022-08-16 15:40:46 +02:00
left: Box::new(KdTree::min_leaf_size_with_depth(
2018-03-05 14:10:50 +01:00
&mut left,
dimension,
comparator,
leaf_size,
depth + 1,
)),
2022-08-16 15:40:46 +02:00
right: Box::new(KdTree::min_leaf_size_with_depth(
2018-03-05 14:10:50 +01:00
right,
dimension,
comparator,
leaf_size,
depth + 1,
)),
2018-03-05 10:37:48 +01:00
}
2018-03-05 11:17:50 +01:00
}
2018-03-08 16:33:03 +01:00
2022-08-16 15:40:46 +02:00
pub fn max_depth<F: Fn(usize, &T, &T) -> Ordering>(
points: &mut [T],
dimension: usize,
comparator: F,
max_depth: usize,
) -> KdTree<T> {
// Compute bounding box of points
KdTree::max_depth_with_depth(points, dimension, &comparator, max_depth, 0)
}
fn max_depth_with_depth<F: Fn(usize, &T, &T) -> Ordering>(
points: &mut [T],
dimension: usize,
comparator: &F,
max_depth: usize,
depth: usize,
) -> KdTree<T> {
// Select axis to work on
let axis = depth % dimension;
// Sort the points by axis
points.sort_by(|a, b| comparator(axis, a, b));
// Find the median
let len = points.len();
// If we reached max depth, make a leaf
if depth >= max_depth {
let mut contained = vec![];
for p in points {
contained.push(p.clone());
}
return KdTree::Leaf(contained);
}
// Else split what's remaining
let delimiter = points.len() / 2;
let median = points[delimiter].clone();
// Build the left and right branches
let mut left = vec![];
for i in &points[0..delimiter + 1] {
left.push(i.clone());
}
let right = &mut points[delimiter + 1..len];
// Recursive call
KdTree::Node {
location: median,
left: Box::new(KdTree::max_depth_with_depth(
&mut left,
dimension,
comparator,
max_depth,
depth + 1,
)),
right: Box::new(KdTree::max_depth_with_depth(
right,
dimension,
comparator,
max_depth,
depth + 1,
)),
}
}
2018-03-08 16:33:03 +01:00
// Fn(location, elements)
pub fn traverse_leaves<F: FnMut(&Vec<(T, Side)>, &Vec<T>)>(&self, callback: &mut F) {
self.traverse_leaves_aux(callback, &mut vec![])
}
2022-08-16 15:40:46 +02:00
pub fn traverse_leaves_aux<F: FnMut(&Vec<(T, Side)>, &Vec<T>)>(
&self,
callback: &mut F,
locations: &mut Vec<(T, Side)>,
) {
2018-03-08 16:33:03 +01:00
// Compute the full bounding box of the points
match *self {
2022-08-16 15:40:46 +02:00
KdTree::Node {
ref location,
ref left,
ref right,
} => {
2018-03-08 16:33:03 +01:00
locations.push((location.clone(), Side::Left));
left.traverse_leaves_aux(callback, locations);
locations.pop();
locations.push((location.clone(), Side::Right));
right.traverse_leaves_aux(callback, locations);
locations.pop();
2022-08-16 15:40:46 +02:00
}
2018-03-08 16:33:03 +01:00
KdTree::Leaf(ref elements) => {
callback(locations, elements);
}
}
}
2018-03-05 11:17:50 +01:00
}
2018-03-05 10:37:48 +01:00
2018-03-05 14:10:50 +01:00
impl<T: fmt::Display> KdTree<T> {
2018-03-05 11:17:50 +01:00
fn print(&self, formatter: &mut fmt::Formatter, indent: &str) -> fmt::Result {
2018-03-05 11:44:43 +01:00
match self {
2022-08-16 15:40:46 +02:00
&KdTree::Node {
ref location,
ref left,
ref right,
} => {
2018-03-05 11:44:43 +01:00
writeln!(formatter, "{}{}", indent, location)?;
left.print(formatter, &format!("{} ", indent))?;
right.print(formatter, &format!("{} ", indent))?;
2018-03-05 14:10:50 +01:00
}
2018-03-05 11:44:43 +01:00
&KdTree::Leaf(ref elements) => {
write!(formatter, "{}[", indent)?;
for element in elements {
write!(formatter, "{}, ", element)?;
}
writeln!(formatter, "]")?;
2018-03-05 14:10:50 +01:00
}
2018-03-05 10:37:48 +01:00
}
2018-03-05 11:17:50 +01:00
Ok(())
2018-03-05 10:37:48 +01:00
}
}
2018-03-05 14:10:50 +01:00
impl<T: fmt::Display> fmt::Display for KdTree<T> {
2018-03-05 11:17:50 +01:00
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
self.print(formatter, "")
}
}