ncollide3d/bounding_volume/
aabb.rs

1//! Axis Aligned Bounding Box.
2
3use crate::bounding_volume::{BoundingSphere, BoundingVolume, HasBoundingVolume};
4use crate::math::{Isometry, Point, Vector, DIM};
5use crate::utils::IsometryOps;
6use na::{self, RealField};
7
8// Seems useful to help type inference. See issue #84.
9/// Computes the axis-aligned bounding box of a shape `g` transformed by `m`.
10///
11/// Same as `g.aabb(m)`.
12#[inline]
13pub fn aabb<N, G: ?Sized>(g: &G, m: &Isometry<N>) -> AABB<N>
14where
15    N: RealField + Copy,
16    G: HasBoundingVolume<N, AABB<N>>,
17{
18    g.bounding_volume(m)
19}
20
21// Seems useful to help type inference. See issue #84.
22/// Computes the axis-aligned bounding box of a shape `g`.
23///
24/// Same as `g.local_aabb(m)`.
25#[inline]
26pub fn local_aabb<N, G: ?Sized>(g: &G) -> AABB<N>
27where
28    N: RealField + Copy,
29    G: HasBoundingVolume<N, AABB<N>>,
30{
31    g.local_bounding_volume()
32}
33
34/// An Axis Aligned Bounding Box.
35#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
36#[derive(Debug, PartialEq, Copy, Clone)]
37pub struct AABB<N: RealField + Copy> {
38    pub mins: Point<N>,
39    pub maxs: Point<N>,
40}
41
42impl<N: RealField + Copy> AABB<N> {
43    /// Creates a new AABB.
44    ///
45    /// # Arguments:
46    ///   * `mins` - position of the point with the smallest coordinates.
47    ///   * `maxs` - position of the point with the highest coordinates. Each component of `mins`
48    ///   must be smaller than the related components of `maxs`.
49    #[inline]
50    pub fn new(mins: Point<N>, maxs: Point<N>) -> AABB<N> {
51        AABB { mins, maxs }
52    }
53
54    /// Creates an invalid AABB with `mins` components set to `N::max_values` and `maxs`components set to `-N::max_values`.
55    ///
56    /// This is often used as the initial values of some AABB merging algorithms.
57    #[inline]
58    pub fn new_invalid() -> Self {
59        Self::new(
60            Vector::repeat(N::max_value().unwrap()).into(),
61            Vector::repeat(-N::max_value().unwrap()).into(),
62        )
63    }
64
65    /// Creates a new AABB from its center and its half-extents.
66    #[inline]
67    pub fn from_half_extents(center: Point<N>, half_extents: Vector<N>) -> Self {
68        Self::new(center - half_extents, center + half_extents)
69    }
70
71    /// Creates a new AABB from a set of points.
72    pub fn from_points<'a, I>(pts: I) -> Self
73    where
74        I: IntoIterator<Item = &'a Point<N>>,
75    {
76        super::aabb_utils::local_point_cloud_aabb(pts)
77    }
78
79    /// Reference to the AABB point with the smallest components along each axis.
80    #[inline]
81    #[deprecated(note = "use the `.mins` public field instead.")]
82    pub fn mins(&self) -> &Point<N> {
83        &self.mins
84    }
85
86    /// Reference to the AABB point with the biggest components along each axis.
87    #[inline]
88    #[deprecated(note = "use the `.maxs` public field instead.")]
89    pub fn maxs(&self) -> &Point<N> {
90        &self.maxs
91    }
92
93    /// The center of this AABB.
94    #[inline]
95    pub fn center(&self) -> Point<N> {
96        na::center(&self.mins, &self.maxs)
97    }
98
99    /// The half extents of this AABB.
100    #[inline]
101    pub fn half_extents(&self) -> Vector<N> {
102        let half: N = na::convert(0.5);
103        (self.maxs - self.mins) * half
104    }
105
106    /// The extents of this AABB.
107    #[inline]
108    pub fn extents(&self) -> Vector<N> {
109        self.maxs - self.mins
110    }
111
112    /// Enlarges this AABB so it also contains the point `pt`.
113    pub fn take_point(&mut self, pt: Point<N>) {
114        self.mins = self.mins.coords.inf(&pt.coords).into();
115        self.maxs = self.maxs.coords.sup(&pt.coords).into();
116    }
117
118    /// Computes the AABB bounding `self` transformed by `m`.
119    #[inline]
120    pub fn transform_by(&self, m: &Isometry<N>) -> Self {
121        let ls_center = self.center();
122        let center = m * ls_center;
123        let ws_half_extents = m.absolute_transform_vector(&self.half_extents());
124
125        AABB::new(center + (-ws_half_extents), center + ws_half_extents)
126    }
127
128    /// The smallest bounding sphere containing this AABB.
129    #[inline]
130    pub fn bounding_sphere(&self) -> BoundingSphere<N> {
131        let center = self.center();
132        let rad = na::distance(&self.mins, &self.maxs);
133
134        BoundingSphere::new(center, rad)
135    }
136
137    #[inline]
138    pub fn contains_local_point(&self, point: &Point<N>) -> bool {
139        for i in 0..DIM {
140            if point[i] < self.mins[i] || point[i] > self.maxs[i] {
141                return false;
142            }
143        }
144
145        true
146    }
147}
148
149impl<N: RealField + Copy> BoundingVolume<N> for AABB<N> {
150    #[inline]
151    fn center(&self) -> Point<N> {
152        self.center()
153    }
154
155    #[inline]
156    fn intersects(&self, other: &AABB<N>) -> bool {
157        na::partial_le(&self.mins, &other.maxs) && na::partial_ge(&self.maxs, &other.mins)
158    }
159
160    #[inline]
161    fn contains(&self, other: &AABB<N>) -> bool {
162        na::partial_le(&self.mins, &other.mins) && na::partial_ge(&self.maxs, &other.maxs)
163    }
164
165    #[inline]
166    fn merge(&mut self, other: &AABB<N>) {
167        self.mins = self.mins.inf(&other.mins);
168        self.maxs = self.maxs.sup(&other.maxs);
169    }
170
171    #[inline]
172    fn merged(&self, other: &AABB<N>) -> AABB<N> {
173        AABB {
174            mins: self.mins.inf(&other.mins),
175            maxs: self.maxs.sup(&other.maxs),
176        }
177    }
178
179    #[inline]
180    fn loosen(&mut self, amount: N) {
181        assert!(
182            amount >= na::zero(),
183            "The loosening margin must be positive."
184        );
185        self.mins = self.mins + Vector::repeat(-amount);
186        self.maxs = self.maxs + Vector::repeat(amount);
187    }
188
189    #[inline]
190    fn loosened(&self, amount: N) -> AABB<N> {
191        assert!(
192            amount >= na::zero(),
193            "The loosening margin must be positive."
194        );
195        AABB {
196            mins: self.mins + Vector::repeat(-amount),
197            maxs: self.maxs + Vector::repeat(amount),
198        }
199    }
200
201    #[inline]
202    fn tighten(&mut self, amount: N) {
203        assert!(
204            amount >= na::zero(),
205            "The tightening margin must be positive."
206        );
207        self.mins = self.mins + Vector::repeat(amount);
208        self.maxs = self.maxs + Vector::repeat(-amount);
209        assert!(
210            na::partial_le(&self.mins, &self.maxs),
211            "The tightening margin is to large."
212        );
213    }
214
215    #[inline]
216    fn tightened(&self, amount: N) -> AABB<N> {
217        assert!(
218            amount >= na::zero(),
219            "The tightening margin must be positive."
220        );
221
222        AABB::new(
223            self.mins + Vector::repeat(amount),
224            self.maxs + Vector::repeat(-amount),
225        )
226    }
227}