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::{Float, 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: Float, U> Box2D<T, U> {
732 #[inline]
734 pub fn is_finite(self) -> bool {
735 self.min.is_finite() && self.max.is_finite()
736 }
737}
738
739impl<T, U> Box2D<T, U>
740where
741 T: Round,
742{
743 #[must_use]
753 pub fn round(&self) -> Self {
754 Box2D::new(self.min.round(), self.max.round())
755 }
756}
757
758impl<T, U> Box2D<T, U>
759where
760 T: Floor + Ceil,
761{
762 #[must_use]
765 pub fn round_in(&self) -> Self {
766 let min = self.min.ceil();
767 let max = self.max.floor();
768 Box2D { min, max }
769 }
770
771 #[must_use]
774 pub fn round_out(&self) -> Self {
775 let min = self.min.floor();
776 let max = self.max.ceil();
777 Box2D { min, max }
778 }
779}
780
781impl<T, U> From<Size2D<T, U>> for Box2D<T, U>
782where
783 T: Copy + Zero + PartialOrd,
784{
785 fn from(b: Size2D<T, U>) -> Self {
786 Self::from_size(b)
787 }
788}
789
790impl<T, U> From<Rect<T, U>> for Box2D<T, U>
791where
792 T: Copy + Add<T, Output = T>,
793{
794 fn from(r: Rect<T, U>) -> Self {
795 r.to_box2d()
796 }
797}
798
799impl<T: Default, U> Default for Box2D<T, U> {
800 fn default() -> Self {
801 Box2D {
802 min: Default::default(),
803 max: Default::default(),
804 }
805 }
806}
807
808#[cfg(test)]
809mod tests {
810 use crate::default::Box2D;
811 use crate::side_offsets::SideOffsets2D;
812 use crate::{point2, size2, vec2, Point2D};
813 #[test]
816 fn test_size() {
817 let b = Box2D::new(point2(-10.0, -10.0), point2(10.0, 10.0));
818 assert_eq!(b.size().width, 20.0);
819 assert_eq!(b.size().height, 20.0);
820 }
821
822 #[test]
823 fn test_width_height() {
824 let b = Box2D::new(point2(-10.0, -10.0), point2(10.0, 10.0));
825 assert!(b.width() == 20.0);
826 assert!(b.height() == 20.0);
827 }
828
829 #[test]
830 fn test_center() {
831 let b = Box2D::new(point2(-10.0, -10.0), point2(10.0, 10.0));
832 assert_eq!(b.center(), Point2D::zero());
833 }
834
835 #[test]
836 fn test_area() {
837 let b = Box2D::new(point2(-10.0, -10.0), point2(10.0, 10.0));
838 assert_eq!(b.area(), 400.0);
839 }
840
841 #[test]
842 fn test_from_points() {
843 let b = Box2D::from_points(&[point2(50.0, 160.0), point2(100.0, 25.0)]);
844 assert_eq!(b.min, point2(50.0, 25.0));
845 assert_eq!(b.max, point2(100.0, 160.0));
846 }
847
848 #[test]
849 fn test_round_in() {
850 let b = Box2D::from_points(&[point2(-25.5, -40.4), point2(60.3, 36.5)]).round_in();
851 assert_eq!(b.min.x, -25.0);
852 assert_eq!(b.min.y, -40.0);
853 assert_eq!(b.max.x, 60.0);
854 assert_eq!(b.max.y, 36.0);
855 }
856
857 #[test]
858 fn test_round_out() {
859 let b = Box2D::from_points(&[point2(-25.5, -40.4), point2(60.3, 36.5)]).round_out();
860 assert_eq!(b.min.x, -26.0);
861 assert_eq!(b.min.y, -41.0);
862 assert_eq!(b.max.x, 61.0);
863 assert_eq!(b.max.y, 37.0);
864 }
865
866 #[test]
867 fn test_round() {
868 let b = Box2D::from_points(&[point2(-25.5, -40.4), point2(60.3, 36.5)]).round();
869 assert_eq!(b.min.x, -25.0);
870 assert_eq!(b.min.y, -40.0);
871 assert_eq!(b.max.x, 60.0);
872 assert_eq!(b.max.y, 37.0);
873 }
874
875 #[test]
876 fn test_from_size() {
877 let b = Box2D::from_size(size2(30.0, 40.0));
878 assert!(b.min == Point2D::zero());
879 assert!(b.size().width == 30.0);
880 assert!(b.size().height == 40.0);
881 }
882
883 #[test]
884 fn test_inner_box() {
885 let b = Box2D::from_points(&[point2(50.0, 25.0), point2(100.0, 160.0)]);
886 let b = b.inner_box(SideOffsets2D::new(10.0, 20.0, 5.0, 10.0));
887 assert_eq!(b.max.x, 80.0);
888 assert_eq!(b.max.y, 155.0);
889 assert_eq!(b.min.x, 60.0);
890 assert_eq!(b.min.y, 35.0);
891 }
892
893 #[test]
894 fn test_outer_box() {
895 let b = Box2D::from_points(&[point2(50.0, 25.0), point2(100.0, 160.0)]);
896 let b = b.outer_box(SideOffsets2D::new(10.0, 20.0, 5.0, 10.0));
897 assert_eq!(b.max.x, 120.0);
898 assert_eq!(b.max.y, 165.0);
899 assert_eq!(b.min.x, 40.0);
900 assert_eq!(b.min.y, 15.0);
901 }
902
903 #[test]
904 fn test_translate() {
905 let size = size2(15.0, 15.0);
906 let mut center = (size / 2.0).to_vector().to_point();
907 let b = Box2D::from_size(size);
908 assert_eq!(b.center(), center);
909 let translation = vec2(10.0, 2.5);
910 let b = b.translate(translation);
911 center += translation;
912 assert_eq!(b.center(), center);
913 assert_eq!(b.max.x, 25.0);
914 assert_eq!(b.max.y, 17.5);
915 assert_eq!(b.min.x, 10.0);
916 assert_eq!(b.min.y, 2.5);
917 }
918
919 #[test]
920 fn test_union() {
921 let b1 = Box2D::from_points(&[point2(-20.0, -20.0), point2(0.0, 20.0)]);
922 let b2 = Box2D::from_points(&[point2(0.0, 20.0), point2(20.0, -20.0)]);
923 let b = b1.union(&b2);
924 assert_eq!(b.max.x, 20.0);
925 assert_eq!(b.max.y, 20.0);
926 assert_eq!(b.min.x, -20.0);
927 assert_eq!(b.min.y, -20.0);
928 }
929
930 #[test]
931 fn test_intersects() {
932 let b1 = Box2D::from_points(&[point2(-15.0, -20.0), point2(10.0, 20.0)]);
933 let b2 = Box2D::from_points(&[point2(-10.0, 20.0), point2(15.0, -20.0)]);
934 assert!(b1.intersects(&b2));
935 }
936
937 #[test]
938 fn test_intersection_unchecked() {
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 let b = b1.intersection_unchecked(&b2);
942 assert_eq!(b.max.x, 10.0);
943 assert_eq!(b.max.y, 20.0);
944 assert_eq!(b.min.x, -10.0);
945 assert_eq!(b.min.y, -20.0);
946 }
947
948 #[test]
949 fn test_intersection() {
950 let b1 = Box2D::from_points(&[point2(-15.0, -20.0), point2(10.0, 20.0)]);
951 let b2 = Box2D::from_points(&[point2(-10.0, 20.0), point2(15.0, -20.0)]);
952 assert!(b1.intersection(&b2).is_some());
953
954 let b1 = Box2D::from_points(&[point2(-15.0, -20.0), point2(-10.0, 20.0)]);
955 let b2 = Box2D::from_points(&[point2(10.0, 20.0), point2(15.0, -20.0)]);
956 assert!(b1.intersection(&b2).is_none());
957 }
958
959 #[test]
960 fn test_scale() {
961 let b = Box2D::from_points(&[point2(-10.0, -10.0), point2(10.0, 10.0)]);
962 let b = b.scale(0.5, 0.5);
963 assert_eq!(b.max.x, 5.0);
964 assert_eq!(b.max.y, 5.0);
965 assert_eq!(b.min.x, -5.0);
966 assert_eq!(b.min.y, -5.0);
967 }
968
969 #[test]
970 fn test_lerp() {
971 let b1 = Box2D::from_points(&[point2(-20.0, -20.0), point2(-10.0, -10.0)]);
972 let b2 = Box2D::from_points(&[point2(10.0, 10.0), point2(20.0, 20.0)]);
973 let b = b1.lerp(b2, 0.5);
974 assert_eq!(b.center(), Point2D::zero());
975 assert_eq!(b.size().width, 10.0);
976 assert_eq!(b.size().height, 10.0);
977 }
978
979 #[test]
980 fn test_contains() {
981 let b = Box2D::from_points(&[point2(-20.0, -20.0), point2(20.0, 20.0)]);
982 assert!(b.contains(point2(-15.3, 10.5)));
983 }
984
985 #[test]
986 fn test_contains_box() {
987 let b1 = Box2D::from_points(&[point2(-20.0, -20.0), point2(20.0, 20.0)]);
988 let b2 = Box2D::from_points(&[point2(-14.3, -16.5), point2(6.7, 17.6)]);
989 assert!(b1.contains_box(&b2));
990 }
991
992 #[test]
993 fn test_inflate() {
994 let b = Box2D::from_points(&[point2(-20.0, -20.0), point2(20.0, 20.0)]);
995 let b = b.inflate(10.0, 5.0);
996 assert_eq!(b.size().width, 60.0);
997 assert_eq!(b.size().height, 50.0);
998 assert_eq!(b.center(), Point2D::zero());
999 }
1000
1001 #[test]
1002 fn test_is_empty() {
1003 for i in 0..2 {
1004 let mut coords_neg = [-20.0, -20.0];
1005 let mut coords_pos = [20.0, 20.0];
1006 coords_neg[i] = 0.0;
1007 coords_pos[i] = 0.0;
1008 let b = Box2D::from_points(&[Point2D::from(coords_neg), Point2D::from(coords_pos)]);
1009 assert!(b.is_empty());
1010 }
1011 }
1012
1013 #[test]
1014 #[rustfmt::skip]
1015 fn test_nan_empty() {
1016 use std::f32::NAN;
1017 assert!(Box2D { min: point2(NAN, 2.0), max: point2(1.0, 3.0) }.is_empty());
1018 assert!(Box2D { min: point2(0.0, NAN), max: point2(1.0, 2.0) }.is_empty());
1019 assert!(Box2D { min: point2(1.0, -2.0), max: point2(NAN, 2.0) }.is_empty());
1020 assert!(Box2D { min: point2(1.0, -2.0), max: point2(0.0, NAN) }.is_empty());
1021 }
1022
1023 #[test]
1024 fn test_from_origin_and_size() {
1025 let b = Box2D::from_origin_and_size(point2(1.0, 2.0), size2(3.0, 4.0));
1026 assert_eq!(b.min, point2(1.0, 2.0));
1027 assert_eq!(b.size(), size2(3.0, 4.0));
1028 }
1029
1030 #[test]
1031 fn test_set_size() {
1032 let mut b = Box2D {
1033 min: point2(1.0, 2.0),
1034 max: point2(3.0, 4.0),
1035 };
1036 b.set_size(size2(5.0, 6.0));
1037
1038 assert_eq!(b.min, point2(1.0, 2.0));
1039 assert_eq!(b.size(), size2(5.0, 6.0));
1040 }
1041}