use std::borrow::Cow;
use nalgebra::{allocator::Allocator, DefaultAllocator, DimName, DimNameDiff, DimNameSub, U1};
use rand::RngExt;
use crate::{curve::NurbsCurve, misc::FloatingPoint, split::Split};
use super::{BoundingBox, BoundingBoxTree};
#[derive(Clone)]
pub struct CurveBoundingBoxTree<'a, T: FloatingPoint, D: DimName>
where
DefaultAllocator: Allocator<D>,
{
curve: Cow<'a, NurbsCurve<T, D>>,
tolerance: T,
}
impl<'a, T: FloatingPoint, D: DimName> CurveBoundingBoxTree<'a, T, D>
where
D: DimNameSub<U1>,
DefaultAllocator: Allocator<D>,
DefaultAllocator: Allocator<DimNameDiff<D, U1>>,
{
pub fn new(curve: &'a NurbsCurve<T, D>, tolerance: Option<T>) -> Self {
let tol = tolerance.unwrap_or_else(|| {
let i = curve.knots_domain_interval();
i / T::from_usize(64).unwrap()
});
Self {
curve: Cow::Borrowed(curve),
tolerance: tol,
}
}
pub fn curve(&self) -> &NurbsCurve<T, D> {
self.curve.as_ref()
}
pub fn curve_owned(self) -> NurbsCurve<T, D> {
self.curve.into_owned()
}
}
impl<T: FloatingPoint, D: DimName> BoundingBoxTree<T, D> for CurveBoundingBoxTree<'_, T, D>
where
D: DimNameSub<U1>,
DefaultAllocator: Allocator<D>,
DefaultAllocator: Allocator<DimNameDiff<D, U1>>,
{
fn is_dividable(&self) -> bool {
let interval = self.curve.knots_domain_interval();
interval > self.tolerance || {
match self.curve.degree() {
1 => {
interval >= T::from_f64(1e-4).unwrap() && self.curve.control_points().len() >= 3
}
_ => false,
}
}
}
fn try_divide(&self) -> anyhow::Result<(Self, Self)> {
let (min, max) = self.curve.knots_domain();
let interval = max - min;
let mid = (min + max) / T::from_usize(2).unwrap();
let mut rng = rand::rng();
let r = interval * T::from_f64(1e-1 * (rng.random::<f64>() - 0.5)).unwrap();
let (head, tail) = self.curve.try_split(mid + r)?;
Ok((
Self {
curve: Cow::Owned(head),
tolerance: self.tolerance,
},
Self {
curve: Cow::Owned(tail),
tolerance: self.tolerance,
},
))
}
fn bounding_box(&self) -> BoundingBox<T, DimNameDiff<D, U1>> {
self.curve.as_ref().into()
}
}