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}