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