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}