parry2d/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 (AABB).
20///
21/// An AABB is the simplest bounding volume, defined by its minimum and maximum corners.
22/// It's called "axis-aligned" because its edges are always parallel to the coordinate axes
23/// (X, Y, and Z in 3D), making it very fast to test and compute.
24///
25/// # Structure
26///
27/// - **mins**: The point with the smallest coordinates on each axis (bottom-left-back corner)
28/// - **maxs**: The point with the largest coordinates on each axis (top-right-front corner)
29/// - **Invariant**: `mins.x ≤ maxs.x`, `mins.y ≤ maxs.y` (and `mins.z ≤ maxs.z` in 3D)
30///
31/// # Properties
32///
33/// - **Axis-aligned**: Edges always parallel to coordinate axes
34/// - **Conservative**: May be larger than the actual shape for rotated objects
35/// - **Fast**: Intersection tests are very cheap (just coordinate comparisons)
36/// - **Hierarchical**: Perfect for spatial data structures (BVH, quadtree, octree)
37///
38/// # Use Cases
39///
40/// AABBs are fundamental to collision detection and are used for:
41///
42/// - **Broad-phase collision detection**: Quickly eliminate distant object pairs
43/// - **Spatial partitioning**: Building BVHs, quadtrees, and octrees
44/// - **View frustum culling**: Determining what's visible
45/// - **Ray tracing acceleration**: Quickly rejecting non-intersecting rays
46/// - **Bounding volume for any shape**: Every shape can compute its AABB
47///
48/// # Performance
49///
50/// AABBs are the fastest bounding volume for:
51/// - Intersection tests: O(1) with just 6 comparisons (3D)
52/// - Merging: O(1) with component-wise min/max
53/// - Contains test: O(1) with coordinate comparisons
54///
55/// # Limitations
56///
57/// - **Rotation invariance**: Must be recomputed when objects rotate
58/// - **Tightness**: May waste space for rotated or complex shapes
59/// - **No orientation**: Cannot represent oriented bounding boxes (OBB)
60///
61/// # Example
62///
63/// ```rust
64/// # #[cfg(all(feature = "dim3", feature = "f32"))] {
65/// use parry3d::bounding_volume::Aabb;
66/// use nalgebra::Point3;
67///
68/// // Create an AABB for a unit cube centered at origin
69/// let mins = Point3::new(-0.5, -0.5, -0.5);
70/// let maxs = Point3::new(0.5, 0.5, 0.5);
71/// let aabb = Aabb::new(mins, maxs);
72///
73/// // Check if a point is inside
74/// let point = Point3::origin();
75/// assert!(aabb.contains_local_point(&point));
76///
77/// // Get center and extents
78/// assert_eq!(aabb.center(), Point3::origin());
79/// assert_eq!(aabb.extents().x, 1.0); // Full width
80/// assert_eq!(aabb.half_extents().x, 0.5); // Half width
81/// # }
82/// ```
83///
84/// ```rust
85/// # #[cfg(all(feature = "dim3", feature = "f32"))] {
86/// use parry3d::bounding_volume::Aabb;
87/// use nalgebra::Point3;
88///
89/// // Create from a set of points
90/// let points = vec![
91///     Point3::new(1.0, 2.0, 3.0),
92///     Point3::new(-1.0, 4.0, 2.0),
93///     Point3::new(0.0, 0.0, 5.0),
94/// ];
95/// let aabb = Aabb::from_points(points);
96///
97/// // The AABB encloses all points
98/// assert_eq!(aabb.mins, Point3::new(-1.0, 0.0, 2.0));
99/// assert_eq!(aabb.maxs, Point3::new(1.0, 4.0, 5.0));
100/// # }
101/// ```
102#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
103#[cfg_attr(feature = "bytemuck", derive(bytemuck::Pod, bytemuck::Zeroable))]
104#[cfg_attr(
105    feature = "rkyv",
106    derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize, CheckBytes),
107    archive(as = "Self")
108)]
109#[derive(Debug, PartialEq, Copy, Clone)]
110#[repr(C)]
111pub struct Aabb {
112    /// The point with minimum coordinates (bottom-left-back corner).
113    ///
114    /// Each component (`x`, `y`, `z`) should be less than or equal to the
115    /// corresponding component in `maxs`.
116    pub mins: Point<Real>,
117
118    /// The point with maximum coordinates (top-right-front corner).
119    ///
120    /// Each component (`x`, `y`, `z`) should be greater than or equal to the
121    /// corresponding component in `mins`.
122    pub maxs: Point<Real>,
123}
124
125impl Aabb {
126    /// The vertex indices of each edge of this `Aabb`.
127    ///
128    /// This gives, for each edge of this `Aabb`, the indices of its
129    /// vertices when taken from the `self.vertices()` array.
130    /// Here is how the faces are numbered, assuming
131    /// a right-handed coordinate system:
132    ///
133    /// ```text
134    ///    y             3 - 2
135    ///    |           7 − 6 |
136    ///    ___ x       |   | 1  (the zero is below 3 and on the left of 1,
137    ///   /            4 - 5     hidden by the 4-5-6-7 face.)
138    ///  z
139    /// ```
140    #[cfg(feature = "dim3")]
141    pub const EDGES_VERTEX_IDS: [(usize, usize); 12] = [
142        (0, 1),
143        (1, 2),
144        (3, 2),
145        (0, 3),
146        (4, 5),
147        (5, 6),
148        (7, 6),
149        (4, 7),
150        (0, 4),
151        (1, 5),
152        (2, 6),
153        (3, 7),
154    ];
155
156    /// The vertex indices of each face of this `Aabb`.
157    ///
158    /// This gives, for each face of this `Aabb`, the indices of its
159    /// vertices when taken from the `self.vertices()` array.
160    /// Here is how the faces are numbered, assuming
161    /// a right-handed coordinate system:
162    ///
163    /// ```text
164    ///    y             3 - 2
165    ///    |           7 − 6 |
166    ///    ___ x       |   | 1  (the zero is below 3 and on the left of 1,
167    ///   /            4 - 5     hidden by the 4-5-6-7 face.)
168    ///  z
169    /// ```
170    #[cfg(feature = "dim3")]
171    pub const FACES_VERTEX_IDS: [(usize, usize, usize, usize); 6] = [
172        // Face with normal +X
173        (1, 2, 6, 5),
174        // Face with normal -X
175        (0, 3, 7, 4),
176        // Face with normal +Y
177        (2, 3, 7, 6),
178        // Face with normal -Y
179        (1, 0, 4, 5),
180        // Face with normal +Z
181        (4, 5, 6, 7),
182        // Face with normal -Z
183        (0, 1, 2, 3),
184    ];
185
186    /// The vertex indices of each face of this `Aabb`.
187    ///
188    /// This gives, for each face of this `Aabb`, the indices of its
189    /// vertices when taken from the `self.vertices()` array.
190    /// Here is how the faces are numbered, assuming
191    /// a right-handed coordinate system:
192    ///
193    /// ```text
194    ///    y             3 - 2
195    ///    |             |   |
196    ///    ___ x         0 - 1
197    /// ```
198    #[cfg(feature = "dim2")]
199    pub const FACES_VERTEX_IDS: [(usize, usize); 4] = [
200        // Face with normal +X
201        (1, 2),
202        // Face with normal -X
203        (3, 0),
204        // Face with normal +Y
205        (2, 3),
206        // Face with normal -Y
207        (0, 1),
208    ];
209
210    /// Creates a new AABB from its minimum and maximum corners.
211    ///
212    /// # Arguments
213    ///
214    /// * `mins` - The point with the smallest coordinates on each axis
215    /// * `maxs` - The point with the largest coordinates on each axis
216    ///
217    /// # Invariant
218    ///
219    /// Each component of `mins` should be ≤ the corresponding component of `maxs`.
220    ///
221    /// # Example
222    ///
223    /// ```
224    /// # #[cfg(all(feature = "dim3", feature = "f32"))] {
225    /// use parry3d::bounding_volume::Aabb;
226    /// use nalgebra::Point3;
227    ///
228    /// // Create a 2x2x2 cube centered at origin
229    /// let aabb = Aabb::new(
230    ///     Point3::new(-1.0, -1.0, -1.0),
231    ///     Point3::new(1.0, 1.0, 1.0)
232    /// );
233    ///
234    /// assert_eq!(aabb.center(), Point3::origin());
235    /// assert_eq!(aabb.extents(), nalgebra::Vector3::new(2.0, 2.0, 2.0));
236    /// # }
237    /// ```
238    #[inline]
239    pub fn new(mins: Point<Real>, maxs: Point<Real>) -> Aabb {
240        Aabb { mins, maxs }
241    }
242
243    /// Creates an invalid AABB with inverted bounds.
244    ///
245    /// The resulting AABB has `mins` set to maximum values and `maxs` set to
246    /// minimum values. This is useful as an initial value for AABB merging
247    /// algorithms (similar to starting a min operation with infinity).
248    ///
249    /// # Example
250    ///
251    /// ```
252    /// # #[cfg(all(feature = "dim3", feature = "f32"))] {
253    /// use parry3d::bounding_volume::{Aabb, BoundingVolume};
254    /// use nalgebra::Point3;
255    ///
256    /// let mut aabb = Aabb::new_invalid();
257    ///
258    /// // Merge with actual points to build proper AABB
259    /// aabb.merge(&Aabb::new(Point3::new(1.0, 2.0, 3.0), Point3::new(1.0, 2.0, 3.0)));
260    /// aabb.merge(&Aabb::new(Point3::new(-1.0, 0.0, 2.0), Point3::new(-1.0, 0.0, 2.0)));
261    ///
262    /// // Now contains the merged bounds
263    /// assert_eq!(aabb.mins, Point3::new(-1.0, 0.0, 2.0));
264    /// assert_eq!(aabb.maxs, Point3::new(1.0, 2.0, 3.0));
265    /// # }
266    /// ```
267    #[inline]
268    pub fn new_invalid() -> Self {
269        Self::new(
270            Vector::repeat(Real::max_value()).into(),
271            Vector::repeat(-Real::max_value()).into(),
272        )
273    }
274
275    /// Creates a new AABB from its center and half-extents.
276    ///
277    /// This is often more intuitive than specifying min and max corners.
278    ///
279    /// # Arguments
280    ///
281    /// * `center` - The center point of the AABB
282    /// * `half_extents` - Half the dimensions along each axis
283    ///
284    /// # Example
285    ///
286    /// ```
287    /// # #[cfg(all(feature = "dim3", feature = "f32"))] {
288    /// use parry3d::bounding_volume::Aabb;
289    /// use nalgebra::{Point3, Vector3};
290    ///
291    /// // Create a 10x6x8 box centered at (5, 0, 0)
292    /// let aabb = Aabb::from_half_extents(
293    ///     Point3::new(5.0, 0.0, 0.0),
294    ///     Vector3::new(5.0, 3.0, 4.0)
295    /// );
296    ///
297    /// assert_eq!(aabb.mins, Point3::new(0.0, -3.0, -4.0));
298    /// assert_eq!(aabb.maxs, Point3::new(10.0, 3.0, 4.0));
299    /// assert_eq!(aabb.center(), Point3::new(5.0, 0.0, 0.0));
300    /// # }
301    /// ```
302    #[inline]
303    pub fn from_half_extents(center: Point<Real>, half_extents: Vector<Real>) -> Self {
304        Self::new(center - half_extents, center + half_extents)
305    }
306
307    /// Creates a new AABB that tightly encloses a set of points (references).
308    ///
309    /// Computes the minimum and maximum coordinates across all points.
310    ///
311    /// # Arguments
312    ///
313    /// * `pts` - An iterator over point references
314    ///
315    /// # Example
316    ///
317    /// ```
318    /// # #[cfg(all(feature = "dim3", feature = "f32"))] {
319    /// use parry3d::bounding_volume::Aabb;
320    /// use nalgebra::Point3;
321    ///
322    /// let points = vec![
323    ///     Point3::new(1.0, 2.0, 3.0),
324    ///     Point3::new(-1.0, 4.0, 2.0),
325    ///     Point3::new(0.0, 0.0, 5.0),
326    /// ];
327    ///
328    /// let aabb = Aabb::from_points_ref(&points);
329    /// assert_eq!(aabb.mins, Point3::new(-1.0, 0.0, 2.0));
330    /// assert_eq!(aabb.maxs, Point3::new(1.0, 4.0, 5.0));
331    /// # }
332    /// ```
333    pub fn from_points_ref<'a, I>(pts: I) -> Self
334    where
335        I: IntoIterator<Item = &'a Point<Real>>,
336    {
337        super::aabb_utils::local_point_cloud_aabb(pts.into_iter().copied())
338    }
339
340    /// Creates a new AABB that tightly encloses a set of points (values).
341    ///
342    /// Computes the minimum and maximum coordinates across all points.
343    ///
344    /// # Arguments
345    ///
346    /// * `pts` - An iterator over point values
347    ///
348    /// # Example
349    ///
350    /// ```
351    /// # #[cfg(all(feature = "dim3", feature = "f32"))] {
352    /// use parry3d::bounding_volume::Aabb;
353    /// use nalgebra::Point3;
354    ///
355    /// let aabb = Aabb::from_points(vec![
356    ///     Point3::new(1.0, 2.0, 3.0),
357    ///     Point3::new(-1.0, 4.0, 2.0),
358    ///     Point3::new(0.0, 0.0, 5.0),
359    /// ]);
360    ///
361    /// assert_eq!(aabb.mins, Point3::new(-1.0, 0.0, 2.0));
362    /// assert_eq!(aabb.maxs, Point3::new(1.0, 4.0, 5.0));
363    /// # }
364    /// ```
365    pub fn from_points<I>(pts: I) -> Self
366    where
367        I: IntoIterator<Item = Point<Real>>,
368    {
369        super::aabb_utils::local_point_cloud_aabb(pts)
370    }
371
372    /// Returns the center point of this AABB.
373    ///
374    /// The center is the midpoint between `mins` and `maxs`.
375    ///
376    /// # Example
377    ///
378    /// ```
379    /// # #[cfg(all(feature = "dim3", feature = "f32"))] {
380    /// use parry3d::bounding_volume::Aabb;
381    /// use nalgebra::Point3;
382    ///
383    /// let aabb = Aabb::new(
384    ///     Point3::new(-2.0, -3.0, -4.0),
385    ///     Point3::new(2.0, 3.0, 4.0)
386    /// );
387    ///
388    /// assert_eq!(aabb.center(), Point3::origin());
389    /// # }
390    /// ```
391    #[inline]
392    pub fn center(&self) -> Point<Real> {
393        na::center(&self.mins, &self.maxs)
394    }
395
396    /// Returns the half-extents of this AABB.
397    ///
398    /// Half-extents are half the dimensions along each axis.
399    ///
400    /// # Example
401    ///
402    /// ```
403    /// # #[cfg(all(feature = "dim3", feature = "f32"))] {
404    /// use parry3d::bounding_volume::Aabb;
405    /// use nalgebra::{Point3, Vector3};
406    ///
407    /// let aabb = Aabb::new(
408    ///     Point3::new(-5.0, -3.0, -2.0),
409    ///     Point3::new(5.0, 3.0, 2.0)
410    /// );
411    ///
412    /// let half = aabb.half_extents();
413    /// assert_eq!(half, Vector3::new(5.0, 3.0, 2.0));
414    ///
415    /// // Full dimensions are 2 * half_extents
416    /// let full = aabb.extents();
417    /// assert_eq!(full, Vector3::new(10.0, 6.0, 4.0));
418    /// # }
419    /// ```
420    #[inline]
421    pub fn half_extents(&self) -> Vector<Real> {
422        let half: Real = na::convert::<f64, Real>(0.5);
423        (self.maxs - self.mins) * half
424    }
425
426    /// Returns the volume of this AABB.
427    ///
428    /// - **2D**: Returns the area (width × height)
429    /// - **3D**: Returns the volume (width × height × depth)
430    ///
431    /// # Example
432    ///
433    /// ```
434    /// # #[cfg(all(feature = "dim3", feature = "f32"))] {
435    /// use parry3d::bounding_volume::Aabb;
436    /// use nalgebra::Point3;
437    ///
438    /// // A 2x3x4 box
439    /// let aabb = Aabb::new(
440    ///     Point3::origin(),
441    ///     Point3::new(2.0, 3.0, 4.0)
442    /// );
443    ///
444    /// assert_eq!(aabb.volume(), 24.0); // 2 * 3 * 4
445    /// # }
446    /// ```
447    #[inline]
448    pub fn volume(&self) -> Real {
449        let extents = self.extents();
450        #[cfg(feature = "dim2")]
451        return extents.x * extents.y;
452        #[cfg(feature = "dim3")]
453        return extents.x * extents.y * extents.z;
454    }
455
456    /// In 3D, returns the half-area. In 2D returns the half-perimeter of the AABB.
457    pub fn half_area_or_perimeter(&self) -> Real {
458        #[cfg(feature = "dim2")]
459        return self.half_perimeter();
460        #[cfg(feature = "dim3")]
461        return self.half_area();
462    }
463
464    /// The half perimeter of this `Aabb`.
465    #[cfg(feature = "dim2")]
466    pub fn half_perimeter(&self) -> Real {
467        let extents = self.extents();
468        extents.x + extents.y
469    }
470
471    /// The half area of this `Aabb`.
472    #[cfg(feature = "dim3")]
473    pub fn half_area(&self) -> Real {
474        let extents = self.extents();
475        extents.x * (extents.y + extents.z) + extents.y * extents.z
476    }
477
478    /// The extents of this `Aabb`.
479    #[inline]
480    pub fn extents(&self) -> Vector<Real> {
481        self.maxs - self.mins
482    }
483
484    /// Enlarges this `Aabb` so it also contains the point `pt`.
485    pub fn take_point(&mut self, pt: Point<Real>) {
486        self.mins = self.mins.coords.inf(&pt.coords).into();
487        self.maxs = self.maxs.coords.sup(&pt.coords).into();
488    }
489
490    /// Computes the `Aabb` bounding `self` transformed by `m`.
491    #[inline]
492    pub fn transform_by(&self, m: &Isometry<Real>) -> Self {
493        let ls_center = self.center();
494        let center = m * ls_center;
495        let ws_half_extents = m.absolute_transform_vector(&self.half_extents());
496
497        Aabb::new(center + (-ws_half_extents), center + ws_half_extents)
498    }
499
500    /// Computes the Aabb bounding `self` translated by `translation`.
501    #[inline]
502    pub fn translated(mut self, translation: &Vector<Real>) -> Self {
503        self.mins += translation;
504        self.maxs += translation;
505        self
506    }
507
508    #[inline]
509    pub fn scaled(self, scale: &Vector<Real>) -> Self {
510        let a = self.mins.coords.component_mul(scale);
511        let b = self.maxs.coords.component_mul(scale);
512        Self {
513            mins: a.inf(&b).into(),
514            maxs: a.sup(&b).into(),
515        }
516    }
517
518    /// Returns an AABB with the same center as `self` but with extents scaled by `scale`.
519    ///
520    /// # Parameters
521    /// - `scale`: the scaling factor. It can be non-uniform and/or negative. The AABB being
522    ///   symmetric wrt. its center, a negative scale value has the same effect as scaling
523    ///   by its absolute value.
524    #[inline]
525    #[must_use]
526    pub fn scaled_wrt_center(self, scale: &Vector<Real>) -> Self {
527        let center = self.center();
528        // Multiply the extents by the scale. Negative scaling might modify the half-extent
529        // sign, so we take the absolute value. The AABB being symmetric that absolute value
530        // is  valid.
531        let half_extents = self.half_extents().component_mul(scale).abs();
532        Self::from_half_extents(center, half_extents)
533    }
534
535    /// The smallest bounding sphere containing this `Aabb`.
536    #[inline]
537    pub fn bounding_sphere(&self) -> BoundingSphere {
538        let center = self.center();
539        let radius = na::distance(&self.mins, &self.maxs) * 0.5;
540        BoundingSphere::new(center, radius)
541    }
542
543    /// Does this AABB contains a point expressed in the same coordinate frame as `self`?
544    #[inline]
545    pub fn contains_local_point(&self, point: &Point<Real>) -> bool {
546        for i in 0..DIM {
547            if point[i] < self.mins[i] || point[i] > self.maxs[i] {
548                return false;
549            }
550        }
551
552        true
553    }
554
555    /// Computes the distance between the origin and this AABB.
556    pub fn distance_to_origin(&self) -> Real {
557        self.mins
558            .coords
559            .sup(&-self.maxs.coords)
560            .sup(&Vector::zeros())
561            .norm()
562    }
563
564    /// Does this AABB intersects an AABB `aabb2` moving at velocity `vel12` relative to `self`?
565    #[inline]
566    pub fn intersects_moving_aabb(&self, aabb2: &Self, vel12: Vector<Real>) -> bool {
567        // Minkowski sum.
568        let msum = Aabb {
569            mins: self.mins - aabb2.maxs.coords,
570            maxs: self.maxs - aabb2.mins.coords,
571        };
572        let ray = Ray::new(Point::origin(), vel12);
573
574        msum.intersects_local_ray(&ray, 1.0)
575    }
576
577    /// Computes the intersection of this `Aabb` and another one.
578    pub fn intersection(&self, other: &Aabb) -> Option<Aabb> {
579        let result = Aabb {
580            mins: Point::from(self.mins.coords.sup(&other.mins.coords)),
581            maxs: Point::from(self.maxs.coords.inf(&other.maxs.coords)),
582        };
583
584        for i in 0..DIM {
585            if result.mins[i] > result.maxs[i] {
586                return None;
587            }
588        }
589
590        Some(result)
591    }
592
593    /// Computes two AABBs for the intersection between two translated and rotated AABBs.
594    ///
595    /// This method returns two AABBs: the first is expressed in the local-space of `self`,
596    /// and the second is expressed in the local-space of `aabb2`.
597    pub fn aligned_intersections(
598        &self,
599        pos12: &Isometry<Real>,
600        aabb2: &Self,
601    ) -> Option<(Aabb, Aabb)> {
602        let pos21 = pos12.inverse();
603
604        let aabb2_1 = aabb2.transform_by(pos12);
605        let inter1_1 = self.intersection(&aabb2_1)?;
606        let inter1_2 = inter1_1.transform_by(&pos21);
607
608        let aabb1_2 = self.transform_by(&pos21);
609        let inter2_2 = aabb2.intersection(&aabb1_2)?;
610        let inter2_1 = inter2_2.transform_by(pos12);
611
612        Some((
613            inter1_1.intersection(&inter2_1)?,
614            inter1_2.intersection(&inter2_2)?,
615        ))
616    }
617
618    /// Returns the difference between this `Aabb` and `rhs`.
619    ///
620    /// Removing another `Aabb` from `self` will result in zero, one, or up to 4 (in 2D) or 8 (in 3D)
621    /// new smaller Aabbs.
622    pub fn difference(&self, rhs: &Aabb) -> ArrayVec<Self, TWO_DIM> {
623        self.difference_with_cut_sequence(rhs).0
624    }
625
626    /// Returns the difference between this `Aabb` and `rhs`.
627    ///
628    /// Removing another `Aabb` from `self` will result in zero, one, or up to 4 (in 2D) or 8 (in 3D)
629    /// new smaller Aabbs.
630    ///
631    /// # Return
632    /// This returns a pair where the first item are the new Aabbs and the second item is
633    /// the sequence of cuts applied to `self` to obtain the new Aabbs. Each cut is performed
634    /// along one axis identified by `-1, -2, -3` for `-X, -Y, -Z` and `1, 2, 3` for `+X, +Y, +Z`, and
635    /// the plane’s bias.
636    ///
637    /// The cuts are applied sequentially. For example, if `result.1[0]` contains `1`, then it means
638    /// that `result.0[0]` is equal to the piece of `self` lying in the negative half-space delimited
639    /// by the plane with outward normal `+X`. Then, the other piece of `self` generated by this cut
640    /// (i.e. the piece of `self` lying in the positive half-space delimited by the plane with outward
641    /// normal `+X`) is the one that will be affected by the next cut.
642    ///
643    /// The returned cut sequence will be empty if the aabbs are disjoint.
644    pub fn difference_with_cut_sequence(
645        &self,
646        rhs: &Aabb,
647    ) -> (ArrayVec<Self, TWO_DIM>, ArrayVec<(i8, Real), TWO_DIM>) {
648        let mut result = ArrayVec::new();
649        let mut cut_sequence = ArrayVec::new();
650
651        // NOTE: special case when the boxes are disjoint.
652        //       This isn’t exactly the same as `!self.intersects(rhs)`
653        //       because of the equality.
654        for i in 0..DIM {
655            if self.mins[i] >= rhs.maxs[i] || self.maxs[i] <= rhs.mins[i] {
656                result.push(*self);
657                return (result, cut_sequence);
658            }
659        }
660
661        let mut rest = *self;
662
663        for i in 0..DIM {
664            if rhs.mins[i] > rest.mins[i] {
665                let mut fragment = rest;
666                fragment.maxs[i] = rhs.mins[i];
667                rest.mins[i] = rhs.mins[i];
668                result.push(fragment);
669                cut_sequence.push((i as i8 + 1, rhs.mins[i]));
670            }
671
672            if rhs.maxs[i] < rest.maxs[i] {
673                let mut fragment = rest;
674                fragment.mins[i] = rhs.maxs[i];
675                rest.maxs[i] = rhs.maxs[i];
676                result.push(fragment);
677                cut_sequence.push((-(i as i8 + 1), -rhs.maxs[i]));
678            }
679        }
680
681        (result, cut_sequence)
682    }
683
684    /// Computes the vertices of this `Aabb`.
685    ///
686    /// The vertices are given in the following order in a right-handed coordinate system:
687    /// ```text
688    ///    y             3 - 2
689    ///    |             |   |
690    ///    ___ x         0 - 1
691    /// ```
692    #[inline]
693    #[cfg(feature = "dim2")]
694    pub fn vertices(&self) -> [Point<Real>; 4] {
695        [
696            Point::new(self.mins.x, self.mins.y),
697            Point::new(self.maxs.x, self.mins.y),
698            Point::new(self.maxs.x, self.maxs.y),
699            Point::new(self.mins.x, self.maxs.y),
700        ]
701    }
702
703    /// Computes the vertices of this `Aabb`.
704    ///
705    /// The vertices are given in the following order, in a right-handed coordinate system:
706    /// ```text
707    ///    y             3 - 2
708    ///    |           7 − 6 |
709    ///    ___ x       |   | 1  (the zero is below 3 and on the left of 1,
710    ///   /            4 - 5     hidden by the 4-5-6-7 face.)
711    ///  z
712    /// ```
713    #[inline]
714    #[cfg(feature = "dim3")]
715    pub fn vertices(&self) -> [Point<Real>; 8] {
716        [
717            Point::new(self.mins.x, self.mins.y, self.mins.z),
718            Point::new(self.maxs.x, self.mins.y, self.mins.z),
719            Point::new(self.maxs.x, self.maxs.y, self.mins.z),
720            Point::new(self.mins.x, self.maxs.y, self.mins.z),
721            Point::new(self.mins.x, self.mins.y, self.maxs.z),
722            Point::new(self.maxs.x, self.mins.y, self.maxs.z),
723            Point::new(self.maxs.x, self.maxs.y, self.maxs.z),
724            Point::new(self.mins.x, self.maxs.y, self.maxs.z),
725        ]
726    }
727
728    /// Splits this `Aabb` at its center, into four parts (as in a quad-tree).
729    #[inline]
730    #[cfg(feature = "dim2")]
731    pub fn split_at_center(&self) -> [Aabb; 4] {
732        let center = self.center();
733
734        [
735            Aabb::new(self.mins, center),
736            Aabb::new(
737                Point::new(center.x, self.mins.y),
738                Point::new(self.maxs.x, center.y),
739            ),
740            Aabb::new(center, self.maxs),
741            Aabb::new(
742                Point::new(self.mins.x, center.y),
743                Point::new(center.x, self.maxs.y),
744            ),
745        ]
746    }
747
748    /// Splits this `Aabb` at its center, into eight parts (as in an octree).
749    #[inline]
750    #[cfg(feature = "dim3")]
751    pub fn split_at_center(&self) -> [Aabb; 8] {
752        let center = self.center();
753
754        [
755            Aabb::new(
756                Point::new(self.mins.x, self.mins.y, self.mins.z),
757                Point::new(center.x, center.y, center.z),
758            ),
759            Aabb::new(
760                Point::new(center.x, self.mins.y, self.mins.z),
761                Point::new(self.maxs.x, center.y, center.z),
762            ),
763            Aabb::new(
764                Point::new(center.x, center.y, self.mins.z),
765                Point::new(self.maxs.x, self.maxs.y, center.z),
766            ),
767            Aabb::new(
768                Point::new(self.mins.x, center.y, self.mins.z),
769                Point::new(center.x, self.maxs.y, center.z),
770            ),
771            Aabb::new(
772                Point::new(self.mins.x, self.mins.y, center.z),
773                Point::new(center.x, center.y, self.maxs.z),
774            ),
775            Aabb::new(
776                Point::new(center.x, self.mins.y, center.z),
777                Point::new(self.maxs.x, center.y, self.maxs.z),
778            ),
779            Aabb::new(
780                Point::new(center.x, center.y, center.z),
781                Point::new(self.maxs.x, self.maxs.y, self.maxs.z),
782            ),
783            Aabb::new(
784                Point::new(self.mins.x, center.y, center.z),
785                Point::new(center.x, self.maxs.y, self.maxs.z),
786            ),
787        ]
788    }
789
790    /// Enlarges this AABB on each side by the given `half_extents`.
791    #[must_use]
792    pub fn add_half_extents(&self, half_extents: &Vector<Real>) -> Self {
793        Self {
794            mins: self.mins - half_extents,
795            maxs: self.maxs + half_extents,
796        }
797    }
798
799    /// Projects every point of `Aabb` on an arbitrary axis.
800    pub fn project_on_axis(&self, axis: &UnitVector<Real>) -> (Real, Real) {
801        let cuboid = Cuboid::new(self.half_extents());
802        let shift = cuboid
803            .local_support_point_toward(axis)
804            .coords
805            .dot(axis)
806            .abs();
807        let center = self.center().coords.dot(axis);
808        (center - shift, center + shift)
809    }
810
811    #[cfg(feature = "dim3")]
812    #[cfg(feature = "alloc")]
813    pub fn intersects_spiral(
814        &self,
815        point: &Point<Real>,
816        center: &Point<Real>,
817        axis: &UnitVector<Real>,
818        linvel: &Vector<Real>,
819        angvel: Real,
820    ) -> bool {
821        use crate::utils::WBasis;
822        use crate::utils::{Interval, IntervalFunction};
823        use alloc::vec;
824
825        struct SpiralPlaneDistance {
826            center: Point<Real>,
827            tangents: [Vector<Real>; 2],
828            linvel: Vector<Real>,
829            angvel: Real,
830            point: na::Vector2<Real>,
831            plane: Vector<Real>,
832            bias: Real,
833        }
834
835        impl SpiralPlaneDistance {
836            fn spiral_pt_at(&self, t: Real) -> Point<Real> {
837                let angle = t * self.angvel;
838
839                // NOTE: we construct the rotation matrix explicitly here instead
840                //       of using `Rotation2::new()` because we will use similar
841                //       formulas on the interval methods.
842                let (sin, cos) = angle.sin_cos();
843                let rotmat = na::Matrix2::new(cos, -sin, sin, cos);
844
845                let rotated_pt = rotmat * self.point;
846                let shift = self.tangents[0] * rotated_pt.x + self.tangents[1] * rotated_pt.y;
847                self.center + self.linvel * t + shift
848            }
849        }
850
851        impl IntervalFunction<Real> for SpiralPlaneDistance {
852            fn eval(&self, t: Real) -> Real {
853                let point_pos = self.spiral_pt_at(t);
854                point_pos.coords.dot(&self.plane) - self.bias
855            }
856
857            fn eval_interval(&self, t: Interval<Real>) -> Interval<Real> {
858                // This is the same as `self.eval` except that `t` is an interval.
859                let angle = t * self.angvel;
860                let (sin, cos) = angle.sin_cos();
861                let rotmat = na::Matrix2::new(cos, -sin, sin, cos);
862
863                let rotated_pt = rotmat * self.point.map(Interval::splat);
864                let shift = self.tangents[0].map(Interval::splat) * rotated_pt.x
865                    + self.tangents[1].map(Interval::splat) * rotated_pt.y;
866                let point_pos =
867                    self.center.map(Interval::splat) + self.linvel.map(Interval::splat) * t + shift;
868                point_pos.coords.dot(&self.plane.map(Interval::splat)) - Interval::splat(self.bias)
869            }
870
871            fn eval_interval_gradient(&self, t: Interval<Real>) -> Interval<Real> {
872                let angle = t * self.angvel;
873                let (sin, cos) = angle.sin_cos();
874                let rotmat = na::Matrix2::new(-sin, -cos, cos, -sin) * Interval::splat(self.angvel);
875
876                let rotated_pt = rotmat * self.point.map(Interval::splat);
877                let shift = self.tangents[0].map(Interval::splat) * rotated_pt.x
878                    + self.tangents[1].map(Interval::splat) * rotated_pt.y;
879                let point_vel = shift + self.linvel.map(Interval::splat);
880                point_vel.dot(&self.plane.map(Interval::splat))
881            }
882        }
883
884        let tangents = axis.orthonormal_basis();
885        let dpos = point - center;
886        let mut distance_fn = SpiralPlaneDistance {
887            center: *center,
888            tangents,
889            linvel: *linvel,
890            angvel,
891            point: na::Vector2::new(dpos.dot(&tangents[0]), dpos.dot(&tangents[1])),
892            plane: Vector::x(),
893            bias: 0.0,
894        };
895
896        // Check the 8 planar faces of the Aabb.
897        let mut roots = vec![];
898        let mut candidates = vec![];
899
900        let planes = [
901            (-self.mins[0], -Vector::x(), 0),
902            (self.maxs[0], Vector::x(), 0),
903            (-self.mins[1], -Vector::y(), 1),
904            (self.maxs[1], Vector::y(), 1),
905            (-self.mins[2], -Vector::z(), 2),
906            (self.maxs[2], Vector::z(), 2),
907        ];
908
909        let range = self.project_on_axis(axis);
910        let range_bias = center.coords.dot(axis);
911        let interval = Interval::sort(range.0, range.1) - range_bias;
912
913        for (bias, axis, i) in &planes {
914            distance_fn.plane = *axis;
915            distance_fn.bias = *bias;
916
917            crate::utils::find_root_intervals_to(
918                &distance_fn,
919                interval,
920                1.0e-5,
921                1.0e-5,
922                100,
923                &mut roots,
924                &mut candidates,
925            );
926
927            for root in roots.drain(..) {
928                let point = distance_fn.spiral_pt_at(root.midpoint());
929                let (j, k) = ((i + 1) % 3, (i + 2) % 3);
930                if point[j] >= self.mins[j]
931                    && point[j] <= self.maxs[j]
932                    && point[k] >= self.mins[k]
933                    && point[k] <= self.maxs[k]
934                {
935                    return true;
936                }
937            }
938        }
939
940        false
941    }
942}
943
944impl BoundingVolume for Aabb {
945    #[inline]
946    fn center(&self) -> Point<Real> {
947        self.center()
948    }
949
950    #[inline]
951    fn intersects(&self, other: &Aabb) -> bool {
952        na::partial_le(&self.mins, &other.maxs) && na::partial_ge(&self.maxs, &other.mins)
953    }
954
955    #[inline]
956    fn contains(&self, other: &Aabb) -> bool {
957        na::partial_le(&self.mins, &other.mins) && na::partial_ge(&self.maxs, &other.maxs)
958    }
959
960    #[inline]
961    fn merge(&mut self, other: &Aabb) {
962        self.mins = self.mins.inf(&other.mins);
963        self.maxs = self.maxs.sup(&other.maxs);
964    }
965
966    #[inline]
967    fn merged(&self, other: &Aabb) -> Aabb {
968        Aabb {
969            mins: self.mins.inf(&other.mins),
970            maxs: self.maxs.sup(&other.maxs),
971        }
972    }
973
974    #[inline]
975    fn loosen(&mut self, amount: Real) {
976        assert!(amount >= 0.0, "The loosening margin must be positive.");
977        self.mins += Vector::repeat(-amount);
978        self.maxs += Vector::repeat(amount);
979    }
980
981    #[inline]
982    fn loosened(&self, amount: Real) -> Aabb {
983        assert!(amount >= 0.0, "The loosening margin must be positive.");
984        Aabb {
985            mins: self.mins + Vector::repeat(-amount),
986            maxs: self.maxs + Vector::repeat(amount),
987        }
988    }
989
990    #[inline]
991    fn tighten(&mut self, amount: Real) {
992        assert!(amount >= 0.0, "The tightening margin must be positive.");
993        self.mins += Vector::repeat(amount);
994        self.maxs += Vector::repeat(-amount);
995        assert!(
996            na::partial_le(&self.mins, &self.maxs),
997            "The tightening margin is to large."
998        );
999    }
1000
1001    #[inline]
1002    fn tightened(&self, amount: Real) -> Aabb {
1003        assert!(amount >= 0.0, "The tightening margin must be positive.");
1004
1005        Aabb::new(
1006            self.mins + Vector::repeat(amount),
1007            self.maxs + Vector::repeat(-amount),
1008        )
1009    }
1010}