use crate::compute_method::math::Float;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct BoundingBox<A> {
pub min: A,
pub max: A,
}
impl<A> BoundingBox<A> {
#[inline]
pub const fn new(min: A, max: A) -> Self {
Self { min, max }
}
}
impl<const D: usize, S> Default for BoundingBox<[S; D]>
where
S: Copy + Float,
{
#[inline]
fn default() -> Self {
Self::new([S::infinity(); D], [-S::infinity(); D])
}
}
#[allow(clippy::needless_range_loop)]
impl<const D: usize, S> BoundingBox<[S; D]>
where
S: Copy + Float,
{
#[inline]
pub fn extend(&mut self, position: [S; D]) {
for i in 0..D {
self.min[i] = self.min[i].min(position[i]);
self.max[i] = self.max[i].max(position[i]);
}
}
#[inline]
pub fn with<I>(positions: I) -> Self
where
I: Iterator<Item = [S; D]>,
{
let mut result = Self::default();
for position in positions {
result.extend(position);
}
result
}
#[inline]
pub fn square_with<I>(positions: I) -> Self
where
I: Iterator<Item = [S; D]>,
{
let mut result = Self::with(positions);
let center = result.center();
let half_length = result
.size()
.into_iter()
.fold(S::ZERO, S::max)
.mean(S::ZERO);
for i in 0..D {
result.min[i] = center[i] - half_length;
result.max[i] = center[i] + half_length;
}
result
}
#[inline]
pub fn center(&self) -> [S; D] {
let mut r = [S::ZERO; D];
for i in 0..D {
r[i] = self.min[i].mean(self.max[i]);
}
r
}
#[inline]
pub fn size(&self) -> [S; D] {
let mut r = [S::ZERO; D];
for i in 0..D {
r[i] = self.max[i] - self.min[i];
}
r
}
#[inline]
pub fn width(&self) -> S {
self.size()[0]
}
}
#[allow(clippy::needless_range_loop)]
impl<const X: usize, const D: usize, S> BoundingBox<[S; D]>
where
Self: SubDivide<Division = [Self; X]>,
S: Copy + Float,
{
#[inline]
pub fn subdivide(&self) -> [Self; X] {
let bbox_min = self.min;
let bbox_max = self.max;
let bbox_center = self.center();
let mut result = [Self::default(); X];
for i in 0..X {
let mut corner_min = [S::ZERO; D];
let mut corner_max = [S::ZERO; D];
for j in 0..D {
if i & (1 << j) == 0 {
corner_min[j] = bbox_center[j];
corner_max[j] = bbox_max[j];
} else {
corner_min[j] = bbox_min[j];
corner_max[j] = bbox_center[j];
}
}
result[i] = Self::new(corner_min, corner_max);
}
result
}
}
pub type Orthant<const X: usize, N> = [Option<N>; X];
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct SizedOrthant<const X: usize, const D: usize, N, S> {
pub orthant: Orthant<X, N>,
pub bbox: BoundingBox<[S; D]>,
}
pub trait SubDivide {
type Division;
}
macro_rules! impl_subdivide {
($($dim: literal),*) => {$(
impl<S> SubDivide for BoundingBox<[S; $dim]> {
type Division = [Self; 2usize.pow($dim)];
}
)*};
}
impl_subdivide!(1, 2, 3, 4, 5, 6, 7, 8, 9);