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};
22#[cfg(feature = "malloc_size_of")]
23use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
24use num_traits::NumCast;
25#[cfg(feature = "serde")]
26use serde::{Deserialize, Serialize};
27
28use core::borrow::Borrow;
29use core::cmp::PartialOrd;
30use core::fmt;
31use core::hash::{Hash, Hasher};
32use core::ops::{Add, Div, DivAssign, Mul, MulAssign, Range, Sub};
33
34#[repr(C)]
63#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
64#[cfg_attr(
65 feature = "serde",
66 serde(bound(serialize = "T: Serialize", deserialize = "T: Deserialize<'de>"))
67)]
68pub struct Box2D<T, U> {
69 pub min: Point2D<T, U>,
70 pub max: Point2D<T, U>,
71}
72
73impl<T: Hash, U> Hash for Box2D<T, U> {
74 fn hash<H: Hasher>(&self, h: &mut H) {
75 self.min.hash(h);
76 self.max.hash(h);
77 }
78}
79
80impl<T: Copy, U> Copy for Box2D<T, U> {}
81
82impl<T: Clone, U> Clone for Box2D<T, U> {
83 fn clone(&self) -> Self {
84 Self::new(self.min.clone(), self.max.clone())
85 }
86}
87
88impl<T: PartialEq, U> PartialEq for Box2D<T, U> {
89 fn eq(&self, other: &Self) -> bool {
90 self.min.eq(&other.min) && self.max.eq(&other.max)
91 }
92}
93
94impl<T: Eq, U> Eq for Box2D<T, U> {}
95
96impl<T: fmt::Debug, U> fmt::Debug for Box2D<T, U> {
97 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
98 f.debug_tuple("Box2D")
99 .field(&self.min)
100 .field(&self.max)
101 .finish()
102 }
103}
104
105#[cfg(feature = "arbitrary")]
106impl<'a, T, U> arbitrary::Arbitrary<'a> for Box2D<T, U>
107where
108 T: arbitrary::Arbitrary<'a>,
109{
110 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
111 Ok(Box2D::new(
112 arbitrary::Arbitrary::arbitrary(u)?,
113 arbitrary::Arbitrary::arbitrary(u)?,
114 ))
115 }
116}
117
118#[cfg(feature = "bytemuck")]
119unsafe impl<T: Zeroable, U> Zeroable for Box2D<T, U> {}
120
121#[cfg(feature = "bytemuck")]
122unsafe impl<T: Pod, U: 'static> Pod for Box2D<T, U> {}
123
124impl<T, U> Box2D<T, U> {
125 #[inline]
127 pub const fn new(min: Point2D<T, U>, max: Point2D<T, U>) -> Self {
128 Box2D { min, max }
129 }
130
131 #[inline]
133 pub fn from_origin_and_size(origin: Point2D<T, U>, size: Size2D<T, U>) -> Self
134 where
135 T: Copy + Add<T, Output = T>,
136 {
137 Box2D {
138 min: origin,
139 max: point2(origin.x + size.width, origin.y + size.height),
140 }
141 }
142
143 #[inline]
145 pub fn from_size(size: Size2D<T, U>) -> Self
146 where
147 T: Zero,
148 {
149 Box2D {
150 min: Point2D::zero(),
151 max: point2(size.width, size.height),
152 }
153 }
154}
155
156#[cfg(feature = "malloc_size_of")]
157impl<T: MallocSizeOf, U> MallocSizeOf for Box2D<T, U> {
158 fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
159 self.min.size_of(ops) + self.max.size_of(ops)
160 }
161}
162
163impl<T, U> Box2D<T, U>
164where
165 T: PartialOrd,
166{
167 #[inline]
172 pub fn is_negative(&self) -> bool {
173 self.max.x < self.min.x || self.max.y < self.min.y
174 }
175
176 #[inline]
178 pub fn is_empty(&self) -> bool {
179 !(self.max.x > self.min.x && self.max.y > self.min.y)
180 }
181
182 #[inline]
184 pub fn intersects(&self, other: &Self) -> bool {
185 (self.min.x < other.max.x)
187 & (self.max.x > other.min.x)
188 & (self.min.y < other.max.y)
189 & (self.max.y > other.min.y)
190 }
191
192 #[inline]
217 pub fn contains(&self, p: Point2D<T, U>) -> bool {
218 (self.min.x <= p.x) & (p.x < self.max.x) & (self.min.y <= p.y) & (p.y < self.max.y)
220 }
221
222 #[inline]
244 pub fn contains_inclusive(&self, p: Point2D<T, U>) -> bool {
245 (self.min.x <= p.x) & (p.x <= self.max.x) & (self.min.y <= p.y) & (p.y <= self.max.y)
247 }
248
249 #[inline]
253 pub fn contains_box(&self, other: &Self) -> bool {
254 other.is_empty()
255 || ((self.min.x <= other.min.x)
256 & (other.max.x <= self.max.x)
257 & (self.min.y <= other.min.y)
258 & (other.max.y <= self.max.y))
259 }
260}
261
262impl<T, U> Box2D<T, U>
263where
264 T: Copy + PartialOrd,
265{
266 #[inline]
267 pub fn to_non_empty(&self) -> Option<Self> {
268 if self.is_empty() {
269 return None;
270 }
271
272 Some(*self)
273 }
274
275 #[inline]
277 pub fn intersection(&self, other: &Self) -> Option<Self> {
278 let b = self.intersection_unchecked(other);
279
280 if b.is_empty() {
281 return None;
282 }
283
284 Some(b)
285 }
286
287 #[inline]
294 pub fn intersection_unchecked(&self, other: &Self) -> Self {
295 Box2D {
296 min: point2(max(self.min.x, other.min.x), max(self.min.y, other.min.y)),
297 max: point2(min(self.max.x, other.max.x), min(self.max.y, other.max.y)),
298 }
299 }
300
301 #[inline]
305 pub fn union(&self, other: &Self) -> Self {
306 if other.is_empty() {
307 return *self;
308 }
309 if self.is_empty() {
310 return *other;
311 }
312
313 Box2D {
314 min: point2(min(self.min.x, other.min.x), min(self.min.y, other.min.y)),
315 max: point2(max(self.max.x, other.max.x), max(self.max.y, other.max.y)),
316 }
317 }
318}
319
320impl<T, U> Box2D<T, U>
321where
322 T: Copy + Add<T, Output = T>,
323{
324 #[inline]
326 pub fn translate(&self, by: Vector2D<T, U>) -> Self {
327 Box2D {
328 min: self.min + by,
329 max: self.max + by,
330 }
331 }
332}
333
334impl<T, U> Box2D<T, U>
335where
336 T: Copy + Sub<T, Output = T>,
337{
338 #[inline]
339 pub fn size(&self) -> Size2D<T, U> {
340 (self.max - self.min).to_size()
341 }
342
343 #[inline]
346 pub fn set_size(&mut self, size: Size2D<T, U>) {
347 let diff = (self.size() - size).to_vector();
348 self.max -= diff;
349 }
350
351 #[inline]
352 pub fn width(&self) -> T {
353 self.max.x - self.min.x
354 }
355
356 #[inline]
357 pub fn height(&self) -> T {
358 self.max.y - self.min.y
359 }
360
361 #[inline]
362 pub fn to_rect(&self) -> Rect<T, U> {
363 Rect {
364 origin: self.min,
365 size: self.size(),
366 }
367 }
368}
369
370impl<T, U> Box2D<T, U>
371where
372 T: Copy + Add<T, Output = T> + Sub<T, Output = T>,
373{
374 #[inline]
376 #[must_use]
377 pub fn inflate(&self, width: T, height: T) -> Self {
378 Box2D {
379 min: point2(self.min.x - width, self.min.y - height),
380 max: point2(self.max.x + width, self.max.y + height),
381 }
382 }
383
384 pub fn inner_box(&self, offsets: SideOffsets2D<T, U>) -> Self {
389 Box2D {
390 min: self.min + vec2(offsets.left, offsets.top),
391 max: self.max - vec2(offsets.right, offsets.bottom),
392 }
393 }
394
395 pub fn outer_box(&self, offsets: SideOffsets2D<T, U>) -> Self {
399 Box2D {
400 min: self.min - vec2(offsets.left, offsets.top),
401 max: self.max + vec2(offsets.right, offsets.bottom),
402 }
403 }
404}
405
406impl<T, U> Box2D<T, U>
407where
408 T: Copy + Zero + PartialOrd,
409{
410 pub fn from_points<I>(points: I) -> Self
458 where
459 I: IntoIterator,
460 I::Item: Borrow<Point2D<T, U>>,
461 {
462 let mut points = points.into_iter();
463
464 let (mut min_x, mut min_y) = match points.next() {
465 Some(first) => first.borrow().to_tuple(),
466 None => return Box2D::zero(),
467 };
468
469 let (mut max_x, mut max_y) = (min_x, min_y);
470 for point in points {
471 let p = point.borrow();
472 if p.x < min_x {
473 min_x = p.x;
474 }
475 if p.x > max_x {
476 max_x = p.x;
477 }
478 if p.y < min_y {
479 min_y = p.y;
480 }
481 if p.y > max_y {
482 max_y = p.y;
483 }
484 }
485
486 Box2D {
487 min: point2(min_x, min_y),
488 max: point2(max_x, max_y),
489 }
490 }
491}
492
493impl<T, U> Box2D<T, U>
494where
495 T: Copy + One + Add<Output = T> + Sub<Output = T> + Mul<Output = T>,
496{
497 #[inline]
499 pub fn lerp(&self, other: Self, t: T) -> Self {
500 Self::new(self.min.lerp(other.min, t), self.max.lerp(other.max, t))
501 }
502}
503
504impl<T, U> Box2D<T, U>
505where
506 T: Copy + One + Add<Output = T> + Div<Output = T>,
507{
508 pub fn center(&self) -> Point2D<T, U> {
509 let two = T::one() + T::one();
510 (self.min + self.max.to_vector()) / two
511 }
512}
513
514impl<T, U> Box2D<T, U>
515where
516 T: Copy + Mul<T, Output = T> + Sub<T, Output = T>,
517{
518 #[inline]
519 pub fn area(&self) -> T {
520 let size = self.size();
521 size.width * size.height
522 }
523}
524
525impl<T, U> Box2D<T, U>
526where
527 T: Zero,
528{
529 pub fn zero() -> Self {
531 Box2D::new(Point2D::zero(), Point2D::zero())
532 }
533}
534
535impl<T: Copy + Mul, U> Mul<T> for Box2D<T, U> {
536 type Output = Box2D<T::Output, U>;
537
538 #[inline]
539 fn mul(self, scale: T) -> Self::Output {
540 Box2D::new(self.min * scale, self.max * scale)
541 }
542}
543
544impl<T: Copy + MulAssign, U> MulAssign<T> for Box2D<T, U> {
545 #[inline]
546 fn mul_assign(&mut self, scale: T) {
547 *self *= Scale::new(scale);
548 }
549}
550
551impl<T: Copy + Div, U> Div<T> for Box2D<T, U> {
552 type Output = Box2D<T::Output, U>;
553
554 #[inline]
555 fn div(self, scale: T) -> Self::Output {
556 Box2D::new(self.min / scale, self.max / scale)
557 }
558}
559
560impl<T: Copy + DivAssign, U> DivAssign<T> for Box2D<T, U> {
561 #[inline]
562 fn div_assign(&mut self, scale: T) {
563 *self /= Scale::new(scale);
564 }
565}
566
567impl<T: Copy + Mul, U1, U2> Mul<Scale<T, U1, U2>> for Box2D<T, U1> {
568 type Output = Box2D<T::Output, U2>;
569
570 #[inline]
571 fn mul(self, scale: Scale<T, U1, U2>) -> Self::Output {
572 Box2D::new(self.min * scale, self.max * scale)
573 }
574}
575
576impl<T: Copy + MulAssign, U> MulAssign<Scale<T, U, U>> for Box2D<T, U> {
577 #[inline]
578 fn mul_assign(&mut self, scale: Scale<T, U, U>) {
579 self.min *= scale;
580 self.max *= scale;
581 }
582}
583
584impl<T: Copy + Div, U1, U2> Div<Scale<T, U1, U2>> for Box2D<T, U2> {
585 type Output = Box2D<T::Output, U1>;
586
587 #[inline]
588 fn div(self, scale: Scale<T, U1, U2>) -> Self::Output {
589 Box2D::new(self.min / scale, self.max / scale)
590 }
591}
592
593impl<T: Copy + DivAssign, U> DivAssign<Scale<T, U, U>> for Box2D<T, U> {
594 #[inline]
595 fn div_assign(&mut self, scale: Scale<T, U, U>) {
596 self.min /= scale;
597 self.max /= scale;
598 }
599}
600
601impl<T, U> Box2D<T, U>
602where
603 T: Copy,
604{
605 #[inline]
606 pub fn x_range(&self) -> Range<T> {
607 self.min.x..self.max.x
608 }
609
610 #[inline]
611 pub fn y_range(&self) -> Range<T> {
612 self.min.y..self.max.y
613 }
614
615 #[inline]
617 pub fn to_untyped(&self) -> Box2D<T, UnknownUnit> {
618 Box2D::new(self.min.to_untyped(), self.max.to_untyped())
619 }
620
621 #[inline]
623 pub fn from_untyped(c: &Box2D<T, UnknownUnit>) -> Box2D<T, U> {
624 Box2D::new(Point2D::from_untyped(c.min), Point2D::from_untyped(c.max))
625 }
626
627 #[inline]
629 pub fn cast_unit<V>(&self) -> Box2D<T, V> {
630 Box2D::new(self.min.cast_unit(), self.max.cast_unit())
631 }
632
633 #[inline]
634 pub fn scale<S: Copy>(&self, x: S, y: S) -> Self
635 where
636 T: Mul<S, Output = T>,
637 {
638 Box2D {
639 min: point2(self.min.x * x, self.min.y * y),
640 max: point2(self.max.x * x, self.max.y * y),
641 }
642 }
643}
644
645impl<T: NumCast + Copy, U> Box2D<T, U> {
646 #[inline]
656 pub fn cast<NewT: NumCast>(&self) -> Box2D<NewT, U> {
657 Box2D::new(self.min.cast(), self.max.cast())
658 }
659
660 pub fn try_cast<NewT: NumCast>(&self) -> Option<Box2D<NewT, U>> {
670 match (self.min.try_cast(), self.max.try_cast()) {
671 (Some(a), Some(b)) => Some(Box2D::new(a, b)),
672 _ => None,
673 }
674 }
675
676 #[inline]
680 pub fn to_f32(&self) -> Box2D<f32, U> {
681 self.cast()
682 }
683
684 #[inline]
686 pub fn to_f64(&self) -> Box2D<f64, U> {
687 self.cast()
688 }
689
690 #[inline]
696 pub fn to_usize(&self) -> Box2D<usize, U> {
697 self.cast()
698 }
699
700 #[inline]
706 pub fn to_u32(&self) -> Box2D<u32, U> {
707 self.cast()
708 }
709
710 #[inline]
716 pub fn to_i32(&self) -> Box2D<i32, U> {
717 self.cast()
718 }
719
720 #[inline]
726 pub fn to_i64(&self) -> Box2D<i64, U> {
727 self.cast()
728 }
729}
730
731impl<T, U> Box2D<T, U>
732where
733 T: Round,
734{
735 #[must_use]
745 pub fn round(&self) -> Self {
746 Box2D::new(self.min.round(), self.max.round())
747 }
748}
749
750impl<T, U> Box2D<T, U>
751where
752 T: Floor + Ceil,
753{
754 #[must_use]
757 pub fn round_in(&self) -> Self {
758 let min = self.min.ceil();
759 let max = self.max.floor();
760 Box2D { min, max }
761 }
762
763 #[must_use]
766 pub fn round_out(&self) -> Self {
767 let min = self.min.floor();
768 let max = self.max.ceil();
769 Box2D { min, max }
770 }
771}
772
773impl<T, U> From<Size2D<T, U>> for Box2D<T, U>
774where
775 T: Copy + Zero + PartialOrd,
776{
777 fn from(b: Size2D<T, U>) -> Self {
778 Self::from_size(b)
779 }
780}
781
782impl<T, U> From<Rect<T, U>> for Box2D<T, U>
783where
784 T: Copy + Add<T, Output = T>,
785{
786 fn from(r: Rect<T, U>) -> Self {
787 r.to_box2d()
788 }
789}
790
791impl<T: Default, U> Default for Box2D<T, U> {
792 fn default() -> Self {
793 Box2D {
794 min: Default::default(),
795 max: Default::default(),
796 }
797 }
798}
799
800#[cfg(any(feature = "std", feature = "libm"))]
801mod float {
802 use super::Box2D;
803 use num_traits::Float;
804
805 impl<T: Float, U> Box2D<T, U> {
806 #[inline]
808 pub fn is_finite(self) -> bool {
809 self.min.is_finite() && self.max.is_finite()
810 }
811 }
812}
813
814#[cfg(test)]
815#[cfg(any(feature = "std", feature = "libm"))]
816mod tests {
817 use crate::default::Box2D;
818 use crate::side_offsets::SideOffsets2D;
819 use crate::{point2, size2, vec2, Point2D};
820 #[test]
823 fn test_size() {
824 let b = Box2D::new(point2(-10.0, -10.0), point2(10.0, 10.0));
825 assert_eq!(b.size().width, 20.0);
826 assert_eq!(b.size().height, 20.0);
827 }
828
829 #[test]
830 fn test_width_height() {
831 let b = Box2D::new(point2(-10.0, -10.0), point2(10.0, 10.0));
832 assert!(b.width() == 20.0);
833 assert!(b.height() == 20.0);
834 }
835
836 #[test]
837 fn test_center() {
838 let b = Box2D::new(point2(-10.0, -10.0), point2(10.0, 10.0));
839 assert_eq!(b.center(), Point2D::zero());
840 }
841
842 #[test]
843 fn test_area() {
844 let b = Box2D::new(point2(-10.0, -10.0), point2(10.0, 10.0));
845 assert_eq!(b.area(), 400.0);
846 }
847
848 #[test]
849 fn test_from_points() {
850 let b = Box2D::from_points(&[point2(50.0, 160.0), point2(100.0, 25.0)]);
851 assert_eq!(b.min, point2(50.0, 25.0));
852 assert_eq!(b.max, point2(100.0, 160.0));
853 }
854
855 #[test]
856 fn test_round_in() {
857 let b = Box2D::from_points(&[point2(-25.5, -40.4), point2(60.3, 36.5)]).round_in();
858 assert_eq!(b.min.x, -25.0);
859 assert_eq!(b.min.y, -40.0);
860 assert_eq!(b.max.x, 60.0);
861 assert_eq!(b.max.y, 36.0);
862 }
863
864 #[test]
865 fn test_round_out() {
866 let b = Box2D::from_points(&[point2(-25.5, -40.4), point2(60.3, 36.5)]).round_out();
867 assert_eq!(b.min.x, -26.0);
868 assert_eq!(b.min.y, -41.0);
869 assert_eq!(b.max.x, 61.0);
870 assert_eq!(b.max.y, 37.0);
871 }
872
873 #[test]
874 fn test_round() {
875 let b = Box2D::from_points(&[point2(-25.5, -40.4), point2(60.3, 36.5)]).round();
876 assert_eq!(b.min.x, -25.0);
877 assert_eq!(b.min.y, -40.0);
878 assert_eq!(b.max.x, 60.0);
879 assert_eq!(b.max.y, 37.0);
880 }
881
882 #[test]
883 fn test_from_size() {
884 let b = Box2D::from_size(size2(30.0, 40.0));
885 assert!(b.min == Point2D::zero());
886 assert!(b.size().width == 30.0);
887 assert!(b.size().height == 40.0);
888 }
889
890 #[test]
891 fn test_inner_box() {
892 let b = Box2D::from_points(&[point2(50.0, 25.0), point2(100.0, 160.0)]);
893 let b = b.inner_box(SideOffsets2D::new(10.0, 20.0, 5.0, 10.0));
894 assert_eq!(b.max.x, 80.0);
895 assert_eq!(b.max.y, 155.0);
896 assert_eq!(b.min.x, 60.0);
897 assert_eq!(b.min.y, 35.0);
898 }
899
900 #[test]
901 fn test_outer_box() {
902 let b = Box2D::from_points(&[point2(50.0, 25.0), point2(100.0, 160.0)]);
903 let b = b.outer_box(SideOffsets2D::new(10.0, 20.0, 5.0, 10.0));
904 assert_eq!(b.max.x, 120.0);
905 assert_eq!(b.max.y, 165.0);
906 assert_eq!(b.min.x, 40.0);
907 assert_eq!(b.min.y, 15.0);
908 }
909
910 #[test]
911 fn test_translate() {
912 let size = size2(15.0, 15.0);
913 let mut center = (size / 2.0).to_vector().to_point();
914 let b = Box2D::from_size(size);
915 assert_eq!(b.center(), center);
916 let translation = vec2(10.0, 2.5);
917 let b = b.translate(translation);
918 center += translation;
919 assert_eq!(b.center(), center);
920 assert_eq!(b.max.x, 25.0);
921 assert_eq!(b.max.y, 17.5);
922 assert_eq!(b.min.x, 10.0);
923 assert_eq!(b.min.y, 2.5);
924 }
925
926 #[test]
927 fn test_union() {
928 let b1 = Box2D::from_points(&[point2(-20.0, -20.0), point2(0.0, 20.0)]);
929 let b2 = Box2D::from_points(&[point2(0.0, 20.0), point2(20.0, -20.0)]);
930 let b = b1.union(&b2);
931 assert_eq!(b.max.x, 20.0);
932 assert_eq!(b.max.y, 20.0);
933 assert_eq!(b.min.x, -20.0);
934 assert_eq!(b.min.y, -20.0);
935 }
936
937 #[test]
938 fn test_intersects() {
939 let b1 = Box2D::from_points(&[point2(-15.0, -20.0), point2(10.0, 20.0)]);
940 let b2 = Box2D::from_points(&[point2(-10.0, 20.0), point2(15.0, -20.0)]);
941 assert!(b1.intersects(&b2));
942 }
943
944 #[test]
945 fn test_intersection_unchecked() {
946 let b1 = Box2D::from_points(&[point2(-15.0, -20.0), point2(10.0, 20.0)]);
947 let b2 = Box2D::from_points(&[point2(-10.0, 20.0), point2(15.0, -20.0)]);
948 let b = b1.intersection_unchecked(&b2);
949 assert_eq!(b.max.x, 10.0);
950 assert_eq!(b.max.y, 20.0);
951 assert_eq!(b.min.x, -10.0);
952 assert_eq!(b.min.y, -20.0);
953 }
954
955 #[test]
956 fn test_intersection() {
957 let b1 = Box2D::from_points(&[point2(-15.0, -20.0), point2(10.0, 20.0)]);
958 let b2 = Box2D::from_points(&[point2(-10.0, 20.0), point2(15.0, -20.0)]);
959 assert!(b1.intersection(&b2).is_some());
960
961 let b1 = Box2D::from_points(&[point2(-15.0, -20.0), point2(-10.0, 20.0)]);
962 let b2 = Box2D::from_points(&[point2(10.0, 20.0), point2(15.0, -20.0)]);
963 assert!(b1.intersection(&b2).is_none());
964 }
965
966 #[test]
967 fn test_scale() {
968 let b = Box2D::from_points(&[point2(-10.0, -10.0), point2(10.0, 10.0)]);
969 let b = b.scale(0.5, 0.5);
970 assert_eq!(b.max.x, 5.0);
971 assert_eq!(b.max.y, 5.0);
972 assert_eq!(b.min.x, -5.0);
973 assert_eq!(b.min.y, -5.0);
974 }
975
976 #[test]
977 fn test_lerp() {
978 let b1 = Box2D::from_points(&[point2(-20.0, -20.0), point2(-10.0, -10.0)]);
979 let b2 = Box2D::from_points(&[point2(10.0, 10.0), point2(20.0, 20.0)]);
980 let b = b1.lerp(b2, 0.5);
981 assert_eq!(b.center(), Point2D::zero());
982 assert_eq!(b.size().width, 10.0);
983 assert_eq!(b.size().height, 10.0);
984 }
985
986 #[test]
987 fn test_contains() {
988 let b = Box2D::from_points(&[point2(-20.0, -20.0), point2(20.0, 20.0)]);
989 assert!(b.contains(point2(-15.3, 10.5)));
990 }
991
992 #[test]
993 fn test_contains_box() {
994 let b1 = Box2D::from_points(&[point2(-20.0, -20.0), point2(20.0, 20.0)]);
995 let b2 = Box2D::from_points(&[point2(-14.3, -16.5), point2(6.7, 17.6)]);
996 assert!(b1.contains_box(&b2));
997 }
998
999 #[test]
1000 fn test_inflate() {
1001 let b = Box2D::from_points(&[point2(-20.0, -20.0), point2(20.0, 20.0)]);
1002 let b = b.inflate(10.0, 5.0);
1003 assert_eq!(b.size().width, 60.0);
1004 assert_eq!(b.size().height, 50.0);
1005 assert_eq!(b.center(), Point2D::zero());
1006 }
1007
1008 #[test]
1009 fn test_is_empty() {
1010 for i in 0..2 {
1011 let mut coords_neg = [-20.0, -20.0];
1012 let mut coords_pos = [20.0, 20.0];
1013 coords_neg[i] = 0.0;
1014 coords_pos[i] = 0.0;
1015 let b = Box2D::from_points(&[Point2D::from(coords_neg), Point2D::from(coords_pos)]);
1016 assert!(b.is_empty());
1017 }
1018 }
1019
1020 #[test]
1021 #[rustfmt::skip]
1022 fn test_nan_empty() {
1023 use std::f32::NAN;
1024 assert!(Box2D { min: point2(NAN, 2.0), max: point2(1.0, 3.0) }.is_empty());
1025 assert!(Box2D { min: point2(0.0, NAN), max: point2(1.0, 2.0) }.is_empty());
1026 assert!(Box2D { min: point2(1.0, -2.0), max: point2(NAN, 2.0) }.is_empty());
1027 assert!(Box2D { min: point2(1.0, -2.0), max: point2(0.0, NAN) }.is_empty());
1028 }
1029
1030 #[test]
1031 fn test_from_origin_and_size() {
1032 let b = Box2D::from_origin_and_size(point2(1.0, 2.0), size2(3.0, 4.0));
1033 assert_eq!(b.min, point2(1.0, 2.0));
1034 assert_eq!(b.size(), size2(3.0, 4.0));
1035 }
1036
1037 #[test]
1038 fn test_set_size() {
1039 let mut b = Box2D {
1040 min: point2(1.0, 2.0),
1041 max: point2(3.0, 4.0),
1042 };
1043 b.set_size(size2(5.0, 6.0));
1044
1045 assert_eq!(b.min, point2(1.0, 2.0));
1046 assert_eq!(b.size(), size2(5.0, 6.0));
1047 }
1048}