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}