parry3d/bounding_volume/
aabb.rs

1//! Axis Aligned Bounding Box.
2
3use crate::bounding_volume::{BoundingSphere, BoundingVolume};
4use crate::math::{Isometry, Point, Real, UnitVector, Vector, DIM, TWO_DIM};
5use crate::shape::{Cuboid, SupportMap};
6use crate::utils::IsometryOps;
7use arrayvec::ArrayVec;
8use na;
9use num::Bounded;
10
11#[cfg(all(feature = "dim3", not(feature = "std")))]
12use na::ComplexField;
13// for .sin_cos()
14
15use crate::query::{Ray, RayCast};
16#[cfg(feature = "rkyv")]
17use rkyv::{bytecheck, CheckBytes};
18
19/// An Axis Aligned Bounding Box.
20#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
21#[cfg_attr(feature = "bytemuck", derive(bytemuck::Pod, bytemuck::Zeroable))]
22#[cfg_attr(
23    feature = "rkyv",
24    derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize, CheckBytes),
25    archive(as = "Self")
26)]
27#[derive(Debug, PartialEq, Copy, Clone)]
28#[repr(C)]
29pub struct Aabb {
30    pub mins: Point<Real>,
31    pub maxs: Point<Real>,
32}
33
34impl Aabb {
35    /// The vertex indices of each edge of this `Aabb`.
36    ///
37    /// This gives, for each edge of this `Aabb`, the indices of its
38    /// vertices when taken from the `self.vertices()` array.
39    /// Here is how the faces are numbered, assuming
40    /// a right-handed coordinate system:
41    ///
42    /// ```text
43    ///    y             3 - 2
44    ///    |           7 − 6 |
45    ///    ___ x       |   | 1  (the zero is below 3 and on the left of 1,
46    ///   /            4 - 5     hidden by the 4-5-6-7 face.)
47    ///  z
48    /// ```
49    #[cfg(feature = "dim3")]
50    pub const EDGES_VERTEX_IDS: [(usize, usize); 12] = [
51        (0, 1),
52        (1, 2),
53        (3, 2),
54        (0, 3),
55        (4, 5),
56        (5, 6),
57        (7, 6),
58        (4, 7),
59        (0, 4),
60        (1, 5),
61        (2, 6),
62        (3, 7),
63    ];
64
65    /// The vertex indices of each face of this `Aabb`.
66    ///
67    /// This gives, for each face of this `Aabb`, the indices of its
68    /// vertices when taken from the `self.vertices()` array.
69    /// Here is how the faces are numbered, assuming
70    /// a right-handed coordinate system:
71    ///
72    /// ```text
73    ///    y             3 - 2
74    ///    |           7 − 6 |
75    ///    ___ x       |   | 1  (the zero is below 3 and on the left of 1,
76    ///   /            4 - 5     hidden by the 4-5-6-7 face.)
77    ///  z
78    /// ```
79    #[cfg(feature = "dim3")]
80    pub const FACES_VERTEX_IDS: [(usize, usize, usize, usize); 6] = [
81        // Face with normal +X
82        (1, 2, 6, 5),
83        // Face with normal -X
84        (0, 3, 7, 4),
85        // Face with normal +Y
86        (2, 3, 7, 6),
87        // Face with normal -Y
88        (1, 0, 4, 5),
89        // Face with normal +Z
90        (4, 5, 6, 7),
91        // Face with normal -Z
92        (0, 1, 2, 3),
93    ];
94
95    /// The vertex indices of each face of this `Aabb`.
96    ///
97    /// This gives, for each face of this `Aabb`, the indices of its
98    /// vertices when taken from the `self.vertices()` array.
99    /// Here is how the faces are numbered, assuming
100    /// a right-handed coordinate system:
101    ///
102    /// ```text
103    ///    y             3 - 2
104    ///    |             |   |
105    ///    ___ x         0 - 1
106    /// ```
107    #[cfg(feature = "dim2")]
108    pub const FACES_VERTEX_IDS: [(usize, usize); 4] = [
109        // Face with normal +X
110        (1, 2),
111        // Face with normal -X
112        (3, 0),
113        // Face with normal +Y
114        (2, 3),
115        // Face with normal -Y
116        (0, 1),
117    ];
118
119    /// Creates a new Aabb.
120    ///
121    /// # Arguments:
122    ///   * `mins` - position of the point with the smallest coordinates.
123    ///   * `maxs` - position of the point with the highest coordinates. Each component of `mins`
124    ///     must be smaller than the related components of `maxs`.
125    #[inline]
126    pub fn new(mins: Point<Real>, maxs: Point<Real>) -> Aabb {
127        Aabb { mins, maxs }
128    }
129
130    /// Creates an invalid `Aabb` with `mins` components set to `Real::max_values` and `maxs`components set to `-Real::max_values`.
131    ///
132    /// This is often used as the initial values of some `Aabb` merging algorithms.
133    #[inline]
134    pub fn new_invalid() -> Self {
135        Self::new(
136            Vector::repeat(Real::max_value()).into(),
137            Vector::repeat(-Real::max_value()).into(),
138        )
139    }
140
141    /// Creates a new `Aabb` from its center and its half-extents.
142    #[inline]
143    pub fn from_half_extents(center: Point<Real>, half_extents: Vector<Real>) -> Self {
144        Self::new(center - half_extents, center + half_extents)
145    }
146
147    /// Creates a new `Aabb` from a set of point references.
148    pub fn from_points_ref<'a, I>(pts: I) -> Self
149    where
150        I: IntoIterator<Item = &'a Point<Real>>,
151    {
152        super::aabb_utils::local_point_cloud_aabb(pts.into_iter().copied())
153    }
154
155    /// Creates a new `Aabb` from a set of points.
156    pub fn from_points<I>(pts: I) -> Self
157    where
158        I: IntoIterator<Item = Point<Real>>,
159    {
160        super::aabb_utils::local_point_cloud_aabb(pts)
161    }
162
163    /// The center of this `Aabb`.
164    #[inline]
165    pub fn center(&self) -> Point<Real> {
166        na::center(&self.mins, &self.maxs)
167    }
168
169    /// The half extents of this `Aabb`.
170    #[inline]
171    pub fn half_extents(&self) -> Vector<Real> {
172        let half: Real = na::convert::<f64, Real>(0.5);
173        (self.maxs - self.mins) * half
174    }
175
176    /// The volume of this `Aabb`.
177    #[inline]
178    pub fn volume(&self) -> Real {
179        let extents = self.extents();
180        #[cfg(feature = "dim2")]
181        return extents.x * extents.y;
182        #[cfg(feature = "dim3")]
183        return extents.x * extents.y * extents.z;
184    }
185
186    /// In 3D, returns the half-area. In 2D returns the half-perimeter of the AABB.
187    pub fn half_area_or_perimeter(&self) -> Real {
188        #[cfg(feature = "dim2")]
189        return self.half_perimeter();
190        #[cfg(feature = "dim3")]
191        return self.half_area();
192    }
193
194    /// The half perimeter of this `Aabb`.
195    #[cfg(feature = "dim2")]
196    pub fn half_perimeter(&self) -> Real {
197        let extents = self.extents();
198        extents.x + extents.y
199    }
200
201    /// The half area of this `Aabb`.
202    #[cfg(feature = "dim3")]
203    pub fn half_area(&self) -> Real {
204        let extents = self.extents();
205        extents.x * (extents.y + extents.z) + extents.y * extents.z
206    }
207
208    /// The extents of this `Aabb`.
209    #[inline]
210    pub fn extents(&self) -> Vector<Real> {
211        self.maxs - self.mins
212    }
213
214    /// Enlarges this `Aabb` so it also contains the point `pt`.
215    pub fn take_point(&mut self, pt: Point<Real>) {
216        self.mins = self.mins.coords.inf(&pt.coords).into();
217        self.maxs = self.maxs.coords.sup(&pt.coords).into();
218    }
219
220    /// Computes the `Aabb` bounding `self` transformed by `m`.
221    #[inline]
222    pub fn transform_by(&self, m: &Isometry<Real>) -> Self {
223        let ls_center = self.center();
224        let center = m * ls_center;
225        let ws_half_extents = m.absolute_transform_vector(&self.half_extents());
226
227        Aabb::new(center + (-ws_half_extents), center + ws_half_extents)
228    }
229
230    /// Computes the Aabb bounding `self` translated by `translation`.
231    #[inline]
232    pub fn translated(mut self, translation: &Vector<Real>) -> Self {
233        self.mins += translation;
234        self.maxs += translation;
235        self
236    }
237
238    #[inline]
239    pub fn scaled(self, scale: &Vector<Real>) -> Self {
240        let a = self.mins.coords.component_mul(scale);
241        let b = self.maxs.coords.component_mul(scale);
242        Self {
243            mins: a.inf(&b).into(),
244            maxs: a.sup(&b).into(),
245        }
246    }
247
248    /// Returns an AABB with the same center as `self` but with extents scaled by `scale`.
249    ///
250    /// # Parameters
251    /// - `scale`: the scaling factor. It can be non-uniform and/or negative. The AABB being
252    ///   symmetric wrt. its center, a negative scale value has the same effect as scaling
253    ///   by its absolute value.
254    #[inline]
255    #[must_use]
256    pub fn scaled_wrt_center(self, scale: &Vector<Real>) -> Self {
257        let center = self.center();
258        // Multiply the extents by the scale. Negative scaling might modify the half-extent
259        // sign, so we take the absolute value. The AABB being symmetric that absolute value
260        // is  valid.
261        let half_extents = self.half_extents().component_mul(scale).abs();
262        Self::from_half_extents(center, half_extents)
263    }
264
265    /// The smallest bounding sphere containing this `Aabb`.
266    #[inline]
267    pub fn bounding_sphere(&self) -> BoundingSphere {
268        let center = self.center();
269        let radius = na::distance(&self.mins, &self.maxs) * 0.5;
270        BoundingSphere::new(center, radius)
271    }
272
273    /// Does this AABB contains a point expressed in the same coordinate frame as `self`?
274    #[inline]
275    pub fn contains_local_point(&self, point: &Point<Real>) -> bool {
276        for i in 0..DIM {
277            if point[i] < self.mins[i] || point[i] > self.maxs[i] {
278                return false;
279            }
280        }
281
282        true
283    }
284
285    /// Computes the distance between the origin and this AABB.
286    pub fn distance_to_origin(&self) -> Real {
287        self.mins
288            .coords
289            .sup(&-self.maxs.coords)
290            .sup(&Vector::zeros())
291            .norm()
292    }
293
294    /// Does this AABB intersects an AABB `aabb2` moving at velocity `vel12` relative to `self`?
295    #[inline]
296    pub fn intersects_moving_aabb(&self, aabb2: &Self, vel12: Vector<Real>) -> bool {
297        // Minkowski sum.
298        let msum = Aabb {
299            mins: self.mins - aabb2.maxs.coords,
300            maxs: self.maxs - aabb2.mins.coords,
301        };
302        let ray = Ray::new(Point::origin(), vel12);
303
304        msum.intersects_local_ray(&ray, 1.0)
305    }
306
307    /// Computes the intersection of this `Aabb` and another one.
308    pub fn intersection(&self, other: &Aabb) -> Option<Aabb> {
309        let result = Aabb {
310            mins: Point::from(self.mins.coords.sup(&other.mins.coords)),
311            maxs: Point::from(self.maxs.coords.inf(&other.maxs.coords)),
312        };
313
314        for i in 0..DIM {
315            if result.mins[i] > result.maxs[i] {
316                return None;
317            }
318        }
319
320        Some(result)
321    }
322
323    /// Computes two AABBs for the intersection between two translated and rotated AABBs.
324    ///
325    /// This method returns two AABBs: the first is expressed in the local-space of `self`,
326    /// and the second is expressed in the local-space of `aabb2`.
327    pub fn aligned_intersections(
328        &self,
329        pos12: &Isometry<Real>,
330        aabb2: &Self,
331    ) -> Option<(Aabb, Aabb)> {
332        let pos21 = pos12.inverse();
333
334        let aabb2_1 = aabb2.transform_by(pos12);
335        let inter1_1 = self.intersection(&aabb2_1)?;
336        let inter1_2 = inter1_1.transform_by(&pos21);
337
338        let aabb1_2 = self.transform_by(&pos21);
339        let inter2_2 = aabb2.intersection(&aabb1_2)?;
340        let inter2_1 = inter2_2.transform_by(pos12);
341
342        Some((
343            inter1_1.intersection(&inter2_1)?,
344            inter1_2.intersection(&inter2_2)?,
345        ))
346    }
347
348    /// Returns the difference between this `Aabb` and `rhs`.
349    ///
350    /// Removing another `Aabb` from `self` will result in zero, one, or up to 4 (in 2D) or 8 (in 3D)
351    /// new smaller Aabbs.
352    pub fn difference(&self, rhs: &Aabb) -> ArrayVec<Self, TWO_DIM> {
353        self.difference_with_cut_sequence(rhs).0
354    }
355
356    /// Returns the difference between this `Aabb` and `rhs`.
357    ///
358    /// Removing another `Aabb` from `self` will result in zero, one, or up to 4 (in 2D) or 8 (in 3D)
359    /// new smaller Aabbs.
360    ///
361    /// # Return
362    /// This returns a pair where the first item are the new Aabbs and the second item is
363    /// the sequence of cuts applied to `self` to obtain the new Aabbs. Each cut is performed
364    /// along one axis identified by `-1, -2, -3` for `-X, -Y, -Z` and `1, 2, 3` for `+X, +Y, +Z`, and
365    /// the plane’s bias.
366    ///
367    /// The cuts are applied sequentially. For example, if `result.1[0]` contains `1`, then it means
368    /// that `result.0[0]` is equal to the piece of `self` lying in the negative half-space delimited
369    /// by the plane with outward normal `+X`. Then, the other piece of `self` generated by this cut
370    /// (i.e. the piece of `self` lying in the positive half-space delimited by the plane with outward
371    /// normal `+X`) is the one that will be affected by the next cut.
372    ///
373    /// The returned cut sequence will be empty if the aabbs are disjoint.
374    pub fn difference_with_cut_sequence(
375        &self,
376        rhs: &Aabb,
377    ) -> (ArrayVec<Self, TWO_DIM>, ArrayVec<(i8, Real), TWO_DIM>) {
378        let mut result = ArrayVec::new();
379        let mut cut_sequence = ArrayVec::new();
380
381        // NOTE: special case when the boxes are disjoint.
382        //       This isn’t exactly the same as `!self.intersects(rhs)`
383        //       because of the equality.
384        for i in 0..DIM {
385            if self.mins[i] >= rhs.maxs[i] || self.maxs[i] <= rhs.mins[i] {
386                result.push(*self);
387                return (result, cut_sequence);
388            }
389        }
390
391        let mut rest = *self;
392
393        for i in 0..DIM {
394            if rhs.mins[i] > rest.mins[i] {
395                let mut fragment = rest;
396                fragment.maxs[i] = rhs.mins[i];
397                rest.mins[i] = rhs.mins[i];
398                result.push(fragment);
399                cut_sequence.push((i as i8 + 1, rhs.mins[i]));
400            }
401
402            if rhs.maxs[i] < rest.maxs[i] {
403                let mut fragment = rest;
404                fragment.mins[i] = rhs.maxs[i];
405                rest.maxs[i] = rhs.maxs[i];
406                result.push(fragment);
407                cut_sequence.push((-(i as i8 + 1), -rhs.maxs[i]));
408            }
409        }
410
411        (result, cut_sequence)
412    }
413
414    /// Computes the vertices of this `Aabb`.
415    ///
416    /// The vertices are given in the following order in a right-handed coordinate system:
417    /// ```text
418    ///    y             3 - 2
419    ///    |             |   |
420    ///    ___ x         0 - 1
421    /// ```
422    #[inline]
423    #[cfg(feature = "dim2")]
424    pub fn vertices(&self) -> [Point<Real>; 4] {
425        [
426            Point::new(self.mins.x, self.mins.y),
427            Point::new(self.maxs.x, self.mins.y),
428            Point::new(self.maxs.x, self.maxs.y),
429            Point::new(self.mins.x, self.maxs.y),
430        ]
431    }
432
433    /// Computes the vertices of this `Aabb`.
434    ///
435    /// The vertices are given in the following order, in a right-handed coordinate system:
436    /// ```text
437    ///    y             3 - 2
438    ///    |           7 − 6 |
439    ///    ___ x       |   | 1  (the zero is below 3 and on the left of 1,
440    ///   /            4 - 5     hidden by the 4-5-6-7 face.)
441    ///  z
442    /// ```
443    #[inline]
444    #[cfg(feature = "dim3")]
445    pub fn vertices(&self) -> [Point<Real>; 8] {
446        [
447            Point::new(self.mins.x, self.mins.y, self.mins.z),
448            Point::new(self.maxs.x, self.mins.y, self.mins.z),
449            Point::new(self.maxs.x, self.maxs.y, self.mins.z),
450            Point::new(self.mins.x, self.maxs.y, self.mins.z),
451            Point::new(self.mins.x, self.mins.y, self.maxs.z),
452            Point::new(self.maxs.x, self.mins.y, self.maxs.z),
453            Point::new(self.maxs.x, self.maxs.y, self.maxs.z),
454            Point::new(self.mins.x, self.maxs.y, self.maxs.z),
455        ]
456    }
457
458    /// Splits this `Aabb` at its center, into four parts (as in a quad-tree).
459    #[inline]
460    #[cfg(feature = "dim2")]
461    pub fn split_at_center(&self) -> [Aabb; 4] {
462        let center = self.center();
463
464        [
465            Aabb::new(self.mins, center),
466            Aabb::new(
467                Point::new(center.x, self.mins.y),
468                Point::new(self.maxs.x, center.y),
469            ),
470            Aabb::new(center, self.maxs),
471            Aabb::new(
472                Point::new(self.mins.x, center.y),
473                Point::new(center.x, self.maxs.y),
474            ),
475        ]
476    }
477
478    /// Splits this `Aabb` at its center, into eight parts (as in an octree).
479    #[inline]
480    #[cfg(feature = "dim3")]
481    pub fn split_at_center(&self) -> [Aabb; 8] {
482        let center = self.center();
483
484        [
485            Aabb::new(
486                Point::new(self.mins.x, self.mins.y, self.mins.z),
487                Point::new(center.x, center.y, center.z),
488            ),
489            Aabb::new(
490                Point::new(center.x, self.mins.y, self.mins.z),
491                Point::new(self.maxs.x, center.y, center.z),
492            ),
493            Aabb::new(
494                Point::new(center.x, center.y, self.mins.z),
495                Point::new(self.maxs.x, self.maxs.y, center.z),
496            ),
497            Aabb::new(
498                Point::new(self.mins.x, center.y, self.mins.z),
499                Point::new(center.x, self.maxs.y, center.z),
500            ),
501            Aabb::new(
502                Point::new(self.mins.x, self.mins.y, center.z),
503                Point::new(center.x, center.y, self.maxs.z),
504            ),
505            Aabb::new(
506                Point::new(center.x, self.mins.y, center.z),
507                Point::new(self.maxs.x, center.y, self.maxs.z),
508            ),
509            Aabb::new(
510                Point::new(center.x, center.y, center.z),
511                Point::new(self.maxs.x, self.maxs.y, self.maxs.z),
512            ),
513            Aabb::new(
514                Point::new(self.mins.x, center.y, center.z),
515                Point::new(center.x, self.maxs.y, self.maxs.z),
516            ),
517        ]
518    }
519
520    /// Enlarges this AABB on each side by the given `half_extents`.
521    #[must_use]
522    pub fn add_half_extents(&self, half_extents: &Vector<Real>) -> Self {
523        Self {
524            mins: self.mins - half_extents,
525            maxs: self.maxs + half_extents,
526        }
527    }
528
529    /// Projects every point of `Aabb` on an arbitrary axis.
530    pub fn project_on_axis(&self, axis: &UnitVector<Real>) -> (Real, Real) {
531        let cuboid = Cuboid::new(self.half_extents());
532        let shift = cuboid
533            .local_support_point_toward(axis)
534            .coords
535            .dot(axis)
536            .abs();
537        let center = self.center().coords.dot(axis);
538        (center - shift, center + shift)
539    }
540
541    #[cfg(feature = "dim3")]
542    #[cfg(feature = "alloc")]
543    pub fn intersects_spiral(
544        &self,
545        point: &Point<Real>,
546        center: &Point<Real>,
547        axis: &UnitVector<Real>,
548        linvel: &Vector<Real>,
549        angvel: Real,
550    ) -> bool {
551        use crate::utils::WBasis;
552        use crate::utils::{Interval, IntervalFunction};
553        use alloc::vec;
554
555        struct SpiralPlaneDistance {
556            center: Point<Real>,
557            tangents: [Vector<Real>; 2],
558            linvel: Vector<Real>,
559            angvel: Real,
560            point: na::Vector2<Real>,
561            plane: Vector<Real>,
562            bias: Real,
563        }
564
565        impl SpiralPlaneDistance {
566            fn spiral_pt_at(&self, t: Real) -> Point<Real> {
567                let angle = t * self.angvel;
568
569                // NOTE: we construct the rotation matrix explicitly here instead
570                //       of using `Rotation2::new()` because we will use similar
571                //       formulas on the interval methods.
572                let (sin, cos) = angle.sin_cos();
573                let rotmat = na::Matrix2::new(cos, -sin, sin, cos);
574
575                let rotated_pt = rotmat * self.point;
576                let shift = self.tangents[0] * rotated_pt.x + self.tangents[1] * rotated_pt.y;
577                self.center + self.linvel * t + shift
578            }
579        }
580
581        impl IntervalFunction<Real> for SpiralPlaneDistance {
582            fn eval(&self, t: Real) -> Real {
583                let point_pos = self.spiral_pt_at(t);
584                point_pos.coords.dot(&self.plane) - self.bias
585            }
586
587            fn eval_interval(&self, t: Interval<Real>) -> Interval<Real> {
588                // This is the same as `self.eval` except that `t` is an interval.
589                let angle = t * self.angvel;
590                let (sin, cos) = angle.sin_cos();
591                let rotmat = na::Matrix2::new(cos, -sin, sin, cos);
592
593                let rotated_pt = rotmat * self.point.map(Interval::splat);
594                let shift = self.tangents[0].map(Interval::splat) * rotated_pt.x
595                    + self.tangents[1].map(Interval::splat) * rotated_pt.y;
596                let point_pos =
597                    self.center.map(Interval::splat) + self.linvel.map(Interval::splat) * t + shift;
598                point_pos.coords.dot(&self.plane.map(Interval::splat)) - Interval::splat(self.bias)
599            }
600
601            fn eval_interval_gradient(&self, t: Interval<Real>) -> Interval<Real> {
602                let angle = t * self.angvel;
603                let (sin, cos) = angle.sin_cos();
604                let rotmat = na::Matrix2::new(-sin, -cos, cos, -sin) * Interval::splat(self.angvel);
605
606                let rotated_pt = rotmat * self.point.map(Interval::splat);
607                let shift = self.tangents[0].map(Interval::splat) * rotated_pt.x
608                    + self.tangents[1].map(Interval::splat) * rotated_pt.y;
609                let point_vel = shift + self.linvel.map(Interval::splat);
610                point_vel.dot(&self.plane.map(Interval::splat))
611            }
612        }
613
614        let tangents = axis.orthonormal_basis();
615        let dpos = point - center;
616        let mut distance_fn = SpiralPlaneDistance {
617            center: *center,
618            tangents,
619            linvel: *linvel,
620            angvel,
621            point: na::Vector2::new(dpos.dot(&tangents[0]), dpos.dot(&tangents[1])),
622            plane: Vector::x(),
623            bias: 0.0,
624        };
625
626        // Check the 8 planar faces of the Aabb.
627        let mut roots = vec![];
628        let mut candidates = vec![];
629
630        let planes = [
631            (-self.mins[0], -Vector::x(), 0),
632            (self.maxs[0], Vector::x(), 0),
633            (-self.mins[1], -Vector::y(), 1),
634            (self.maxs[1], Vector::y(), 1),
635            (-self.mins[2], -Vector::z(), 2),
636            (self.maxs[2], Vector::z(), 2),
637        ];
638
639        let range = self.project_on_axis(axis);
640        let range_bias = center.coords.dot(axis);
641        let interval = Interval::sort(range.0, range.1) - range_bias;
642
643        for (bias, axis, i) in &planes {
644            distance_fn.plane = *axis;
645            distance_fn.bias = *bias;
646
647            crate::utils::find_root_intervals_to(
648                &distance_fn,
649                interval,
650                1.0e-5,
651                1.0e-5,
652                100,
653                &mut roots,
654                &mut candidates,
655            );
656
657            for root in roots.drain(..) {
658                let point = distance_fn.spiral_pt_at(root.midpoint());
659                let (j, k) = ((i + 1) % 3, (i + 2) % 3);
660                if point[j] >= self.mins[j]
661                    && point[j] <= self.maxs[j]
662                    && point[k] >= self.mins[k]
663                    && point[k] <= self.maxs[k]
664                {
665                    return true;
666                }
667            }
668        }
669
670        false
671    }
672}
673
674impl BoundingVolume for Aabb {
675    #[inline]
676    fn center(&self) -> Point<Real> {
677        self.center()
678    }
679
680    #[inline]
681    fn intersects(&self, other: &Aabb) -> bool {
682        na::partial_le(&self.mins, &other.maxs) && na::partial_ge(&self.maxs, &other.mins)
683    }
684
685    #[inline]
686    fn contains(&self, other: &Aabb) -> bool {
687        na::partial_le(&self.mins, &other.mins) && na::partial_ge(&self.maxs, &other.maxs)
688    }
689
690    #[inline]
691    fn merge(&mut self, other: &Aabb) {
692        self.mins = self.mins.inf(&other.mins);
693        self.maxs = self.maxs.sup(&other.maxs);
694    }
695
696    #[inline]
697    fn merged(&self, other: &Aabb) -> Aabb {
698        Aabb {
699            mins: self.mins.inf(&other.mins),
700            maxs: self.maxs.sup(&other.maxs),
701        }
702    }
703
704    #[inline]
705    fn loosen(&mut self, amount: Real) {
706        assert!(amount >= 0.0, "The loosening margin must be positive.");
707        self.mins += Vector::repeat(-amount);
708        self.maxs += Vector::repeat(amount);
709    }
710
711    #[inline]
712    fn loosened(&self, amount: Real) -> Aabb {
713        assert!(amount >= 0.0, "The loosening margin must be positive.");
714        Aabb {
715            mins: self.mins + Vector::repeat(-amount),
716            maxs: self.maxs + Vector::repeat(amount),
717        }
718    }
719
720    #[inline]
721    fn tighten(&mut self, amount: Real) {
722        assert!(amount >= 0.0, "The tightening margin must be positive.");
723        self.mins += Vector::repeat(amount);
724        self.maxs += Vector::repeat(-amount);
725        assert!(
726            na::partial_le(&self.mins, &self.maxs),
727            "The tightening margin is to large."
728        );
729    }
730
731    #[inline]
732    fn tightened(&self, amount: Real) -> Aabb {
733        assert!(amount >= 0.0, "The tightening margin must be positive.");
734
735        Aabb::new(
736            self.mins + Vector::repeat(amount),
737            self.maxs + Vector::repeat(-amount),
738        )
739    }
740}