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