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