use glam::DVec3;
use tracing::warn;
pub trait Locate<T: ?Sized> {
fn locate(&self, target: &T) -> DVec3;
}
impl<T: ?Sized> Locate<T> for DVec3 {
fn locate(&self, _target: &T) -> DVec3 {
*self
}
}
pub struct Centroid;
impl Locate<DVec3> for Centroid {
fn locate(&self, target: &DVec3) -> DVec3 {
*target
}
}
impl<T> Locate<[T]> for Centroid
where
Centroid: Locate<T>,
{
fn locate(&self, target: &[T]) -> DVec3 {
target.iter().map(|x| self.locate(x)).sum::<DVec3>() / target.len() as f64
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct AabbPoint(pub DVec3);
impl AabbPoint {
pub const CENTER: Self = Self(DVec3::ZERO);
}
impl<T: Aabb + ?Sized> Locate<T> for AabbPoint {
fn locate(&self, target: &T) -> DVec3 {
let center = target.aabb_center();
let half_size = target.aabb_size() / 2.0;
center + self.0 * half_size
}
}
pub trait Aabb {
fn aabb(&self) -> [DVec3; 2];
fn aabb_size(&self) -> DVec3 {
let [min, max] = self.aabb();
max - min
}
fn aabb_center(&self) -> DVec3 {
let [min, max] = self.aabb();
(max + min) / 2.0
}
}
impl Aabb for DVec3 {
fn aabb(&self) -> [DVec3; 2] {
[*self; 2]
}
}
impl<T: Aabb> Aabb for [T] {
fn aabb(&self) -> [DVec3; 2] {
let [min, max] = self
.iter()
.map(|x| x.aabb())
.reduce(|[acc_min, acc_max], [min, max]| [acc_min.min(min), acc_max.max(max)])
.unwrap_or([DVec3::ZERO, DVec3::ZERO]);
if min == max {
warn!("Empty bounding box, is the slice empty?")
}
[min, max]
}
}
impl<T: Aabb> Aabb for Vec<T> {
fn aabb(&self) -> [DVec3; 2] {
self.as_slice().aabb()
}
}