ndmath/
aabb.rs

1use crate::{Scalar, VecN};
2
3/// Trait for axis-aligned bounding boxes
4pub trait Aabb: Sized {
5    /// The vector type
6    type Vector: VecN;
7    /// The origin-aligned aabb with 0 volume
8    const ORIGIN_ZERO_SIZE: Self;
9    /// Get the origin value of a dimension
10    fn origin_dim(&self, dim: usize) -> <Self::Vector as VecN>::Scalar;
11    /// Get a mutable reference to the origin value of a dimension
12    fn origin_dim_mut(&mut self, dim: usize) -> &mut <Self::Vector as VecN>::Scalar;
13    /// Get the size value of a dimension
14    fn size_dim(&self, dim: usize) -> <Self::Vector as VecN>::Scalar;
15    /// Get a mutable reference to the size value of a dimension
16    fn size_dim_mut(&mut self, dim: usize) -> &mut <Self::Vector as VecN>::Scalar;
17    /// Set the origin value of a dimension
18    fn set_origin_dim(&mut self, dim: usize, val: <Self::Vector as VecN>::Scalar) {
19        *self.origin_dim_mut(dim) = val;
20    }
21    /// Set the size value of a dimension
22    fn set_size_dim(&mut self, dim: usize, val: <Self::Vector as VecN>::Scalar) {
23        *self.size_dim_mut(dim) = val;
24    }
25    /// Get the end value of a dimension
26    fn end_dim(&self, dim: usize) -> <Self::Vector as VecN>::Scalar {
27        self.origin_dim(dim) + self.size_dim(dim)
28    }
29    /// The the center value of a dimension
30    fn center_dim(&self, dim: usize) -> <Self::Vector as VecN>::Scalar {
31        self.origin_dim(dim) + self.size_dim(dim) / <Self::Vector as VecN>::Scalar::TWO
32    }
33    /// The center of the aabb
34    fn center(&self) -> Self::Vector {
35        let mut v = Self::Vector::ZERO;
36        for i in 0..Self::Vector::N {
37            v.set_dim(i, self.center_dim(i));
38        }
39        v
40    }
41    /// Check if the aabb contains a vector
42    fn contains(&self, v: Self::Vector) -> bool {
43        for i in 0..Self::Vector::N {
44            let d = v.dim(i);
45            let origin = self.origin_dim(i);
46            if d < origin || d > origin + self.size_dim(i) {
47                return false;
48            }
49        }
50        true
51    }
52    /// Get the aabb the bounds a list of vectors
53    fn bounding<I>(iter: I) -> Option<Self>
54    where
55        I: IntoIterator<Item = Self::Vector>,
56        Self::Vector: Clone,
57    {
58        let mut iter = iter.into_iter();
59        let mut min = iter.next()?;
60        let mut max = min.clone();
61        for v in iter {
62            for i in 0..Self::Vector::N {
63                let d = v.dim(i);
64                if d < min.dim(i) {
65                    min.set_dim(i, d);
66                } else if d > max.dim(i) {
67                    max.set_dim(i, d);
68                }
69            }
70        }
71        let mut res = Self::ORIGIN_ZERO_SIZE;
72        for i in 0..Self::Vector::N {
73            let min = min.dim(i);
74            res.set_origin_dim(i, min);
75            res.set_size_dim(i, max.dim(i) - min);
76        }
77        Some(res)
78    }
79}
80
81impl<T, const N: usize> Aabb for [[T; N]; 2]
82where
83    T: Scalar,
84{
85    type Vector = [T; N];
86    const ORIGIN_ZERO_SIZE: Self = [[<Self::Vector as VecN>::Scalar::ZERO; N]; 2];
87    fn origin_dim(&self, dim: usize) -> <Self::Vector as VecN>::Scalar {
88        self[0][dim]
89    }
90    fn origin_dim_mut(&mut self, dim: usize) -> &mut <Self::Vector as VecN>::Scalar {
91        &mut self[0][dim]
92    }
93    fn size_dim(&self, dim: usize) -> <Self::Vector as VecN>::Scalar {
94        self[1][dim]
95    }
96    fn size_dim_mut(&mut self, dim: usize) -> &mut <Self::Vector as VecN>::Scalar {
97        &mut self[1][dim]
98    }
99}
100
101macro_rules! aabb_impl {
102    ($($size:literal),* $(,)?) => {
103        $(
104            impl<T> Aabb for [T; $size * 2]
105            where
106                T: Scalar,
107            {
108                type Vector = [T; $size];
109                const ORIGIN_ZERO_SIZE: Self = [<Self::Vector as VecN>::Scalar::ZERO; $size * 2];
110                fn origin_dim(&self, dim: usize) -> <Self::Vector as VecN>::Scalar {
111                    self[dim]
112                }
113                fn origin_dim_mut(&mut self, dim: usize) -> &mut <Self::Vector as VecN>::Scalar {
114                    &mut self[dim]
115                }
116                fn size_dim(&self, dim: usize) -> <Self::Vector as VecN>::Scalar {
117                    self[Self::Vector::N + dim]
118                }
119                fn size_dim_mut(&mut self, dim: usize) -> &mut <Self::Vector as VecN>::Scalar {
120                    &mut self[Self::Vector::N + dim]
121                }
122            }
123        )*
124    };
125}
126
127aabb_impl!(1, 2, 3, 4, 5, 6, 7, 8);
128
129macro_rules! dim_trait {
130    (
131        $doc:literal,
132        $trait:ident,
133        $get_origin:ident,
134        $get_origin_mut:ident,
135        $set_origin:ident,
136        $get_size:ident,
137        $get_size_mut:ident,
138        $set_size:ident,
139        $get_end:ident,
140        $index:literal
141    ) => {
142        #[doc = $doc]
143        pub trait $trait: Aabb {
144            /// Get the origin value of the dimension
145            fn $get_origin(&self) -> <Self::Vector as VecN>::Scalar;
146            /// Get a mutable reference to the origin value of the dimension
147            fn $get_origin_mut(&mut self) -> &mut <Self::Vector as VecN>::Scalar;
148            /// Get the size value of the dimension
149            fn $get_size(&self) -> <Self::Vector as VecN>::Scalar;
150            /// Get a mutable reference to the size value of the dimension
151            fn $get_size_mut(&mut self) -> &mut <Self::Vector as VecN>::Scalar;
152            /// Set the origin value of the dimension
153            fn $set_origin(&mut self, x: <Self::Vector as VecN>::Scalar) {
154                *self.$get_origin_mut() = x;
155            }
156            /// Set the size value of the dimension
157            fn $set_size(&mut self, x: <Self::Vector as VecN>::Scalar) {
158                *self.$get_size_mut() = x;
159            }
160            /// Get the end value of the dimension
161            fn $get_end(&self) -> <Self::Vector as VecN>::Scalar {
162                self.end_dim($index)
163            }
164        }
165
166        impl<A> $trait for A
167        where
168            A: Aabb,
169        {
170            fn $get_origin(&self) -> <Self::Vector as VecN>::Scalar {
171                self.origin_dim($index)
172            }
173            fn $get_origin_mut(&mut self) -> &mut <Self::Vector as VecN>::Scalar {
174                self.origin_dim_mut($index)
175            }
176            fn $get_size(&self) -> <Self::Vector as VecN>::Scalar {
177                self.size_dim($index)
178            }
179            fn $get_size_mut(&mut self) -> &mut <Self::Vector as VecN>::Scalar {
180                self.size_dim_mut($index)
181            }
182        }
183    };
184}
185
186dim_trait!(
187    "Trait for axis-aligned bounding boxes with a width",
188    XAabb,
189    left,
190    left_mut,
191    set_left,
192    width,
193    width_mut,
194    set_width,
195    right,
196    0
197);
198dim_trait!(
199    "Trait for axis-aligned bounding boxes with a height",
200    YAabb,
201    top,
202    top_mut,
203    set_top,
204    height,
205    height_mut,
206    set_height,
207    bottom,
208    1
209);
210dim_trait!(
211    "Trait for axis-aligned bounding boxes with a depth",
212    ZAabb,
213    back,
214    back_mut,
215    set_back,
216    depth,
217    depth_mut,
218    set_depth,
219    front,
220    2
221);