primitives/foundation/
rect.rs

1#![allow(unused_imports)]
2use std::{
3    borrow::Borrow,
4    cmp::PartialOrd,
5    fmt,
6    hash::{Hash, Hasher},
7    ops::{Add, Div, DivAssign, Mul, MulAssign, Range, Sub},
8};
9
10use crate::prelude::{One, Zero};
11
12use super::{Box2D, Point, Size};
13
14/// A 2d Rectangle optionally tagged with a unit.
15///
16/// # Representation
17///
18/// `Rect` is represented by an origin point and a size.
19///
20/// See [`Box2D`] for a rectangle represented by two endpoints.
21///
22/// # Empty rectangle
23///
24/// A rectangle is considered empty (see [`is_empty`]) if any of the following is true:
25/// - it's area is empty,
26/// - it's area is negative (`size.x < 0` or `size.y < 0`),
27/// - it contains NaNs.
28///
29/// [`is_empty`]: #method.is_empty
30/// [`Box2D`]: struct.Box2D.html
31#[repr(C)]
32#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
33#[cfg_attr(
34    feature = "serde",
35    serde(bound(serialize = "T: Serialize", deserialize = "T: Deserialize<'de>"))
36)]
37pub struct Rect<T> {
38    /// Origin of rectangle
39    pub origin: Point<T>,
40    /// Size of rectangle
41    pub size: Size<T>,
42}
43
44impl<T: Hash> Hash for Rect<T> {
45    fn hash<H: Hasher>(&self, h: &mut H) {
46        self.origin.hash(h);
47        self.size.hash(h);
48    }
49}
50
51impl<T: Copy> Copy for Rect<T> {}
52
53impl<T: Clone> Clone for Rect<T> {
54    fn clone(&self) -> Self {
55        Self::new(self.origin.clone(), self.size.clone())
56    }
57}
58
59impl<T: PartialEq> PartialEq for Rect<T> {
60    fn eq(&self, other: &Self) -> bool {
61        self.origin.eq(&other.origin) && self.size.eq(&other.size)
62    }
63}
64
65impl<T: Eq> Eq for Rect<T> {}
66
67impl<T: fmt::Debug> fmt::Debug for Rect<T> {
68    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
69        write!(f, "Rect(")?;
70        fmt::Debug::fmt(&self.size, f)?;
71        write!(f, " at ")?;
72        fmt::Debug::fmt(&self.origin, f)?;
73        write!(f, ")")
74    }
75}
76
77impl<T: Default> Default for Rect<T> {
78    fn default() -> Self {
79        Rect::new(Default::default(), Default::default())
80    }
81}
82
83impl<T> Rect<T> {
84    /// Constructor.
85    #[inline]
86    pub const fn new(origin: Point<T>, size: Size<T>) -> Self {
87        Rect { origin, size }
88    }
89}
90
91// impl<T> Rect<T>
92// where
93//     T: Zero,
94// {
95//     /// Constructor, setting all sides to zero.
96//     #[inline]
97//     pub fn zero() -> Self {
98//         Rect::new(Point::origin(), Size::zero())
99//     }
100
101//     /// Creates a rect of the given size, at offset zero.
102//     #[inline]
103//     pub fn from_size(size: Size<T>) -> Self {
104//         Rect {
105//             origin: Point::zero(),
106//             size,
107//         }
108//     }
109// }
110
111impl<T> Rect<T>
112where
113    T: Copy + Add<T, Output = T>,
114{
115    /// Retrieve origin of rectangle
116    #[inline]
117    pub fn min(&self) -> Point<T> {
118        self.origin
119    }
120
121    // #[inline]
122    // pub fn max(&self) -> Point<T> {
123    //     self.origin + self.size
124    // }
125
126    /// Retrieve maximum x of rectangle
127    #[inline]
128    pub fn max_x(&self) -> T {
129        self.origin.x + self.size.width
130    }
131
132    /// Retrieve minimum x of rectangle
133    #[inline]
134    pub fn min_x(&self) -> T {
135        self.origin.x
136    }
137
138    /// Retrieve maximum y of rectangle
139    #[inline]
140    pub fn max_y(&self) -> T {
141        self.origin.y + self.size.height
142    }
143
144    /// Retrieve minimum y of rectangle
145    #[inline]
146    pub fn min_y(&self) -> T {
147        self.origin.y
148    }
149
150    /// Retrieve rectangle width
151    #[inline]
152    pub fn width(&self) -> T {
153        self.size.width
154    }
155
156    /// Retrieve rectangle height
157    #[inline]
158    pub fn height(&self) -> T {
159        self.size.height
160    }
161
162    /// Retrieve x range of rectangle
163    #[inline]
164    pub fn x_range(&self) -> Range<T> {
165        self.min_x()..self.max_x()
166    }
167
168    /// Retrieve y range of rectangle
169    #[inline]
170    pub fn y_range(&self) -> Range<T> {
171        self.min_y()..self.max_y()
172    }
173
174    // /// Returns the same rectangle, translated by a vector.
175    // #[inline]
176    // #[must_use]
177    // pub fn translate(&self, by: Vector<T>) -> Self {
178    //     Self::new(self.origin + by, self.size)
179    // }
180
181    // #[inline]
182    // pub fn to_box2d(&self) -> Box2D<T> {
183    //     Box2D {
184    //         min: self.min(),
185    //         max: self.max(),
186    //     }
187    // }
188}
189
190// impl<T> Rect<T>
191// where
192//     T: Copy + PartialOrd + Add<T, Output = T>,
193// {
194//     /// Returns true if this rectangle contains the point. Points are considered
195//     /// in the rectangle if they are on the left or top edge, but outside if they
196//     /// are on the right or bottom edge.
197//     #[inline]
198//     pub fn contains(&self, p: Point<T>) -> bool {
199//         self.to_box2d().contains(p)
200//     }
201
202//     #[inline]
203//     pub fn intersects(&self, other: &Self) -> bool {
204//         self.to_box2d().intersects(&other.to_box2d())
205//     }
206// }
207
208// impl<T> Rect<T>
209// where
210//     T: Copy + PartialOrd + Add<T, Output = T> + Sub<T, Output = T>,
211// {
212//     #[inline]
213//     pub fn intersection(&self, other: &Self) -> Option<Self> {
214//         let box2d = self.to_box2d().intersection_unchecked(&other.to_box2d());
215
216//         if box2d.is_empty() {
217//             return None;
218//         }
219
220//         Some(box2d.to_rect())
221//     }
222// }
223
224impl<T> Rect<T>
225where
226    T: Copy + Add<T, Output = T> + Sub<T, Output = T>,
227{
228    /// Create inflated rectangle
229    #[inline]
230    #[must_use]
231    pub fn inflate(&self, width: T, height: T) -> Self {
232        Rect::new(
233            Point::new(self.origin.x - width, self.origin.y - height),
234            Size::new(
235                self.size.width + width + width,
236                self.size.height + height + height,
237            ),
238        )
239    }
240}
241
242// impl<T> Rect<T>
243// where
244//     T: Copy + Zero + PartialOrd + Add<T, Output = T>,
245// {
246//     /// Returns true if this rectangle contains the interior of rect. Always
247//     /// returns true if rect is empty, and always returns false if rect is
248//     /// nonempty but this rectangle is empty.
249//     #[inline]
250//     pub fn contains_rect(&self, rect: &Self) -> bool {
251//         rect.is_empty()
252//             || (self.min_x() <= rect.min_x()
253//                 && rect.max_x() <= self.max_x()
254//                 && self.min_y() <= rect.min_y()
255//                 && rect.max_y() <= self.max_y())
256//     }
257// }
258
259// TODO:
260// impl<T> Rect<T>
261// where
262//     T: Copy + Zero + PartialOrd + Add<T, Output = T> + Sub<T, Output = T>,
263// {
264//     /// Calculate the size and position of an inner rectangle.
265//     ///
266//     /// Subtracts the side offsets from all sides. The horizontal and vertical
267//     /// offsets must not be larger than the original side length.
268//     /// This method assumes y oriented downward.
269//     pub fn inner_rect(&self, offsets: SideOffsets2D<T, U>) -> Self {
270//         let rect = Rect::new(
271//             Point::new(self.origin.x + offsets.left, self.origin.y + offsets.top),
272//             Size::new(
273//                 self.size.width - offsets.horizontal(),
274//                 self.size.height - offsets.vertical(),
275//             ),
276//         );
277//         debug_assert!(rect.size.width >= Zero::zero());
278//         debug_assert!(rect.size.height >= Zero::zero());
279//         rect
280//     }
281// }
282
283// impl<T> Rect<T>
284// where
285//     T: Copy + Add<T, Output = T> + Sub<T, Output = T>,
286// {
287//     /// Calculate the size and position of an outer rectangle.
288//     ///
289//     /// Add the offsets to all sides. The expanded rectangle is returned.
290//     /// This method assumes y oriented downward.
291//     pub fn outer_rect(&self, offsets: SideOffsets2D<T, U>) -> Self {
292//         Rect::new(
293//             Point::new(self.origin.x - offsets.left, self.origin.y - offsets.top),
294//             Size::new(
295//                 self.size.width + offsets.horizontal(),
296//                 self.size.height + offsets.vertical(),
297//             ),
298//         )
299//     }
300// }
301
302// impl<T> Rect<T>
303// where
304//     T: Copy + Zero + PartialOrd + Sub<T, Output = T>,
305// {
306//     /// Returns the smallest rectangle defined by the top/bottom/left/right-most
307//     /// points provided as parameter.
308//     ///
309//     /// Note: This function has a behavior that can be surprising because
310//     /// the right-most and bottom-most points are exactly on the edge
311//     /// of the rectangle while the `contains` function is has exclusive
312//     /// semantic on these edges. This means that the right-most and bottom-most
313//     /// points provided to `from_points` will count as not contained by the rect.
314//     /// This behavior may change in the future.
315//     pub fn from_points<I>(points: I) -> Self
316//     where
317//         I: IntoIterator,
318//         I::Item: Borrow<Point<T>>,
319//     {
320//         Box2D::from_points(points).to_rect()
321//     }
322// }
323
324// impl<T> Rect<T>
325// where
326//     T: Copy + One + Add<Output = T> + Sub<Output = T> + Mul<Output = T>,
327// {
328//     /// Linearly interpolate between this rectangle and another rectangle.
329//     #[inline]
330//     pub fn lerp(&self, other: Self, t: T) -> Self {
331//         Self::new(
332//             self.origin.lerp(other.origin, t),
333//             self.size.lerp(other.size, t),
334//         )
335//     }
336// }
337
338// impl<T> Rect<T>
339// where
340//     T: Copy + One + Add<Output = T> + Div<Output = T>,
341// {
342//     pub fn center(&self) -> Point<T> {
343//         let two = T::one() + T::one();
344//         self.origin + self.size.to_vector() / two
345//     }
346// }
347
348// impl<T> Rect<T>
349// where
350//     T: Copy + PartialOrd + Add<T, Output = T> + Sub<T, Output = T> + Zero,
351// {
352//     #[inline]
353//     pub fn union(&self, other: &Self) -> Self {
354//         if self.size == Zero::zero() {
355//             return *other;
356//         }
357//         if other.size == Zero::zero() {
358//             return *self;
359//         }
360
361//         self.to_box2d().union(&other.to_box2d()).to_rect()
362//     }
363// }
364
365impl<T> Rect<T> {
366    /// Create scaled rectangle
367    #[inline]
368    pub fn scale<S: Copy>(&self, x: S, y: S) -> Self
369    where
370        T: Copy + Mul<S, Output = T>,
371    {
372        Rect::new(
373            Point::new(self.origin.x * x, self.origin.y * y),
374            Size::new(self.size.width * x, self.size.height * y),
375        )
376    }
377}
378
379impl<T: Copy + Mul<T, Output = T>> Rect<T> {
380    /// Retrieve area of rectangle
381    #[inline]
382    pub fn area(&self) -> T {
383        self.size.area()
384    }
385}
386
387// impl<T: Copy + Zero + PartialOrd> Rect<T> {
388//     #[inline]
389//     pub fn is_empty(&self) -> bool {
390//         self.size.is_empty()
391//     }
392// }
393
394// impl<T: Copy + Zero + PartialOrd> Rect<T> {
395//     #[inline]
396//     pub fn to_non_empty(&self) -> Option<Self> {
397//         if self.is_empty() {
398//             return None;
399//         }
400
401//         Some(*self)
402//     }
403// }
404
405// impl<T: Copy + Mul> Mul<T> for Rect<T> {
406//     type Output = Rect<T::Output>;
407
408//     #[inline]
409//     fn mul(self, scale: T) -> Self::Output {
410//         Rect::new(self.origin * scale, self.size * scale)
411//     }
412// }
413
414// TODO:
415// impl<T: Copy + MulAssign> MulAssign<T> for Rect<T> {
416//     #[inline]
417//     fn mul_assign(&mut self, scale: T) {
418//         *self *= Scale::new(scale);
419//     }
420// }
421
422// impl<T: Copy + Div> Div<T> for Rect<T> {
423//     type Output = Rect<T::Output>;
424
425//     #[inline]
426//     fn div(self, scale: T) -> Self::Output {
427//         Rect::new(self.origin / scale.clone(), self.size / scale)
428//     }
429// }
430
431// impl<T: Copy + DivAssign> DivAssign<T> for Rect<T> {
432//     #[inline]
433//     fn div_assign(&mut self, scale: T) {
434//         *self /= Scale::new(scale);
435//     }
436// }
437
438// impl<T: Copy + Mul> Mul<Scale<T>> for Rect<T> {
439//     type Output = Rect<T::Output>;
440
441//     #[inline]
442//     fn mul(self, scale: Scale<T>) -> Self::Output {
443//         Rect::new(self.origin * scale.clone(), self.size * scale)
444//     }
445// }
446
447// impl<T: Copy + MulAssign> MulAssign<Scale<T>> for Rect<T> {
448//     #[inline]
449//     fn mul_assign(&mut self, scale: Scale<T>) {
450//         self.origin *= scale.clone();
451//         self.size *= scale;
452//     }
453// }
454
455// impl<T: Copy + Div> Div<Scale<T>> for Rect<T> {
456//     type Output = Rect<T::Output, U1>;
457
458//     #[inline]
459//     fn div(self, scale: Scale<T>) -> Self::Output {
460//         Rect::new(self.origin / scale.clone(), self.size / scale)
461//     }
462// }
463
464// impl<T: Copy + DivAssign> DivAssign<Scale<T>> for Rect<T> {
465//     #[inline]
466//     fn div_assign(&mut self, scale: Scale<T>) {
467//         self.origin /= scale.clone();
468//         self.size /= scale;
469//     }
470// }
471
472// impl<T: Copy> Rect<T> {
473//     /// Drop the units, preserving only the numeric value.
474//     #[inline]
475//     pub fn to_untyped(&self) -> Rect<T> {
476//         Rect::new(self.origin.to_untyped(), self.size.to_untyped())
477//     }
478
479//     /// Tag a unitless value with units.
480//     #[inline]
481//     pub fn from_untyped(r: &Rect<T>) -> Rect<T> {
482//         Rect::new(Point::from_untyped(r.origin), Size::from_untyped(r.size))
483//     }
484
485//     /// Cast the unit
486//     #[inline]
487//     pub fn cast_unit<V>(&self) -> Rect<T> {
488//         Rect::new(self.origin.cast_unit(), self.size.cast_unit())
489//     }
490// }
491
492// impl<T: Floor + Ceil + Round + Add<T, Output = T> + Sub<T, Output = T>> Rect<T> {
493//     /// Return a rectangle with edges rounded to integer coordinates, such that
494//     /// the returned rectangle has the same set of pixel centers as the original
495//     /// one.
496//     /// Edges at offset 0.5 round up.
497//     /// Suitable for most places where integral device coordinates
498//     /// are needed, but note that any translation should be applied first to
499//     /// avoid pixel rounding errors.
500//     /// Note that this is *not* rounding to nearest integer if the values are negative.
501//     /// They are always rounding as floor(n + 0.5).
502//     ///
503//     /// # Usage notes
504//     /// Note, that when using with floating-point `T` types that method can significantly
505//     /// loose precision for large values, so if you need to call this method very often it
506//     /// is better to use [`Box2D`].
507//     ///
508//     /// [`Box2D`]: struct.Box2D.html
509//     #[must_use]
510//     pub fn round(&self) -> Self {
511//         self.to_box2d().round().to_rect()
512//     }
513
514//     /// Return a rectangle with edges rounded to integer coordinates, such that
515//     /// the original rectangle contains the resulting rectangle.
516//     ///
517//     /// # Usage notes
518//     /// Note, that when using with floating-point `T` types that method can significantly
519//     /// loose precision for large values, so if you need to call this method very often it
520//     /// is better to use [`Box2D`].
521//     ///
522//     /// [`Box2D`]: struct.Box2D.html
523//     #[must_use]
524//     pub fn round_in(&self) -> Self {
525//         self.to_box2d().round_in().to_rect()
526//     }
527
528//     /// Return a rectangle with edges rounded to integer coordinates, such that
529//     /// the original rectangle is contained in the resulting rectangle.
530//     ///
531//     /// # Usage notes
532//     /// Note, that when using with floating-point `T` types that method can significantly
533//     /// loose precision for large values, so if you need to call this method very often it
534//     /// is better to use [`Box2D`].
535//     ///
536//     /// [`Box2D`]: struct.Box2D.html
537//     #[must_use]
538//     pub fn round_out(&self) -> Self {
539//         self.to_box2d().round_out().to_rect()
540//     }
541// }
542
543// impl<T> From<Size<T>> for Rect<T>
544// where
545//     T: Zero,
546// {
547//     fn from(size: Size<T>) -> Self {
548//         Self::from_size(size)
549//     }
550// }
551
552/// Shorthand for `Rect::new(Point::new(x, y), Size::new(w, h))`.
553pub const fn rect<T>(x: T, y: T, w: T, h: T) -> Rect<T> {
554    Rect::new(Point::new(x, y), Size::new(w, h))
555}
556
557#[cfg(test)]
558mod tests {
559    use crate::foundation::{Point, Rect, Size};
560    // use crate::default::{Point, Rect, Size};
561    // use crate::side_offsets::SideOffsets2D;
562    // use crate::{point2, rect, size2, vec2};
563
564    // #[test]
565    // fn test_translate() {
566    //     let p = Rect::new(Point::new(0u32, 0u32), Size::new(50u32, 40u32));
567    //     let pp = p.translate(vec2(10, 15));
568
569    //     assert!(pp.size.width == 50);
570    //     assert!(pp.size.height == 40);
571    //     assert!(pp.origin.x == 10);
572    //     assert!(pp.origin.y == 15);
573
574    //     let r = Rect::new(Point::new(-10, -5), Size::new(50, 40));
575    //     let rr = r.translate(vec2(0, -10));
576
577    //     assert!(rr.size.width == 50);
578    //     assert!(rr.size.height == 40);
579    //     assert!(rr.origin.x == -10);
580    //     assert!(rr.origin.y == -15);
581    // }
582
583    // #[test]
584    // fn test_union() {
585    //     let p = Rect::new(Point::new(0, 0), Size::new(50, 40));
586    //     let q = Rect::new(Point::new(20, 20), Size::new(5, 5));
587    //     let r = Rect::new(Point::new(-15, -30), Size::new(200, 15));
588    //     let s = Rect::new(Point::new(20, -15), Size::new(250, 200));
589
590    //     let pq = p.union(&q);
591    //     assert!(pq.origin == Point::new(0, 0));
592    //     assert!(pq.size == Size::new(50, 40));
593
594    //     let pr = p.union(&r);
595    //     assert!(pr.origin == Point::new(-15, -30));
596    //     assert!(pr.size == Size::new(200, 70));
597
598    //     let ps = p.union(&s);
599    //     assert!(ps.origin == Point::new(0, -15));
600    //     assert!(ps.size == Size::new(270, 200));
601    // }
602
603    // #[test]
604    // fn test_intersection() {
605    //     let p = Rect::new(Point::new(0, 0), Size::new(10, 20));
606    //     let q = Rect::new(Point::new(5, 15), Size::new(10, 10));
607    //     let r = Rect::new(Point::new(-5, -5), Size::new(8, 8));
608
609    //     let pq = p.intersection(&q);
610    //     assert!(pq.is_some());
611    //     let pq = pq.unwrap();
612    //     assert!(pq.origin == Point::new(5, 15));
613    //     assert!(pq.size == Size::new(5, 5));
614
615    //     let pr = p.intersection(&r);
616    //     assert!(pr.is_some());
617    //     let pr = pr.unwrap();
618    //     assert!(pr.origin == Point::new(0, 0));
619    //     assert!(pr.size == Size::new(3, 3));
620
621    //     let qr = q.intersection(&r);
622    //     assert!(qr.is_none());
623    // }
624
625    // #[test]
626    // fn test_intersection_overflow() {
627    //     // test some scenarios where the intersection can overflow but
628    //     // the min_x() and max_x() don't. Gecko currently fails these cases
629    //     let p = Rect::new(Point::new(-2147483648, -2147483648), Size::new(0, 0));
630    //     let q = Rect::new(
631    //         Point::new(2136893440, 2136893440),
632    //         Size::new(279552, 279552),
633    //     );
634    //     let r = Rect::new(Point::new(-2147483648, -2147483648), Size::new(1, 1));
635
636    //     assert!(p.is_empty());
637    //     let pq = p.intersection(&q);
638    //     assert!(pq.is_none());
639
640    //     let qr = q.intersection(&r);
641    //     assert!(qr.is_none());
642    // }
643
644    // #[test]
645    // fn test_contains() {
646    //     let r = Rect::new(Point::new(-20, 15), Size::new(100, 200));
647
648    //     assert!(r.contains(Point::new(0, 50)));
649    //     assert!(r.contains(Point::new(-10, 200)));
650
651    //     // The `contains` method is inclusive of the top/left edges, but not the
652    //     // bottom/right edges.
653    //     assert!(r.contains(Point::new(-20, 15)));
654    //     assert!(!r.contains(Point::new(80, 15)));
655    //     assert!(!r.contains(Point::new(80, 215)));
656    //     assert!(!r.contains(Point::new(-20, 215)));
657
658    //     // Points beyond the top-left corner.
659    //     assert!(!r.contains(Point::new(-25, 15)));
660    //     assert!(!r.contains(Point::new(-15, 10)));
661
662    //     // Points beyond the top-right corner.
663    //     assert!(!r.contains(Point::new(85, 20)));
664    //     assert!(!r.contains(Point::new(75, 10)));
665
666    //     // Points beyond the bottom-right corner.
667    //     assert!(!r.contains(Point::new(85, 210)));
668    //     assert!(!r.contains(Point::new(75, 220)));
669
670    //     // Points beyond the bottom-left corner.
671    //     assert!(!r.contains(Point::new(-25, 210)));
672    //     assert!(!r.contains(Point::new(-15, 220)));
673
674    //     let r = Rect::new(Point::new(-20.0, 15.0), Size::new(100.0, 200.0));
675    //     assert!(r.contains_rect(&r));
676    //     assert!(!r.contains_rect(&r.translate(vec2(0.1, 0.0))));
677    //     assert!(!r.contains_rect(&r.translate(vec2(-0.1, 0.0))));
678    //     assert!(!r.contains_rect(&r.translate(vec2(0.0, 0.1))));
679    //     assert!(!r.contains_rect(&r.translate(vec2(0.0, -0.1))));
680    //     // Empty rectangles are always considered as contained in other rectangles,
681    //     // even if their origin is not.
682    //     let p = Point::new(1.0, 1.0);
683    //     assert!(!r.contains(p));
684    //     assert!(r.contains_rect(&Rect::new(p, Size::zero())));
685    // }
686
687    #[test]
688    fn test_scale() {
689        let p = Rect::new(Point::new(0u32, 0u32), Size::new(50u32, 40u32));
690        let pp = p.scale(10, 15);
691
692        assert!(pp.size.width == 500);
693        assert!(pp.size.height == 600);
694        assert!(pp.origin.x == 0);
695        assert!(pp.origin.y == 0);
696
697        let r = Rect::new(Point::new(-10, -5), Size::new(50, 40));
698        let rr = r.scale(1, 20);
699
700        assert!(rr.size.width == 50);
701        assert!(rr.size.height == 800);
702        assert!(rr.origin.x == -10);
703        assert!(rr.origin.y == -100);
704    }
705
706    #[test]
707    fn test_inflate() {
708        let p = Rect::new(Point::new(0, 0), Size::new(10, 10));
709        let pp = p.inflate(10, 20);
710
711        assert!(pp.size.width == 30);
712        assert!(pp.size.height == 50);
713        assert!(pp.origin.x == -10);
714        assert!(pp.origin.y == -20);
715
716        let r = Rect::new(Point::new(0, 0), Size::new(10, 20));
717        let rr = r.inflate(-2, -5);
718
719        assert!(rr.size.width == 6);
720        assert!(rr.size.height == 10);
721        assert!(rr.origin.x == 2);
722        assert!(rr.origin.y == 5);
723    }
724
725    // #[test]
726    // fn test_inner_outer_rect() {
727    //     let inner_rect = Rect::new(point2(20, 40), size2(80, 100));
728    //     let offsets = SideOffsets2D::new(20, 10, 10, 10);
729    //     let outer_rect = inner_rect.outer_rect(offsets);
730    //     assert_eq!(outer_rect.origin.x, 10);
731    //     assert_eq!(outer_rect.origin.y, 20);
732    //     assert_eq!(outer_rect.size.width, 100);
733    //     assert_eq!(outer_rect.size.height, 130);
734    //     assert_eq!(outer_rect.inner_rect(offsets), inner_rect);
735    // }
736
737    #[test]
738    fn test_min_max_x_y() {
739        let p = Rect::new(Point::new(0u32, 0u32), Size::new(50u32, 40u32));
740        assert!(p.max_y() == 40);
741        assert!(p.min_y() == 0);
742        assert!(p.max_x() == 50);
743        assert!(p.min_x() == 0);
744
745        let r = Rect::new(Point::new(-10, -5), Size::new(50, 40));
746        assert!(r.max_y() == 35);
747        assert!(r.min_y() == -5);
748        assert!(r.max_x() == 40);
749        assert!(r.min_x() == -10);
750    }
751
752    #[test]
753    fn test_width_height() {
754        let r = Rect::new(Point::new(-10, -5), Size::new(50, 40));
755        assert!(r.width() == 50);
756        assert!(r.height() == 40);
757    }
758
759    // #[test]
760    // fn test_is_empty() {
761    //     assert!(Rect::new(Point::new(0u32, 0u32), Size::new(0u32, 0u32)).is_empty());
762    //     assert!(Rect::new(Point::new(0u32, 0u32), Size::new(10u32, 0u32)).is_empty());
763    //     assert!(Rect::new(Point::new(0u32, 0u32), Size::new(0u32, 10u32)).is_empty());
764    //     assert!(!Rect::new(Point::new(0u32, 0u32), Size::new(1u32, 1u32)).is_empty());
765    //     assert!(Rect::new(Point::new(10u32, 10u32), Size::new(0u32, 0u32)).is_empty());
766    //     assert!(Rect::new(Point::new(10u32, 10u32), Size::new(10u32, 0u32)).is_empty());
767    //     assert!(Rect::new(Point::new(10u32, 10u32), Size::new(0u32, 10u32)).is_empty());
768    //     assert!(!Rect::new(Point::new(10u32, 10u32), Size::new(1u32, 1u32)).is_empty());
769    // }
770
771    // #[test]
772    // fn test_round() {
773    //     let mut x = -2.0;
774    //     let mut y = -2.0;
775    //     let mut w = -2.0;
776    //     let mut h = -2.0;
777    //     while x < 2.0 {
778    //         while y < 2.0 {
779    //             while w < 2.0 {
780    //                 while h < 2.0 {
781    //                     let rect = Rect::new(Point::new(x, y), Size::new(w, h));
782
783    //                     assert!(rect.contains_rect(&rect.round_in()));
784    //                     assert!(rect.round_in().inflate(1.0, 1.0).contains_rect(&rect));
785
786    //                     assert!(rect.round_out().contains_rect(&rect));
787    //                     assert!(rect.inflate(1.0, 1.0).contains_rect(&rect.round_out()));
788
789    //                     assert!(rect.inflate(1.0, 1.0).contains_rect(&rect.round()));
790    //                     assert!(rect.round().inflate(1.0, 1.0).contains_rect(&rect));
791
792    //                     h += 0.1;
793    //                 }
794    //                 w += 0.1;
795    //             }
796    //             y += 0.1;
797    //         }
798    //         x += 0.1
799    //     }
800    // }
801
802    // #[test]
803    // fn test_center() {
804    //     let r: Rect<i32> = rect(-2, 5, 4, 10);
805    //     assert_eq!(r.center(), point2(0, 10));
806
807    //     let r: Rect<f32> = rect(1.0, 2.0, 3.0, 4.0);
808    //     assert_eq!(r.center(), point2(2.5, 4.0));
809    // }
810
811    // #[test]
812    // fn test_nan() {
813    //     let r1: Rect<f32> = rect(-2.0, 5.0, 4.0, std::f32::NAN);
814    //     let r2: Rect<f32> = rect(std::f32::NAN, -1.0, 3.0, 10.0);
815
816    //     assert_eq!(r1.intersection(&r2), None);
817    // }
818}