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, Copy, 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, Copy, 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, Copy, 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) -> Positive <I> {
173 Positive::unchecked (self.max - self.min + I::one())
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::RngExt
219 {
220 // NOTE: 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 dimensions (self) -> Vector2 <Positive <I>> {
315 (self.max.0 - self.min.0 + I::one()).map (Positive::unchecked)
316 }
317 #[inline]
318 pub fn width (self) -> Positive <I> {
319 Positive::unchecked (self.max.0.x - self.min.0.x + I::one())
320 }
321 #[inline]
322 pub fn height (self) -> Positive <I> {
323 Positive::unchecked (self.max.0.y - self.min.0.y + I::one())
324 }
325 #[inline]
326 pub fn contains (self, point : Point2 <I>) -> bool {
327 self.min.0.x <= point.0.x && point.0.x <= self.max.0.x &&
328 self.min.0.y <= point.0.y && point.0.y <= self.max.0.y
329 }
330 /// Clamp a given point to the AABB.
331 ///
332 /// ```
333 /// # use math_utils::geometry::integer::*;
334 /// let b = Aabb2::from_points ([-1, -1].into(), [1, 1].into());
335 /// assert_eq!(b.clamp ([-2, 0].into()), [-1, 0].into());
336 /// assert_eq!(b.clamp ([ 2, 2].into()), [ 1, 1].into());
337 /// assert_eq!(b.clamp ([ 0, 0].into()), [ 0, 0].into());
338 /// ```
339 pub fn clamp (self, point : Point2 <I>) -> Point2 <I> {
340 [ Ord::max (Ord::min (self.max.0.x, point.0.x), self.min.0.x),
341 Ord::max (Ord::min (self.max.0.y, point.0.y), self.min.0.y),
342 ].into()
343 }
344 /// Generate a random point contained in the AABB
345 ///
346 /// ```
347 /// # use rand;
348 /// # use rand_xorshift;
349 /// # use math_utils::geometry::integer::*;
350 /// # fn main () {
351 /// use rand_xorshift;
352 /// use rand::SeedableRng;
353 /// // random sequence will be the same each time this is run
354 /// let mut rng = rand_xorshift::XorShiftRng::seed_from_u64 (0);
355 /// let aabb = Aabb2::<i32>::with_minmax (
356 /// [-10, -10].into(),
357 /// [ 10, 10].into());
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 /// let point = aabb.rand_point (&mut rng);
365 /// assert!(aabb.contains (point));
366 /// let point = aabb.rand_point (&mut rng);
367 /// assert!(aabb.contains (point));
368 /// # }
369 /// ```
370 #[inline]
371 pub fn rand_point <R> (self, rng : &mut R) -> Point2 <I> where
372 I : rand::distr::uniform::SampleUniform,
373 R : rand::RngExt
374 {
375 // NOTE: integer aabbs include their max points so we increase the max by 1
376 [ rng.random_range (self.min.0.x..self.max.0.x+I::one()),
377 rng.random_range (self.min.0.y..self.max.0.y+I::one())
378 ].into()
379 }
380 #[inline]
381 pub fn intersects (self, other : Aabb2 <I>) -> bool {
382 intersect::integer::discrete_aabb2_aabb2 (self, other)
383 }
384}
385
386impl <I : Integer> Aabb3 <I> {
387 /// Construct a new AABB with given min and max points.
388 ///
389 /// Debug panic if points are not min/max:
390 ///
391 /// ```should_panic
392 /// # use math_utils::geometry::integer::*;
393 /// let b = Aabb3::with_minmax ([1, 1, 1].into(), [0, 0, 0].into()); // panic!
394 /// ```
395 ///
396 /// Identical points are allowed:
397 ///
398 /// ```
399 /// # use math_utils::geometry::integer::*;
400 /// let b = Aabb3::with_minmax ([0, 0, 0].into(), [0, 0, 0].into()); // ok
401 /// ```
402 #[inline]
403 pub fn with_minmax (min : Point3 <I>, max : Point3 <I>) -> Self where
404 I : std::fmt::Debug
405 {
406 debug_assert_eq!(min, point3_min (min, max));
407 debug_assert_eq!(max, point3_max (min, max));
408 Aabb3 { min, max }
409 }
410 /// Construct a new AABB using the two given points to determine min/max.
411 ///
412 /// Identical points are allowed:
413 ///
414 /// ```
415 /// # use math_utils::geometry::integer::*;
416 /// let b = Aabb3::from_points ([0, 0, 0].into(), [0, 0, 0].into()); // ok
417 /// ```
418 #[inline]
419 pub fn from_points (a : Point3 <I>, b : Point3 <I>) -> Self {
420 let min = point3_min (a, b);
421 let max = point3_max (a, b);
422 Aabb3 { min, max }
423 }
424 /// Construct the minimum AABB containing the given set of points.
425 ///
426 /// Identical points are allowed:
427 ///
428 /// ```
429 /// # use math_utils::geometry::integer::*;
430 /// let b = Aabb3::containing (&[[0, 0, 0].into(), [0, 0, 0].into()]); // ok!
431 /// ```
432 ///
433 /// A single point is allowed:
434 ///
435 /// ```
436 /// # use math_utils::geometry::integer::*;
437 /// let b = Aabb3::containing (&[[0, 0, 0].into()]); // ok!
438 /// ```
439 ///
440 /// Debug panic if no points are given:
441 ///
442 /// ```should_panic
443 /// # use math_utils::geometry::integer::*;
444 /// let b = Aabb3::<i32>::containing (&[]); // panic!
445 /// ```
446 #[inline]
447 pub fn containing (points : &[Point3 <I>]) -> Self where I : std::fmt::Debug {
448 debug_assert!(!points.is_empty());
449 let mut min = point3_max_value();
450 let mut max = point3_min_value();
451 for point in points {
452 min = point3_min (min, *point);
453 max = point3_max (max, *point);
454 }
455 Aabb3::with_minmax (min, max)
456 }
457 /// Create a new AABB that is the union of the two input AABBs
458 #[inline]
459 pub fn union (a : Aabb3 <I>, b : Aabb3 <I>) -> Self where I : std::fmt::Debug {
460 Aabb3::with_minmax (point3_min (a.min(), b.min()), point3_max (a.max(), b.max()))
461 }
462 #[inline]
463 pub const fn min (self) -> Point3 <I> {
464 self.min
465 }
466 #[inline]
467 pub const fn max (self) -> Point3 <I> {
468 self.max
469 }
470 #[inline]
471 pub fn dimensions (self) -> Vector3 <Positive <I>> {
472 (self.max.0 - self.min.0 + I::one()).map (Positive::unchecked)
473 }
474 #[inline]
475 pub fn width (self) -> Positive <I> {
476 Positive::unchecked (self.max.0.x - self.min.0.x + I::one())
477 }
478 #[inline]
479 pub fn height (self) -> Positive <I> {
480 Positive::unchecked (self.max.0.y - self.min.0.y + I::one())
481 }
482 #[inline]
483 pub fn depth (self) -> Positive <I> {
484 Positive::unchecked (self.max.0.z - self.min.0.z + I::one())
485 }
486 #[inline]
487 pub fn contains (self, point : Point3 <I>) -> bool {
488 self.min.0.x <= point.0.x && point.0.x <= self.max.0.x &&
489 self.min.0.y <= point.0.y && point.0.y <= self.max.0.y &&
490 self.min.0.z <= point.0.z && point.0.z <= self.max.0.z
491 }
492 /// Clamp a given point to the AABB.
493 ///
494 /// ```
495 /// # use math_utils::geometry::integer::*;
496 /// let b = Aabb3::with_minmax ([-1, -1, -1].into(), [1, 1, 1].into());
497 /// assert_eq!(b.clamp ([-2, 0, 0].into()), [-1, 0, 0].into());
498 /// assert_eq!(b.clamp ([ 2, 2, 0].into()), [ 1, 1, 0].into());
499 /// assert_eq!(b.clamp ([-1, 2, 3].into()), [-1, 1, 1].into());
500 /// assert_eq!(b.clamp ([ 0, 0, 0].into()), [ 0, 0, 0].into());
501 /// ```
502 pub fn clamp (self, point : Point3 <I>) -> Point3 <I> {
503 [ Ord::max (Ord::min (self.max.0.x, point.0.x), self.min.0.x),
504 Ord::max (Ord::min (self.max.0.y, point.0.y), self.min.0.y),
505 Ord::max (Ord::min (self.max.0.z, point.0.z), self.min.0.z)
506 ].into()
507 }
508 /// Generate a random point contained in the AABB
509 ///
510 /// ```
511 /// # use rand;
512 /// # use rand_xorshift;
513 /// # use math_utils::geometry::integer::*;
514 /// # fn main () {
515 /// use rand::SeedableRng;
516 /// // random sequence will be the same each time this is run
517 /// let mut rng = rand_xorshift::XorShiftRng::seed_from_u64 (0);
518 /// let aabb = Aabb3::<i32>::with_minmax (
519 /// [-10, -10, -10].into(),
520 /// [ 10, 10, 10].into());
521 /// let point = aabb.rand_point (&mut rng);
522 /// assert!(aabb.contains (point));
523 /// let point = aabb.rand_point (&mut rng);
524 /// assert!(aabb.contains (point));
525 /// let point = aabb.rand_point (&mut rng);
526 /// assert!(aabb.contains (point));
527 /// let point = aabb.rand_point (&mut rng);
528 /// assert!(aabb.contains (point));
529 /// let point = aabb.rand_point (&mut rng);
530 /// assert!(aabb.contains (point));
531 /// # }
532 /// ```
533 #[inline]
534 pub fn rand_point <R> (self, rng : &mut R) -> Point3 <I> where
535 I : rand::distr::uniform::SampleUniform,
536 R : rand::RngExt
537 {
538 // NOTE: integer aabbs include their max points so we increase the max by 1
539 [ rng.random_range (self.min.0.x..self.max.0.x+I::one()),
540 rng.random_range (self.min.0.y..self.max.0.y+I::one()),
541 rng.random_range (self.min.0.z..self.max.0.z+I::one())
542 ].into()
543 }
544 #[inline]
545 pub fn intersects (self, other : Aabb3 <I>) -> bool {
546 intersect::integer::discrete_aabb3_aabb3 (self, other)
547 }
548}