1use super::UnknownUnit;
11use length::Length;
12use scale::TypedScale;
13use num::*;
14use box2d::TypedBox2D;
15use point::TypedPoint2D;
16use vector::TypedVector2D;
17use side_offsets::TypedSideOffsets2D;
18use size::TypedSize2D;
19use approxord::{min, max};
20
21use num_traits::NumCast;
22#[cfg(feature = "serde")]
23use serde::{Deserialize, Deserializer, Serialize, Serializer};
24
25use core::borrow::Borrow;
26use core::cmp::PartialOrd;
27use core::fmt;
28use core::hash::{Hash, Hasher};
29use core::ops::{Add, Div, Mul, Sub, Range};
30
31
32#[repr(C)]
34pub struct TypedRect<T, U = UnknownUnit> {
35 pub origin: TypedPoint2D<T, U>,
36 pub size: TypedSize2D<T, U>,
37}
38
39pub type Rect<T> = TypedRect<T, UnknownUnit>;
41
42#[cfg(feature = "serde")]
43impl<'de, T: Copy + Deserialize<'de>, U> Deserialize<'de> for TypedRect<T, U> {
44 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
45 where
46 D: Deserializer<'de>,
47 {
48 let (origin, size) = try!(Deserialize::deserialize(deserializer));
49 Ok(TypedRect::new(origin, size))
50 }
51}
52
53#[cfg(feature = "serde")]
54impl<T: Serialize, U> Serialize for TypedRect<T, U> {
55 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
56 where
57 S: Serializer,
58 {
59 (&self.origin, &self.size).serialize(serializer)
60 }
61}
62
63impl<T: Hash, U> Hash for TypedRect<T, U> {
64 fn hash<H: Hasher>(&self, h: &mut H) {
65 self.origin.hash(h);
66 self.size.hash(h);
67 }
68}
69
70impl<T: Copy, U> Copy for TypedRect<T, U> {}
71
72impl<T: Copy, U> Clone for TypedRect<T, U> {
73 fn clone(&self) -> Self {
74 *self
75 }
76}
77
78impl<T: PartialEq, U> PartialEq<TypedRect<T, U>> for TypedRect<T, U> {
79 fn eq(&self, other: &Self) -> bool {
80 self.origin.eq(&other.origin) && self.size.eq(&other.size)
81 }
82}
83
84impl<T: Eq, U> Eq for TypedRect<T, U> {}
85
86impl<T: fmt::Debug, U> fmt::Debug for TypedRect<T, U> {
87 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
88 write!(f, "TypedRect({:?} at {:?})", self.size, self.origin)
89 }
90}
91
92impl<T: fmt::Display, U> fmt::Display for TypedRect<T, U> {
93 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
94 write!(formatter, "Rect({} at {})", self.size, self.origin)
95 }
96}
97
98impl<T: Default, U> Default for TypedRect<T, U> {
99 fn default() -> Self {
100 TypedRect::new(Default::default(), Default::default())
101 }
102}
103
104impl<T, U> TypedRect<T, U> {
105 pub fn new(origin: TypedPoint2D<T, U>, size: TypedSize2D<T, U>) -> Self {
107 TypedRect {
108 origin,
109 size,
110 }
111 }
112}
113
114impl<T, U> TypedRect<T, U>
115where
116 T: Copy + Zero
117{
118 pub fn from_size(size: TypedSize2D<T, U>) -> Self {
120 TypedRect {
121 origin: TypedPoint2D::zero(),
122 size,
123 }
124 }
125}
126
127impl<T, U> TypedRect<T, U>
128where
129 T: Copy + Clone + Zero + PartialOrd + PartialEq + Add<T, Output = T> + Sub<T, Output = T>,
130{
131 #[inline]
132 pub fn intersects(&self, other: &Self) -> bool {
133 self.origin.x < other.origin.x + other.size.width
134 && other.origin.x < self.origin.x + self.size.width
135 && self.origin.y < other.origin.y + other.size.height
136 && other.origin.y < self.origin.y + self.size.height
137 }
138
139 #[inline]
140 pub fn max_x(&self) -> T {
141 self.origin.x + self.size.width
142 }
143
144 #[inline]
145 pub fn min_x(&self) -> T {
146 self.origin.x
147 }
148
149 #[inline]
150 pub fn max_y(&self) -> T {
151 self.origin.y + self.size.height
152 }
153
154 #[inline]
155 pub fn min_y(&self) -> T {
156 self.origin.y
157 }
158
159 #[inline]
160 pub fn max_x_typed(&self) -> Length<T, U> {
161 Length::new(self.max_x())
162 }
163
164 #[inline]
165 pub fn min_x_typed(&self) -> Length<T, U> {
166 Length::new(self.min_x())
167 }
168
169 #[inline]
170 pub fn max_y_typed(&self) -> Length<T, U> {
171 Length::new(self.max_y())
172 }
173
174 #[inline]
175 pub fn min_y_typed(&self) -> Length<T, U> {
176 Length::new(self.min_y())
177 }
178
179 #[inline]
180 pub fn x_range(&self) -> Range<T> {
181 self.min_x()..self.max_x()
182 }
183
184 #[inline]
185 pub fn y_range(&self) -> Range<T> {
186 self.min_y()..self.max_y()
187 }
188
189 #[inline]
190 pub fn intersection(&self, other: &Self) -> Option<Self> {
191 if !self.intersects(other) {
192 return None;
193 }
194
195 let upper_left = TypedPoint2D::new(
196 max(self.min_x(), other.min_x()),
197 max(self.min_y(), other.min_y()),
198 );
199 let lower_right_x = min(self.max_x(), other.max_x());
200 let lower_right_y = min(self.max_y(), other.max_y());
201
202 Some(TypedRect::new(
203 upper_left,
204 TypedSize2D::new(lower_right_x - upper_left.x, lower_right_y - upper_left.y),
205 ))
206 }
207
208 #[inline]
210 #[cfg_attr(feature = "unstable", must_use)]
211 pub fn translate(&self, by: &TypedVector2D<T, U>) -> Self {
212 Self::new(self.origin + *by, self.size)
213 }
214
215 #[inline]
219 pub fn contains(&self, other: &TypedPoint2D<T, U>) -> bool {
220 self.origin.x <= other.x && other.x < self.origin.x + self.size.width
221 && self.origin.y <= other.y && other.y < self.origin.y + self.size.height
222 }
223
224 #[inline]
228 pub fn contains_rect(&self, rect: &Self) -> bool {
229 rect.is_empty()
230 || (self.min_x() <= rect.min_x() && rect.max_x() <= self.max_x()
231 && self.min_y() <= rect.min_y() && rect.max_y() <= self.max_y())
232 }
233
234 #[inline]
235 #[cfg_attr(feature = "unstable", must_use)]
236 pub fn inflate(&self, width: T, height: T) -> Self {
237 TypedRect::new(
238 TypedPoint2D::new(self.origin.x - width, self.origin.y - height),
239 TypedSize2D::new(
240 self.size.width + width + width,
241 self.size.height + height + height,
242 ),
243 )
244 }
245
246 #[inline]
247 #[cfg_attr(feature = "unstable", must_use)]
248 pub fn inflate_typed(&self, width: Length<T, U>, height: Length<T, U>) -> Self {
249 self.inflate(width.get(), height.get())
250 }
251
252 #[inline]
253 pub fn top_right(&self) -> TypedPoint2D<T, U> {
254 TypedPoint2D::new(self.max_x(), self.origin.y)
255 }
256
257 #[inline]
258 pub fn bottom_left(&self) -> TypedPoint2D<T, U> {
259 TypedPoint2D::new(self.origin.x, self.max_y())
260 }
261
262 #[inline]
263 pub fn bottom_right(&self) -> TypedPoint2D<T, U> {
264 TypedPoint2D::new(self.max_x(), self.max_y())
265 }
266
267 #[inline]
268 pub fn to_box2d(&self) -> TypedBox2D<T, U> {
269 TypedBox2D {
270 min: self.origin,
271 max: self.bottom_right(),
272 }
273 }
274
275 #[inline]
276 #[cfg_attr(feature = "unstable", must_use)]
277 pub fn translate_by_size(&self, size: &TypedSize2D<T, U>) -> Self {
278 self.translate(&size.to_vector())
279 }
280
281 pub fn inner_rect(&self, offsets: TypedSideOffsets2D<T, U>) -> Self {
286 let rect = TypedRect::new(
287 TypedPoint2D::new(
288 self.origin.x + offsets.left,
289 self.origin.y + offsets.top
290 ),
291 TypedSize2D::new(
292 self.size.width - offsets.horizontal(),
293 self.size.height - offsets.vertical()
294 )
295 );
296 debug_assert!(rect.size.width >= Zero::zero());
297 debug_assert!(rect.size.height >= Zero::zero());
298 rect
299 }
300
301 pub fn outer_rect(&self, offsets: TypedSideOffsets2D<T, U>) -> Self {
305 TypedRect::new(
306 TypedPoint2D::new(
307 self.origin.x - offsets.left,
308 self.origin.y - offsets.top
309 ),
310 TypedSize2D::new(
311 self.size.width + offsets.horizontal(),
312 self.size.height + offsets.vertical()
313 )
314 )
315 }
316
317 pub fn from_points<I>(points: I) -> Self
327 where
328 I: IntoIterator,
329 I::Item: Borrow<TypedPoint2D<T, U>>,
330 {
331 let mut points = points.into_iter();
332
333 let (mut min_x, mut min_y) = match points.next() {
334 Some(first) => (first.borrow().x, first.borrow().y),
335 None => return TypedRect::zero(),
336 };
337
338 let (mut max_x, mut max_y) = (min_x, min_y);
339 for point in points {
340 let p = point.borrow();
341 if p.x < min_x {
342 min_x = p.x
343 }
344 if p.x > max_x {
345 max_x = p.x
346 }
347 if p.y < min_y {
348 min_y = p.y
349 }
350 if p.y > max_y {
351 max_y = p.y
352 }
353 }
354 TypedRect::new(
355 TypedPoint2D::new(min_x, min_y),
356 TypedSize2D::new(max_x - min_x, max_y - min_y),
357 )
358 }
359}
360
361impl<T, U> TypedRect<T, U>
362where
363 T: Copy + One + Add<Output = T> + Sub<Output = T> + Mul<Output = T>,
364{
365 #[inline]
369 pub fn lerp(&self, other: Self, t: T) -> Self {
370 Self::new(
371 self.origin.lerp(other.origin, t),
372 self.size.lerp(other.size, t),
373 )
374 }
375}
376
377impl<T, U> TypedRect<T, U>
378where
379 T: Copy + One + Add<Output = T> + Div<Output = T>,
380{
381 pub fn center(&self) -> TypedPoint2D<T, U> {
382 let two = T::one() + T::one();
383 self.origin + self.size.to_vector() / two
384 }
385}
386
387impl<T, U> TypedRect<T, U>
388where
389 T: Copy + Clone + PartialOrd + Add<T, Output = T> + Sub<T, Output = T> + Zero,
390{
391 #[inline]
392 pub fn union(&self, other: &Self) -> Self {
393 if self.size == Zero::zero() {
394 return *other;
395 }
396 if other.size == Zero::zero() {
397 return *self;
398 }
399
400 let upper_left = TypedPoint2D::new(
401 min(self.min_x(), other.min_x()),
402 min(self.min_y(), other.min_y()),
403 );
404
405 let lower_right_x = max(self.max_x(), other.max_x());
406 let lower_right_y = max(self.max_y(), other.max_y());
407
408 TypedRect::new(
409 upper_left,
410 TypedSize2D::new(lower_right_x - upper_left.x, lower_right_y - upper_left.y),
411 )
412 }
413}
414
415impl<T, U> TypedRect<T, U> {
416 #[inline]
417 pub fn scale<S: Copy>(&self, x: S, y: S) -> Self
418 where
419 T: Copy + Clone + Mul<S, Output = T>,
420 {
421 TypedRect::new(
422 TypedPoint2D::new(self.origin.x * x, self.origin.y * y),
423 TypedSize2D::new(self.size.width * x, self.size.height * y),
424 )
425 }
426}
427
428impl<T: Copy + Clone + Mul<T, Output = T>, U> TypedRect<T, U> {
429 #[inline]
430 pub fn area(&self) -> T {
431 self.size.area()
432 }
433}
434
435impl<T: Copy + PartialEq + Zero, U> TypedRect<T, U> {
436 pub fn zero() -> Self {
438 TypedRect::new(TypedPoint2D::origin(), TypedSize2D::zero())
439 }
440
441 pub fn is_empty(&self) -> bool {
443 self.size.width == Zero::zero() || self.size.height == Zero::zero()
444 }
445}
446
447impl<T: Copy + Mul<T, Output = T>, U> Mul<T> for TypedRect<T, U> {
448 type Output = Self;
449 #[inline]
450 fn mul(self, scale: T) -> Self {
451 TypedRect::new(self.origin * scale, self.size * scale)
452 }
453}
454
455impl<T: Copy + Div<T, Output = T>, U> Div<T> for TypedRect<T, U> {
456 type Output = Self;
457 #[inline]
458 fn div(self, scale: T) -> Self {
459 TypedRect::new(self.origin / scale, self.size / scale)
460 }
461}
462
463impl<T: Copy + Mul<T, Output = T>, U1, U2> Mul<TypedScale<T, U1, U2>> for TypedRect<T, U1> {
464 type Output = TypedRect<T, U2>;
465 #[inline]
466 fn mul(self, scale: TypedScale<T, U1, U2>) -> TypedRect<T, U2> {
467 TypedRect::new(self.origin * scale, self.size * scale)
468 }
469}
470
471impl<T: Copy + Div<T, Output = T>, U1, U2> Div<TypedScale<T, U1, U2>> for TypedRect<T, U2> {
472 type Output = TypedRect<T, U1>;
473 #[inline]
474 fn div(self, scale: TypedScale<T, U1, U2>) -> TypedRect<T, U1> {
475 TypedRect::new(self.origin / scale, self.size / scale)
476 }
477}
478
479impl<T: Copy, Unit> TypedRect<T, Unit> {
480 pub fn to_untyped(&self) -> Rect<T> {
482 TypedRect::new(self.origin.to_untyped(), self.size.to_untyped())
483 }
484
485 pub fn from_untyped(r: &Rect<T>) -> TypedRect<T, Unit> {
487 TypedRect::new(
488 TypedPoint2D::from_untyped(&r.origin),
489 TypedSize2D::from_untyped(&r.size),
490 )
491 }
492}
493
494impl<T0: NumCast + Copy, Unit> TypedRect<T0, Unit> {
495 pub fn cast<T1: NumCast + Copy>(&self) -> TypedRect<T1, Unit> {
501 TypedRect::new(
502 self.origin.cast(),
503 self.size.cast(),
504 )
505 }
506
507 pub fn try_cast<T1: NumCast + Copy>(&self) -> Option<TypedRect<T1, Unit>> {
513 match (self.origin.try_cast(), self.size.try_cast()) {
514 (Some(origin), Some(size)) => Some(TypedRect::new(origin, size)),
515 _ => None,
516 }
517 }
518}
519
520impl<T: Floor + Ceil + Round + Add<T, Output = T> + Sub<T, Output = T>, U> TypedRect<T, U> {
521 #[cfg_attr(feature = "unstable", must_use)]
531 pub fn round(&self) -> Self {
532 let origin = self.origin.round();
533 let size = self.origin.add_size(&self.size).round() - origin;
534 TypedRect::new(origin, TypedSize2D::new(size.x, size.y))
535 }
536
537 #[cfg_attr(feature = "unstable", must_use)]
540 pub fn round_in(&self) -> Self {
541 let origin = self.origin.ceil();
542 let size = self.origin.add_size(&self.size).floor() - origin;
543 TypedRect::new(origin, TypedSize2D::new(size.x, size.y))
544 }
545
546 #[cfg_attr(feature = "unstable", must_use)]
549 pub fn round_out(&self) -> Self {
550 let origin = self.origin.floor();
551 let size = self.origin.add_size(&self.size).ceil() - origin;
552 TypedRect::new(origin, TypedSize2D::new(size.x, size.y))
553 }
554}
555
556impl<T: NumCast + Copy, Unit> TypedRect<T, Unit> {
558 pub fn to_f32(&self) -> TypedRect<f32, Unit> {
560 self.cast()
561 }
562
563 pub fn to_f64(&self) -> TypedRect<f64, Unit> {
565 self.cast()
566 }
567
568 pub fn to_usize(&self) -> TypedRect<usize, Unit> {
574 self.cast()
575 }
576
577 pub fn to_u32(&self) -> TypedRect<u32, Unit> {
583 self.cast()
584 }
585
586 pub fn to_i32(&self) -> TypedRect<i32, Unit> {
592 self.cast()
593 }
594
595 pub fn to_i64(&self) -> TypedRect<i64, Unit> {
601 self.cast()
602 }
603}
604
605impl<T, U> From<TypedSize2D<T, U>> for TypedRect<T, U>
606where T: Copy + Zero
607{
608 fn from(size: TypedSize2D<T, U>) -> Self {
609 Self::from_size(size)
610 }
611}
612
613pub fn rect<T: Copy, U>(x: T, y: T, w: T, h: T) -> TypedRect<T, U> {
615 TypedRect::new(TypedPoint2D::new(x, y), TypedSize2D::new(w, h))
616}
617
618#[cfg(test)]
619mod tests {
620 use point::{Point2D, point2};
621 use vector::vec2;
622 use side_offsets::SideOffsets2D;
623 use size::Size2D;
624 use super::*;
625
626 #[test]
627 fn test_translate() {
628 let p = Rect::new(Point2D::new(0u32, 0u32), Size2D::new(50u32, 40u32));
629 let pp = p.translate(&vec2(10, 15));
630
631 assert!(pp.size.width == 50);
632 assert!(pp.size.height == 40);
633 assert!(pp.origin.x == 10);
634 assert!(pp.origin.y == 15);
635
636 let r = Rect::new(Point2D::new(-10, -5), Size2D::new(50, 40));
637 let rr = r.translate(&vec2(0, -10));
638
639 assert!(rr.size.width == 50);
640 assert!(rr.size.height == 40);
641 assert!(rr.origin.x == -10);
642 assert!(rr.origin.y == -15);
643 }
644
645 #[test]
646 fn test_translate_by_size() {
647 let p = Rect::new(Point2D::new(0u32, 0u32), Size2D::new(50u32, 40u32));
648 let pp = p.translate_by_size(&Size2D::new(10, 15));
649
650 assert!(pp.size.width == 50);
651 assert!(pp.size.height == 40);
652 assert!(pp.origin.x == 10);
653 assert!(pp.origin.y == 15);
654
655 let r = Rect::new(Point2D::new(-10, -5), Size2D::new(50, 40));
656 let rr = r.translate_by_size(&Size2D::new(0, -10));
657
658 assert!(rr.size.width == 50);
659 assert!(rr.size.height == 40);
660 assert!(rr.origin.x == -10);
661 assert!(rr.origin.y == -15);
662 }
663
664 #[test]
665 fn test_union() {
666 let p = Rect::new(Point2D::new(0, 0), Size2D::new(50, 40));
667 let q = Rect::new(Point2D::new(20, 20), Size2D::new(5, 5));
668 let r = Rect::new(Point2D::new(-15, -30), Size2D::new(200, 15));
669 let s = Rect::new(Point2D::new(20, -15), Size2D::new(250, 200));
670
671 let pq = p.union(&q);
672 assert!(pq.origin == Point2D::new(0, 0));
673 assert!(pq.size == Size2D::new(50, 40));
674
675 let pr = p.union(&r);
676 assert!(pr.origin == Point2D::new(-15, -30));
677 assert!(pr.size == Size2D::new(200, 70));
678
679 let ps = p.union(&s);
680 assert!(ps.origin == Point2D::new(0, -15));
681 assert!(ps.size == Size2D::new(270, 200));
682 }
683
684 #[test]
685 fn test_intersection() {
686 let p = Rect::new(Point2D::new(0, 0), Size2D::new(10, 20));
687 let q = Rect::new(Point2D::new(5, 15), Size2D::new(10, 10));
688 let r = Rect::new(Point2D::new(-5, -5), Size2D::new(8, 8));
689
690 let pq = p.intersection(&q);
691 assert!(pq.is_some());
692 let pq = pq.unwrap();
693 assert!(pq.origin == Point2D::new(5, 15));
694 assert!(pq.size == Size2D::new(5, 5));
695
696 let pr = p.intersection(&r);
697 assert!(pr.is_some());
698 let pr = pr.unwrap();
699 assert!(pr.origin == Point2D::new(0, 0));
700 assert!(pr.size == Size2D::new(3, 3));
701
702 let qr = q.intersection(&r);
703 assert!(qr.is_none());
704 }
705
706 #[test]
707 fn test_contains() {
708 let r = Rect::new(Point2D::new(-20, 15), Size2D::new(100, 200));
709
710 assert!(r.contains(&Point2D::new(0, 50)));
711 assert!(r.contains(&Point2D::new(-10, 200)));
712
713 assert!(r.contains(&Point2D::new(-20, 15)));
716 assert!(!r.contains(&Point2D::new(80, 15)));
717 assert!(!r.contains(&Point2D::new(80, 215)));
718 assert!(!r.contains(&Point2D::new(-20, 215)));
719
720 assert!(!r.contains(&Point2D::new(-25, 15)));
722 assert!(!r.contains(&Point2D::new(-15, 10)));
723
724 assert!(!r.contains(&Point2D::new(85, 20)));
726 assert!(!r.contains(&Point2D::new(75, 10)));
727
728 assert!(!r.contains(&Point2D::new(85, 210)));
730 assert!(!r.contains(&Point2D::new(75, 220)));
731
732 assert!(!r.contains(&Point2D::new(-25, 210)));
734 assert!(!r.contains(&Point2D::new(-15, 220)));
735
736 let r = Rect::new(Point2D::new(-20.0, 15.0), Size2D::new(100.0, 200.0));
737 assert!(r.contains_rect(&r));
738 assert!(!r.contains_rect(&r.translate(&vec2(0.1, 0.0))));
739 assert!(!r.contains_rect(&r.translate(&vec2(-0.1, 0.0))));
740 assert!(!r.contains_rect(&r.translate(&vec2(0.0, 0.1))));
741 assert!(!r.contains_rect(&r.translate(&vec2(0.0, -0.1))));
742 let p = Point2D::new(1.0, 1.0);
745 assert!(!r.contains(&p));
746 assert!(r.contains_rect(&Rect::new(p, Size2D::zero())));
747 }
748
749 #[test]
750 fn test_scale() {
751 let p = Rect::new(Point2D::new(0u32, 0u32), Size2D::new(50u32, 40u32));
752 let pp = p.scale(10, 15);
753
754 assert!(pp.size.width == 500);
755 assert!(pp.size.height == 600);
756 assert!(pp.origin.x == 0);
757 assert!(pp.origin.y == 0);
758
759 let r = Rect::new(Point2D::new(-10, -5), Size2D::new(50, 40));
760 let rr = r.scale(1, 20);
761
762 assert!(rr.size.width == 50);
763 assert!(rr.size.height == 800);
764 assert!(rr.origin.x == -10);
765 assert!(rr.origin.y == -100);
766 }
767
768 #[test]
769 fn test_inflate() {
770 let p = Rect::new(Point2D::new(0, 0), Size2D::new(10, 10));
771 let pp = p.inflate(10, 20);
772
773 assert!(pp.size.width == 30);
774 assert!(pp.size.height == 50);
775 assert!(pp.origin.x == -10);
776 assert!(pp.origin.y == -20);
777
778 let r = Rect::new(Point2D::new(0, 0), Size2D::new(10, 20));
779 let rr = r.inflate(-2, -5);
780
781 assert!(rr.size.width == 6);
782 assert!(rr.size.height == 10);
783 assert!(rr.origin.x == 2);
784 assert!(rr.origin.y == 5);
785 }
786
787 #[test]
788 fn test_inner_outer_rect() {
789 let inner_rect: Rect<i32> = Rect::new(Point2D::new(20, 40), Size2D::new(80, 100));
790 let offsets = SideOffsets2D::new(20, 10, 10, 10);
791 let outer_rect = inner_rect.outer_rect(offsets);
792 assert_eq!(outer_rect.origin.x, 10);
793 assert_eq!(outer_rect.origin.y, 20);
794 assert_eq!(outer_rect.size.width, 100);
795 assert_eq!(outer_rect.size.height, 130);
796 assert_eq!(outer_rect.inner_rect(offsets), inner_rect);
797 }
798
799 #[test]
800 fn test_min_max_x_y() {
801 let p = Rect::new(Point2D::new(0u32, 0u32), Size2D::new(50u32, 40u32));
802 assert!(p.max_y() == 40);
803 assert!(p.min_y() == 0);
804 assert!(p.max_x() == 50);
805 assert!(p.min_x() == 0);
806
807 let r = Rect::new(Point2D::new(-10, -5), Size2D::new(50, 40));
808 assert!(r.max_y() == 35);
809 assert!(r.min_y() == -5);
810 assert!(r.max_x() == 40);
811 assert!(r.min_x() == -10);
812 }
813
814 #[test]
815 fn test_is_empty() {
816 assert!(Rect::new(Point2D::new(0u32, 0u32), Size2D::new(0u32, 0u32)).is_empty());
817 assert!(Rect::new(Point2D::new(0u32, 0u32), Size2D::new(10u32, 0u32)).is_empty());
818 assert!(Rect::new(Point2D::new(0u32, 0u32), Size2D::new(0u32, 10u32)).is_empty());
819 assert!(!Rect::new(Point2D::new(0u32, 0u32), Size2D::new(1u32, 1u32)).is_empty());
820 assert!(Rect::new(Point2D::new(10u32, 10u32), Size2D::new(0u32, 0u32)).is_empty());
821 assert!(Rect::new(Point2D::new(10u32, 10u32), Size2D::new(10u32, 0u32)).is_empty());
822 assert!(Rect::new(Point2D::new(10u32, 10u32), Size2D::new(0u32, 10u32)).is_empty());
823 assert!(!Rect::new(Point2D::new(10u32, 10u32), Size2D::new(1u32, 1u32)).is_empty());
824 }
825
826 #[test]
827 fn test_round() {
828 let mut x = -2.0;
829 let mut y = -2.0;
830 let mut w = -2.0;
831 let mut h = -2.0;
832 while x < 2.0 {
833 while y < 2.0 {
834 while w < 2.0 {
835 while h < 2.0 {
836 let rect = Rect::new(Point2D::new(x, y), Size2D::new(w, h));
837
838 assert!(rect.contains_rect(&rect.round_in()));
839 assert!(rect.round_in().inflate(1.0, 1.0).contains_rect(&rect));
840
841 assert!(rect.round_out().contains_rect(&rect));
842 assert!(rect.inflate(1.0, 1.0).contains_rect(&rect.round_out()));
843
844 assert!(rect.inflate(1.0, 1.0).contains_rect(&rect.round()));
845 assert!(rect.round().inflate(1.0, 1.0).contains_rect(&rect));
846
847 h += 0.1;
848 }
849 w += 0.1;
850 }
851 y += 0.1;
852 }
853 x += 0.1
854 }
855 }
856
857 #[test]
858 fn test_center() {
859 let r: Rect<i32> = rect(-2, 5, 4, 10);
860 assert_eq!(r.center(), point2(0, 10));
861
862 let r: Rect<f32> = rect(1.0, 2.0, 3.0, 4.0);
863 assert_eq!(r.center(), point2(2.5, 4.0));
864 }
865}