1use he3d_math::Vec3;
2
3#[derive(Clone, Copy, Debug, PartialEq)]
6pub struct Aabb {
7 pub min: Vec3,
10 pub max: Vec3,
13}
14
15impl Aabb {
16 #[must_use]
19 pub fn new(a: Vec3, b: Vec3) -> Self {
20 Self {
21 min: a.min(b),
22 max: a.max(b),
23 }
24 }
25
26 #[must_use]
29 pub fn from_center_half_extents(center: Vec3, half_extents: Vec3) -> Self {
30 Self {
31 min: center - half_extents,
32 max: center + half_extents,
33 }
34 }
35
36 #[must_use]
39 pub fn center(&self) -> Vec3 {
40 (self.min + self.max) * 0.5
41 }
42
43 #[must_use]
46 pub fn half_extents(&self) -> Vec3 {
47 (self.max - self.min) * 0.5
48 }
49
50 #[must_use]
53 pub fn overlaps(&self, other: &Self) -> bool {
54 self.min.cmple(other.max).all() && self.max.cmpge(other.min).all()
55 }
56
57 #[must_use]
60 pub fn merged(&self, other: &Self) -> Self {
61 Self {
62 min: self.min.min(other.min),
63 max: self.max.max(other.max),
64 }
65 }
66
67 #[must_use]
70 pub fn contains_point(&self, point: Vec3) -> bool {
71 point.cmpge(self.min).all() && point.cmple(self.max).all()
72 }
73
74 #[must_use]
77 pub fn expanded(&self, margin: f32) -> Self {
78 let margin = Vec3::splat(margin);
79 Self {
80 min: self.min - margin,
81 max: self.max + margin,
82 }
83 }
84}
85
86#[cfg(test)]
87mod tests {
88 use super::Aabb;
89 use he3d_math::Vec3;
90
91 #[test]
92 fn orders_corners() {
93 let aabb = Aabb::new(Vec3::new(1.0, 2.0, 3.0), Vec3::new(-1.0, -2.0, -3.0));
94 assert_eq!(aabb.min, Vec3::new(-1.0, -2.0, -3.0));
95 assert_eq!(aabb.max, Vec3::new(1.0, 2.0, 3.0));
96 }
97
98 #[test]
99 fn touching_faces_overlap() {
100 let a = Aabb::from_center_half_extents(Vec3::ZERO, Vec3::ONE);
101 let b = Aabb::from_center_half_extents(Vec3::new(2.0, 0.0, 0.0), Vec3::ONE);
102 assert!(a.overlaps(&b));
103 }
104
105 #[test]
106 fn separated_boxes_do_not_overlap() {
107 let a = Aabb::from_center_half_extents(Vec3::ZERO, Vec3::ONE);
108 let b = Aabb::from_center_half_extents(Vec3::new(2.5, 0.0, 0.0), Vec3::ONE);
109 assert!(!a.overlaps(&b));
110 }
111}