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}