use crate::{DeDupError, Scalar};
use vob::Vob;
#[derive(Clone, Debug)]
pub struct Aabb<T: Scalar> {
pub min: [T; 3],
pub max: [T; 3],
}
impl<T: Scalar> Aabb<T> {
pub(crate) fn new_from_checked_data(
input_vertices: &[impl Into<[T; 3]> + Clone + Sync],
used_vertices: &Option<Vob>,
) -> Result<Aabb<T>, DeDupError> {
let mut aabb = Aabb {
min: [T::infinity(); 3],
max: [T::neg_infinity(); 3],
};
let mut update_aabb = |v: [T; 3]| -> Result<(), DeDupError> {
v.finite_check()?;
aabb.extend(v);
Ok(())
};
if let Some(used_vertices) = used_vertices {
for i in used_vertices.iter_set_bits(..) {
update_aabb(input_vertices.ᚦget(i).clone().into())?
}
} else {
for v in input_vertices.iter() {
update_aabb(v.clone().into())?
}
}
Ok(aabb)
}
#[inline(always)]
pub(crate) fn extend(&mut self, point: [T; 3]) {
self.min[0] = self.min[0].min(point[0]);
self.min[1] = self.min[1].min(point[1]);
self.min[2] = self.min[2].min(point[2]);
self.max[0] = self.max[0].max(point[0]);
self.max[1] = self.max[1].max(point[1]);
self.max[2] = self.max[2].max(point[2]);
}
#[inline(always)]
pub(crate) fn center(&self, scale: T) -> [T; 3] {
let inv_scale = T::ONE / scale;
let cx = (((self.min[0] * scale) + (self.max[0] * scale)) / T::TWO) * inv_scale;
let cy = (((self.min[1] * scale) + (self.max[1] * scale)) / T::TWO) * inv_scale;
let cz = (((self.min[2] * scale) + (self.max[2] * scale)) / T::TWO) * inv_scale;
[cx, cy, cz]
}
pub(crate) fn longest_axis_and_center(&self) -> (usize, [T; 3]) {
let mut max_val = self.min[0].abs().max(self.max[0].abs());
max_val = max_val.max(self.min[1].abs().max(self.max[1].abs()));
max_val = max_val.max(self.min[2].abs().max(self.max[2].abs()));
let scale = if max_val > T::QUARTER_OF_MAX {
T::ONE / T::FOUR } else {
T::ONE };
let size_x = (self.max[0] * scale) - (self.min[0] * scale);
let size_y = (self.max[1] * scale) - (self.min[1] * scale);
let size_z = (self.max[2] * scale) - (self.min[2] * scale);
let axis = if size_x >= size_y && size_x >= size_z {
0
} else if size_y >= size_z {
1
} else {
2
};
(axis, self.center(scale))
}
}
pub trait Array3<T: Scalar> {
fn sub(&self, other: [T; 3]) -> [T; 3];
fn get_hash(self) -> (T::Bits, T::Bits, T::Bits);
fn finite_check(self) -> Result<(), DeDupError>;
}
impl<T: Scalar> Array3<T> for [T; 3] {
#[inline(always)]
fn sub(&self, other: [T; 3]) -> [T; 3] {
[self[0] - other[0], self[1] - other[1], self[2] - other[2]]
}
#[inline(always)]
fn get_hash(self) -> (T::Bits, T::Bits, T::Bits) {
let x = self[0] + T::zero();
let y = self[1] + T::zero();
let z = self[2] + T::zero();
(x.to_bits(), y.to_bits(), z.to_bits())
}
#[inline(always)]
fn finite_check(self) -> Result<(), DeDupError> {
if !(self[0].is_finite() && self[1].is_finite() && self[2].is_finite()) {
return Err(DeDupError(
format!("Non finite vertex coordinate found {self:?}").to_string(),
));
}
Ok(())
}
}
pub(crate) trait UnsafeVob {
fn ᚦget(&self, index: usize) -> bool;
fn ᚦset(&mut self, bit: usize, flag: bool);
}
impl UnsafeVob for Vob {
#[cfg(not(debug_assertions))]
#[inline(always)]
fn ᚦget(&self, bit: usize) -> bool {
unsafe { self.get_unchecked(bit) }
}
#[cfg(debug_assertions)]
#[inline(always)]
fn ᚦget(&self, bit: usize) -> bool {
self.get(bit).unwrap()
}
#[cfg(not(debug_assertions))]
#[inline(always)]
fn ᚦset(&mut self, bit: usize, flag: bool) {
unsafe {
let _ = self.set_unchecked(bit, flag);
}
}
#[cfg(debug_assertions)]
#[inline(always)]
fn ᚦset(&mut self, bit: usize, flag: bool) {
let _ = self.set(bit, flag);
}
}
#[allow(dead_code)]
pub(crate) trait UnsafeArray<T> {
fn ᚦget(&self, index: usize) -> &T;
}
impl<T> UnsafeArray<T> for [T] {
#[cfg(debug_assertions)]
#[inline(always)]
fn ᚦget(&self, index: usize) -> &T {
self.get(index).unwrap()
}
#[cfg(not(debug_assertions))]
#[inline(always)]
fn ᚦget(&self, index: usize) -> &T {
unsafe { self.get_unchecked(index) }
}
}