use he3d_math::Vec3;
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Aabb {
pub min: Vec3,
pub max: Vec3,
}
impl Aabb {
#[must_use]
pub fn new(a: Vec3, b: Vec3) -> Self {
Self {
min: a.min(b),
max: a.max(b),
}
}
#[must_use]
pub fn from_center_half_extents(center: Vec3, half_extents: Vec3) -> Self {
Self {
min: center - half_extents,
max: center + half_extents,
}
}
#[must_use]
pub fn center(&self) -> Vec3 {
(self.min + self.max) * 0.5
}
#[must_use]
pub fn half_extents(&self) -> Vec3 {
(self.max - self.min) * 0.5
}
#[must_use]
pub fn overlaps(&self, other: &Self) -> bool {
self.min.cmple(other.max).all() && self.max.cmpge(other.min).all()
}
#[must_use]
pub fn merged(&self, other: &Self) -> Self {
Self {
min: self.min.min(other.min),
max: self.max.max(other.max),
}
}
#[must_use]
pub fn contains_point(&self, point: Vec3) -> bool {
point.cmpge(self.min).all() && point.cmple(self.max).all()
}
#[must_use]
pub fn expanded(&self, margin: f32) -> Self {
let margin = Vec3::splat(margin);
Self {
min: self.min - margin,
max: self.max + margin,
}
}
}
#[cfg(test)]
mod tests {
use super::Aabb;
use he3d_math::Vec3;
#[test]
fn orders_corners() {
let aabb = Aabb::new(Vec3::new(1.0, 2.0, 3.0), Vec3::new(-1.0, -2.0, -3.0));
assert_eq!(aabb.min, Vec3::new(-1.0, -2.0, -3.0));
assert_eq!(aabb.max, Vec3::new(1.0, 2.0, 3.0));
}
#[test]
fn touching_faces_overlap() {
let a = Aabb::from_center_half_extents(Vec3::ZERO, Vec3::ONE);
let b = Aabb::from_center_half_extents(Vec3::new(2.0, 0.0, 0.0), Vec3::ONE);
assert!(a.overlaps(&b));
}
#[test]
fn separated_boxes_do_not_overlap() {
let a = Aabb::from_center_half_extents(Vec3::ZERO, Vec3::ONE);
let b = Aabb::from_center_half_extents(Vec3::new(2.5, 0.0, 0.0), Vec3::ONE);
assert!(!a.overlaps(&b));
}
}