bounding_box/lib.rs
1#![doc = include_str!("../README.md")]
2
3#[cfg(feature = "approx")]
4use approx::ulps_eq;
5
6#[cfg(feature = "serde")]
7use serde::{Deserialize, Serialize};
8
9/**
10A rectilinear, 2-dimensional [bounding box](https://en.wikipedia.org/wiki/Minimum_bounding_rectangle).
11
12A 2-dimensional rectilinear bounding box is described by four values: minimum
13x-value, maximum x-value, minimum y-value and and maximum y-value. This struct
14can be created either from any type which implements [`Into<BoundingBox>`] or
15from the constructors [`new`](BoundingBox::new) or
16[`try_new`](BoundingBox::try_new). The values defining a bounding box (`xmin`,
17`xmax`, `ymin`, `ymax`) are called "extremas".
18
19Since a bounding box only consists of four f64 values (32 bytes), it is cheap to
20copy, hence it implements the
21[`Copy`](https://doc.rust-lang.org/std/marker/trait.Copy.html) trait.
22
23# Features
24
25This struct can be serialized / deserialized if the `serde` feature is enabled.
26 */
27#[derive(Debug, Clone, Copy, PartialEq)]
28#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
29pub struct BoundingBox {
30 xmin: f64,
31 xmax: f64,
32 ymin: f64,
33 ymax: f64,
34}
35
36impl BoundingBox {
37 /**
38 Generates a bounding box from minimum and maximum x- and y-values.
39
40 # Panics
41 Panics if `xmin > xmax` or if `ymin > ymax`.
42
43 # Examples
44
45 ```
46 use bounding_box::BoundingBox;
47
48 let _ = BoundingBox::new(0.0, 1.0, 0.0, 1.0);
49 ```
50
51 This example panics because `xmin > xmax`.
52
53 ```should_panic
54 use bounding_box::BoundingBox;
55
56 let _ = BoundingBox::new(2.0, 1.0, 0.0, 1.0);
57 ```
58 */
59 pub fn new(xmin: f64, xmax: f64, ymin: f64, ymax: f64) -> Self {
60 return Self::try_new(xmin, xmax, ymin, ymax)
61 .expect("one of the conditions xmin <= xmax and ymin <= ymax is not fulfilled");
62 }
63
64 /**
65 Like [`BoundingBox::new`], but returns `None` instead of panicking if `xmin > xmax` or if `ymin > ymax`.
66
67 # Examples
68
69 ```
70 use bounding_box::BoundingBox;
71
72 assert!(BoundingBox::try_new(0.0, 1.0, 0.0, 1.0).is_some());
73 assert!(BoundingBox::try_new(2.0, 1.0, 0.0, 1.0).is_none());
74 ```
75 */
76 pub fn try_new(xmin: f64, xmax: f64, ymin: f64, ymax: f64) -> Option<Self> {
77 if xmin > xmax || ymin > ymax {
78 return None;
79 }
80 return Some(BoundingBox {
81 xmin,
82 xmax,
83 ymin,
84 ymax,
85 });
86 }
87
88 /**
89 Returns the minimum x-value of the bounding box.
90 */
91 pub fn xmin(&self) -> f64 {
92 return self.xmin;
93 }
94
95 /**
96 Returns the maximum x-value of the bounding box.
97 */
98 pub fn xmax(&self) -> f64 {
99 return self.xmax;
100 }
101
102 /**
103 Returns the minimum y-value of the bounding box.
104 */
105 pub fn ymin(&self) -> f64 {
106 return self.ymin;
107 }
108
109 /**
110 Returns the maximum y-value of the bounding box.
111 */
112 pub fn ymax(&self) -> f64 {
113 return self.ymax;
114 }
115
116 /**
117 Fallible sets a new value for `xmin`. If the new value is bigger than `xmax`, the old value is left unchanged
118 and this function returns `false`. Otherwise, it returns `true` and the old value is replaced by the new value.
119
120 # Examples
121
122 ```
123 use bounding_box::BoundingBox;
124
125 let mut bb = BoundingBox::new(0.0, 1.0, 0.0, 1.0);
126
127 assert_eq!(bb.xmin(), 0.0);
128 assert!(bb.try_set_xmin(0.5));
129 assert_eq!(bb.xmin(), 0.5);
130
131 assert!(!bb.try_set_xmin(1.5));
132 assert_eq!(bb.xmin(), 0.5);
133 ```
134 */
135 pub fn try_set_xmin(&mut self, val: f64) -> bool {
136 if val > self.xmax {
137 return false;
138 } else {
139 self.xmin = val;
140 return true;
141 }
142 }
143
144 /**
145 Fallible sets a new value for `xmax`. If the new value is smaller than `xmin`, the old value is left unchanged
146 and this function returns `false`. Otherwise, it returns `true` and the old value is replaced by the new value.
147
148 # Examples
149
150 ```
151 use bounding_box::BoundingBox;
152
153 let mut bb = BoundingBox::new(0.0, 1.0, 0.0, 1.0);
154
155 assert_eq!(bb.xmax(), 1.0);
156 assert!(bb.try_set_xmax(0.5));
157 assert_eq!(bb.xmax(), 0.5);
158
159 assert!(!bb.try_set_xmax(-0.5));
160 assert_eq!(bb.xmax(), 0.5);
161 ```
162 */
163 pub fn try_set_xmax(&mut self, val: f64) -> bool {
164 if val < self.xmin {
165 return false;
166 } else {
167 self.xmax = val;
168 return true;
169 }
170 }
171
172 /**
173 Fallible sets a new value for `ymin`. If the new value is bigger than `ymax`, the old value is left unchanged
174 and this function returns `false`. Otherwise, it returns `true` and the old value is replaced by the new value.
175
176 # Examples
177
178 ```
179 use bounding_box::BoundingBox;
180
181 let mut bb = BoundingBox::new(0.0, 1.0, 0.0, 1.0);
182
183 assert_eq!(bb.ymin(), 0.0);
184 assert!(bb.try_set_ymin(0.5));
185 assert_eq!(bb.ymin(), 0.5);
186
187 assert!(!bb.try_set_ymin(1.5));
188 assert_eq!(bb.ymin(), 0.5);
189 ```
190 */
191 pub fn try_set_ymin(&mut self, val: f64) -> bool {
192 if val > self.ymax {
193 return false;
194 } else {
195 self.ymin = val;
196 return true;
197 }
198 }
199
200 /**
201 Fallible sets a new value for `ymax`. If the new value is smaller than `ymin`, the old value is left unchanged
202 and this function returns `false`. Otherwise, it returns `true` and the old value is replaced by the new value.
203
204 # Examples
205
206 ```
207 use bounding_box::BoundingBox;
208
209 let mut bb = BoundingBox::new(0.0, 1.0, 0.0, 1.0);
210
211 assert_eq!(bb.ymax(), 1.0);
212 assert!(bb.try_set_ymax(0.5));
213 assert_eq!(bb.ymax(), 0.5);
214
215 assert!(!bb.try_set_ymax(-0.5));
216 assert_eq!(bb.ymax(), 0.5);
217 ```
218 */
219 pub fn try_set_ymax(&mut self, val: f64) -> bool {
220 if val < self.ymin {
221 return false;
222 } else {
223 self.ymax = val;
224 return true;
225 }
226 }
227
228 /**
229 Creates a bounding box from an iterator over vertices.
230
231 If the iterator is empty, this function returns `None`.
232 ```
233 use bounding_box::BoundingBox;
234
235 let verts = vec![
236 [1.0, 0.0],
237 [-5.0, 2.0],
238 [3.0, -12.3],
239 [7.0, 0.0],
240 [2.0, 11.0],
241 [1.0, -6.0],
242 ];
243
244 let bb = BoundingBox::from_points(verts.into_iter()).expect("iterator yields at least one elment");
245 assert_eq!(bb.xmin(), -5.0);
246 assert_eq!(bb.xmax(), 7.0);
247 assert_eq!(bb.ymin(), -12.3);
248 assert_eq!(bb.ymax(), 11.0);
249 ```
250 */
251 pub fn from_points<'a, T: Into<[f64; 2]>, I: Iterator<Item = T>>(mut verts: I) -> Option<Self> {
252 match verts.next() {
253 Some(pt) => {
254 let pt: [f64; 2] = pt.into();
255 let mut xmin = pt[0];
256 let mut xmax = pt[0];
257 let mut ymin = pt[1];
258 let mut ymax = pt[1];
259 for vert in verts {
260 let pt: [f64; 2] = vert.into();
261 if pt[0] > xmax {
262 xmax = pt[0]
263 }
264 if pt[0] < xmin {
265 xmin = pt[0]
266 }
267 if pt[1] > ymax {
268 ymax = pt[1]
269 }
270 if pt[1] < ymin {
271 ymin = pt[1]
272 }
273 }
274 return Some(BoundingBox::new(xmin, xmax, ymin, ymax));
275 }
276 None => return None,
277 }
278 }
279
280 /**
281 Creates a bounding box from an iterator over any types implementing
282 [`Into<BoundingBox>`].
283
284 If the iterator is empty, this function returns `None`.
285
286 ```
287 use bounding_box::BoundingBox;
288
289 struct Circle {
290 center: [f64; 2],
291 radius: f64
292 }
293
294 impl From<&Circle> for BoundingBox {
295 fn from(c: &Circle) -> BoundingBox {
296 return BoundingBox::new(c.center[0] - c.radius,
297 c.center[0] + c.radius,
298 c.center[1] - c.radius,
299 c.center[1] + c.radius);
300 }
301 }
302
303 let c1 = Circle {center: [0.0, 0.0], radius: 1.0};
304 let c2 = Circle {center: [0.0, 2.0], radius: 1.0};
305 let c3 = Circle {center: [0.0, 2.0], radius: 2.0};
306
307 let bb = BoundingBox::from_bounded_entities([&c1, &c2, &c3].into_iter()).expect("iterator has at least one element");
308 assert_eq!(bb.xmin(), -2.0);
309 assert_eq!(bb.xmax(), 2.0);
310 assert_eq!(bb.ymin(), -1.0);
311 assert_eq!(bb.ymax(), 4.0);
312 ```
313 */
314 pub fn from_bounded_entities<T: Into<BoundingBox>, I: Iterator<Item = T>>(
315 mut entities: I,
316 ) -> Option<Self> {
317 let first_bb: BoundingBox = entities.next()?.into();
318 let bb = entities.fold(first_bb, |acc, drawable| drawable.into().union(&acc));
319 return Some(bb);
320 }
321
322 /**
323 Creates the union of two bounding boxes.
324
325 The union of two bounding boxes is the minimum bounding box which contains both bounding boxes.
326
327 # Examples
328
329 ```
330 use bounding_box::BoundingBox;
331
332 let bb1 = BoundingBox::new(-1.0, 3.5, 2.0, 3.0);
333 let bb2 = BoundingBox::new(-5.0, 2.5, -1.0, 5.0);
334 let bb = bb1.union(&bb2);
335
336 assert_eq!(bb.xmin(), -5.0);
337 assert_eq!(bb.xmax(), 3.5);
338 assert_eq!(bb.ymin(), -1.0);
339 assert_eq!(bb.ymax(), 5.0);
340 ```
341 */
342 pub fn union(&self, other: &BoundingBox) -> BoundingBox {
343 let xmin: f64;
344 let xmax: f64;
345 let ymin: f64;
346 let ymax: f64;
347 if self.xmin > other.xmin {
348 xmin = other.xmin;
349 } else {
350 xmin = self.xmin;
351 }
352 if self.xmax > other.xmax {
353 xmax = self.xmax;
354 } else {
355 xmax = other.xmax;
356 }
357 if self.ymin > other.ymin {
358 ymin = other.ymin;
359 } else {
360 ymin = self.ymin;
361 }
362 if self.ymax > other.ymax {
363 ymax = self.ymax;
364 } else {
365 ymax = other.ymax;
366 }
367 return BoundingBox {
368 xmin,
369 xmax,
370 ymin,
371 ymax,
372 };
373 }
374
375 /**
376 Returns true if `self` contains a given point.
377
378 A point is also seen as included if it is located on the edge of a bounding box.
379
380 # Examples
381 ```
382 use bounding_box::BoundingBox;
383
384 let bb = BoundingBox::new(0.0, 1.0, 0.0, 1.0);
385
386 assert!(bb.contains_point([0.5, 0.5]));
387 assert!(bb.contains_point([0.0, 0.0]));
388 assert!(bb.contains_point([0.0, 0.0]));
389 assert!(!bb.contains_point([-1.0, 0.0]));
390 assert!(!bb.contains_point([0.0, 2.0]));
391 */
392 pub fn contains_point<T: Into<[f64; 2]>>(&self, point: T) -> bool {
393 let point: [f64; 2] = point.into();
394 return (self.xmin < point[0] || self.xmin == point[0])
395 && (self.ymin < point[1] || self.ymin == point[1])
396 && (self.xmax > point[0] || self.xmax == point[0])
397 && (self.ymax > point[1] || self.ymax == point[1]);
398 }
399
400 /**
401 Like [`BoundingBox::contains_point`], but with absolute and ULPs tolerances.
402
403 This variant of [`BoundingBox::contains_point`] allows specifying an absolute and
404 an [ULP](https://en.wikipedia.org/wiki/Unit_in_the_last_place) tolerance. These tolerances
405 are used to check if the given point lies "approximately" on an edge of the bounding box.
406
407 # Examples
408 ```
409 use bounding_box::BoundingBox;
410
411 let bb = BoundingBox::new(0.0, 1.0, 0.0, 1.0);
412
413 // Exact check: Point is outside the bounding box
414 assert!(!bb.contains_point([1.0001, 1.0]));
415
416 // Check using tolerances: Point is inside bounding box
417 assert!(bb.approx_contains_point([1.0001, 1.0], 1e-3, 0));
418
419 // Check using a finer tolerance: Point is outside the bounding box
420 assert!(!bb.approx_contains_point([1.0001, 1.0], 1e-6, 0));
421 ```
422
423 # Features
424
425 This function uses the [`ulps_eq`](https://docs.rs/approx/latest/approx/macro.ulps_eq.html)
426 macro of the [approx] crate, therefore the `approx ` feature needs to be enabled.
427 */
428 #[cfg(feature = "approx")]
429 pub fn approx_contains_point<T: Into<[f64; 2]>>(
430 &self,
431 point: T,
432 epsilon: f64,
433 max_ulps: u32,
434 ) -> bool {
435 let point: [f64; 2] = point.into();
436 return (self.xmin < point[0]
437 || ulps_eq!(self.xmin, point[0], epsilon = epsilon, max_ulps = max_ulps))
438 && (self.ymin < point[1]
439 || ulps_eq!(self.ymin, point[1], epsilon = epsilon, max_ulps = max_ulps))
440 && (self.xmax > point[0]
441 || ulps_eq!(self.xmax, point[0], epsilon = epsilon, max_ulps = max_ulps))
442 && (self.ymax > point[1]
443 || ulps_eq!(self.ymax, point[1], epsilon = epsilon, max_ulps = max_ulps));
444 }
445
446 /**
447 Returns true if `self` contains `other`.
448
449 A bounding box contains another bounding box, if the latter can be placed inside the former.
450 This is true even if the boxes share some extremums. This also means that a bounding box always contains itself (see examples).
451
452 # Examples
453 ```
454 use bounding_box::BoundingBox;
455
456 // bb1 contains bb2, but not the other way around
457 let bb1 = BoundingBox::new(0.0, 1.0, 0.0, 1.0);
458 let bb2 = BoundingBox::new(0.2, 0.8, 0.2, 0.8);
459 assert!(bb1.contains(&bb2));
460 assert!(!bb2.contains(&bb1));
461
462 // bb1 contains itself
463 assert!(bb1.contains(&bb1));
464
465 // bb1 and bb2 share a border
466 let bb1 = BoundingBox::new(0.0, 1.0, 0.0, 1.0);
467 let bb2 = BoundingBox::new(0.2, 1.0, 0.2, 0.8);
468 assert!(bb1.contains(&bb2));
469
470 // bb1 and bb2 are separated from each other, and therefore neither of one contains the other
471 let bb1 = BoundingBox::new(0.0, 1.0, 0.0, 1.0);
472 let bb2 = BoundingBox::new(2.0, 3.0, 2.0, 3.0);
473 assert!(!bb1.contains(&bb2));
474 assert!(!bb2.contains(&bb1));
475 ```
476 */
477 pub fn contains(&self, other: &Self) -> bool {
478 return self.xmin <= other.xmin
479 && self.ymin <= other.ymin
480 && self.xmax >= other.xmax
481 && self.ymax >= other.ymax;
482 }
483
484 /**
485 Like [`BoundingBox::contains`], but with absolute and ULPs tolerances.
486
487 This variant of [`BoundingBox::contains`] allows specifying an absolute and
488 an [ULP](https://en.wikipedia.org/wiki/Unit_in_the_last_place) tolerance. These tolerances
489 are used to check if the extremas of the boxes are "approximately" equal.
490 This check is performed using the [`ulps_eq`](https://docs.rs/approx/latest/approx/macro.ulps_eq.html)
491 macro of the [approx] crate. Please see its documentation.
492
493 ```
494 use bounding_box::BoundingBox;
495
496 // bb1 contains bb2 depending on the selected tolerances
497 let bb1 = BoundingBox::new(0.0, 1.0, 0.0, 1.0);
498 let bb2 = BoundingBox::new(0.0, 1.0001, 0.0, 0.5);
499
500 assert!(!bb1.contains(&bb2));
501 assert!(bb1.approx_contains(&bb2, 1e-3, 0));
502 assert!(!bb1.approx_contains(&bb2, 1e-6, 0));
503 ```
504
505 # Features
506
507 This function uses the [`ulps_eq`](https://docs.rs/approx/latest/approx/macro.ulps_eq.html)
508 macro of the [approx] crate, therefore the `approx ` feature needs to be enabled.
509 */
510 #[cfg(feature = "approx")]
511 pub fn approx_contains(&self, other: &Self, epsilon: f64, max_ulps: u32) -> bool {
512 return (self.xmin < other.xmin
513 || ulps_eq!(
514 self.xmin,
515 other.xmin,
516 epsilon = epsilon,
517 max_ulps = max_ulps
518 ))
519 && (self.ymin < other.ymin
520 || ulps_eq!(
521 self.ymin,
522 other.ymin,
523 epsilon = epsilon,
524 max_ulps = max_ulps
525 ))
526 && (self.xmax > other.xmax
527 || ulps_eq!(
528 self.xmax,
529 other.xmax,
530 epsilon = epsilon,
531 max_ulps = max_ulps
532 ))
533 && (self.ymax > other.ymax
534 || ulps_eq!(
535 self.ymax,
536 other.ymax,
537 epsilon = epsilon,
538 max_ulps = max_ulps
539 ));
540 }
541
542 /**
543 Check if the two bounding boxes are approximately equal.
544 This check is performed using the [`ulps_eq`](https://docs.rs/approx/latest/approx/macro.ulps_eq.html)
545 macro of the [approx] crate. Please see its documentation.
546
547 ```
548 use bounding_box::BoundingBox;
549
550 // bb1 contains bb2 depending on the selected tolerances
551 let bb1 = BoundingBox::new(0.0, 1.0, 0.0, 1.0);
552 let bb2 = BoundingBox::new(0.0, 1.0001, 0.0, 1.0);
553
554 assert!(!bb1.eq(&bb2));
555 assert!(bb1.approx_eq(&bb2, 1e-3, 0));
556 assert!(!bb1.approx_eq(&bb2, 1e-6, 0));
557 ```
558
559 # Features
560
561 This function uses the [`ulps_eq`](https://docs.rs/approx/latest/approx/macro.ulps_eq.html)
562 macro of the [approx] crate, therefore the `approx ` feature needs to be enabled.
563 */
564 #[cfg(feature = "approx")]
565 pub fn approx_eq(&self, other: &Self, epsilon: f64, max_ulps: u32) -> bool {
566 return ulps_eq!(
567 self.xmin(),
568 other.xmin(),
569 epsilon = epsilon,
570 max_ulps = max_ulps
571 ) && ulps_eq!(
572 self.xmax(),
573 other.xmax(),
574 epsilon = epsilon,
575 max_ulps = max_ulps
576 ) && ulps_eq!(
577 self.ymin(),
578 other.ymin(),
579 epsilon = epsilon,
580 max_ulps = max_ulps
581 ) && ulps_eq!(
582 self.ymax(),
583 other.ymax(),
584 epsilon = epsilon,
585 max_ulps = max_ulps
586 );
587 }
588
589 /**
590 Returns true if the bounding boxes intersect.
591
592 The boxes are NOT intersecting if they are just [touching](BoundingBox::touches).
593
594 # Examples
595 ```
596 use bounding_box::BoundingBox;
597
598 // bb1 and bb2 intersect
599 let bb1 = BoundingBox::new(0.0, 1.0, 0.0, 1.0);
600 let bb2 = BoundingBox::new(-1.0, 1.0, 0.2, 0.8);
601 assert!(bb1.intersects(&bb2));
602
603 // bb1 and bb2 do not intersect
604 let bb1 = BoundingBox::new(-1.0, 3.5, 2.0, 3.0);
605 let bb2 = BoundingBox::new(-5.0, 2.5, -1.0, 1.0);
606 assert!(!bb1.intersects(&bb2));
607
608 // bb2 is contained in bb1
609 let bb1 = BoundingBox::new(0.0, 1.0, 0.0, 1.0);
610 let bb2 = BoundingBox::new(0.2, 1.0, 0.2, 0.8);
611 assert!(bb1.intersects(&bb2));
612
613 // bb1 is contained in bb2
614 let bb1 = BoundingBox::new(0.0, 1.0, 0.0, 1.0);
615 let bb2 = BoundingBox::new(0.2, 1.0, 0.2, 0.8);
616 assert!(bb2.intersects(&bb1));
617
618 // bb1 touches bb2 => no intersection
619 let bb1 = BoundingBox::new(0.0, 1.0, 0.0, 1.0);
620 let bb2 = BoundingBox::new(1.0, 2.0, 0.0, 1.0);
621 assert!(!bb2.intersects(&bb1));
622 ```
623 */
624 pub fn intersects(&self, other: &Self) -> bool {
625 return self.xmin() < other.xmax()
626 && other.xmin() < self.xmax()
627 && self.ymin() < other.ymax()
628 && other.ymin() < self.ymax();
629 }
630
631 /**
632 Check if the bounding boxes are touching.
633
634 The bounding boxes are touching if they share at least one extremum and are not intersecting each other.
635
636 # Examples
637 ```
638 use bounding_box::BoundingBox;
639
640 // bb1 touches bb2 => no intersection
641 let bb1 = BoundingBox::new(0.0, 1.0, 0.0, 1.0);
642 let bb2 = BoundingBox::new(1.0, 2.0, 0.0, 1.0);
643 assert!(bb2.touches(&bb1));
644
645 // bb1 is included in bb2 and two edges are touching
646 let bb1 = BoundingBox::new(0.0, 1.0, 0.0, 1.0);
647 let bb2 = BoundingBox::new(0.0, 2.0, 0.0, 1.0);
648 assert!(!bb2.touches(&bb1));
649
650 let bb1 = BoundingBox::new(0.0, 1.0, 0.0, 1.0);
651 let bb2 = BoundingBox::new(1.0001, 2.0, 0.0, 1.0);
652 assert!(!bb2.touches(&bb1));
653 ```
654 */
655 pub fn touches(&self, other: &Self) -> bool {
656 if self.intersects(&other) {
657 return false;
658 } else {
659 return self.xmin() == other.xmax()
660 || self.xmax() == other.xmin()
661 || self.ymin() == other.ymax()
662 || self.ymax() == other.ymin();
663 }
664 }
665
666 /**
667 Like [`BoundingBox::touches`], but with absolute and ULPs tolerances.
668
669 This variant of [`BoundingBox::touches`] allows specifying an absolute and
670 an [ULP](https://en.wikipedia.org/wiki/Unit_in_the_last_place) tolerance. These tolerances
671 are used to check if the boxes share at least one extremas "approximately".
672 This check is performed using the [`ulps_eq`](https://docs.rs/approx/latest/approx/macro.ulps_eq.html)
673 macro of the [approx] crate. Please see its documentation.
674
675 # Examples
676 ```
677 use bounding_box::BoundingBox;
678
679 let bb1 = BoundingBox::new(0.0, 1.0, 0.0, 1.0);
680 let bb2 = BoundingBox::new(1.0001, 2.0, 0.0, 1.0);
681 assert!(!bb1.touches(&bb2));
682 assert!(bb1.approx_touches(&bb2, 1e-3, 0));
683 assert!(!bb1.approx_touches(&bb2, 1e-6, 0));
684 ```
685
686 # Features
687
688 This function uses the [`ulps_eq`](https://docs.rs/approx/latest/approx/macro.ulps_eq.html)
689 macro of the [approx] crate, therefore the `approx ` feature needs to be enabled.
690 */
691 #[cfg(feature = "approx")]
692 pub fn approx_touches(&self, other: &Self, epsilon: f64, max_ulps: u32) -> bool {
693 if self.intersects(&other) {
694 return false;
695 } else {
696 return ulps_eq!(
697 self.xmin(),
698 other.xmax(),
699 epsilon = epsilon,
700 max_ulps = max_ulps
701 ) || ulps_eq!(
702 self.xmax(),
703 other.xmin(),
704 epsilon = epsilon,
705 max_ulps = max_ulps
706 ) || ulps_eq!(
707 self.ymin(),
708 other.ymax(),
709 epsilon = epsilon,
710 max_ulps = max_ulps
711 ) || ulps_eq!(
712 self.ymax(),
713 other.ymin(),
714 epsilon = epsilon,
715 max_ulps = max_ulps
716 );
717 }
718 }
719
720 /**
721 Returns the width of the bounding box.
722
723 # Examples
724 ```
725 use bounding_box::BoundingBox;
726
727 let bb = BoundingBox::new(-1.0, 1.0, 2.0, 7.0);
728 assert_eq!(bb.width(), 2.0);
729 ```
730 */
731 pub fn width(&self) -> f64 {
732 return self.xmax - self.xmin;
733 }
734
735 /**
736 Returns the height of the bounding box.
737
738 # Examples
739 ```
740 use bounding_box::BoundingBox;
741
742 let bb = BoundingBox::new(-1.0, 1.0, 2.0, 7.0);
743 assert_eq!(bb.height(), 5.0);
744 ```
745 */
746 pub fn height(&self) -> f64 {
747 return self.ymax - self.ymin;
748 }
749
750 /**
751 Returns the center of the bounding box.
752
753 # Examples
754 ```
755 use bounding_box::BoundingBox;
756
757 let bb = BoundingBox::new(-1.0, 1.0, 2.0, 7.0);
758 assert_eq!(bb.center(), [0.0, 4.5]);
759 ```
760 */
761 pub fn center(&self) -> [f64; 2] {
762 let x = 0.5 * (self.xmax + self.xmin);
763 let y = 0.5 * (self.ymax + self.ymin);
764 return [x, y];
765 }
766
767 /**
768 Translates the bounding box by the given `shift`.
769
770 # Examples
771 ```
772 use bounding_box::BoundingBox;
773
774 let mut bb = BoundingBox::new(0.0, 1.0, 1.0, 2.0);
775 bb.translate([1.0, -1.0]);
776 assert_eq!(bb.xmin(), 1.0);
777 assert_eq!(bb.xmax(), 2.0);
778 assert_eq!(bb.ymin(), 0.0);
779 assert_eq!(bb.ymax(), 1.0);
780 ```
781 */
782 pub fn translate<T: Into<[f64; 2]>>(&mut self, shift: T) -> () {
783 let shift: [f64; 2] = shift.into();
784 self.xmin += shift[0];
785 self.xmax += shift[0];
786 self.ymin += shift[1];
787 self.ymax += shift[1];
788 }
789
790 /**
791 Scales the width and height of `self` while keeping the center fixed.
792
793 The bounding box is scaled by multiplying its width and height by the factor
794 and then recalculating the extremas by adding / subtracting half the width / height
795 from the center.
796
797 # Examples
798 ```
799 use bounding_box::BoundingBox;
800
801 let mut bb = BoundingBox::new(0.0, 1.0, 2.0, 4.0);
802
803 assert_eq!(bb.center(), [0.5, 3.0]);
804 assert_eq!(bb.width(), 1.0);
805 assert_eq!(bb.height(), 2.0);
806
807 bb.scale(2.0);
808
809 assert_eq!(bb.center(), [0.5, 3.0]);
810 assert_eq!(bb.width(), 2.0);
811 assert_eq!(bb.height(), 4.0);
812
813 assert_eq!(bb.xmin(), -0.5);
814 assert_eq!(bb.xmax(), 1.5);
815 assert_eq!(bb.ymin(), 1.0);
816 assert_eq!(bb.ymax(), 5.0);
817 ```
818 */
819 pub fn scale(&mut self, factor: f64) -> () {
820 let dw = 0.5 * (factor - 1.0) * self.width();
821 let dh = 0.5 * (factor - 1.0) * self.height();
822 self.xmin = self.xmin - dw;
823 self.xmax = self.xmax + dw;
824 self.ymin = self.ymin - dh;
825 self.ymax = self.ymax + dh;
826 }
827
828 /**
829 Remove any singular dimensions by "buffering" them with `add_to_extr`.
830
831 The value `add_to_extr` is applied to both the minimum and the maximum value of a singular dimension.
832 For example, if the bounding box width is 0 (`xmin` = `xmax`) and `add_to_extr = 1.0`, the new width will be 2.0.
833
834 # Examples
835 ```
836 use bounding_box::BoundingBox;
837
838 let mut bb = BoundingBox::new(0.0, 0.0, -1.0, 1.0);
839 assert_eq!(bb.width(), 0.0);
840
841 bb.remove_singular_dimensions(1.0);
842 assert_eq!(bb.width(), 2.0);
843 assert_eq!(bb.xmin(), -1.0);
844 assert_eq!(bb.xmax(), 1.0);
845
846 // =================================================
847
848 let mut bb = BoundingBox::new(-1.0, 1.0, 2.0, 2.0);
849 assert_eq!(bb.height(), 0.0);
850
851 bb.remove_singular_dimensions(3.0);
852 assert_eq!(bb.height(), 6.0);
853 assert_eq!(bb.ymin(), -1.0);
854 assert_eq!(bb.ymax(), 5.0);
855 ```
856 */
857 pub fn remove_singular_dimensions(&mut self, add_to_extr: f64) {
858 if self.width() == 0.0 {
859 self.xmin -= add_to_extr;
860 self.xmax += add_to_extr;
861 }
862 if self.height() == 0.0 {
863 self.ymin -= add_to_extr;
864 self.ymax += add_to_extr;
865 }
866 }
867
868 /**
869 Returns true if the bounding box is finite.
870
871 # Examples
872 ```
873 use std::f64::INFINITY;
874 use bounding_box::BoundingBox;
875
876 assert!(BoundingBox::new(0.0, 1.0, 0.0, 1.0).is_finite());
877 assert!(!BoundingBox::new(0.0, INFINITY, 0.0, 1.0).is_finite());
878 ```
879 */
880 pub fn is_finite(&self) -> bool {
881 return self.xmin.is_finite()
882 && self.xmax.is_finite()
883 && self.ymin.is_finite()
884 && self.ymax.is_finite();
885 }
886}
887
888/**
889This trait provides an associated method
890[`bounding_box`](ToBoundingBox::bounding_box) for all types `T` which
891implement [`Into<BoundingBox>`] for a shared reference `T` and therefore avoids
892typing `BoundingBox::from(&T)`:
893
894```
895use bounding_box::{BoundingBox, ToBoundingBox};
896
897struct Circle {
898 center: [f64; 2],
899 radius: f64
900}
901
902impl From<&Circle> for BoundingBox {
903 fn from(c: &Circle) -> BoundingBox {
904 return BoundingBox::new(c.center[0] - c.radius,
905 c.center[0] + c.radius,
906 c.center[1] - c.radius,
907 c.center[1] + c.radius);
908 }
909}
910
911let c = Circle {center: [0.0, 0.0], radius: 1.0};
912assert_eq!(c.bounding_box(), BoundingBox::from(&c));
913```
914
915Of course this trait can also be implemented manually, but it is heavily
916recommended to instead implement `From<&T> for BoundingBox` instead.
917 */
918pub trait ToBoundingBox {
919 /**
920 Returns a bounding box for the implementor.
921
922 # Example
923
924 ```
925 use bounding_box::{BoundingBox, ToBoundingBox};
926
927 struct Circle {
928 center: [f64; 2],
929 radius: f64
930 }
931
932 impl From<&Circle> for BoundingBox {
933 fn from(c: &Circle) -> BoundingBox {
934 return BoundingBox::new(c.center[0] - c.radius,
935 c.center[0] + c.radius,
936 c.center[1] - c.radius,
937 c.center[1] + c.radius);
938 }
939 }
940
941 let c = Circle {center: [0.0, 0.0], radius: 1.0};
942 let bb = c.bounding_box();
943 assert_eq!(bb.xmin(), -1.0);
944 assert_eq!(bb.ymin(), -1.0);
945 assert_eq!(bb.xmax(), 1.0);
946 assert_eq!(bb.ymax(), 1.0);
947 ```
948 */
949 fn bounding_box(&self) -> BoundingBox;
950}
951
952impl<T> ToBoundingBox for T
953where
954 for<'a> &'a T: Into<BoundingBox>,
955{
956 fn bounding_box(&self) -> BoundingBox {
957 self.into()
958 }
959}