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}