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}