1use super::UnknownUnit;
11use crate::approxord::{max, min};
12use crate::num::*;
13use crate::point::{point2, Point2D};
14use crate::rect::Rect;
15use crate::scale::Scale;
16use crate::side_offsets::SideOffsets2D;
17use crate::size::Size2D;
18use crate::vector::{vec2, Vector2D};
19
20#[cfg(feature = "bytemuck")]
21use bytemuck::{Pod, Zeroable};
22use num_traits::{Float, NumCast};
23#[cfg(feature = "serde")]
24use serde::{Deserialize, Serialize};
25
26use core::borrow::Borrow;
27use core::cmp::PartialOrd;
28use core::fmt;
29use core::hash::{Hash, Hasher};
30use core::ops::{Add, Div, DivAssign, Mul, MulAssign, Range, Sub};
31
32#[repr(C)]
61#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
62#[cfg_attr(
63 feature = "serde",
64 serde(bound(serialize = "T: Serialize", deserialize = "T: Deserialize<'de>"))
65)]
66pub struct Box2D<T, U> {
67 pub min: Point2D<T, U>,
68 pub max: Point2D<T, U>,
69}
70
71impl<T: Hash, U> Hash for Box2D<T, U> {
72 fn hash<H: Hasher>(&self, h: &mut H) {
73 self.min.hash(h);
74 self.max.hash(h);
75 }
76}
77
78impl<T: Copy, U> Copy for Box2D<T, U> {}
79
80impl<T: Clone, U> Clone for Box2D<T, U> {
81 fn clone(&self) -> Self {
82 Self::new(self.min.clone(), self.max.clone())
83 }
84}
85
86impl<T: PartialEq, U> PartialEq for Box2D<T, U> {
87 fn eq(&self, other: &Self) -> bool {
88 self.min.eq(&other.min) && self.max.eq(&other.max)
89 }
90}
91
92impl<T: Eq, U> Eq for Box2D<T, U> {}
93
94impl<T: fmt::Debug, U> fmt::Debug for Box2D<T, U> {
95 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
96 f.debug_tuple("Box2D")
97 .field(&self.min)
98 .field(&self.max)
99 .finish()
100 }
101}
102
103#[cfg(feature = "arbitrary")]
104impl<'a, T, U> arbitrary::Arbitrary<'a> for Box2D<T, U>
105where
106 T: arbitrary::Arbitrary<'a>,
107{
108 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
109 Ok(Box2D::new(
110 arbitrary::Arbitrary::arbitrary(u)?,
111 arbitrary::Arbitrary::arbitrary(u)?,
112 ))
113 }
114}
115
116#[cfg(feature = "bytemuck")]
117unsafe impl<T: Zeroable, U> Zeroable for Box2D<T, U> {}
118
119#[cfg(feature = "bytemuck")]
120unsafe impl<T: Pod, U: 'static> Pod for Box2D<T, U> {}
121
122impl<T, U> Box2D<T, U> {
123 #[inline]
125 pub const fn new(min: Point2D<T, U>, max: Point2D<T, U>) -> Self {
126 Box2D { min, max }
127 }
128
129 #[inline]
131 pub fn from_origin_and_size(origin: Point2D<T, U>, size: Size2D<T, U>) -> Self
132 where
133 T: Copy + Add<T, Output = T>,
134 {
135 Box2D {
136 min: origin,
137 max: point2(origin.x + size.width, origin.y + size.height),
138 }
139 }
140
141 #[inline]
143 pub fn from_size(size: Size2D<T, U>) -> Self
144 where
145 T: Zero,
146 {
147 Box2D {
148 min: Point2D::zero(),
149 max: point2(size.width, size.height),
150 }
151 }
152}
153
154impl<T, U> Box2D<T, U>
155where
156 T: PartialOrd,
157{
158 #[inline]
163 pub fn is_negative(&self) -> bool {
164 self.max.x < self.min.x || self.max.y < self.min.y
165 }
166
167 #[inline]
169 pub fn is_empty(&self) -> bool {
170 !(self.max.x > self.min.x && self.max.y > self.min.y)
171 }
172
173 #[inline]
175 pub fn intersects(&self, other: &Self) -> bool {
176 (self.min.x < other.max.x)
178 & (self.max.x > other.min.x)
179 & (self.min.y < other.max.y)
180 & (self.max.y > other.min.y)
181 }
182
183 #[inline]
187 pub fn contains(&self, p: Point2D<T, U>) -> bool {
188 (self.min.x <= p.x) & (p.x < self.max.x) & (self.min.y <= p.y) & (p.y < self.max.y)
190 }
191
192 #[inline]
195 pub fn contains_inclusive(&self, p: Point2D<T, U>) -> bool {
196 (self.min.x <= p.x) & (p.x <= self.max.x) & (self.min.y <= p.y) & (p.y <= self.max.y)
198 }
199
200 #[inline]
204 pub fn contains_box(&self, other: &Self) -> bool {
205 other.is_empty()
206 || ((self.min.x <= other.min.x)
207 & (other.max.x <= self.max.x)
208 & (self.min.y <= other.min.y)
209 & (other.max.y <= self.max.y))
210 }
211}
212
213impl<T, U> Box2D<T, U>
214where
215 T: Copy + PartialOrd,
216{
217 #[inline]
218 pub fn to_non_empty(&self) -> Option<Self> {
219 if self.is_empty() {
220 return None;
221 }
222
223 Some(*self)
224 }
225
226 #[inline]
228 pub fn intersection(&self, other: &Self) -> Option<Self> {
229 let b = self.intersection_unchecked(other);
230
231 if b.is_empty() {
232 return None;
233 }
234
235 Some(b)
236 }
237
238 #[inline]
245 pub fn intersection_unchecked(&self, other: &Self) -> Self {
246 Box2D {
247 min: point2(max(self.min.x, other.min.x), max(self.min.y, other.min.y)),
248 max: point2(min(self.max.x, other.max.x), min(self.max.y, other.max.y)),
249 }
250 }
251
252 #[inline]
256 pub fn union(&self, other: &Self) -> Self {
257 if other.is_empty() {
258 return *self;
259 }
260 if self.is_empty() {
261 return *other;
262 }
263
264 Box2D {
265 min: point2(min(self.min.x, other.min.x), min(self.min.y, other.min.y)),
266 max: point2(max(self.max.x, other.max.x), max(self.max.y, other.max.y)),
267 }
268 }
269}
270
271impl<T, U> Box2D<T, U>
272where
273 T: Copy + Add<T, Output = T>,
274{
275 #[inline]
277 pub fn translate(&self, by: Vector2D<T, U>) -> Self {
278 Box2D {
279 min: self.min + by,
280 max: self.max + by,
281 }
282 }
283}
284
285impl<T, U> Box2D<T, U>
286where
287 T: Copy + Sub<T, Output = T>,
288{
289 #[inline]
290 pub fn size(&self) -> Size2D<T, U> {
291 (self.max - self.min).to_size()
292 }
293
294 #[inline]
297 pub fn set_size(&mut self, size: Size2D<T, U>) {
298 let diff = (self.size() - size).to_vector();
299 self.max -= diff;
300 }
301
302 #[inline]
303 pub fn width(&self) -> T {
304 self.max.x - self.min.x
305 }
306
307 #[inline]
308 pub fn height(&self) -> T {
309 self.max.y - self.min.y
310 }
311
312 #[inline]
313 pub fn to_rect(&self) -> Rect<T, U> {
314 Rect {
315 origin: self.min,
316 size: self.size(),
317 }
318 }
319}
320
321impl<T, U> Box2D<T, U>
322where
323 T: Copy + Add<T, Output = T> + Sub<T, Output = T>,
324{
325 #[inline]
327 #[must_use]
328 pub fn inflate(&self, width: T, height: T) -> Self {
329 Box2D {
330 min: point2(self.min.x - width, self.min.y - height),
331 max: point2(self.max.x + width, self.max.y + height),
332 }
333 }
334
335 pub fn inner_box(&self, offsets: SideOffsets2D<T, U>) -> Self {
340 Box2D {
341 min: self.min + vec2(offsets.left, offsets.top),
342 max: self.max - vec2(offsets.right, offsets.bottom),
343 }
344 }
345
346 pub fn outer_box(&self, offsets: SideOffsets2D<T, U>) -> Self {
350 Box2D {
351 min: self.min - vec2(offsets.left, offsets.top),
352 max: self.max + vec2(offsets.right, offsets.bottom),
353 }
354 }
355}
356
357impl<T, U> Box2D<T, U>
358where
359 T: Copy + Zero + PartialOrd,
360{
361 pub fn from_points<I>(points: I) -> Self
363 where
364 I: IntoIterator,
365 I::Item: Borrow<Point2D<T, U>>,
366 {
367 let mut points = points.into_iter();
368
369 let (mut min_x, mut min_y) = match points.next() {
370 Some(first) => first.borrow().to_tuple(),
371 None => return Box2D::zero(),
372 };
373
374 let (mut max_x, mut max_y) = (min_x, min_y);
375 for point in points {
376 let p = point.borrow();
377 if p.x < min_x {
378 min_x = p.x
379 }
380 if p.x > max_x {
381 max_x = p.x
382 }
383 if p.y < min_y {
384 min_y = p.y
385 }
386 if p.y > max_y {
387 max_y = p.y
388 }
389 }
390
391 Box2D {
392 min: point2(min_x, min_y),
393 max: point2(max_x, max_y),
394 }
395 }
396}
397
398impl<T, U> Box2D<T, U>
399where
400 T: Copy + One + Add<Output = T> + Sub<Output = T> + Mul<Output = T>,
401{
402 #[inline]
404 pub fn lerp(&self, other: Self, t: T) -> Self {
405 Self::new(self.min.lerp(other.min, t), self.max.lerp(other.max, t))
406 }
407}
408
409impl<T, U> Box2D<T, U>
410where
411 T: Copy + One + Add<Output = T> + Div<Output = T>,
412{
413 pub fn center(&self) -> Point2D<T, U> {
414 let two = T::one() + T::one();
415 (self.min + self.max.to_vector()) / two
416 }
417}
418
419impl<T, U> Box2D<T, U>
420where
421 T: Copy + Mul<T, Output = T> + Sub<T, Output = T>,
422{
423 #[inline]
424 pub fn area(&self) -> T {
425 let size = self.size();
426 size.width * size.height
427 }
428}
429
430impl<T, U> Box2D<T, U>
431where
432 T: Zero,
433{
434 pub fn zero() -> Self {
436 Box2D::new(Point2D::zero(), Point2D::zero())
437 }
438}
439
440impl<T: Copy + Mul, U> Mul<T> for Box2D<T, U> {
441 type Output = Box2D<T::Output, U>;
442
443 #[inline]
444 fn mul(self, scale: T) -> Self::Output {
445 Box2D::new(self.min * scale, self.max * scale)
446 }
447}
448
449impl<T: Copy + MulAssign, U> MulAssign<T> for Box2D<T, U> {
450 #[inline]
451 fn mul_assign(&mut self, scale: T) {
452 *self *= Scale::new(scale);
453 }
454}
455
456impl<T: Copy + Div, U> Div<T> for Box2D<T, U> {
457 type Output = Box2D<T::Output, U>;
458
459 #[inline]
460 fn div(self, scale: T) -> Self::Output {
461 Box2D::new(self.min / scale, self.max / scale)
462 }
463}
464
465impl<T: Copy + DivAssign, U> DivAssign<T> for Box2D<T, U> {
466 #[inline]
467 fn div_assign(&mut self, scale: T) {
468 *self /= Scale::new(scale);
469 }
470}
471
472impl<T: Copy + Mul, U1, U2> Mul<Scale<T, U1, U2>> for Box2D<T, U1> {
473 type Output = Box2D<T::Output, U2>;
474
475 #[inline]
476 fn mul(self, scale: Scale<T, U1, U2>) -> Self::Output {
477 Box2D::new(self.min * scale, self.max * scale)
478 }
479}
480
481impl<T: Copy + MulAssign, U> MulAssign<Scale<T, U, U>> for Box2D<T, U> {
482 #[inline]
483 fn mul_assign(&mut self, scale: Scale<T, U, U>) {
484 self.min *= scale;
485 self.max *= scale;
486 }
487}
488
489impl<T: Copy + Div, U1, U2> Div<Scale<T, U1, U2>> for Box2D<T, U2> {
490 type Output = Box2D<T::Output, U1>;
491
492 #[inline]
493 fn div(self, scale: Scale<T, U1, U2>) -> Self::Output {
494 Box2D::new(self.min / scale, self.max / scale)
495 }
496}
497
498impl<T: Copy + DivAssign, U> DivAssign<Scale<T, U, U>> for Box2D<T, U> {
499 #[inline]
500 fn div_assign(&mut self, scale: Scale<T, U, U>) {
501 self.min /= scale;
502 self.max /= scale;
503 }
504}
505
506impl<T, U> Box2D<T, U>
507where
508 T: Copy,
509{
510 #[inline]
511 pub fn x_range(&self) -> Range<T> {
512 self.min.x..self.max.x
513 }
514
515 #[inline]
516 pub fn y_range(&self) -> Range<T> {
517 self.min.y..self.max.y
518 }
519
520 #[inline]
522 pub fn to_untyped(&self) -> Box2D<T, UnknownUnit> {
523 Box2D::new(self.min.to_untyped(), self.max.to_untyped())
524 }
525
526 #[inline]
528 pub fn from_untyped(c: &Box2D<T, UnknownUnit>) -> Box2D<T, U> {
529 Box2D::new(Point2D::from_untyped(c.min), Point2D::from_untyped(c.max))
530 }
531
532 #[inline]
534 pub fn cast_unit<V>(&self) -> Box2D<T, V> {
535 Box2D::new(self.min.cast_unit(), self.max.cast_unit())
536 }
537
538 #[inline]
539 pub fn scale<S: Copy>(&self, x: S, y: S) -> Self
540 where
541 T: Mul<S, Output = T>,
542 {
543 Box2D {
544 min: point2(self.min.x * x, self.min.y * y),
545 max: point2(self.max.x * x, self.max.y * y),
546 }
547 }
548}
549
550impl<T: NumCast + Copy, U> Box2D<T, U> {
551 #[inline]
561 pub fn cast<NewT: NumCast>(&self) -> Box2D<NewT, U> {
562 Box2D::new(self.min.cast(), self.max.cast())
563 }
564
565 pub fn try_cast<NewT: NumCast>(&self) -> Option<Box2D<NewT, U>> {
575 match (self.min.try_cast(), self.max.try_cast()) {
576 (Some(a), Some(b)) => Some(Box2D::new(a, b)),
577 _ => None,
578 }
579 }
580
581 #[inline]
585 pub fn to_f32(&self) -> Box2D<f32, U> {
586 self.cast()
587 }
588
589 #[inline]
591 pub fn to_f64(&self) -> Box2D<f64, U> {
592 self.cast()
593 }
594
595 #[inline]
601 pub fn to_usize(&self) -> Box2D<usize, U> {
602 self.cast()
603 }
604
605 #[inline]
611 pub fn to_u32(&self) -> Box2D<u32, U> {
612 self.cast()
613 }
614
615 #[inline]
621 pub fn to_i32(&self) -> Box2D<i32, U> {
622 self.cast()
623 }
624
625 #[inline]
631 pub fn to_i64(&self) -> Box2D<i64, U> {
632 self.cast()
633 }
634}
635
636impl<T: Float, U> Box2D<T, U> {
637 #[inline]
639 pub fn is_finite(self) -> bool {
640 self.min.is_finite() && self.max.is_finite()
641 }
642}
643
644impl<T, U> Box2D<T, U>
645where
646 T: Round,
647{
648 #[must_use]
658 pub fn round(&self) -> Self {
659 Box2D::new(self.min.round(), self.max.round())
660 }
661}
662
663impl<T, U> Box2D<T, U>
664where
665 T: Floor + Ceil,
666{
667 #[must_use]
670 pub fn round_in(&self) -> Self {
671 let min = self.min.ceil();
672 let max = self.max.floor();
673 Box2D { min, max }
674 }
675
676 #[must_use]
679 pub fn round_out(&self) -> Self {
680 let min = self.min.floor();
681 let max = self.max.ceil();
682 Box2D { min, max }
683 }
684}
685
686impl<T, U> From<Size2D<T, U>> for Box2D<T, U>
687where
688 T: Copy + Zero + PartialOrd,
689{
690 fn from(b: Size2D<T, U>) -> Self {
691 Self::from_size(b)
692 }
693}
694
695impl<T: Default, U> Default for Box2D<T, U> {
696 fn default() -> Self {
697 Box2D {
698 min: Default::default(),
699 max: Default::default(),
700 }
701 }
702}
703
704#[cfg(test)]
705mod tests {
706 use crate::default::Box2D;
707 use crate::side_offsets::SideOffsets2D;
708 use crate::{point2, size2, vec2, Point2D};
709 #[test]
712 fn test_size() {
713 let b = Box2D::new(point2(-10.0, -10.0), point2(10.0, 10.0));
714 assert_eq!(b.size().width, 20.0);
715 assert_eq!(b.size().height, 20.0);
716 }
717
718 #[test]
719 fn test_width_height() {
720 let b = Box2D::new(point2(-10.0, -10.0), point2(10.0, 10.0));
721 assert!(b.width() == 20.0);
722 assert!(b.height() == 20.0);
723 }
724
725 #[test]
726 fn test_center() {
727 let b = Box2D::new(point2(-10.0, -10.0), point2(10.0, 10.0));
728 assert_eq!(b.center(), Point2D::zero());
729 }
730
731 #[test]
732 fn test_area() {
733 let b = Box2D::new(point2(-10.0, -10.0), point2(10.0, 10.0));
734 assert_eq!(b.area(), 400.0);
735 }
736
737 #[test]
738 fn test_from_points() {
739 let b = Box2D::from_points(&[point2(50.0, 160.0), point2(100.0, 25.0)]);
740 assert_eq!(b.min, point2(50.0, 25.0));
741 assert_eq!(b.max, point2(100.0, 160.0));
742 }
743
744 #[test]
745 fn test_round_in() {
746 let b = Box2D::from_points(&[point2(-25.5, -40.4), point2(60.3, 36.5)]).round_in();
747 assert_eq!(b.min.x, -25.0);
748 assert_eq!(b.min.y, -40.0);
749 assert_eq!(b.max.x, 60.0);
750 assert_eq!(b.max.y, 36.0);
751 }
752
753 #[test]
754 fn test_round_out() {
755 let b = Box2D::from_points(&[point2(-25.5, -40.4), point2(60.3, 36.5)]).round_out();
756 assert_eq!(b.min.x, -26.0);
757 assert_eq!(b.min.y, -41.0);
758 assert_eq!(b.max.x, 61.0);
759 assert_eq!(b.max.y, 37.0);
760 }
761
762 #[test]
763 fn test_round() {
764 let b = Box2D::from_points(&[point2(-25.5, -40.4), point2(60.3, 36.5)]).round();
765 assert_eq!(b.min.x, -25.0);
766 assert_eq!(b.min.y, -40.0);
767 assert_eq!(b.max.x, 60.0);
768 assert_eq!(b.max.y, 37.0);
769 }
770
771 #[test]
772 fn test_from_size() {
773 let b = Box2D::from_size(size2(30.0, 40.0));
774 assert!(b.min == Point2D::zero());
775 assert!(b.size().width == 30.0);
776 assert!(b.size().height == 40.0);
777 }
778
779 #[test]
780 fn test_inner_box() {
781 let b = Box2D::from_points(&[point2(50.0, 25.0), point2(100.0, 160.0)]);
782 let b = b.inner_box(SideOffsets2D::new(10.0, 20.0, 5.0, 10.0));
783 assert_eq!(b.max.x, 80.0);
784 assert_eq!(b.max.y, 155.0);
785 assert_eq!(b.min.x, 60.0);
786 assert_eq!(b.min.y, 35.0);
787 }
788
789 #[test]
790 fn test_outer_box() {
791 let b = Box2D::from_points(&[point2(50.0, 25.0), point2(100.0, 160.0)]);
792 let b = b.outer_box(SideOffsets2D::new(10.0, 20.0, 5.0, 10.0));
793 assert_eq!(b.max.x, 120.0);
794 assert_eq!(b.max.y, 165.0);
795 assert_eq!(b.min.x, 40.0);
796 assert_eq!(b.min.y, 15.0);
797 }
798
799 #[test]
800 fn test_translate() {
801 let size = size2(15.0, 15.0);
802 let mut center = (size / 2.0).to_vector().to_point();
803 let b = Box2D::from_size(size);
804 assert_eq!(b.center(), center);
805 let translation = vec2(10.0, 2.5);
806 let b = b.translate(translation);
807 center += translation;
808 assert_eq!(b.center(), center);
809 assert_eq!(b.max.x, 25.0);
810 assert_eq!(b.max.y, 17.5);
811 assert_eq!(b.min.x, 10.0);
812 assert_eq!(b.min.y, 2.5);
813 }
814
815 #[test]
816 fn test_union() {
817 let b1 = Box2D::from_points(&[point2(-20.0, -20.0), point2(0.0, 20.0)]);
818 let b2 = Box2D::from_points(&[point2(0.0, 20.0), point2(20.0, -20.0)]);
819 let b = b1.union(&b2);
820 assert_eq!(b.max.x, 20.0);
821 assert_eq!(b.max.y, 20.0);
822 assert_eq!(b.min.x, -20.0);
823 assert_eq!(b.min.y, -20.0);
824 }
825
826 #[test]
827 fn test_intersects() {
828 let b1 = Box2D::from_points(&[point2(-15.0, -20.0), point2(10.0, 20.0)]);
829 let b2 = Box2D::from_points(&[point2(-10.0, 20.0), point2(15.0, -20.0)]);
830 assert!(b1.intersects(&b2));
831 }
832
833 #[test]
834 fn test_intersection_unchecked() {
835 let b1 = Box2D::from_points(&[point2(-15.0, -20.0), point2(10.0, 20.0)]);
836 let b2 = Box2D::from_points(&[point2(-10.0, 20.0), point2(15.0, -20.0)]);
837 let b = b1.intersection_unchecked(&b2);
838 assert_eq!(b.max.x, 10.0);
839 assert_eq!(b.max.y, 20.0);
840 assert_eq!(b.min.x, -10.0);
841 assert_eq!(b.min.y, -20.0);
842 }
843
844 #[test]
845 fn test_intersection() {
846 let b1 = Box2D::from_points(&[point2(-15.0, -20.0), point2(10.0, 20.0)]);
847 let b2 = Box2D::from_points(&[point2(-10.0, 20.0), point2(15.0, -20.0)]);
848 assert!(b1.intersection(&b2).is_some());
849
850 let b1 = Box2D::from_points(&[point2(-15.0, -20.0), point2(-10.0, 20.0)]);
851 let b2 = Box2D::from_points(&[point2(10.0, 20.0), point2(15.0, -20.0)]);
852 assert!(b1.intersection(&b2).is_none());
853 }
854
855 #[test]
856 fn test_scale() {
857 let b = Box2D::from_points(&[point2(-10.0, -10.0), point2(10.0, 10.0)]);
858 let b = b.scale(0.5, 0.5);
859 assert_eq!(b.max.x, 5.0);
860 assert_eq!(b.max.y, 5.0);
861 assert_eq!(b.min.x, -5.0);
862 assert_eq!(b.min.y, -5.0);
863 }
864
865 #[test]
866 fn test_lerp() {
867 let b1 = Box2D::from_points(&[point2(-20.0, -20.0), point2(-10.0, -10.0)]);
868 let b2 = Box2D::from_points(&[point2(10.0, 10.0), point2(20.0, 20.0)]);
869 let b = b1.lerp(b2, 0.5);
870 assert_eq!(b.center(), Point2D::zero());
871 assert_eq!(b.size().width, 10.0);
872 assert_eq!(b.size().height, 10.0);
873 }
874
875 #[test]
876 fn test_contains() {
877 let b = Box2D::from_points(&[point2(-20.0, -20.0), point2(20.0, 20.0)]);
878 assert!(b.contains(point2(-15.3, 10.5)));
879 }
880
881 #[test]
882 fn test_contains_box() {
883 let b1 = Box2D::from_points(&[point2(-20.0, -20.0), point2(20.0, 20.0)]);
884 let b2 = Box2D::from_points(&[point2(-14.3, -16.5), point2(6.7, 17.6)]);
885 assert!(b1.contains_box(&b2));
886 }
887
888 #[test]
889 fn test_inflate() {
890 let b = Box2D::from_points(&[point2(-20.0, -20.0), point2(20.0, 20.0)]);
891 let b = b.inflate(10.0, 5.0);
892 assert_eq!(b.size().width, 60.0);
893 assert_eq!(b.size().height, 50.0);
894 assert_eq!(b.center(), Point2D::zero());
895 }
896
897 #[test]
898 fn test_is_empty() {
899 for i in 0..2 {
900 let mut coords_neg = [-20.0, -20.0];
901 let mut coords_pos = [20.0, 20.0];
902 coords_neg[i] = 0.0;
903 coords_pos[i] = 0.0;
904 let b = Box2D::from_points(&[Point2D::from(coords_neg), Point2D::from(coords_pos)]);
905 assert!(b.is_empty());
906 }
907 }
908
909 #[test]
910 #[rustfmt::skip]
911 fn test_nan_empty() {
912 use std::f32::NAN;
913 assert!(Box2D { min: point2(NAN, 2.0), max: point2(1.0, 3.0) }.is_empty());
914 assert!(Box2D { min: point2(0.0, NAN), max: point2(1.0, 2.0) }.is_empty());
915 assert!(Box2D { min: point2(1.0, -2.0), max: point2(NAN, 2.0) }.is_empty());
916 assert!(Box2D { min: point2(1.0, -2.0), max: point2(0.0, NAN) }.is_empty());
917 }
918
919 #[test]
920 fn test_from_origin_and_size() {
921 let b = Box2D::from_origin_and_size(point2(1.0, 2.0), size2(3.0, 4.0));
922 assert_eq!(b.min, point2(1.0, 2.0));
923 assert_eq!(b.size(), size2(3.0, 4.0));
924 }
925
926 #[test]
927 fn test_set_size() {
928 let mut b = Box2D {
929 min: point2(1.0, 2.0),
930 max: point2(3.0, 4.0),
931 };
932 b.set_size(size2(5.0, 6.0));
933
934 assert_eq!(b.min, point2(1.0, 2.0));
935 assert_eq!(b.size(), size2(5.0, 6.0));
936 }
937}