truck_base/
bounding_box.rs

1use cgmath::*;
2use serde::*;
3use std::cmp::Ordering;
4use std::ops::Index;
5
6/// bounding box
7#[derive(Clone, Copy, PartialEq, Eq, Debug, Serialize, Deserialize)]
8pub struct BoundingBox<V>(V, V);
9
10/// The trait for defining the bounding box
11pub trait Bounded:
12    Copy + MetricSpace<Metric = Self::Scalar> + Index<usize, Output = Self::Scalar> + PartialEq {
13    /// the scalar of vector
14    type Scalar: BaseFloat;
15    /// the result of subtraction
16    type Vector;
17    #[doc(hidden)]
18    fn infinity() -> Self;
19    #[doc(hidden)]
20    fn neg_infinity() -> Self;
21    #[doc(hidden)]
22    fn max(self, other: Self) -> Self;
23    #[doc(hidden)]
24    fn min(self, other: Self) -> Self;
25    #[doc(hidden)]
26    fn max_component(one: Self::Vector) -> Self::Scalar;
27    #[doc(hidden)]
28    fn diagonal(self, other: Self) -> Self::Vector;
29    #[doc(hidden)]
30    fn mid(self, other: Self) -> Self;
31}
32
33macro_rules! pr2 {
34    ($a: expr, $b: expr) => {
35        $b
36    };
37}
38macro_rules! impl_bounded {
39    ($typename: ident, $vectortype: ident, $($num: expr),*) => {
40        impl<S: BaseFloat> Bounded for $typename<S> {
41            type Scalar = S;
42            type Vector = $vectortype<S>;
43            fn infinity() -> $typename<S> {
44                $typename::new($(pr2!($num, S::infinity())),*)
45            }
46            fn neg_infinity() -> $typename<S> {
47                $typename::new($(pr2!($num, S::neg_infinity())),*)
48            }
49            fn max(self, other: Self) -> Self {
50                $typename::new(
51                    $(
52                        if self[$num] < other[$num] {
53                            other[$num]
54                        } else {
55                            self[$num]
56                        }
57                    ),*
58                )
59            }
60            fn min(self, other: Self) -> Self {
61                $typename::new(
62                    $(
63                        if self[$num] > other[$num] {
64                            other[$num]
65                        } else {
66                            self[$num]
67                        }
68                    ),*
69                )
70            }
71            fn max_component(one: Self::Vector) -> S {
72                let mut max = S::neg_infinity();
73                $(if max < one[$num] { max = one[$num] })*
74                max
75            }
76            fn diagonal(self, other: Self) -> Self::Vector { self - other }
77            fn mid(self, other: Self) -> Self {
78                self + (other - self) / (S::one() + S::one())
79            }
80        }
81    };
82}
83impl_bounded!(Vector1, Vector1, 0);
84impl_bounded!(Point1, Vector1, 0);
85impl_bounded!(Vector2, Vector2, 0, 1);
86impl_bounded!(Point2, Vector2, 0, 1);
87impl_bounded!(Vector3, Vector3, 0, 1, 2);
88impl_bounded!(Point3, Vector3, 0, 1, 2);
89impl_bounded!(Vector4, Vector4, 0, 1, 2, 3);
90
91impl<V: Bounded> Default for BoundingBox<V> {
92    #[inline(always)]
93    fn default() -> Self { BoundingBox(V::infinity(), V::neg_infinity()) }
94}
95
96impl<V: Bounded> BoundingBox<V> {
97    /// Creates an empty bounding box
98    #[inline(always)]
99    pub fn new() -> Self { Self::default() }
100    /// Adds a point to the bounding box.
101    /// # Examples
102    /// ```
103    /// use truck_base::{cgmath64::*, bounding_box::*, tolerance::*};
104    /// let mut bdd_box = BoundingBox::new();
105    /// bdd_box.push(Vector2::new(-1.0,  1.0));
106    /// bdd_box.push(Vector2::new(1.0,  -1.0));
107    /// assert_eq!(bdd_box.min(), Vector2::new(-1.0,  -1.0));
108    /// assert_eq!(bdd_box.max(), Vector2::new(1.0,  1.0));
109    /// ```
110    /// # Remarks
111    /// If the added point has NAN component, then the point is not added.
112    /// ```
113    /// use truck_base::{cgmath64::*, bounding_box::*, tolerance::*};
114    /// let mut bdd_box = BoundingBox::new();
115    /// bdd_box.push(Vector2::new(-1.0,  1.0));
116    /// bdd_box.push(Vector2::new(1.0,  -1.0));
117    /// bdd_box.push(Vector2::new(std::f64::NAN, 1.0));
118    /// bdd_box.push(Vector2::new(-1.0, std::f64::NAN));
119    /// assert_eq!(bdd_box.min(), Vector2::new(-1.0,  -1.0));
120    /// assert_eq!(bdd_box.max(), Vector2::new(1.0,  1.0));
121    /// ```
122    #[inline(always)]
123    pub fn push(&mut self, point: V) {
124        self.0 = self.0.min(point);
125        self.1 = self.1.max(point);
126    }
127
128    /// Returns the bounding box is empty or not.
129    /// # Examples
130    /// ```
131    /// use truck_base::{cgmath64::*, bounding_box::*, tolerance::*};
132    /// let mut bdd_box = BoundingBox::new();
133    /// assert!(bdd_box.is_empty());
134    /// bdd_box.push(Vector2::new(-1.0,  1.0));
135    /// assert!(!bdd_box.is_empty());
136    /// ```
137    #[inline(always)]
138    pub fn is_empty(self) -> bool { self.0[0] > self.1[0] }
139    /// Returns the reference to the maximum point.
140    /// # Examples
141    /// ```
142    /// use truck_base::{cgmath64::*, bounding_box::*, tolerance::*};
143    /// let mut bdd_box = BoundingBox::new();
144    /// bdd_box.push(Vector2::new(-1.0,  1.0));
145    /// bdd_box.push(Vector2::new(1.0,  -1.0));
146    /// assert_eq!(bdd_box.max(), Vector2::new(1.0,  1.0));
147    /// ```
148    /// # Remarks
149    /// If the bounding box is empty, returned vector consists `NEG_INFINITY` components.
150    /// ```
151    /// use truck_base::{cgmath64::*, bounding_box::*, tolerance::*};
152    /// let bdd_box = BoundingBox::<Vector2>::new();
153    /// assert_eq!(bdd_box.max(), Vector2::from([f64::NEG_INFINITY; 2]));
154    /// ```
155    #[inline(always)]
156    pub const fn max(self) -> V { self.1 }
157    /// Returns the reference to the minimal point.
158    /// # Examples
159    /// ```
160    /// use truck_base::{cgmath64::*, bounding_box::*, tolerance::*};
161    /// let mut bdd_box = BoundingBox::new();
162    /// bdd_box.push(Vector2::new(-1.0,  1.0));
163    /// bdd_box.push(Vector2::new(1.0,  -1.0));
164    /// assert_eq!(bdd_box.min(), Vector2::new(-1.0,  -1.0));
165    /// ```
166    /// # Remarks
167    /// If the bounding box is empty, returned vector consists `INFINITY` components.
168    /// ```
169    /// use truck_base::{cgmath64::*, bounding_box::*, tolerance::*};
170    /// let bdd_box = BoundingBox::<Vector2>::new();
171    /// assert_eq!(bdd_box.min(), Vector2::from([f64::INFINITY; 2]));
172    /// ```
173    #[inline(always)]
174    pub const fn min(self) -> V { self.0 }
175    /// Returns the diagonal vector.
176    /// # Examples
177    /// ```
178    /// use truck_base::{cgmath64::*, bounding_box::*, tolerance::*};
179    /// let mut bdd_box = BoundingBox::new();
180    /// bdd_box.push(Vector2::new(-2.0,  -3.0));
181    /// bdd_box.push(Vector2::new(6.0,  4.0));
182    /// assert_eq!(bdd_box.diagonal(), Vector2::new(8.0,  7.0));
183    /// ```
184    /// # Remarks
185    /// If the bounding box is empty, returned vector consists `f64::NEG_INFINITY` components.
186    /// ```
187    /// use truck_base::{cgmath64::*, bounding_box::*, tolerance::*};
188    /// let bdd_box = BoundingBox::<Vector2>::new();
189    /// assert_eq!(bdd_box.diagonal(), Vector2::new(f64::NEG_INFINITY, f64::NEG_INFINITY));
190    /// ```
191    #[inline(always)]
192    pub fn diagonal(self) -> V::Vector { self.1.diagonal(self.0) }
193
194    /// Returns the diameter of the bounding box.
195    /// # Examples
196    /// ```
197    /// use truck_base::{cgmath64::*, bounding_box::*, tolerance::*};
198    /// let mut bdd_box = BoundingBox::new();
199    /// bdd_box.push(Vector2::new(-1.0,  -3.0));
200    /// bdd_box.push(Vector2::new(2.0,  1.0));
201    /// assert_eq!(bdd_box.diameter(), 5.0);
202    /// ```
203    /// # Remarks
204    /// If the bounding box is empty, returns `f64::NEG_INFINITY`.
205    /// ```
206    /// use truck_base::{cgmath64::*, bounding_box::*, tolerance::*};
207    /// let bdd_box = BoundingBox::<Vector3>::new();
208    /// assert_eq!(bdd_box.diameter(), f64::NEG_INFINITY);
209    /// ```
210    #[inline(always)]
211    pub fn diameter(self) -> V::Scalar {
212        match self.is_empty() {
213            true => num_traits::Float::neg_infinity(),
214            false => self.0.distance(self.1),
215        }
216    }
217
218    /// Returns the maximum length of the edges of the bounding box.
219    /// # Examples
220    /// ```
221    /// use truck_base::{cgmath64::*, bounding_box::*, tolerance::*};
222    /// let mut bdd_box = BoundingBox::new();
223    /// bdd_box.push(Vector3::new(-1.0, -3.0,  2.0));
224    /// bdd_box.push(Vector3::new(2.0, 1.0,  10.0));
225    /// assert_eq!(bdd_box.size(), 8.0);
226    /// ```
227    /// # Remarks
228    /// If the bounding box is empty, returns `f64::NEG_INFINITY`.
229    /// ```
230    /// use truck_base::{cgmath64::*, bounding_box::*, tolerance::*};
231    /// let bdd_box = BoundingBox::<Vector3>::new();
232    /// assert_eq!(bdd_box.size(), f64::NEG_INFINITY);
233    /// ```
234    #[inline(always)]
235    pub fn size(self) -> V::Scalar { V::max_component(self.diagonal()) }
236
237    /// Returns the center of the bounding box.
238    /// # Examples
239    /// ```
240    /// use truck_base::{cgmath64::*, bounding_box::*, tolerance::*};
241    /// let mut bdd_box = BoundingBox::new();
242    /// bdd_box.push(Vector2::new(-1.0,  -3.0));
243    /// bdd_box.push(Vector2::new(5.0,  1.0));
244    /// assert_eq!(bdd_box.center(), Vector2::new(2.0,  -1.0));
245    /// ```
246    /// # Remarks
247    /// If the bounding box is empty, returned vector consists `std::f64::NAN` components.
248    /// ```
249    /// use truck_base::{cgmath64::*, bounding_box::*, tolerance::*};
250    /// let bdd_box = BoundingBox::<Vector3>::new();
251    /// let center = bdd_box.center();
252    /// assert!(center[0].is_nan());
253    /// assert!(center[1].is_nan());
254    /// assert!(center[2].is_nan());
255    /// ```
256    #[inline(always)]
257    pub fn center(self) -> V { self.0.mid(self.1) }
258    /// Returns whether `self` contains `pt` or not.
259    /// # Examples
260    /// ```
261    /// use truck_base::{cgmath64::*, bounding_box::*};
262    /// let bdd_box = BoundingBox::from_iter(vec![Point2::new(0.0, 0.0), Point2::new(1.0, 1.0)]);
263    /// assert!(bdd_box.contains(Point2::new(0.5, 0.5)));
264    /// assert!(bdd_box.contains(Point2::new(0.0, 0.5)));
265    /// assert!(!bdd_box.contains(Point2::new(-0.1, 0.5)));
266    /// ```
267    #[inline(always)]
268    pub fn contains(self, pt: V) -> bool { self + BoundingBox(pt, pt) == self }
269}
270
271impl<V> BoundingBox<V> where V: Index<usize> {}
272
273impl<'a, V: Bounded> FromIterator<&'a V> for BoundingBox<V> {
274    fn from_iter<I: IntoIterator<Item = &'a V>>(iter: I) -> BoundingBox<V> {
275        let mut bdd_box = BoundingBox::new();
276        let bdd_box_mut = &mut bdd_box;
277        iter.into_iter().for_each(move |pt| bdd_box_mut.push(*pt));
278        bdd_box
279    }
280}
281
282impl<V: Bounded> FromIterator<V> for BoundingBox<V> {
283    fn from_iter<I: IntoIterator<Item = V>>(iter: I) -> BoundingBox<V> {
284        let mut bdd_box = BoundingBox::new();
285        let bdd_box_mut = &mut bdd_box;
286        iter.into_iter().for_each(move |pt| bdd_box_mut.push(pt));
287        bdd_box
288    }
289}
290
291impl<V: Bounded> std::ops::AddAssign<&BoundingBox<V>> for BoundingBox<V> {
292    /// Puts the points in `other` into `self`.
293    /// # Examples
294    /// ```
295    /// use truck_base::{cgmath64::*, bounding_box::*, tolerance::*};
296    /// let mut bdd_box = BoundingBox::from_iter(&[
297    ///     Vector2::new(3.0, 2.0), Vector2::new(5.0,  6.0),
298    /// ]);
299    /// bdd_box += &BoundingBox::from_iter(&[
300    ///     Vector2::new(4.0, 1.0), Vector2::new(7.0,  4.0),
301    /// ]);
302    /// assert_eq!(bdd_box.min(), Vector2::new(3.0,  1.0));
303    /// assert_eq!(bdd_box.max(), Vector2::new(7.0,  6.0));
304    ///
305    /// bdd_box += &BoundingBox::new();
306    /// assert_eq!(bdd_box.min(), Vector2::new(3.0,  1.0));
307    /// assert_eq!(bdd_box.max(), Vector2::new(7.0,  6.0));
308    /// ```
309    #[inline(always)]
310    fn add_assign(&mut self, other: &BoundingBox<V>) { *self += *other }
311}
312
313impl<V: Bounded> std::ops::AddAssign<BoundingBox<V>> for BoundingBox<V> {
314    /// Puts the points in `other` into `self`.
315    /// # Examples
316    /// ```
317    /// use truck_base::{cgmath64::*, bounding_box::*, tolerance::*};
318    /// let mut bdd_box = BoundingBox::from_iter(&[
319    ///     Vector2::new(3.0, 2.0), Vector2::new(5.0,  6.0),
320    /// ]);
321    /// bdd_box += BoundingBox::from_iter(&[
322    ///     Vector2::new(4.0, 1.0), Vector2::new(7.0,  4.0),
323    /// ]);
324    /// assert_eq!(bdd_box.min(), Vector2::new(3.0,  1.0));
325    /// assert_eq!(bdd_box.max(), Vector2::new(7.0,  6.0));
326    ///
327    /// bdd_box += BoundingBox::new();
328    /// assert_eq!(bdd_box.min(), Vector2::new(3.0,  1.0));
329    /// assert_eq!(bdd_box.max(), Vector2::new(7.0,  6.0));
330    /// ```
331    #[inline(always)]
332    fn add_assign(&mut self, other: BoundingBox<V>) {
333        self.0 = self.0.min(other.0);
334        self.1 = self.1.max(other.1);
335    }
336}
337
338impl<V: Bounded> std::ops::Add<&BoundingBox<V>> for &BoundingBox<V> {
339    type Output = BoundingBox<V>;
340    /// Returns the direct sum of `self` and other.
341    /// # Examples
342    /// ```
343    /// use truck_base::{cgmath64::*, bounding_box::*, tolerance::*};
344    /// let bdd_box0 = BoundingBox::from_iter(&[
345    ///     Vector2::new(3.0, 2.0), Vector2::new(5.0, 6.0),
346    /// ]);
347    /// let bdd_box1 = BoundingBox::from_iter(&[
348    ///     Vector2::new(4.0, 1.0), Vector2::new(7.0, 4.0),
349    /// ]);
350    /// let bdd_box = &bdd_box0 + &bdd_box1;
351    /// assert_eq!(bdd_box.min(), Vector2::new(3.0, 1.0));
352    /// assert_eq!(bdd_box.max(), Vector2::new(7.0, 6.0));
353    ///
354    /// let cloned_bdd_box = &bdd_box + &BoundingBox::new();
355    /// assert_eq!(cloned_bdd_box.min(), Vector2::new(3.0, 1.0));
356    /// assert_eq!(cloned_bdd_box.max(), Vector2::new(7.0, 6.0));
357    /// ```
358    #[inline(always)]
359    fn add(self, other: &BoundingBox<V>) -> BoundingBox<V> { *self + *other }
360}
361
362impl<V: Bounded> std::ops::Add<&BoundingBox<V>> for BoundingBox<V> {
363    type Output = BoundingBox<V>;
364    /// Returns the direct sum of `self` and other.
365    /// # Examples
366    /// ```
367    /// use truck_base::{cgmath64::*, bounding_box::*, tolerance::*};
368    /// let bdd_box0 = BoundingBox::from_iter(&[
369    ///     Vector2::new(3.0, 2.0), Vector2::new(5.0,  6.0),
370    /// ]);
371    /// let bdd_box1 = BoundingBox::from_iter(&[
372    ///     Vector2::new(4.0, 1.0), Vector2::new(7.0,  4.0),
373    /// ]);
374    /// let bdd_box = bdd_box0 + &bdd_box1;
375    /// assert_eq!(bdd_box.min(), Vector2::new(3.0,  1.0));
376    /// assert_eq!(bdd_box.max(), Vector2::new(7.0,  6.0));
377    ///
378    /// let cloned_bdd_box = bdd_box + &BoundingBox::new();
379    /// assert_eq!(cloned_bdd_box.min(), Vector2::new(3.0,  1.0));
380    /// assert_eq!(cloned_bdd_box.max(), Vector2::new(7.0,  6.0));
381    /// ```
382    #[inline(always)]
383    fn add(self, other: &BoundingBox<V>) -> BoundingBox<V> { self + *other }
384}
385
386impl<V: Bounded> std::ops::Add<BoundingBox<V>> for &BoundingBox<V> {
387    type Output = BoundingBox<V>;
388    /// Returns the direct sum of `self` and other.
389    /// # Examples
390    /// ```
391    /// use truck_base::{cgmath64::*, bounding_box::*, tolerance::*};
392    /// let bdd_box0 = BoundingBox::from_iter(&[
393    ///     Vector2::new(3.0, 2.0), Vector2::new(5.0,  6.0),
394    /// ]);
395    /// let bdd_box1 = BoundingBox::from_iter(&[
396    ///     Vector2::new(4.0, 1.0), Vector2::new(7.0,  4.0),
397    /// ]);
398    /// let bdd_box = &bdd_box0 + bdd_box1;
399    /// assert_eq!(bdd_box.min(), Vector2::new(3.0,  1.0));
400    /// assert_eq!(bdd_box.max(), Vector2::new(7.0,  6.0));
401    ///
402    /// let cloned_bdd_box = &bdd_box + BoundingBox::new();
403    /// assert_eq!(cloned_bdd_box.min(), Vector2::new(3.0,  1.0));
404    /// assert_eq!(cloned_bdd_box.max(), Vector2::new(7.0,  6.0));
405    /// ```
406    #[inline(always)]
407    fn add(self, other: BoundingBox<V>) -> BoundingBox<V> { other + self }
408}
409
410impl<V: Bounded> std::ops::Add<BoundingBox<V>> for BoundingBox<V> {
411    type Output = BoundingBox<V>;
412    /// Returns the direct sum of `self` and other.
413    /// # Examples
414    /// ```
415    /// use truck_base::{cgmath64::*, bounding_box::*, tolerance::*};
416    /// let bdd_box0 = BoundingBox::from_iter(&[
417    ///     Vector2::new(3.0, 2.0), Vector2::new(5.0,  6.0),
418    /// ]);
419    /// let bdd_box1 = BoundingBox::from_iter(&[
420    ///     Vector2::new(4.0, 1.0), Vector2::new(7.0,  4.0),
421    /// ]);
422    /// let bdd_box = bdd_box0 + bdd_box1;
423    /// assert_eq!(bdd_box.min(), Vector2::new(3.0,  1.0));
424    /// assert_eq!(bdd_box.max(), Vector2::new(7.0,  6.0));
425    ///
426    /// let cloned_bdd_box = bdd_box + BoundingBox::new();
427    /// assert_eq!(cloned_bdd_box.min(), Vector2::new(3.0,  1.0));
428    /// assert_eq!(cloned_bdd_box.max(), Vector2::new(7.0,  6.0));
429    /// ```
430    #[inline(always)]
431    fn add(mut self, other: BoundingBox<V>) -> BoundingBox<V> {
432        self += other;
433        self
434    }
435}
436
437impl<V: Bounded> std::ops::BitXorAssign<&BoundingBox<V>> for BoundingBox<V> {
438    /// Assigns the intersection of `self` and `other` to `self`.
439    /// # Examples
440    /// ```
441    /// use truck_base::{cgmath64::*, bounding_box::*, tolerance::*};
442    /// let mut bdd_box = BoundingBox::from_iter(&[
443    ///     Vector2::new(3.0, 2.0), Vector2::new(5.0,  6.0),
444    /// ]);
445    /// bdd_box ^= &BoundingBox::from_iter(&[
446    ///     Vector2::new(4.0, 1.0), Vector2::new(7.0,  4.0),
447    /// ]);
448    /// assert_eq!(bdd_box.min(), Vector2::new(4.0,  2.0));
449    /// assert_eq!(bdd_box.max(), Vector2::new(5.0,  4.0));
450    ///
451    /// bdd_box ^= &BoundingBox::new();
452    /// assert!(bdd_box.is_empty());
453    /// ```
454    #[inline(always)]
455    fn bitxor_assign(&mut self, other: &BoundingBox<V>) { *self ^= *other; }
456}
457
458impl<V: Bounded> std::ops::BitXorAssign<BoundingBox<V>> for BoundingBox<V> {
459    /// Assigns the intersection of `self` and `other` to `self`.
460    /// # Examples
461    /// ```
462    /// use truck_base::{cgmath64::*, bounding_box::*, tolerance::*};
463    /// let mut bdd_box = BoundingBox::from_iter(&[
464    ///     Vector2::new(3.0, 2.0), Vector2::new(5.0,  6.0),
465    /// ]);
466    /// bdd_box ^= BoundingBox::from_iter(&[
467    ///     Vector2::new(4.0, 1.0), Vector2::new(7.0,  4.0),
468    /// ]);
469    /// assert_eq!(bdd_box.min(), Vector2::new(4.0,  2.0));
470    /// assert_eq!(bdd_box.max(), Vector2::new(5.0,  4.0));
471    ///
472    /// bdd_box ^= BoundingBox::new();
473    /// assert!(bdd_box.is_empty());
474    /// ```
475    #[inline(always)]
476    fn bitxor_assign(&mut self, other: BoundingBox<V>) {
477        self.0 = self.0.max(other.0);
478        self.1 = self.1.min(other.1);
479    }
480}
481
482impl<V: Bounded> std::ops::BitXor<&BoundingBox<V>> for &BoundingBox<V> {
483    type Output = BoundingBox<V>;
484    /// Returns the intersection of `self` and `other`.
485    /// # Examples
486    /// ```
487    /// use truck_base::{cgmath64::*, bounding_box::*, tolerance::*};
488    /// let bdd_box0 = BoundingBox::from_iter(&[
489    ///     Vector2::new(3.0, 2.0), Vector2::new(5.0,  6.0),
490    /// ]);
491    /// let bdd_box1 = BoundingBox::from_iter(&[
492    ///     Vector2::new(4.0, 1.0), Vector2::new(7.0,  4.0),
493    /// ]);
494    /// let bdd_box = &bdd_box0 ^ &bdd_box1;
495    /// assert_eq!(bdd_box.min(), Vector2::new(4.0,  2.0));
496    /// assert_eq!(bdd_box.max(), Vector2::new(5.0,  4.0));
497    ///
498    /// let new_empty = &bdd_box ^ &BoundingBox::new();
499    /// assert!(new_empty.is_empty());
500    /// ```
501    #[inline(always)]
502    fn bitxor(self, other: &BoundingBox<V>) -> BoundingBox<V> { *self ^ *other }
503}
504
505impl<V: Bounded> std::ops::BitXor<&BoundingBox<V>> for BoundingBox<V> {
506    type Output = BoundingBox<V>;
507    /// Returns the intersection of `self` and `other`.
508    /// # Examples
509    /// ```
510    /// use truck_base::{cgmath64::*, bounding_box::*, tolerance::*};
511    /// let bdd_box0 = BoundingBox::from_iter(&[
512    ///     Vector2::new(3.0,  2.0), Vector2::new(5.0,  6.0),
513    /// ]);
514    /// let bdd_box1 = BoundingBox::from_iter(&[
515    ///     Vector2::new(4.0,  1.0), Vector2::new(7.0,  4.0),
516    /// ]);
517    /// let bdd_box = bdd_box0 ^ &bdd_box1;
518    /// assert_eq!(bdd_box.min(), Vector2::new(4.0,  2.0));
519    /// assert_eq!(bdd_box.max(), Vector2::new(5.0,  4.0));
520    ///
521    /// let new_empty = bdd_box ^ &BoundingBox::new();
522    /// assert!(new_empty.is_empty());
523    /// ```
524    #[inline(always)]
525    fn bitxor(self, other: &BoundingBox<V>) -> BoundingBox<V> { self ^ *other }
526}
527
528impl<V: Bounded> std::ops::BitXor<BoundingBox<V>> for &BoundingBox<V> {
529    type Output = BoundingBox<V>;
530    /// Returns the intersection of `self` and `other`.
531    /// # Examples
532    /// ```
533    /// use truck_base::{cgmath64::*, bounding_box::*, tolerance::*};
534    /// let bdd_box0 = BoundingBox::from_iter(&[
535    ///     Vector2::new(3.0,  2.0), Vector2::new(5.0,  6.0),
536    /// ]);
537    /// let bdd_box1 = BoundingBox::from_iter(&[
538    ///     Vector2::new(4.0,  1.0), Vector2::new(7.0,  4.0),
539    /// ]);
540    /// let bdd_box = &bdd_box0 ^ bdd_box1;
541    /// assert_eq!(bdd_box.min(), Vector2::new(4.0,  2.0));
542    /// assert_eq!(bdd_box.max(), Vector2::new(5.0,  4.0));
543    ///
544    /// let new_empty = &bdd_box ^ BoundingBox::new();
545    /// assert!(new_empty.is_empty());
546    /// ```
547    #[inline(always)]
548    fn bitxor(self, other: BoundingBox<V>) -> BoundingBox<V> { other ^ self }
549}
550
551impl<V: Bounded> std::ops::BitXor<BoundingBox<V>> for BoundingBox<V> {
552    type Output = BoundingBox<V>;
553    /// Returns the intersection of `self` and `other`.
554    /// # Examples
555    /// ```
556    /// use truck_base::{cgmath64::*, bounding_box::*, tolerance::*};
557    /// let bdd_box0 = BoundingBox::from_iter(&[
558    ///     Vector2::new(3.0,  2.0), Vector2::new(5.0,  6.0),
559    /// ]);
560    /// let bdd_box1 = BoundingBox::from_iter(&[
561    ///     Vector2::new(4.0,  1.0), Vector2::new(7.0,  4.0),
562    /// ]);
563    /// let bdd_box = bdd_box0 ^ bdd_box1;
564    /// assert_eq!(bdd_box.min(), Vector2::new(4.0,  2.0));
565    /// assert_eq!(bdd_box.max(), Vector2::new(5.0,  4.0));
566    ///
567    /// let new_empty = bdd_box ^ BoundingBox::new();
568    /// assert!(new_empty.is_empty());
569    /// ```
570    #[inline(always)]
571    fn bitxor(mut self, other: BoundingBox<V>) -> BoundingBox<V> {
572        self ^= other;
573        self
574    }
575}
576
577impl<V: Bounded> PartialOrd for BoundingBox<V> {
578    /// Inclusion relationship
579    /// # Examples
580    /// ```
581    /// use truck_base::{cgmath64::*, bounding_box::*};
582    /// let bbx0 = BoundingBox::from_iter(&[
583    ///     Point2::new(0.0, 0.0),
584    ///     Point2::new(1.0, 1.0),
585    /// ]);
586    /// let bbx1 = BoundingBox::from_iter(&[
587    ///     Point2::new(0.25, 0.25),
588    ///     Point2::new(0.75, 0.75),
589    /// ]);
590    /// // bbx0 includes bbx1.
591    /// assert!(bbx0 > bbx1);
592    ///
593    /// let bbx2 = BoundingBox::from_iter(&[
594    ///     Point2::new(-1.0, -1.0),
595    ///     Point2::new(0.75, 0.75),
596    /// ]);
597    /// // bbx0 does not include bbx2, and bbx2 does not include bbx0.
598    /// assert!(!(bbx0 > bbx2));
599    /// assert!(!(bbx0 < bbx2));
600    /// assert!(!(bbx0 == bbx2));
601    /// ```
602    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
603        let max = self + other;
604        match (self == &max, other == &max) {
605            (true, true) => Some(Ordering::Equal),
606            (true, false) => Some(Ordering::Greater),
607            (false, true) => Some(Ordering::Less),
608            (false, false) => None,
609        }
610    }
611}