#![forbid(unsafe_code)]
#![deny(missing_docs, missing_debug_implementations)]
mod build;
mod iter;
mod look_up;
mod nearest;
pub use build::DEF_NODE_LEN;
use std::marker::PhantomData;
use std::num::NonZeroUsize;
use std::ops::Deref;
use num_traits::{Num, Zero};
#[cfg(feature = "serde")]
use serde::{de::DeserializeOwned, Deserialize, Serialize};
pub trait Point: Clone {
const DIM: usize;
type Coord: Num + Copy + PartialOrd;
fn coord(&self, axis: usize) -> Self::Coord;
fn build<F>(f: F) -> Self
where
F: FnMut(usize) -> Self::Coord;
fn min(&self, other: &Self) -> Self {
Self::build(|axis| {
let this = self.coord(axis);
let other = other.coord(axis);
if this < other {
this
} else {
other
}
})
}
fn max(&self, other: &Self) -> Self {
Self::build(|axis| {
let this = self.coord(axis);
let other = other.coord(axis);
if this > other {
this
} else {
other
}
})
}
}
impl<T, const N: usize> Point for [T; N]
where
T: Num + Copy + PartialOrd,
{
const DIM: usize = N;
type Coord = T;
#[inline]
fn coord(&self, axis: usize) -> Self::Coord {
self[axis]
}
fn build<F>(mut f: F) -> Self
where
F: FnMut(usize) -> Self::Coord,
{
let mut res = [T::zero(); N];
(0..N).for_each(|axis| res[axis] = f(axis));
res
}
}
impl<T, const N: usize> Distance<[T; N]> for [T; N]
where
T: Num + Copy + PartialOrd,
{
fn distance_2(&self, point: &[T; N]) -> T {
(0..N).fold(T::zero(), |res, axis| {
let diff = self[axis] - point[axis];
res + diff * diff
})
}
}
pub trait Object {
type Point: Point;
fn aabb(&self) -> (Self::Point, Self::Point);
}
pub trait Distance<P>
where
P: Point,
{
fn distance_2(&self, point: &P) -> P::Coord;
fn contains(&self, point: &P) -> bool {
self.distance_2(point) == P::Coord::zero()
}
}
const TWIG_LEN: usize = 4;
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum Node<O>
where
O: Object,
{
Branch {
len: NonZeroUsize,
#[cfg_attr(
feature = "serde",
serde(bound = "O::Point: Serialize + DeserializeOwned")
)]
aabb: (O::Point, O::Point),
},
Twig([usize; TWIG_LEN]),
Leaf(O),
}
const ROOT_IDX: usize = 0;
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(transparent))]
pub struct RTree<O, S = Box<[Node<O>]>>
where
O: Object,
S: AsRef<[Node<O>]>,
{
nodes: S,
_marker: PhantomData<O>,
}
impl<O, S> RTree<O, S>
where
O: Object,
S: AsRef<[Node<O>]>,
{
pub fn new_unchecked(nodes: S) -> Self {
assert!(!nodes.as_ref().is_empty());
Self {
nodes,
_marker: PhantomData,
}
}
pub fn objects(&self) -> impl Iterator<Item = &O> {
self.nodes.as_ref().iter().filter_map(|node| match node {
Node::Branch { .. } | Node::Twig(_) => None,
Node::Leaf(obj) => Some(obj),
})
}
}
impl<O, S> Deref for RTree<O, S>
where
O: Object,
S: AsRef<[Node<O>]>,
{
type Target = [Node<O>];
fn deref(&self) -> &Self::Target {
self.nodes.as_ref()
}
}
impl<O, S> AsRef<[Node<O>]> for RTree<O, S>
where
O: Object,
S: AsRef<[Node<O>]>,
{
fn as_ref(&self) -> &[Node<O>] {
self.nodes.as_ref()
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::cmp::Ordering;
use proptest::{collection::vec, strategy::Strategy};
pub fn random_points(len: usize) -> impl Strategy<Value = Vec<[f32; 3]>> {
(
vec(0.0_f32..=1.0, len),
vec(0.0_f32..=1.0, len),
vec(0.0_f32..=1.0, len),
)
.prop_map(|(x, y, z)| {
x.into_iter()
.zip(y)
.zip(z)
.map(|((x, y), z)| [x, y, z])
.collect()
})
}
#[derive(Debug, Clone, PartialEq)]
pub struct RandomObject(pub [f32; 3], pub [f32; 3]);
impl Eq for RandomObject {}
impl PartialOrd for RandomObject {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for RandomObject {
fn cmp(&self, other: &Self) -> Ordering {
(self.0, self.1).partial_cmp(&(other.0, other.1)).unwrap()
}
}
impl Object for RandomObject {
type Point = [f32; 3];
fn aabb(&self) -> (Self::Point, Self::Point) {
(self.0, self.1)
}
}
impl Distance<[f32; 3]> for RandomObject {
fn distance_2(&self, point: &[f32; 3]) -> f32 {
self.aabb().distance_2(point)
}
fn contains(&self, point: &[f32; 3]) -> bool {
self.aabb().contains(point)
}
}
pub fn random_objects(len: usize) -> impl Strategy<Value = Vec<RandomObject>> {
(random_points(len), random_points(len)).prop_map(|(left, right)| {
left.into_iter()
.zip(right)
.map(|(left, right)| {
let lower = left.min(&right);
let upper = left.max(&right);
RandomObject(lower, upper)
})
.collect()
})
}
}