mesh_geometry/utils/
aabb.rs

1use crate::{Float, Point3};
2
3/// Axis-aligned bounding box in 3D.
4#[derive(Debug, Clone, Copy, PartialEq)]
5pub struct Aabb<T: Float> {
6    /// Minimum corner of the bounding box
7    pub min: Point3<T>,
8    /// Maximum corner of the bounding box
9    pub max: Point3<T>,
10}
11
12impl<T: Float> Aabb<T> {
13    /// Empty box: min=+∞, max=-∞
14    pub fn empty() -> Self {
15        let inf = T::infinity();
16        let neg = T::neg_infinity();
17        Aabb {
18            min: Point3::new(inf, inf, inf),
19            max: Point3::new(neg, neg, neg),
20        }
21    }
22
23    /// Build from a list of points
24    pub fn from_points(pts: &[Point3<T>]) -> Self {
25        let mut bb: Aabb<T> = Aabb::empty();
26        for &p in pts {
27            bb.min.x = bb.min.x.min(p.x);
28            bb.min.y = bb.min.y.min(p.y);
29            bb.min.z = bb.min.z.min(p.z);
30            bb.max.x = bb.max.x.max(p.x);
31            bb.max.y = bb.max.y.max(p.y);
32            bb.max.z = bb.max.z.max(p.z);
33        }
34        bb
35    }
36
37    /// Extend this box to include `p`
38    pub fn grow(&mut self, p: Point3<T>) {
39        self.min.x = self.min.x.min(p.x);
40        self.min.y = self.min.y.min(p.y);
41        self.min.z = self.min.z.min(p.z);
42        self.max.x = self.max.x.max(p.x);
43        self.max.y = self.max.y.max(p.y);
44        self.max.z = self.max.z.max(p.z);
45    }
46
47    /// Test intersection with another AABB
48    pub fn intersects(&self, other: &Aabb<T>) -> bool {
49        !(self.max.x < other.min.x ||
50          self.min.x > other.max.x ||
51          self.max.y < other.min.y ||
52          self.min.y > other.max.y ||
53          self.max.z < other.min.z ||
54          self.min.z > other.max.z)
55    }
56
57    /// Test if `p` is inside (inclusive)
58    pub fn contains(&self, p: Point3<T>) -> bool {
59        p.x >= self.min.x && p.x <= self.max.x &&
60        p.y >= self.min.y && p.y <= self.max.y &&
61        p.z >= self.min.z && p.z <= self.max.z
62    }
63}
64
65#[cfg(test)]
66mod tests {
67    use super::*;
68    use crate::Point3;
69
70    #[test]
71    fn aabb_from_and_contains() {
72        let pts = [
73            Point3::new(-1.0,2.0,0.0),
74            Point3::new(3.0,-2.0,5.0),
75        ];
76        let bb = Aabb::from_points(&pts);
77        assert!(bb.contains(Point3::new(0.0,0.0,2.5)));
78        assert!(!bb.contains(Point3::new(-2.0,0.0,0.0)));
79    }
80
81    #[test]
82    fn aabb_intersect() {
83        let b1 = Aabb {
84            min: Point3::new(0.0,0.0,0.0),
85            max: Point3::new(1.0,1.0,1.0),
86        };
87        let b2 = Aabb {
88            min: Point3::new(0.5,0.5,0.5),
89            max: Point3::new(2.0,2.0,2.0),
90        };
91        assert!(b1.intersects(&b2));
92        let b3 = Aabb {
93            min: Point3::new(2.0,2.0,2.0),
94            max: Point3::new(3.0,3.0,3.0),
95        };
96        assert!(!b1.intersects(&b3));
97    }
98}