use crate::vec3::Vec3;
#[derive(Clone, Copy, PartialEq, Debug)]
pub struct Aabb {
pub min: [f64; 3],
pub max: [f64; 3],
}
impl Aabb {
#[inline]
pub fn new(min: [f64; 3], max: [f64; 3]) -> Self {
Self { min, max }
}
pub fn from_positions(positions: &[f64]) -> Aabb {
if positions.len() < 3 {
return Aabb::new([0.0, 0.0, 0.0], [0.0, 0.0, 0.0]);
}
let mut min = [f64::INFINITY; 3];
let mut max = [f64::NEG_INFINITY; 3];
let mut i = 0;
while i + 2 < positions.len() {
for axis in 0..3 {
let v = positions[i + axis];
if v < min[axis] {
min[axis] = v;
}
if v > max[axis] {
max[axis] = v;
}
}
i += 3;
}
Aabb::new(min, max)
}
#[inline]
pub fn inflate(&self, m: f64) -> Aabb {
Aabb::new(
[self.min[0] - m, self.min[1] - m, self.min[2] - m],
[self.max[0] + m, self.max[1] + m, self.max[2] + m],
)
}
#[inline]
pub fn center(&self) -> Vec3 {
[
(self.min[0] + self.max[0]) / 2.0,
(self.min[1] + self.max[1]) / 2.0,
(self.min[2] + self.max[2]) / 2.0,
]
}
#[inline]
pub fn intersects(&self, b: &Aabb) -> bool {
self.min[0] <= b.max[0]
&& self.max[0] >= b.min[0]
&& self.min[1] <= b.max[1]
&& self.max[1] >= b.min[1]
&& self.min[2] <= b.max[2]
&& self.max[2] >= b.min[2]
}
}
pub fn signed_gap(a: &Aabb, b: &Aabb) -> f64 {
let mut squared_distance = 0.0;
let mut min_overlap = f64::INFINITY;
let mut penetrating = true;
for i in 0..3 {
let gap = (b.min[i] - a.max[i]).max(a.min[i] - b.max[i]);
if gap > 0.0 {
squared_distance += gap * gap;
penetrating = false;
} else {
let overlap = a.max[i].min(b.max[i]) - a.min[i].max(b.min[i]);
if overlap < min_overlap {
min_overlap = overlap;
}
}
}
if penetrating {
-min_overlap
} else {
squared_distance.sqrt()
}
}
pub fn overlap_bounds(a: &Aabb, b: &Aabb) -> Aabb {
let mut min = [
a.min[0].max(b.min[0]),
a.min[1].max(b.min[1]),
a.min[2].max(b.min[2]),
];
let mut max = [
a.max[0].min(b.max[0]),
a.max[1].min(b.max[1]),
a.max[2].min(b.max[2]),
];
for i in 0..3 {
if max[i] < min[i] {
let mid = (min[i] + max[i]) / 2.0;
min[i] = mid;
max[i] = mid;
}
}
Aabb::new(min, max)
}
pub fn bounds_of_points(a: Vec3, b: Vec3) -> Aabb {
Aabb::new(
[a[0].min(b[0]), a[1].min(b[1]), a[2].min(b[2])],
[a[0].max(b[0]), a[1].max(b[1]), a[2].max(b[2])],
)
}
#[inline]
pub fn aabb_contains(outer: &Aabb, inner: &Aabb) -> bool {
outer.min[0] <= inner.min[0]
&& outer.max[0] >= inner.max[0]
&& outer.min[1] <= inner.min[1]
&& outer.max[1] >= inner.max[1]
&& outer.min[2] <= inner.min[2]
&& outer.max[2] >= inner.max[2]
}