@@ -11,6 +11,7 @@ use std::fmt::Debug;
1111mod polygon;
1212mod polytope;
1313mod primitives;
14+ use crate :: util:: index_set_nth_power_iter;
1415pub use polygon:: * ;
1516pub use polytope:: * ;
1617pub use primitives:: * ;
@@ -86,25 +87,25 @@ where
8687
8788#[ derive( Debug , Clone , PartialEq , Eq , Serialize , Deserialize ) ]
8889#[ serde( bound(
89- serialize = "OVector <T, D>: Serialize" ,
90- deserialize = "OVector <T, D>: Deserialize<'de>"
90+ serialize = "OPoint <T, D>: Serialize" ,
91+ deserialize = "OPoint <T, D>: Deserialize<'de>"
9192) ) ]
9293pub struct AxisAlignedBoundingBox < T , D >
9394where
9495 T : Scalar ,
9596 D : DimName ,
9697 DefaultAllocator : Allocator < T , D > ,
9798{
98- min : OVector < T , D > ,
99- max : OVector < T , D > ,
99+ min : OPoint < T , D > ,
100+ max : OPoint < T , D > ,
100101}
101102
102103impl < T , D > Copy for AxisAlignedBoundingBox < T , D >
103104where
104105 T : Scalar ,
105106 D : DimName ,
106107 DefaultAllocator : Allocator < T , D > ,
107- OVector < T , D > : Copy ,
108+ OPoint < T , D > : Copy ,
108109{
109110}
110111
@@ -117,18 +118,18 @@ where
117118 D : DimName ,
118119 DefaultAllocator : Allocator < T , D > ,
119120{
120- pub fn new ( min : OVector < T , D > , max : OVector < T , D > ) -> Self {
121+ pub fn new ( min : OPoint < T , D > , max : OPoint < T , D > ) -> Self {
121122 for i in 0 ..D :: dim ( ) {
122123 assert ! ( min[ i] <= max[ i] ) ;
123124 }
124125 Self { min, max }
125126 }
126127
127- pub fn min ( & self ) -> & OVector < T , D > {
128+ pub fn min ( & self ) -> & OPoint < T , D > {
128129 & self . min
129130 }
130131
131- pub fn max ( & self ) -> & OVector < T , D > {
132+ pub fn max ( & self ) -> & OPoint < T , D > {
132133 & self . max
133134 }
134135}
@@ -140,7 +141,7 @@ where
140141 DefaultAllocator : Allocator < T , D > ,
141142{
142143 fn from ( point : OPoint < T , D > ) -> Self {
143- AxisAlignedBoundingBox :: new ( point. coords . clone ( ) , point. coords )
144+ AxisAlignedBoundingBox :: new ( point. clone ( ) , point)
144145 }
145146}
146147
@@ -152,13 +153,21 @@ where
152153{
153154 /// Computes the minimal bounding box which encloses both `this` and `other`.
154155 pub fn enclose ( & self , other : & AxisAlignedBoundingBox < T , D > ) -> Self {
155- let min = self . min . iter ( ) . zip ( & other. min ) . map ( |( a, b) | T :: min ( * a, * b) ) ;
156+ let min = self
157+ . min
158+ . iter ( )
159+ . zip ( & other. min . coords )
160+ . map ( |( a, b) | T :: min ( * a, * b) ) ;
156161 let min = OVector :: < T , D > :: from_iterator ( min) ;
157162
158- let max = self . max . iter ( ) . zip ( & other. max ) . map ( |( a, b) | T :: max ( * a, * b) ) ;
163+ let max = self
164+ . max
165+ . iter ( )
166+ . zip ( & other. max . coords )
167+ . map ( |( a, b) | T :: max ( * a, * b) ) ;
159168 let max = OVector :: < T , D > :: from_iterator ( max) ;
160169
161- AxisAlignedBoundingBox :: new ( min, max)
170+ AxisAlignedBoundingBox :: new ( min. into ( ) , max. into ( ) )
162171 }
163172
164173 pub fn from_points < ' a > ( points : impl IntoIterator < Item = & ' a OPoint < T , D > > ) -> Option < Self > {
@@ -179,37 +188,37 @@ where
179188 }
180189
181190 pub fn center ( & self ) -> OPoint < T , D > {
182- OPoint :: from ( ( self . max ( ) + self . min ( ) ) / T :: from_f64 ( 2.0 ) . unwrap ( ) )
191+ OPoint :: from ( ( & self . max ( ) . coords + & self . min ( ) . coords ) / T :: from_f64 ( 2.0 ) . unwrap ( ) )
183192 }
184193
185194 /// Uniformly scales each axis by the given scale amount, with respect to the center of
186195 /// the box.
187196 ///
188197 /// ```rust
189198 /// # use fenris_geometry::AxisAlignedBoundingBox;
190- /// use nalgebra::vector;
199+ /// use nalgebra::{point, vector} ;
191200 /// use matrixcompare::assert_matrix_eq;
192201 ///
193- /// let aabb = AxisAlignedBoundingBox::new(vector ![0.0, 0.0], vector ![1.0, 1.0]);
202+ /// let aabb = AxisAlignedBoundingBox::new(point ![0.0, 0.0], point ![1.0, 1.0]);
194203 /// let scaled = aabb.uniformly_scale(0.5);
195204 ///
196- /// assert_matrix_eq!(scaled.min(), vector![0.25, 0.25], comp = float);
197- /// assert_matrix_eq!(scaled.max(), vector![0.75, 0.75], comp = float);
205+ /// assert_matrix_eq!(scaled.min().coords , vector![0.25, 0.25], comp = float);
206+ /// assert_matrix_eq!(scaled.max().coords , vector![0.75, 0.75], comp = float);
198207 /// ```
199208 #[ replace_float_literals( T :: from_f64( literal) . unwrap( ) ) ]
200209 pub fn uniformly_scale ( & self , scale : T ) -> Self {
201210 assert ! ( scale >= T :: zero( ) ) ;
202211 let s = scale;
203212 let ( a, b) = ( & self . min , & self . max ) ;
204- let ref c = self . center ( ) . coords ;
213+ let ref c = self . center ( ) ;
205214 Self {
206215 min : c + ( a - c) * s,
207216 max : c + ( b - c) * s,
208217 }
209218 }
210219
211220 pub fn contains_point ( & self , point : & OPoint < T , D > ) -> bool {
212- ( 0 ..D :: dim ( ) ) . all ( |dim| point[ dim] > self . min [ dim] && point[ dim] < self . max [ dim] )
221+ ( 0 ..D :: dim ( ) ) . all ( |dim| point[ dim] >= self . min [ dim] && point[ dim] <= self . max [ dim] )
213222 }
214223
215224 pub fn intersects ( & self , other : & Self ) -> bool {
@@ -227,18 +236,91 @@ where
227236 ///
228237 /// ```rust
229238 /// # use fenris_geometry::AxisAlignedBoundingBox;
230- /// # use nalgebra::vector ;
231- /// let aabb = AxisAlignedBoundingBox::new(vector ![0.0, 0.0], vector ![1.0, 1.0]);
239+ /// # use nalgebra::point ;
240+ /// let aabb = AxisAlignedBoundingBox::new(point ![0.0, 0.0], point ![1.0, 1.0]);
232241 /// let grown = aabb.grow_uniformly(1.0);
233- /// assert_eq!(grown.min(), &vector ![-1.0, -1.0]);
234- /// assert_eq!(grown.max(), &vector ![2.0, 2.0]);
242+ /// assert_eq!(grown.min(), &point ![-1.0, -1.0]);
243+ /// assert_eq!(grown.max(), &point ![2.0, 2.0]);
235244 /// ```
236245 ///
237246 pub fn grow_uniformly ( & self , distance : T ) -> Self {
238247 let min = self . min ( ) . map ( |b_i| b_i - distance) ;
239248 let max = self . max ( ) . map ( |b_i| b_i + distance) ;
240249 Self :: new ( min, max)
241250 }
251+
252+ /// Creates an iterator over the corners of the bounding box.
253+ pub fn corners_iter < ' a > ( & ' a self ) -> impl ' a + Iterator < Item = OPoint < T , D > >
254+ where
255+ DefaultAllocator : Allocator < usize , D > ,
256+ {
257+ // We can enumerate the corners by looking at {0, 1}^D, i.e. the D-th power of the
258+ // set {0, 1}, and associating 0 and 1 with min and max coordinates for the i-th axis.
259+ index_set_nth_power_iter :: < D > ( 2 ) . map ( move |multi_idx| {
260+ OVector :: < T , D > :: from_fn ( |idx, _| match multi_idx[ idx] {
261+ 0 => self . min [ idx] . clone ( ) ,
262+ 1 => self . max [ idx] . clone ( ) ,
263+ _ => unreachable ! ( ) ,
264+ } )
265+ . into ( )
266+ } )
267+ }
268+
269+ /// Compute the point in the bounding box furthest away from the given point.
270+ ///
271+ /// # Panics
272+ ///
273+ /// Panics if two distances cannot be ordered. This typically only happens if
274+ /// one of the numbers is not a number (NaN) or the comparison is not sensible, such as
275+ /// comparing two infinities. Since given finite coordinates no distance should be infinite,
276+ /// this method will realistically only panic in cases where one of the points
277+ /// --- either of the bounding box or the query point --- has components that are not
278+ /// finite numbers.
279+ #[ replace_float_literals( T :: from_f64( literal) . unwrap( ) ) ]
280+ pub fn furthest_point_to ( & self , point : & OPoint < T , D > ) -> OPoint < T , D >
281+ where
282+ DefaultAllocator : Allocator < usize , D > ,
283+ {
284+ // It turns out that we can choose, along each dimension, the point in the interval
285+ // [a_i, b_i] furthest away from p_i.
286+ point
287+ . coords
288+ . zip_zip_map ( & self . min . coords , & self . max . coords , |p_i, a_i, b_i| {
289+ let mid = ( a_i + b_i) / 2.0 ;
290+ if p_i < mid {
291+ b_i
292+ } else {
293+ a_i
294+ }
295+ } )
296+ . into ( )
297+ }
298+
299+ /// The squared distance to the point in the bounding box furthest away from the given point.
300+ ///
301+ /// # Panics
302+ ///
303+ /// Panic behavior is identical to [`furthest_point_to`](Self::furthest_point_to).
304+ pub fn max_dist2_to ( & self , point : & OPoint < T , D > ) -> T
305+ where
306+ // TODO: Use DimAllocator and SmallDim
307+ DefaultAllocator : Allocator < usize , D > ,
308+ {
309+ ( self . furthest_point_to ( point) - point) . norm_squared ( )
310+ }
311+
312+ /// The distance to the point in the bounding box furthest away from the given point.
313+ ///
314+ /// # Panics
315+ ///
316+ /// Panic behavior is identical to [`max_dist2_to`](Self::max_dist2_to).
317+ pub fn max_dist_to ( & self , point : & OPoint < T , D > ) -> T
318+ where
319+ // TODO: Use DimAllocator and SmallDim
320+ DefaultAllocator : Allocator < usize , D > ,
321+ {
322+ self . max_dist2_to ( point) . sqrt ( )
323+ }
242324}
243325
244326fn intervals_intersect < T : Real > ( [ l1, u1] : [ T ; 2 ] , [ l2, u2] : [ T ; 2 ] ) -> bool {
0 commit comments