math_utils/geometry/primitive/
integer.rs

1//! Integer Interval and Aabb primitives.
2//!
3//! Note that unlike Aabbs over scalar types, Aabbs over Integers are *closed* (they
4//! include their boundary points). This means that there can be degenerate Aabbs
5//! containing a single point (when `min = max`), or line or plane in higher dimensions.
6// TODO: more types? ortho lines, planes?
7
8#[cfg(feature = "derive_serdes")]
9use serde::{Deserialize, Serialize};
10
11use crate::*;
12use crate::geometry::intersect;
13
14/// 1D interval
15#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
16#[derive(Clone, Debug, Eq, PartialEq)]
17pub struct Interval <I> {
18  min : I,
19  max : I
20}
21
22/// 2D axis-aligned bounding box
23#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
24#[derive(Clone, Debug, Eq, PartialEq)]
25pub struct Aabb2 <I> {
26  min : Point2 <I>,
27  max : Point2 <I>
28}
29
30/// 3D axis-aligned bounding box
31#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
32#[derive(Clone, Debug, Eq, PartialEq)]
33pub struct Aabb3 <I> {
34  min : Point3 <I>,
35  max : Point3 <I>
36}
37
38/// Coordinate-wise min
39pub fn point2_min <I : Integer> (a : &Point2 <I>, b : &Point2 <I>) -> Point2 <I> {
40  [ Ord::min (a.0.x, b.0.x),
41    Ord::min (a.0.y, b.0.y)
42  ].into()
43}
44/// Coordinate-wise max
45pub fn point2_max <I : Integer> (a : &Point2 <I>, b : &Point2 <I>) -> Point2 <I> {
46  [ Ord::max (a.0.x, b.0.x),
47    Ord::max (a.0.y, b.0.y)
48  ].into()
49}
50/// Minimum representable point
51pub fn point2_min_value <I : Integer> () -> Point2 <I> {
52  [ I::min_value(), I::min_value() ].into()
53}
54/// Maximum representable point
55pub fn point2_max_value <I : Integer> () -> Point2 <I> {
56  [ I::max_value(), I::max_value() ].into()
57}
58
59/// Coordinate-wise min
60pub fn point3_min <I : Integer> (a : &Point3 <I>, b : &Point3 <I>) -> Point3 <I> {
61  [ Ord::min (a.0.x, b.0.x),
62    Ord::min (a.0.y, b.0.y),
63    Ord::min (a.0.z, b.0.z)
64  ].into()
65}
66/// Coordinate-wise max
67pub fn point3_max <I : Integer> (a : &Point3 <I>, b : &Point3 <I>) -> Point3 <I> {
68  [ Ord::max (a.0.x, b.0.x),
69    Ord::max (a.0.y, b.0.y),
70    Ord::max (a.0.z, b.0.z)
71  ].into()
72}
73/// Minimum representable point
74pub fn point3_min_value <I : Integer> () -> Point3 <I> {
75  [ I::min_value(), I::min_value(), I::min_value() ].into()
76}
77/// Maximum representable point
78pub fn point3_max_value <I : Integer> () -> Point3 <I> {
79  [ I::max_value(), I::max_value(), I::max_value() ].into()
80}
81
82impl <I : Integer> Interval <I> {
83  /// Construct a new AABB with given min and max points.
84  ///
85  /// Debug panic if points are not min/max:
86  ///
87  /// ```should_panic
88  /// # use math_utils::geometry::integer::*;
89  /// let b = Interval::with_minmax (1, 0);  // panic!
90  /// ```
91  ///
92  /// Identical points are allowed:
93  ///
94  /// ```
95  /// # use math_utils::geometry::integer::*;
96  /// let b = Interval::with_minmax (0, 0);  // ok
97  /// ```
98  #[inline]
99  pub fn with_minmax (min : I, max : I) -> Self where I : std::fmt::Debug {
100    debug_assert_eq!(min, Ord::min (min, max));
101    debug_assert_eq!(max, Ord::max (min, max));
102    Interval { min, max }
103  }
104  /// Construct a new AABB using the two given points to determine min/max.
105  ///
106  /// Identical points are allowed:
107  ///
108  /// ```
109  /// # use math_utils::geometry::integer::*;
110  /// let b = Interval::from_points (0, 0);  // ok!
111  /// ```
112  #[inline]
113  pub fn from_points (a : I, b : I) -> Self {
114    let min = Ord::min (a, b);
115    let max = Ord::max (a, b);
116    Interval { min, max }
117  }
118  /// Construct the minimum AABB containing the given set of points.
119  ///
120  /// Identical points are allowed:
121  ///
122  /// ```
123  /// # use math_utils::geometry::integer::*;
124  /// let b = Interval::containing (&[0, 0]);  // ok!
125  /// ```
126  ///
127  /// A single point is allowed:
128  ///
129  /// ```
130  /// # use math_utils::geometry::integer::*;
131  /// let b = Interval::containing (&[0]);  // ok!
132  /// ```
133  ///
134  /// Debug panic if no points are given:
135  ///
136  /// ```should_panic
137  /// # use math_utils::geometry::integer::*;
138  /// let b = Interval::<i32>::containing (&[]);  // panic!
139  /// ```
140  #[inline]
141  pub fn containing (points : &[I]) -> Self where I : std::fmt::Debug {
142    debug_assert!(!points.is_empty());
143    let mut min = I::max_value();
144    let mut max = I::min_value();
145    for point in points {
146      if *point < min {
147        min = *point;
148      }
149      if *point > max {
150        max = *point;
151      }
152    }
153    Interval::with_minmax (min, max)
154  }
155  /// Create a new AABB that is the union of the two input AABBs
156  #[inline]
157  pub fn union (a : &Interval <I>, b : &Interval <I>) -> Self where I : std::fmt::Debug {
158    Interval::with_minmax (
159      Ord::min (a.min(), b.min()),
160      Ord::max (a.max(), b.max())
161    )
162  }
163  #[inline]
164  pub const fn min (&self) -> I {
165    self.min
166  }
167  #[inline]
168  pub const fn max (&self) -> I {
169    self.max
170  }
171  #[inline]
172  pub fn width (&self) -> I {
173    self.max - self.min
174  }
175  #[inline]
176  pub fn contains (&self, point : I) -> bool {
177    self.min <= point && point <= self.max
178  }
179  /// Clamp a given point to the AABB interval.
180  ///
181  /// ```
182  /// # use math_utils::geometry::integer::*;
183  /// let b = Interval::from_points (-1, 1);
184  /// assert_eq!(b.clamp (-2), -1);
185  /// assert_eq!(b.clamp ( 2),  1);
186  /// assert_eq!(b.clamp ( 0),  0);
187  /// ```
188  pub fn clamp (&self, point : I) -> I {
189    Ord::max (Ord::min (self.max, point), self.min)
190  }
191  /// Generate a random point contained in the AABB.
192  ///
193  /// ```
194  /// # use rand;
195  /// # use rand_xorshift;
196  /// # use math_utils::geometry::integer::*;
197  /// # fn main () {
198  /// use rand_xorshift;
199  /// use rand::SeedableRng;
200  /// // random sequence will be the same each time this is run
201  /// let mut rng = rand_xorshift::XorShiftRng::seed_from_u64 (0);
202  /// let aabb = Interval::<i32>::with_minmax (-10, 10);
203  /// let point = aabb.rand_point (&mut rng);
204  /// assert!(aabb.contains (point));
205  /// let point = aabb.rand_point (&mut rng);
206  /// assert!(aabb.contains (point));
207  /// let point = aabb.rand_point (&mut rng);
208  /// assert!(aabb.contains (point));
209  /// let point = aabb.rand_point (&mut rng);
210  /// assert!(aabb.contains (point));
211  /// let point = aabb.rand_point (&mut rng);
212  /// assert!(aabb.contains (point));
213  /// # }
214  /// ```
215  #[inline]
216  pub fn rand_point <R> (&self, rng : &mut R) -> I where
217    I : rand::distr::uniform::SampleUniform,
218    R : rand::Rng
219  {
220    // NB: integer aabbs include their max points so we increase the max by 1
221    rng.random_range (self.min..self.max + I::one())
222  }
223  #[inline]
224  pub fn intersects (&self, other : &Interval <I>) -> bool {
225    intersect::integer::discrete_interval (self, other)
226  }
227}
228
229impl <I : Integer> Aabb2 <I> {
230  /// Construct a new AABB with given min and max points.
231  ///
232  /// Debug panic if points are not min/max:
233  ///
234  /// ```should_panic
235  /// # use math_utils::geometry::integer::*;
236  /// let b = Aabb2::with_minmax ([1, 1].into(), [0, 0].into());  // panic!
237  /// ```
238  ///
239  /// Identical points are allowed:
240  ///
241  /// ```
242  /// # use math_utils::geometry::integer::*;
243  /// let b = Aabb2::with_minmax ([0, 0].into(), [0, 0].into());  // ok
244  /// ```
245  #[inline]
246  pub fn with_minmax (min : Point2 <I>, max : Point2 <I>) -> Self where
247    I : std::fmt::Debug
248  {
249    debug_assert_eq!(min, point2_min (&min, &max));
250    debug_assert_eq!(max, point2_max (&min, &max));
251    Aabb2 { min, max }
252  }
253  /// Construct a new AABB using the two given points to determine min/max.
254  ///
255  /// Identical points are allowed:
256  ///
257  /// ```
258  /// # use math_utils::geometry::integer::*;
259  /// let b = Aabb2::from_points ([0, 0].into(), [0, 0].into());  // ok
260  /// ```
261  #[inline]
262  pub fn from_points (a : Point2 <I>, b : Point2 <I>) -> Self {
263    let min = point2_min (&a, &b);
264    let max = point2_max (&a, &b);
265    Aabb2 { min, max }
266  }
267  /// Construct the minimum AABB containing the given set of points.
268  ///
269  /// Identical points are allowed:
270  ///
271  /// ```
272  /// # use math_utils::geometry::integer::*;
273  /// let b = Aabb2::containing (&[[0, 0].into(), [0, 0].into()]);  // ok!
274  /// ```
275  ///
276  /// A single point is allowed:
277  ///
278  /// ```
279  /// # use math_utils::geometry::integer::*;
280  /// let b = Aabb2::containing (&[[0, 0].into()]);  // ok!
281  /// ```
282  ///
283  /// Debug panic if no points are given:
284  ///
285  /// ```should_panic
286  /// # use math_utils::geometry::integer::*;
287  /// let b = Aabb2::<i32>::containing (&[]);  // panic!
288  /// ```
289  #[inline]
290  pub fn containing (points : &[Point2 <I>]) -> Self where I : std::fmt::Debug {
291    debug_assert!(!points.is_empty());
292    let mut min = point2_max_value();
293    let mut max = point2_min_value();
294    for point in points {
295      min = point2_min (&min, point);
296      max = point2_max (&max, point);
297    }
298    Aabb2::with_minmax (min, max)
299  }
300  /// Create a new AABB that is the union of the two input AABBs
301  #[inline]
302  pub fn union (a : &Aabb2 <I>, b : &Aabb2 <I>) -> Self where I : std::fmt::Debug {
303    Aabb2::with_minmax (point2_min (a.min(), b.min()), point2_max (a.max(), b.max()))
304  }
305  #[inline]
306  pub const fn min (&self) -> &Point2 <I> {
307    &self.min
308  }
309  #[inline]
310  pub const fn max (&self) -> &Point2 <I> {
311    &self.max
312  }
313  #[inline]
314  pub fn width (&self) -> I {
315    self.max.0.x - self.min.0.x
316  }
317  #[inline]
318  pub fn height (&self) -> I {
319    self.max.0.y - self.min.0.y
320  }
321  #[inline]
322  pub fn contains (&self, point : &Point2 <I>) -> bool {
323    self.min.0.x <= point.0.x && point.0.x <= self.max.0.x &&
324    self.min.0.y <= point.0.y && point.0.y <= self.max.0.y
325  }
326  /// Clamp a given point to the AABB.
327  ///
328  /// ```
329  /// # use math_utils::geometry::integer::*;
330  /// let b = Aabb2::from_points ([-1, -1].into(), [1, 1].into());
331  /// assert_eq!(b.clamp (&[-2, 0].into()), [-1, 0].into());
332  /// assert_eq!(b.clamp (&[ 2, 2].into()), [ 1, 1].into());
333  /// assert_eq!(b.clamp (&[ 0, 0].into()), [ 0, 0].into());
334  /// ```
335  pub fn clamp (&self, point : &Point2 <I>) -> Point2 <I> {
336    [ Ord::max (Ord::min (self.max.0.x, point.0.x), self.min.0.x),
337      Ord::max (Ord::min (self.max.0.y, point.0.y), self.min.0.y),
338    ].into()
339  }
340  /// Generate a random point contained in the AABB
341  ///
342  /// ```
343  /// # use rand;
344  /// # use rand_xorshift;
345  /// # use math_utils::geometry::integer::*;
346  /// # fn main () {
347  /// use rand_xorshift;
348  /// use rand::SeedableRng;
349  /// // random sequence will be the same each time this is run
350  /// let mut rng = rand_xorshift::XorShiftRng::seed_from_u64 (0);
351  /// let aabb = Aabb2::<i32>::with_minmax (
352  ///   [-10, -10].into(),
353  ///   [ 10,  10].into());
354  /// let point = aabb.rand_point (&mut rng);
355  /// assert!(aabb.contains (&point));
356  /// let point = aabb.rand_point (&mut rng);
357  /// assert!(aabb.contains (&point));
358  /// let point = aabb.rand_point (&mut rng);
359  /// assert!(aabb.contains (&point));
360  /// let point = aabb.rand_point (&mut rng);
361  /// assert!(aabb.contains (&point));
362  /// let point = aabb.rand_point (&mut rng);
363  /// assert!(aabb.contains (&point));
364  /// # }
365  /// ```
366  #[inline]
367  pub fn rand_point <R> (&self, rng : &mut R) -> Point2 <I> where
368    I : rand::distr::uniform::SampleUniform,
369    R : rand::Rng
370  {
371    // NB: integer aabbs include their max points so we increase the max by 1
372    [ rng.random_range (self.min.0.x..self.max.0.x+I::one()),
373      rng.random_range (self.min.0.y..self.max.0.y+I::one())
374    ].into()
375  }
376  #[inline]
377  pub fn intersects (&self, other : &Aabb2 <I>) -> bool {
378    intersect::integer::discrete_aabb2_aabb2 (self, other)
379  }
380}
381
382impl <I : Integer> Aabb3 <I> {
383  /// Construct a new AABB with given min and max points.
384  ///
385  /// Debug panic if points are not min/max:
386  ///
387  /// ```should_panic
388  /// # use math_utils::geometry::integer::*;
389  /// let b = Aabb3::with_minmax ([1, 1, 1].into(), [0, 0, 0].into());  // panic!
390  /// ```
391  ///
392  /// Identical points are allowed:
393  ///
394  /// ```
395  /// # use math_utils::geometry::integer::*;
396  /// let b = Aabb3::with_minmax ([0, 0, 0].into(), [0, 0, 0].into());  // ok
397  /// ```
398  #[inline]
399  pub fn with_minmax (min : Point3 <I>, max : Point3 <I>) -> Self where
400    I : std::fmt::Debug
401  {
402    debug_assert_eq!(min, point3_min (&min, &max));
403    debug_assert_eq!(max, point3_max (&min, &max));
404    Aabb3 { min, max }
405  }
406  /// Construct a new AABB using the two given points to determine min/max.
407  ///
408  /// Identical points are allowed:
409  ///
410  /// ```
411  /// # use math_utils::geometry::integer::*;
412  /// let b = Aabb3::from_points ([0, 0, 0].into(), [0, 0, 0].into());  // ok
413  /// ```
414  #[inline]
415  pub fn from_points (a : Point3 <I>, b : Point3 <I>) -> Self {
416    let min = point3_min (&a, &b);
417    let max = point3_max (&a, &b);
418    Aabb3 { min, max }
419  }
420  /// Construct the minimum AABB containing the given set of points.
421  ///
422  /// Identical points are allowed:
423  ///
424  /// ```
425  /// # use math_utils::geometry::integer::*;
426  /// let b = Aabb3::containing (&[[0, 0, 0].into(), [0, 0, 0].into()]);  // ok!
427  /// ```
428  ///
429  /// A single point is allowed:
430  ///
431  /// ```
432  /// # use math_utils::geometry::integer::*;
433  /// let b = Aabb3::containing (&[[0, 0, 0].into()]);  // ok!
434  /// ```
435  ///
436  /// Debug panic if no points are given:
437  ///
438  /// ```should_panic
439  /// # use math_utils::geometry::integer::*;
440  /// let b = Aabb3::<i32>::containing (&[]);  // panic!
441  /// ```
442  #[inline]
443  pub fn containing (points : &[Point3 <I>]) -> Self where I : std::fmt::Debug {
444    debug_assert!(!points.is_empty());
445    let mut min = point3_max_value();
446    let mut max = point3_min_value();
447    for point in points {
448      min = point3_min (&min, point);
449      max = point3_max (&max, point);
450    }
451    Aabb3::with_minmax (min, max)
452  }
453  /// Create a new AABB that is the union of the two input AABBs
454  #[inline]
455  pub fn union (a : &Aabb3 <I>, b : &Aabb3 <I>) -> Self where I : std::fmt::Debug {
456    Aabb3::with_minmax (point3_min (a.min(), b.min()), point3_max (a.max(), b.max()))
457  }
458  #[inline]
459  pub const fn min (&self) -> &Point3 <I> {
460    &self.min
461  }
462  #[inline]
463  pub const fn max (&self) -> &Point3 <I> {
464    &self.max
465  }
466  #[inline]
467  pub fn width (&self) -> I {
468    self.max.0.x - self.min.0.x
469  }
470  #[inline]
471  pub fn height (&self) -> I {
472    self.max.0.y - self.min.0.y
473  }
474  #[inline]
475  pub fn depth (&self) -> I {
476    self.max.0.z - self.min.0.z
477  }
478  #[inline]
479  pub fn contains (&self, point : &Point3 <I>) -> bool {
480    self.min.0.x <= point.0.x && point.0.x <= self.max.0.x &&
481    self.min.0.y <= point.0.y && point.0.y <= self.max.0.y &&
482    self.min.0.z <= point.0.z && point.0.z <= self.max.0.z
483  }
484  /// Clamp a given point to the AABB.
485  ///
486  /// ```
487  /// # use math_utils::geometry::integer::*;
488  /// let b = Aabb3::with_minmax ([-1, -1, -1].into(), [1, 1, 1].into());
489  /// assert_eq!(b.clamp (&[-2, 0, 0].into()), [-1, 0, 0].into());
490  /// assert_eq!(b.clamp (&[ 2, 2, 0].into()), [ 1, 1, 0].into());
491  /// assert_eq!(b.clamp (&[-1, 2, 3].into()), [-1, 1, 1].into());
492  /// assert_eq!(b.clamp (&[ 0, 0, 0].into()), [ 0, 0, 0].into());
493  /// ```
494  pub fn clamp (&self, point : &Point3 <I>) -> Point3 <I> {
495    [ Ord::max (Ord::min (self.max.0.x, point.0.x), self.min.0.x),
496      Ord::max (Ord::min (self.max.0.y, point.0.y), self.min.0.y),
497      Ord::max (Ord::min (self.max.0.z, point.0.z), self.min.0.z)
498    ].into()
499  }
500  /// Generate a random point contained in the AABB
501  ///
502  /// ```
503  /// # use rand;
504  /// # use rand_xorshift;
505  /// # use math_utils::geometry::integer::*;
506  /// # fn main () {
507  /// use rand::SeedableRng;
508  /// // random sequence will be the same each time this is run
509  /// let mut rng = rand_xorshift::XorShiftRng::seed_from_u64 (0);
510  /// let aabb = Aabb3::<i32>::with_minmax (
511  ///   [-10, -10, -10].into(),
512  ///   [ 10,  10,  10].into());
513  /// let point = aabb.rand_point (&mut rng);
514  /// assert!(aabb.contains (&point));
515  /// let point = aabb.rand_point (&mut rng);
516  /// assert!(aabb.contains (&point));
517  /// let point = aabb.rand_point (&mut rng);
518  /// assert!(aabb.contains (&point));
519  /// let point = aabb.rand_point (&mut rng);
520  /// assert!(aabb.contains (&point));
521  /// let point = aabb.rand_point (&mut rng);
522  /// assert!(aabb.contains (&point));
523  /// # }
524  /// ```
525  #[inline]
526  pub fn rand_point <R> (&self, rng : &mut R) -> Point3 <I> where
527    I : rand::distr::uniform::SampleUniform,
528    R : rand::Rng
529  {
530    // NB: integer aabbs include their max points so we increase the max by 1
531    [ rng.random_range (self.min.0.x..self.max.0.x+I::one()),
532      rng.random_range (self.min.0.y..self.max.0.y+I::one()),
533      rng.random_range (self.min.0.z..self.max.0.z+I::one())
534    ].into()
535  }
536  #[inline]
537  pub fn intersects (&self, other : &Aabb3 <I>) -> bool {
538    intersect::integer::discrete_aabb3_aabb3 (self, other)
539  }
540}