collision/volume/aabb/
mod.rs

1//! Axis-aligned bounding boxes
2//!
3//! An AABB is a geometric object which encompasses a set of points and is not
4//! rotated. It is either a rectangle or a rectangular prism (depending on the
5//! dimension) where the slope of every line is either 0 or undefined. These
6//! are useful for very cheap collision detection.
7
8pub use self::aabb2::Aabb2;
9pub use self::aabb3::Aabb3;
10
11use std::cmp::{Ordering, PartialOrd};
12
13use cgmath::{BaseNum, Point2, Point3};
14use cgmath::prelude::*;
15
16use crate::traits::Bound;
17
18mod aabb2;
19mod aabb3;
20
21pub(crate) fn min<S: PartialOrd + Copy>(lhs: S, rhs: S) -> S {
22    match lhs.partial_cmp(&rhs) {
23        Some(Ordering::Less) | Some(Ordering::Equal) | None => lhs,
24        _ => rhs,
25    }
26}
27
28pub(crate) fn max<S: PartialOrd + Copy>(lhs: S, rhs: S) -> S {
29    match lhs.partial_cmp(&rhs) {
30        Some(Ordering::Greater) | Some(Ordering::Equal) | None => lhs,
31        _ => rhs,
32    }
33}
34
35/// Compute the minimum/maximum of the given values
36pub trait MinMax {
37    /// Compute the minimum
38    fn min(a: Self, b: Self) -> Self;
39
40    /// Compute the maximum
41    fn max(a: Self, b: Self) -> Self;
42}
43
44impl<S: PartialOrd> MinMax for Point2<S>
45where
46    S: BaseNum,
47{
48    fn min(a: Point2<S>, b: Point2<S>) -> Point2<S> {
49        Point2::new(min(a.x, b.x), min(a.y, b.y))
50    }
51
52    fn max(a: Point2<S>, b: Point2<S>) -> Point2<S> {
53        Point2::new(max(a.x, b.x), max(a.y, b.y))
54    }
55}
56
57impl<S: PartialOrd> MinMax for Point3<S>
58where
59    S: BaseNum,
60{
61    fn min(a: Point3<S>, b: Point3<S>) -> Point3<S> {
62        Point3::new(min(a.x, b.x), min(a.y, b.y), min(a.z, b.z))
63    }
64
65    fn max(a: Point3<S>, b: Point3<S>) -> Point3<S> {
66        Point3::new(max(a.x, b.x), max(a.y, b.y), max(a.z, b.z))
67    }
68}
69
70/// Base trait describing an axis aligned bounding box.
71pub trait Aabb: Sized {
72    /// Scalar type
73    type Scalar: BaseNum;
74
75    /// Vector type
76    type Diff: VectorSpace<Scalar = Self::Scalar> + ElementWise + Array<Element = Self::Scalar>;
77
78    /// Point type
79    type Point: EuclideanSpace<Scalar = Self::Scalar, Diff = Self::Diff> + MinMax;
80
81    /// Create a new AABB using two points as opposing corners.
82    fn new(p1: Self::Point, p2: Self::Point) -> Self;
83
84    /// Create a new empty AABB
85    fn zero() -> Self {
86        let p = Self::Point::origin();
87        Self::new(p, p)
88    }
89
90    /// Return a shared reference to the point nearest to (-inf, -inf).
91    fn min(&self) -> Self::Point;
92
93    /// Return a shared reference to the point nearest to (inf, inf).
94    fn max(&self) -> Self::Point;
95
96    /// Return the dimensions of this AABB.
97    #[inline]
98    fn dim(&self) -> Self::Diff {
99        self.max() - self.min()
100    }
101
102    /// Return the volume this AABB encloses.
103    #[inline]
104    fn volume(&self) -> Self::Scalar {
105        self.dim().product()
106    }
107
108    /// Return the center point of this AABB.
109    #[inline]
110    fn center(&self) -> Self::Point {
111        let two = Self::Scalar::one() + Self::Scalar::one();
112        self.min() + self.dim() / two
113    }
114
115    /// Returns a new AABB that is grown to include the given point.
116    fn grow(&self, p: Self::Point) -> Self {
117        Aabb::new(MinMax::min(self.min(), p), MinMax::max(self.max(), p))
118    }
119
120    /// Add a vector to every point in the AABB, returning a new AABB.
121    #[inline]
122    fn add_v(&self, v: Self::Diff) -> Self {
123        Aabb::new(self.min() + v, self.max() + v)
124    }
125
126    /// Add a margin of the given width around the AABB, returning a new AABB.
127    fn add_margin(&self, margin: Self::Diff) -> Self;
128
129    /// Multiply every point in the AABB by a scalar, returning a new AABB.
130    #[inline]
131    fn mul_s(&self, s: Self::Scalar) -> Self {
132        Aabb::new(self.min() * s, self.max() * s)
133    }
134
135    /// Multiply every point in the AABB by a vector, returning a new AABB.
136    fn mul_v(&self, v: Self::Diff) -> Self {
137        let min = Self::Point::from_vec(self.min().to_vec().mul_element_wise(v));
138        let max = Self::Point::from_vec(self.max().to_vec().mul_element_wise(v));
139        Aabb::new(min, max)
140    }
141
142    /// Apply an arbitrary transform to the corners of this bounding box,
143    /// return a new conservative bound.
144    fn transform<T>(&self, transform: &T) -> Self
145    where
146        T: Transform<Self::Point>;
147}
148
149impl<A> Bound for A
150where
151    A: Aabb,
152    A::Point: EuclideanSpace,
153{
154    type Point = A::Point;
155
156    fn min_extent(&self) -> A::Point {
157        self.min()
158    }
159
160    fn max_extent(&self) -> A::Point {
161        self.max()
162    }
163
164    fn with_margin(&self, add: <A::Point as EuclideanSpace>::Diff) -> Self {
165        self.add_margin(add)
166    }
167
168    fn transform_volume<T>(&self, transform: &T) -> Self
169    where
170        T: Transform<Self::Point>,
171    {
172        self.transform(transform)
173    }
174
175    fn empty() -> Self {
176        A::zero()
177    }
178}