use crate::math::vec::Vector3;
use crate::geometry::{Encloses, Intersects, Plane, Point3};
pub struct AABB {
min: Point3,
max: Point3,
}
impl AABB {
pub fn from_points(p0: &Point3, p1: &Point3) -> Self {
Self {
min: p0.min(p1),
max: p0.max(p1),
}
}
pub const fn from_corners(top_left: &Point3, bottom_right: &Point3) -> Self {
Self {
min: *top_left,
max: *bottom_right,
}
}
}
impl AABB {
pub const TOP_NORMAL: Vector3 = Vector3::UNIT_Y;
pub const BOTTOM_NORMAL: Vector3 = Vector3::NEG_UNIT_Y;
pub const FRONT_NORMAL: Vector3 = Vector3::UNIT_Z;
pub const BACK_NORMAL: Vector3 = Vector3::NEG_UNIT_Z;
pub const LEFT_NORMAL: Vector3 = Vector3::NEG_UNIT_X;
pub const RIGHT_NORMAL: Vector3 = Vector3::UNIT_X;
#[inline(always)]
pub const fn top_plane(&self) -> Plane {
Plane::from_normal_distance(Vector3::UNIT_Y.as_vec3(), self.max.as_vec3().y())
}
#[inline(always)]
pub const fn bottom_plane(&self) -> Plane {
Plane::from_normal_distance(Vector3::NEG_UNIT_Y.as_vec3(), self.min.as_vec3().y())
}
#[inline(always)]
pub const fn front_plane(&self) -> Plane {
Plane::from_normal_distance(Vector3::UNIT_Z.as_vec3(), self.min.as_vec3().z())
}
#[inline(always)]
pub const fn back_plane(&self) -> Plane {
Plane::from_normal_distance(Vector3::NEG_UNIT_Z.as_vec3(), self.max.as_vec3().z())
}
#[inline(always)]
pub fn left_plane(&self) -> Plane {
Plane::from_normal_distance(Vector3::NEG_UNIT_X.as_vec3(), self.min.as_vec3().x())
}
#[inline(always)]
pub const fn right_plane(&self) -> Plane {
Plane::from_normal_distance(Vector3::UNIT_X.as_vec3(), self.max.as_vec3().x())
}
pub const fn top(&self) -> Vector3 {
Vector3::new(0.0, self.max.as_vec3().y(), 0.0)
}
pub const fn bottom(&self) -> Vector3 {
Vector3::new(0.0, self.min.as_vec3().y(), 0.0)
}
pub const fn front(&self) -> Vector3 {
Vector3::new(0.0, 0.0, self.min.as_vec3().z())
}
pub const fn back(&self) -> Vector3 {
Vector3::new(0.0, 0.0, self.max.as_vec3().z())
}
pub const fn left(&self) -> Vector3 {
Vector3::new(self.min.as_vec3().x(), 0.0, 0.0)
}
pub const fn right(&self) -> Vector3 {
Vector3::new(self.max.as_vec3().x(), 0.0, 0.0)
}
pub const fn min(&self) -> &Point3 {
&self.min
}
pub const fn max(&self) -> &Point3 {
&self.max
}
pub fn center(&self) -> Point3 {
const HALF: f32 = 0.5;
Point3::new(
(self.min.x() + self.max.x()) * HALF,
(self.min.y() + self.max.y()) * HALF,
(self.min.z() + self.max.z()) * HALF,
)
}
pub fn size(&self) -> Vector3 {
Vector3::from_points(&self.min, &self.max)
}
pub fn volume(&self) -> f32 {
let size = self.size();
size.x() * size.y() * size.z()
}
pub fn planes(&self) -> [Plane; 6] {
[
self.top_plane(),
self.bottom_plane(),
self.front_plane(),
self.back_plane(),
self.left_plane(),
self.right_plane(),
]
}
pub fn vectors(&self) -> [Vector3; 6] {
[
self.top(),
self.bottom(),
self.front(),
self.back(),
self.left(),
self.right(),
]
}
}
impl AABB {
pub fn contains_point(&self, point: &Point3) -> bool {
self.min.x() <= point.x()
&& self.min.y() <= point.y()
&& self.min.z() <= point.z()
&& self.max.x() >= point.x()
&& self.max.y() >= point.y()
&& self.max.z() >= point.z()
}
}
impl Intersects for AABB {
fn intersects(&self, other: &Self) -> bool {
self.min.x() <= other.max.x()
&& self.min.y() <= other.max.y()
&& self.min.z() <= other.max.z()
&& self.max.x() >= other.min.x()
&& self.max.y() >= other.min.y()
&& self.max.z() >= other.min.z()
}
}
impl Encloses for AABB {
fn encloses(&self, other: &Self) -> bool {
self.min.x() <= other.min.x()
&& self.min.y() <= other.min.y()
&& self.min.z() <= other.min.z()
&& self.max.x() >= other.max.x()
&& self.max.y() >= other.max.y()
&& self.max.z() >= other.max.z()
}
}
impl Encloses<Point3> for AABB {
fn encloses(&self, point: &Point3) -> bool {
self.contains_point(point)
}
}
impl AABB {
pub fn nearest_point(&self, point: &Point3) -> Point3 {
Point3::new(
point.x().max(self.min.x()).min(self.max.x()),
point.y().max(self.min.y()).min(self.max.y()),
point.z().max(self.min.z()).min(self.max.z()),
)
}
pub fn distance_to(&self, point: &Point3) -> f32 {
Vector3::from_points(&self.nearest_point(point), point).magnitude()
}
pub fn square_distance_to(&self, point: &Point3) -> f32 {
Vector3::from_points(&self.nearest_point(point), point).square_magnitude()
}
}
#[cfg(test)]
#[path = "aabb.test.rs"]
mod test;