1use super::UnknownUnit;
11use crate::box2d::Box2D;
12use crate::num::*;
13use crate::point::Point2D;
14use crate::scale::Scale;
15use crate::side_offsets::SideOffsets2D;
16use crate::size::Size2D;
17use crate::vector::Vector2D;
18
19#[cfg(feature = "bytemuck")]
20use bytemuck::{Pod, Zeroable};
21use num_traits::{Float, NumCast};
22#[cfg(feature = "serde")]
23use serde::{Deserialize, Serialize};
24
25use core::borrow::Borrow;
26use core::cmp::PartialOrd;
27use core::fmt;
28use core::hash::{Hash, Hasher};
29use core::ops::{Add, Div, DivAssign, Mul, MulAssign, Range, Sub};
30
31#[repr(C)]
48#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
49#[cfg_attr(
50 feature = "serde",
51 serde(bound(serialize = "T: Serialize", deserialize = "T: Deserialize<'de>"))
52)]
53pub struct Rect<T, U> {
54 pub origin: Point2D<T, U>,
55 pub size: Size2D<T, U>,
56}
57
58#[cfg(feature = "arbitrary")]
59impl<'a, T, U> arbitrary::Arbitrary<'a> for Rect<T, U>
60where
61 T: arbitrary::Arbitrary<'a>,
62{
63 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
64 let (origin, size) = arbitrary::Arbitrary::arbitrary(u)?;
65 Ok(Rect { origin, size })
66 }
67}
68
69#[cfg(feature = "bytemuck")]
70unsafe impl<T: Zeroable, U> Zeroable for Rect<T, U> {}
71
72#[cfg(feature = "bytemuck")]
73unsafe impl<T: Pod, U: 'static> Pod for Rect<T, U> {}
74
75impl<T: Hash, U> Hash for Rect<T, U> {
76 fn hash<H: Hasher>(&self, h: &mut H) {
77 self.origin.hash(h);
78 self.size.hash(h);
79 }
80}
81
82impl<T: Copy, U> Copy for Rect<T, U> {}
83
84impl<T: Clone, U> Clone for Rect<T, U> {
85 fn clone(&self) -> Self {
86 Self::new(self.origin.clone(), self.size.clone())
87 }
88}
89
90impl<T: PartialEq, U> PartialEq for Rect<T, U> {
91 fn eq(&self, other: &Self) -> bool {
92 self.origin.eq(&other.origin) && self.size.eq(&other.size)
93 }
94}
95
96impl<T: Eq, U> Eq for Rect<T, U> {}
97
98impl<T: fmt::Debug, U> fmt::Debug for Rect<T, U> {
99 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
100 write!(f, "Rect(")?;
101 fmt::Debug::fmt(&self.size, f)?;
102 write!(f, " at ")?;
103 fmt::Debug::fmt(&self.origin, f)?;
104 write!(f, ")")
105 }
106}
107
108impl<T: Default, U> Default for Rect<T, U> {
109 fn default() -> Self {
110 Rect::new(Default::default(), Default::default())
111 }
112}
113
114impl<T, U> Rect<T, U> {
115 #[inline]
117 pub const fn new(origin: Point2D<T, U>, size: Size2D<T, U>) -> Self {
118 Rect { origin, size }
119 }
120}
121
122impl<T, U> Rect<T, U>
123where
124 T: Zero,
125{
126 #[inline]
128 pub fn zero() -> Self {
129 Rect::new(Point2D::origin(), Size2D::zero())
130 }
131
132 #[inline]
134 pub fn from_size(size: Size2D<T, U>) -> Self {
135 Rect {
136 origin: Point2D::zero(),
137 size,
138 }
139 }
140}
141
142impl<T, U> Rect<T, U>
143where
144 T: Copy + Add<T, Output = T>,
145{
146 #[inline]
147 pub fn min(&self) -> Point2D<T, U> {
148 self.origin
149 }
150
151 #[inline]
152 pub fn max(&self) -> Point2D<T, U> {
153 self.origin + self.size
154 }
155
156 #[inline]
157 pub fn max_x(&self) -> T {
158 self.origin.x + self.size.width
159 }
160
161 #[inline]
162 pub fn min_x(&self) -> T {
163 self.origin.x
164 }
165
166 #[inline]
167 pub fn max_y(&self) -> T {
168 self.origin.y + self.size.height
169 }
170
171 #[inline]
172 pub fn min_y(&self) -> T {
173 self.origin.y
174 }
175
176 #[inline]
177 pub fn width(&self) -> T {
178 self.size.width
179 }
180
181 #[inline]
182 pub fn height(&self) -> T {
183 self.size.height
184 }
185
186 #[inline]
187 pub fn x_range(&self) -> Range<T> {
188 self.min_x()..self.max_x()
189 }
190
191 #[inline]
192 pub fn y_range(&self) -> Range<T> {
193 self.min_y()..self.max_y()
194 }
195
196 #[inline]
198 #[must_use]
199 pub fn translate(&self, by: Vector2D<T, U>) -> Self {
200 Self::new(self.origin + by, self.size)
201 }
202
203 #[inline]
204 pub fn to_box2d(&self) -> Box2D<T, U> {
205 Box2D {
206 min: self.min(),
207 max: self.max(),
208 }
209 }
210}
211
212impl<T, U> Rect<T, U>
213where
214 T: Copy + PartialOrd + Add<T, Output = T>,
215{
216 #[inline]
220 pub fn contains(&self, p: Point2D<T, U>) -> bool {
221 self.to_box2d().contains(p)
222 }
223
224 #[inline]
225 pub fn intersects(&self, other: &Self) -> bool {
226 self.to_box2d().intersects(&other.to_box2d())
227 }
228}
229
230impl<T, U> Rect<T, U>
231where
232 T: Copy + PartialOrd + Add<T, Output = T> + Sub<T, Output = T>,
233{
234 #[inline]
235 pub fn intersection(&self, other: &Self) -> Option<Self> {
236 let box2d = self.to_box2d().intersection_unchecked(&other.to_box2d());
237
238 if box2d.is_empty() {
239 return None;
240 }
241
242 Some(box2d.to_rect())
243 }
244}
245
246impl<T, U> Rect<T, U>
247where
248 T: Copy + Add<T, Output = T> + Sub<T, Output = T>,
249{
250 #[inline]
251 #[must_use]
252 pub fn inflate(&self, width: T, height: T) -> Self {
253 Rect::new(
254 Point2D::new(self.origin.x - width, self.origin.y - height),
255 Size2D::new(
256 self.size.width + width + width,
257 self.size.height + height + height,
258 ),
259 )
260 }
261}
262
263impl<T, U> Rect<T, U>
264where
265 T: Copy + Zero + PartialOrd + Add<T, Output = T>,
266{
267 #[inline]
271 pub fn contains_rect(&self, rect: &Self) -> bool {
272 rect.is_empty()
273 || (self.min_x() <= rect.min_x()
274 && rect.max_x() <= self.max_x()
275 && self.min_y() <= rect.min_y()
276 && rect.max_y() <= self.max_y())
277 }
278}
279
280impl<T, U> Rect<T, U>
281where
282 T: Copy + Zero + PartialOrd + Add<T, Output = T> + Sub<T, Output = T>,
283{
284 pub fn inner_rect(&self, offsets: SideOffsets2D<T, U>) -> Self {
290 let rect = Rect::new(
291 Point2D::new(self.origin.x + offsets.left, self.origin.y + offsets.top),
292 Size2D::new(
293 self.size.width - offsets.horizontal(),
294 self.size.height - offsets.vertical(),
295 ),
296 );
297 debug_assert!(rect.size.width >= Zero::zero());
298 debug_assert!(rect.size.height >= Zero::zero());
299 rect
300 }
301}
302
303impl<T, U> Rect<T, U>
304where
305 T: Copy + Add<T, Output = T> + Sub<T, Output = T>,
306{
307 pub fn outer_rect(&self, offsets: SideOffsets2D<T, U>) -> Self {
312 Rect::new(
313 Point2D::new(self.origin.x - offsets.left, self.origin.y - offsets.top),
314 Size2D::new(
315 self.size.width + offsets.horizontal(),
316 self.size.height + offsets.vertical(),
317 ),
318 )
319 }
320}
321
322impl<T, U> Rect<T, U>
323where
324 T: Copy + Zero + PartialOrd + Sub<T, Output = T>,
325{
326 pub fn from_points<I>(points: I) -> Self
336 where
337 I: IntoIterator,
338 I::Item: Borrow<Point2D<T, U>>,
339 {
340 Box2D::from_points(points).to_rect()
341 }
342}
343
344impl<T, U> Rect<T, U>
345where
346 T: Copy + One + Add<Output = T> + Sub<Output = T> + Mul<Output = T>,
347{
348 #[inline]
350 pub fn lerp(&self, other: Self, t: T) -> Self {
351 Self::new(
352 self.origin.lerp(other.origin, t),
353 self.size.lerp(other.size, t),
354 )
355 }
356}
357
358impl<T, U> Rect<T, U>
359where
360 T: Copy + One + Add<Output = T> + Div<Output = T>,
361{
362 pub fn center(&self) -> Point2D<T, U> {
363 let two = T::one() + T::one();
364 self.origin + self.size.to_vector() / two
365 }
366}
367
368impl<T, U> Rect<T, U>
369where
370 T: Copy + PartialOrd + Add<T, Output = T> + Sub<T, Output = T> + Zero,
371{
372 #[inline]
373 pub fn union(&self, other: &Self) -> Self {
374 self.to_box2d().union(&other.to_box2d()).to_rect()
375 }
376}
377
378impl<T, U> Rect<T, U> {
379 #[inline]
380 pub fn scale<S: Copy>(&self, x: S, y: S) -> Self
381 where
382 T: Copy + Mul<S, Output = T>,
383 {
384 Rect::new(
385 Point2D::new(self.origin.x * x, self.origin.y * y),
386 Size2D::new(self.size.width * x, self.size.height * y),
387 )
388 }
389}
390
391impl<T: Copy + Mul<T, Output = T>, U> Rect<T, U> {
392 #[inline]
393 pub fn area(&self) -> T {
394 self.size.area()
395 }
396}
397
398impl<T: Copy + Zero + PartialOrd, U> Rect<T, U> {
399 #[inline]
400 pub fn is_empty(&self) -> bool {
401 self.size.is_empty()
402 }
403}
404
405impl<T: Copy + Zero + PartialOrd, U> Rect<T, U> {
406 #[inline]
407 pub fn to_non_empty(&self) -> Option<Self> {
408 if self.is_empty() {
409 return None;
410 }
411
412 Some(*self)
413 }
414}
415
416impl<T: Copy + Mul, U> Mul<T> for Rect<T, U> {
417 type Output = Rect<T::Output, U>;
418
419 #[inline]
420 fn mul(self, scale: T) -> Self::Output {
421 Rect::new(self.origin * scale, self.size * scale)
422 }
423}
424
425impl<T: Copy + MulAssign, U> MulAssign<T> for Rect<T, U> {
426 #[inline]
427 fn mul_assign(&mut self, scale: T) {
428 *self *= Scale::new(scale);
429 }
430}
431
432impl<T: Copy + Div, U> Div<T> for Rect<T, U> {
433 type Output = Rect<T::Output, U>;
434
435 #[inline]
436 fn div(self, scale: T) -> Self::Output {
437 Rect::new(self.origin / scale.clone(), self.size / scale)
438 }
439}
440
441impl<T: Copy + DivAssign, U> DivAssign<T> for Rect<T, U> {
442 #[inline]
443 fn div_assign(&mut self, scale: T) {
444 *self /= Scale::new(scale);
445 }
446}
447
448impl<T: Copy + Mul, U1, U2> Mul<Scale<T, U1, U2>> for Rect<T, U1> {
449 type Output = Rect<T::Output, U2>;
450
451 #[inline]
452 fn mul(self, scale: Scale<T, U1, U2>) -> Self::Output {
453 Rect::new(self.origin * scale.clone(), self.size * scale)
454 }
455}
456
457impl<T: Copy + MulAssign, U> MulAssign<Scale<T, U, U>> for Rect<T, U> {
458 #[inline]
459 fn mul_assign(&mut self, scale: Scale<T, U, U>) {
460 self.origin *= scale.clone();
461 self.size *= scale;
462 }
463}
464
465impl<T: Copy + Div, U1, U2> Div<Scale<T, U1, U2>> for Rect<T, U2> {
466 type Output = Rect<T::Output, U1>;
467
468 #[inline]
469 fn div(self, scale: Scale<T, U1, U2>) -> Self::Output {
470 Rect::new(self.origin / scale.clone(), self.size / scale)
471 }
472}
473
474impl<T: Copy + DivAssign, U> DivAssign<Scale<T, U, U>> for Rect<T, U> {
475 #[inline]
476 fn div_assign(&mut self, scale: Scale<T, U, U>) {
477 self.origin /= scale.clone();
478 self.size /= scale;
479 }
480}
481
482impl<T: Copy, U> Rect<T, U> {
483 #[inline]
485 pub fn to_untyped(&self) -> Rect<T, UnknownUnit> {
486 Rect::new(self.origin.to_untyped(), self.size.to_untyped())
487 }
488
489 #[inline]
491 pub fn from_untyped(r: &Rect<T, UnknownUnit>) -> Rect<T, U> {
492 Rect::new(
493 Point2D::from_untyped(r.origin),
494 Size2D::from_untyped(r.size),
495 )
496 }
497
498 #[inline]
500 pub fn cast_unit<V>(&self) -> Rect<T, V> {
501 Rect::new(self.origin.cast_unit(), self.size.cast_unit())
502 }
503}
504
505impl<T: NumCast + Copy, U> Rect<T, U> {
506 #[inline]
516 pub fn cast<NewT: NumCast>(&self) -> Rect<NewT, U> {
517 Rect::new(self.origin.cast(), self.size.cast())
518 }
519
520 pub fn try_cast<NewT: NumCast>(&self) -> Option<Rect<NewT, U>> {
530 match (self.origin.try_cast(), self.size.try_cast()) {
531 (Some(origin), Some(size)) => Some(Rect::new(origin, size)),
532 _ => None,
533 }
534 }
535
536 #[inline]
540 pub fn to_f32(&self) -> Rect<f32, U> {
541 self.cast()
542 }
543
544 #[inline]
546 pub fn to_f64(&self) -> Rect<f64, U> {
547 self.cast()
548 }
549
550 #[inline]
556 pub fn to_usize(&self) -> Rect<usize, U> {
557 self.cast()
558 }
559
560 #[inline]
566 pub fn to_u32(&self) -> Rect<u32, U> {
567 self.cast()
568 }
569
570 #[inline]
576 pub fn to_u64(&self) -> Rect<u64, U> {
577 self.cast()
578 }
579
580 #[inline]
586 pub fn to_i32(&self) -> Rect<i32, U> {
587 self.cast()
588 }
589
590 #[inline]
596 pub fn to_i64(&self) -> Rect<i64, U> {
597 self.cast()
598 }
599}
600
601impl<T: Float, U> Rect<T, U> {
602 #[inline]
604 pub fn is_finite(self) -> bool {
605 self.origin.is_finite() && self.size.is_finite()
606 }
607}
608
609impl<T: Floor + Ceil + Round + Add<T, Output = T> + Sub<T, Output = T>, U> Rect<T, U> {
610 #[must_use]
625 pub fn round(&self) -> Self {
626 self.to_box2d().round().to_rect()
627 }
628
629 #[must_use]
637 pub fn round_in(&self) -> Self {
638 self.to_box2d().round_in().to_rect()
639 }
640
641 #[must_use]
649 pub fn round_out(&self) -> Self {
650 self.to_box2d().round_out().to_rect()
651 }
652}
653
654impl<T, U> From<Size2D<T, U>> for Rect<T, U>
655where
656 T: Zero,
657{
658 fn from(size: Size2D<T, U>) -> Self {
659 Self::from_size(size)
660 }
661}
662
663pub const fn rect<T, U>(x: T, y: T, w: T, h: T) -> Rect<T, U> {
665 Rect::new(Point2D::new(x, y), Size2D::new(w, h))
666}
667
668#[cfg(test)]
669mod tests {
670 use crate::default::{Point2D, Rect, Size2D};
671 use crate::side_offsets::SideOffsets2D;
672 use crate::{point2, rect, size2, vec2};
673
674 #[test]
675 fn test_translate() {
676 let p = Rect::new(Point2D::new(0u32, 0u32), Size2D::new(50u32, 40u32));
677 let pp = p.translate(vec2(10, 15));
678
679 assert!(pp.size.width == 50);
680 assert!(pp.size.height == 40);
681 assert!(pp.origin.x == 10);
682 assert!(pp.origin.y == 15);
683
684 let r = Rect::new(Point2D::new(-10, -5), Size2D::new(50, 40));
685 let rr = r.translate(vec2(0, -10));
686
687 assert!(rr.size.width == 50);
688 assert!(rr.size.height == 40);
689 assert!(rr.origin.x == -10);
690 assert!(rr.origin.y == -15);
691 }
692
693 #[test]
694 fn test_union() {
695 let p = Rect::new(Point2D::new(0, 0), Size2D::new(50, 40));
696 let q = Rect::new(Point2D::new(20, 20), Size2D::new(5, 5));
697 let r = Rect::new(Point2D::new(-15, -30), Size2D::new(200, 15));
698 let s = Rect::new(Point2D::new(20, -15), Size2D::new(250, 200));
699
700 let pq = p.union(&q);
701 assert!(pq.origin == Point2D::new(0, 0));
702 assert!(pq.size == Size2D::new(50, 40));
703
704 let pr = p.union(&r);
705 assert!(pr.origin == Point2D::new(-15, -30));
706 assert!(pr.size == Size2D::new(200, 70));
707
708 let ps = p.union(&s);
709 assert!(ps.origin == Point2D::new(0, -15));
710 assert!(ps.size == Size2D::new(270, 200));
711 }
712
713 #[test]
714 fn test_intersection() {
715 let p = Rect::new(Point2D::new(0, 0), Size2D::new(10, 20));
716 let q = Rect::new(Point2D::new(5, 15), Size2D::new(10, 10));
717 let r = Rect::new(Point2D::new(-5, -5), Size2D::new(8, 8));
718
719 let pq = p.intersection(&q);
720 assert!(pq.is_some());
721 let pq = pq.unwrap();
722 assert!(pq.origin == Point2D::new(5, 15));
723 assert!(pq.size == Size2D::new(5, 5));
724
725 let pr = p.intersection(&r);
726 assert!(pr.is_some());
727 let pr = pr.unwrap();
728 assert!(pr.origin == Point2D::new(0, 0));
729 assert!(pr.size == Size2D::new(3, 3));
730
731 let qr = q.intersection(&r);
732 assert!(qr.is_none());
733 }
734
735 #[test]
736 fn test_intersection_overflow() {
737 let p = Rect::new(Point2D::new(-2147483648, -2147483648), Size2D::new(0, 0));
740 let q = Rect::new(
741 Point2D::new(2136893440, 2136893440),
742 Size2D::new(279552, 279552),
743 );
744 let r = Rect::new(Point2D::new(-2147483648, -2147483648), Size2D::new(1, 1));
745
746 assert!(p.is_empty());
747 let pq = p.intersection(&q);
748 assert!(pq.is_none());
749
750 let qr = q.intersection(&r);
751 assert!(qr.is_none());
752 }
753
754 #[test]
755 fn test_contains() {
756 let r = Rect::new(Point2D::new(-20, 15), Size2D::new(100, 200));
757
758 assert!(r.contains(Point2D::new(0, 50)));
759 assert!(r.contains(Point2D::new(-10, 200)));
760
761 assert!(r.contains(Point2D::new(-20, 15)));
764 assert!(!r.contains(Point2D::new(80, 15)));
765 assert!(!r.contains(Point2D::new(80, 215)));
766 assert!(!r.contains(Point2D::new(-20, 215)));
767
768 assert!(!r.contains(Point2D::new(-25, 15)));
770 assert!(!r.contains(Point2D::new(-15, 10)));
771
772 assert!(!r.contains(Point2D::new(85, 20)));
774 assert!(!r.contains(Point2D::new(75, 10)));
775
776 assert!(!r.contains(Point2D::new(85, 210)));
778 assert!(!r.contains(Point2D::new(75, 220)));
779
780 assert!(!r.contains(Point2D::new(-25, 210)));
782 assert!(!r.contains(Point2D::new(-15, 220)));
783
784 let r = Rect::new(Point2D::new(-20.0, 15.0), Size2D::new(100.0, 200.0));
785 assert!(r.contains_rect(&r));
786 assert!(!r.contains_rect(&r.translate(vec2(0.1, 0.0))));
787 assert!(!r.contains_rect(&r.translate(vec2(-0.1, 0.0))));
788 assert!(!r.contains_rect(&r.translate(vec2(0.0, 0.1))));
789 assert!(!r.contains_rect(&r.translate(vec2(0.0, -0.1))));
790 let p = Point2D::new(1.0, 1.0);
793 assert!(!r.contains(p));
794 assert!(r.contains_rect(&Rect::new(p, Size2D::zero())));
795 }
796
797 #[test]
798 fn test_scale() {
799 let p = Rect::new(Point2D::new(0u32, 0u32), Size2D::new(50u32, 40u32));
800 let pp = p.scale(10, 15);
801
802 assert!(pp.size.width == 500);
803 assert!(pp.size.height == 600);
804 assert!(pp.origin.x == 0);
805 assert!(pp.origin.y == 0);
806
807 let r = Rect::new(Point2D::new(-10, -5), Size2D::new(50, 40));
808 let rr = r.scale(1, 20);
809
810 assert!(rr.size.width == 50);
811 assert!(rr.size.height == 800);
812 assert!(rr.origin.x == -10);
813 assert!(rr.origin.y == -100);
814 }
815
816 #[test]
817 fn test_inflate() {
818 let p = Rect::new(Point2D::new(0, 0), Size2D::new(10, 10));
819 let pp = p.inflate(10, 20);
820
821 assert!(pp.size.width == 30);
822 assert!(pp.size.height == 50);
823 assert!(pp.origin.x == -10);
824 assert!(pp.origin.y == -20);
825
826 let r = Rect::new(Point2D::new(0, 0), Size2D::new(10, 20));
827 let rr = r.inflate(-2, -5);
828
829 assert!(rr.size.width == 6);
830 assert!(rr.size.height == 10);
831 assert!(rr.origin.x == 2);
832 assert!(rr.origin.y == 5);
833 }
834
835 #[test]
836 fn test_inner_outer_rect() {
837 let inner_rect = Rect::new(point2(20, 40), size2(80, 100));
838 let offsets = SideOffsets2D::new(20, 10, 10, 10);
839 let outer_rect = inner_rect.outer_rect(offsets);
840 assert_eq!(outer_rect.origin.x, 10);
841 assert_eq!(outer_rect.origin.y, 20);
842 assert_eq!(outer_rect.size.width, 100);
843 assert_eq!(outer_rect.size.height, 130);
844 assert_eq!(outer_rect.inner_rect(offsets), inner_rect);
845 }
846
847 #[test]
848 fn test_min_max_x_y() {
849 let p = Rect::new(Point2D::new(0u32, 0u32), Size2D::new(50u32, 40u32));
850 assert!(p.max_y() == 40);
851 assert!(p.min_y() == 0);
852 assert!(p.max_x() == 50);
853 assert!(p.min_x() == 0);
854
855 let r = Rect::new(Point2D::new(-10, -5), Size2D::new(50, 40));
856 assert!(r.max_y() == 35);
857 assert!(r.min_y() == -5);
858 assert!(r.max_x() == 40);
859 assert!(r.min_x() == -10);
860 }
861
862 #[test]
863 fn test_width_height() {
864 let r = Rect::new(Point2D::new(-10, -5), Size2D::new(50, 40));
865 assert!(r.width() == 50);
866 assert!(r.height() == 40);
867 }
868
869 #[test]
870 fn test_is_empty() {
871 assert!(Rect::new(Point2D::new(0u32, 0u32), Size2D::new(0u32, 0u32)).is_empty());
872 assert!(Rect::new(Point2D::new(0u32, 0u32), Size2D::new(10u32, 0u32)).is_empty());
873 assert!(Rect::new(Point2D::new(0u32, 0u32), Size2D::new(0u32, 10u32)).is_empty());
874 assert!(!Rect::new(Point2D::new(0u32, 0u32), Size2D::new(1u32, 1u32)).is_empty());
875 assert!(Rect::new(Point2D::new(10u32, 10u32), Size2D::new(0u32, 0u32)).is_empty());
876 assert!(Rect::new(Point2D::new(10u32, 10u32), Size2D::new(10u32, 0u32)).is_empty());
877 assert!(Rect::new(Point2D::new(10u32, 10u32), Size2D::new(0u32, 10u32)).is_empty());
878 assert!(!Rect::new(Point2D::new(10u32, 10u32), Size2D::new(1u32, 1u32)).is_empty());
879 }
880
881 #[test]
882 fn test_round() {
883 let mut x = -2.0;
884 let mut y = -2.0;
885 let mut w = -2.0;
886 let mut h = -2.0;
887 while x < 2.0 {
888 while y < 2.0 {
889 while w < 2.0 {
890 while h < 2.0 {
891 let rect = Rect::new(Point2D::new(x, y), Size2D::new(w, h));
892
893 assert!(rect.contains_rect(&rect.round_in()));
894 assert!(rect.round_in().inflate(1.0, 1.0).contains_rect(&rect));
895
896 assert!(rect.round_out().contains_rect(&rect));
897 assert!(rect.inflate(1.0, 1.0).contains_rect(&rect.round_out()));
898
899 assert!(rect.inflate(1.0, 1.0).contains_rect(&rect.round()));
900 assert!(rect.round().inflate(1.0, 1.0).contains_rect(&rect));
901
902 h += 0.1;
903 }
904 w += 0.1;
905 }
906 y += 0.1;
907 }
908 x += 0.1
909 }
910 }
911
912 #[test]
913 fn test_center() {
914 let r: Rect<i32> = rect(-2, 5, 4, 10);
915 assert_eq!(r.center(), point2(0, 10));
916
917 let r: Rect<f32> = rect(1.0, 2.0, 3.0, 4.0);
918 assert_eq!(r.center(), point2(2.5, 4.0));
919 }
920
921 #[test]
922 fn test_nan() {
923 let r1: Rect<f32> = rect(-2.0, 5.0, 4.0, std::f32::NAN);
924 let r2: Rect<f32> = rect(std::f32::NAN, -1.0, 3.0, 10.0);
925
926 assert_eq!(r1.intersection(&r2), None);
927 }
928}