embedded_graphics_core/primitives/rectangle/
mod.rs

1//! The rectangle primitive.
2
3mod points;
4
5use crate::{
6    geometry::{AnchorPoint, AnchorX, AnchorY, Dimensions, Point, Size},
7    primitives::PointsIter,
8};
9use az::SaturatingAs;
10use core::{
11    cmp::min,
12    ops::{Range, RangeInclusive},
13};
14pub use points::Points;
15
16/// Rectangle primitive
17///
18/// # Examples
19///
20/// ## Create some rectangles with different styles
21///
22/// ```rust
23/// use embedded_graphics::{
24///     pixelcolor::Rgb565, prelude::*, primitives::{Rectangle, PrimitiveStyleBuilder},
25/// };
26/// # use embedded_graphics::mock_display::MockDisplay;
27/// # let mut display = MockDisplay::default();
28///
29/// // Rectangle with red 3 pixel wide stroke and green fill with the top left corner at (30, 20) and
30/// // a size of (10, 15)
31/// let style = PrimitiveStyleBuilder::new()
32///     .stroke_color(Rgb565::RED)
33///     .stroke_width(3)
34///     .fill_color(Rgb565::GREEN)
35///     .build();
36///
37/// Rectangle::new(Point::new(30, 20), Size::new(10, 15))
38///     .into_styled(style)
39///     .draw(&mut display)?;
40///
41/// // Rectangle with translation applied
42/// Rectangle::new(Point::new(30, 20), Size::new(10, 15))
43///     .translate(Point::new(-20, -10))
44///     .into_styled(style)
45///     .draw(&mut display)?;
46/// # Ok::<(), core::convert::Infallible>(())
47/// ```
48#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
49#[cfg_attr(feature = "defmt", derive(::defmt::Format))]
50pub struct Rectangle {
51    /// Top left point of the rectangle.
52    pub top_left: Point,
53
54    /// Size of the rectangle.
55    pub size: Size,
56}
57
58impl Dimensions for Rectangle {
59    fn bounding_box(&self) -> Rectangle {
60        *self
61    }
62}
63
64impl PointsIter for Rectangle {
65    type Iter = Points;
66
67    fn points(&self) -> Self::Iter {
68        self::Points::new(self)
69    }
70}
71
72/// Returns the center offset.
73///
74/// The center offset is defined as the offset between the top left corner and
75/// the center point of a rectangle with the given size.
76const fn center_offset(size: Size) -> Size {
77    size.saturating_sub(Size::new_equal(1)).div_u32(2)
78}
79
80impl Rectangle {
81    /// Creates a new rectangle from the top left point and the size.
82    pub const fn new(top_left: Point, size: Size) -> Self {
83        Rectangle { top_left, size }
84    }
85
86    /// Creates a new rectangle from two corners.
87    pub fn with_corners(corner_1: Point, corner_2: Point) -> Self {
88        let left = min(corner_1.x, corner_2.x);
89        let top = min(corner_1.y, corner_2.y);
90
91        Rectangle {
92            top_left: Point::new(left, top),
93            size: Size::from_bounding_box(corner_1, corner_2),
94        }
95    }
96
97    /// Creates a new rectangle from the center point and the size.
98    ///
99    /// For rectangles with even width and/or height the top left corner doesn't
100    /// align with the pixel grid. Because of this the coordinates of the top left
101    /// corner will be rounded up to the nearest integer coordinate.
102    pub const fn with_center(center: Point, size: Size) -> Self {
103        Rectangle {
104            top_left: center.sub_size(center_offset(size)),
105            size,
106        }
107    }
108
109    /// Returns a zero sized rectangle.
110    pub const fn zero() -> Rectangle {
111        Rectangle::new(Point::zero(), Size::zero())
112    }
113
114    /// Returns the center of this rectangle.
115    ///
116    /// For rectangles with even width and/or height the returned value is rounded down
117    /// to the nearest integer coordinate.
118    pub fn center(&self) -> Point {
119        self.top_left + center_offset(self.size)
120    }
121
122    /// Returns the bottom right corner of this rectangle.
123    ///
124    /// Because the smallest rectangle that can be represented by its corners
125    /// has a size of 1 x 1 pixels, this function returns `None` if the width or
126    /// height of the rectangle is zero.
127    pub fn bottom_right(&self) -> Option<Point> {
128        if self.size.width > 0 && self.size.height > 0 {
129            Some(self.top_left + self.size - Point::new(1, 1))
130        } else {
131            None
132        }
133    }
134
135    /// Return whether the rectangle contains a given point.
136    pub fn contains(&self, point: Point) -> bool {
137        if point.x >= self.top_left.x && point.y >= self.top_left.y {
138            self.bottom_right().map_or(false, |bottom_right| {
139                point.x <= bottom_right.x && point.y <= bottom_right.y
140            })
141        } else {
142            false
143        }
144    }
145
146    /// Returns a new `Rectangle` containing the intersection of `self` and `other`.
147    ///
148    /// If no intersection is present, this method will return a zero sized rectangle.
149    ///
150    /// # Examples
151    ///
152    /// ## Intersection
153    ///
154    /// This example draws two rectangles to a mock display using the `.` character, along with
155    /// their intersection shown with `#` characters.
156    ///
157    /// ```rust
158    /// use embedded_graphics::{
159    ///     mock_display::MockDisplay, pixelcolor::BinaryColor, prelude::*,
160    ///     primitives::{Rectangle, PrimitiveStyle},
161    /// };
162    ///
163    /// let mut display = MockDisplay::new();
164    /// # display.set_allow_overdraw(true);
165    ///
166    /// let rect1 = Rectangle::new(Point::zero(), Size::new(7, 8));
167    /// let rect2 = Rectangle::new(Point::new(2, 3), Size::new(10, 7));
168    ///
169    /// let intersection = rect1.intersection(&rect2);
170    ///
171    /// rect1
172    ///     .into_styled(PrimitiveStyle::with_stroke(BinaryColor::Off, 1))
173    ///     .draw(&mut display)?;
174    ///
175    /// rect2
176    ///     .into_styled(PrimitiveStyle::with_stroke(BinaryColor::Off, 1))
177    ///     .draw(&mut display)?;
178    ///
179    /// intersection
180    ///     .into_styled(PrimitiveStyle::with_stroke(BinaryColor::On, 1))
181    ///     .draw(&mut display)?;
182    ///
183    /// display.assert_pattern(&[
184    ///     ".......     ",
185    ///     ".     .     ",
186    ///     ".     .     ",
187    ///     ". #####.....",
188    ///     ". #   #    .",
189    ///     ". #   #    .",
190    ///     ". #   #    .",
191    ///     "..#####    .",
192    ///     "  .        .",
193    ///     "  ..........",
194    /// ]);
195    /// # Ok::<(), core::convert::Infallible>(())
196    /// ```
197    ///
198    /// ## No intersection
199    ///
200    /// This example creates two rectangles with no intersection between them. In this case,
201    /// `intersection` returns a zero-sized rectangle.
202    ///
203    /// ```rust
204    /// use embedded_graphics::{prelude::*, primitives::{Rectangle, PrimitiveStyle}};
205    ///
206    /// let rect1 = Rectangle::new(Point::zero(), Size::new(7, 8));
207    /// let rect2 = Rectangle::new(Point::new(10, 15), Size::new(10, 7));
208    ///
209    /// let intersection = rect1.intersection(&rect2);
210    ///
211    /// assert!(intersection.is_zero_sized());
212    /// # Ok::<(), core::convert::Infallible>(())
213    /// ```
214    pub fn intersection(&self, other: &Rectangle) -> Rectangle {
215        match (other.bottom_right(), self.bottom_right()) {
216            (Some(other_bottom_right), Some(self_bottom_right)) => {
217                if overlaps(
218                    self.top_left.x..=self_bottom_right.x,
219                    other.top_left.x..=other_bottom_right.x,
220                ) && overlaps(
221                    self.top_left.y..=self_bottom_right.y,
222                    other.top_left.y..=other_bottom_right.y,
223                ) {
224                    return Rectangle::with_corners(
225                        self.top_left.component_max(other.top_left),
226                        self_bottom_right.component_min(other_bottom_right),
227                    );
228                }
229            }
230            (Some(_other_bottom_right), None) => {
231                // Check if zero sized self is inside other
232                if other.contains(self.top_left) {
233                    return *self;
234                }
235            }
236            (None, Some(_self_bottom_right)) => {
237                // Check if zero sized other is inside self
238                if self.contains(other.top_left) {
239                    return *other;
240                }
241            }
242            (None, None) => (),
243        };
244
245        // No overlap present
246        Rectangle::zero()
247    }
248
249    /// Returns a resized copy of this rectangle.
250    ///
251    /// The rectangle is resized relative to the given anchor point.
252    ///
253    /// # Examples
254    ///
255    /// ```
256    /// use embedded_graphics::{
257    ///     prelude::*,
258    ///     primitives::rectangle::Rectangle,
259    ///     geometry::AnchorPoint,
260    /// };
261    ///
262    /// let rect = Rectangle::new(Point::new(20, 20), Size::new(10, 20));
263    /// let resized = rect.resized(Size::new(20, 10), AnchorPoint::Center);
264    ///
265    /// assert_eq!(
266    ///     resized,
267    ///     Rectangle::new(Point::new(15, 25), Size::new(20, 10))
268    /// );
269    /// ```
270    pub fn resized(&self, size: Size, anchor_point: AnchorPoint) -> Self {
271        let mut resized = self.clone();
272        resized.resize_width_mut(size.width, anchor_point.x());
273        resized.resize_height_mut(size.height, anchor_point.y());
274
275        resized
276    }
277
278    /// Returns a new rectangle with the given width, resized relative to the given anchor edge.
279    ///
280    /// # Examples
281    ///
282    /// ```
283    /// use embedded_graphics::{
284    ///     prelude::*,
285    ///     primitives::rectangle::Rectangle,
286    ///     geometry::AnchorX,
287    /// };
288    ///
289    /// let rect = Rectangle::new(Point::new(20, 20), Size::new(10, 20));
290    /// let resized = rect.resized_width(20, AnchorX::Center);
291    ///
292    /// assert_eq!(
293    ///     resized,
294    ///     Rectangle::new(Point::new(15, 20), Size::new(20, 20))
295    /// );
296    /// ```
297    pub fn resized_width(&self, width: u32, anchor_x: AnchorX) -> Self {
298        let mut resized = self.clone();
299        resized.resize_width_mut(width, anchor_x);
300
301        resized
302    }
303
304    /// Returns a new rectangle with the given height, resized relative to the given anchor edge.
305    ///
306    /// # Examples
307    ///
308    /// ```
309    /// use embedded_graphics::{
310    ///     prelude::*,
311    ///     primitives::rectangle::Rectangle,
312    ///     geometry::AnchorY,
313    /// };
314    ///
315    /// let rect = Rectangle::new(Point::new(20, 20), Size::new(10, 20));
316    /// let resized = rect.resized_height(10, AnchorY::Center);
317    ///
318    /// assert_eq!(
319    ///     resized,
320    ///     Rectangle::new(Point::new(20, 25), Size::new(10, 10))
321    /// );
322    /// ```
323    pub fn resized_height(&self, height: u32, anchor_y: AnchorY) -> Self {
324        let mut resized = self.clone();
325        resized.resize_height_mut(height, anchor_y);
326
327        resized
328    }
329
330    fn resize_width_mut(&mut self, width: u32, anchor_x: AnchorX) {
331        // Assume size = 1 for zero sized dimensions.
332        let delta =
333            self.size.width.saturating_as::<i32>().max(1) - width.saturating_as::<i32>().max(1);
334
335        self.top_left.x += match anchor_x {
336            AnchorX::Left => 0,
337            AnchorX::Center => delta / 2,
338            AnchorX::Right => delta,
339        };
340        self.size.width = width;
341    }
342
343    fn resize_height_mut(&mut self, height: u32, anchor_y: AnchorY) {
344        // Assume size = 1 for zero sized dimensions.
345        let delta =
346            self.size.height.saturating_as::<i32>().max(1) - height.saturating_as::<i32>().max(1);
347
348        self.top_left.y += match anchor_y {
349            AnchorY::Top => 0,
350            AnchorY::Center => delta / 2,
351            AnchorY::Bottom => delta,
352        };
353        self.size.height = height;
354    }
355
356    /// Offset the rectangle by a given value.
357    ///
358    /// Negative values will shrink the rectangle.
359    pub fn offset(&self, offset: i32) -> Self {
360        let size = if offset >= 0 {
361            self.size.saturating_add(Size::new_equal(offset as u32 * 2))
362        } else {
363            self.size
364                .saturating_sub(Size::new_equal((-offset) as u32 * 2))
365        };
366
367        Self::with_center(self.center(), size)
368    }
369
370    /// Returns an anchor point.
371    ///
372    /// # Examples
373    /// ```
374    /// use embedded_graphics::{
375    ///     prelude::*,
376    ///     primitives::rectangle::Rectangle,
377    ///     geometry::AnchorPoint,
378    /// };
379    ///
380    /// let mut rect = Rectangle::new(Point::new(20, 20), Size::new(11, 21));
381    ///
382    /// assert_eq!(rect.anchor_point(AnchorPoint::TopLeft), Point::new(20, 20));
383    /// assert_eq!(
384    ///     rect.anchor_point(AnchorPoint::BottomCenter),
385    ///     Point::new(25, 40)
386    /// );
387    /// ```
388    pub fn anchor_point(&self, anchor_point: AnchorPoint) -> Point {
389        Point::new(
390            self.anchor_x(anchor_point.x()),
391            self.anchor_y(anchor_point.y()),
392        )
393    }
394
395    /// Returns the X coordinate of a given anchor edge of the rectangle.
396    ///
397    /// # Examples
398    ///
399    /// ```
400    /// use embedded_graphics::{
401    ///     prelude::*,
402    ///     primitives::rectangle::Rectangle,
403    ///     geometry::AnchorX,
404    /// };
405    ///
406    /// let mut rect = Rectangle::new(Point::new(20, 20), Size::new(11, 21));
407    ///
408    /// assert_eq!(rect.anchor_x(AnchorX::Left), 20);
409    /// assert_eq!(rect.anchor_x(AnchorX::Center), 25);
410    /// ```
411    pub fn anchor_x(&self, anchor_x: AnchorX) -> i32 {
412        // Assume size = 1 for zero sized dimensions.
413        let delta = self.size.width.saturating_as::<i32>().max(1) - 1;
414
415        self.top_left.x
416            + match anchor_x {
417                AnchorX::Left => 0,
418                AnchorX::Center => delta / 2,
419                AnchorX::Right => delta,
420            }
421    }
422
423    /// Returns the Y coordinate of a given anchor edge of the rectangle.
424    ///
425    /// # Examples
426    ///
427    /// ```
428    /// use embedded_graphics::{
429    ///     prelude::*,
430    ///     primitives::rectangle::Rectangle,
431    ///     geometry::AnchorY,
432    /// };
433    ///
434    /// let mut rect = Rectangle::new(Point::new(20, 20), Size::new(11, 21));
435    ///
436    /// assert_eq!(rect.anchor_y(AnchorY::Top), 20);
437    /// assert_eq!(rect.anchor_y(AnchorY::Bottom), 40);
438    /// ```
439    pub fn anchor_y(&self, anchor_y: AnchorY) -> i32 {
440        // Assume size = 1 for zero sized dimensions.
441        let delta = self.size.height.saturating_as::<i32>().max(1) - 1;
442
443        self.top_left.y
444            + match anchor_y {
445                AnchorY::Top => 0,
446                AnchorY::Center => delta / 2,
447                AnchorY::Bottom => delta,
448            }
449    }
450
451    /// Returns the range of Y coordinates in this rectangle.
452    ///
453    /// # Examples
454    ///
455    /// ```
456    /// use embedded_graphics::{prelude::*, primitives::Rectangle};
457    ///
458    /// let rect = Rectangle::new(Point::new(10, 20), Size::new(3, 4));
459    /// assert_eq!(rect.rows(), 20..24);
460    /// ```
461    ///
462    /// By combining this method with [`columns`] it is possible to iterate over all pixels inside
463    /// the rectangle. This can be more flexible than using the [`points`] iterator, for example,
464    /// if a different iteration order is required or some operations should be called once per row.
465    ///
466    /// ```
467    /// use embedded_graphics::{prelude::*, primitives::Rectangle};
468    ///
469    /// let rect = Rectangle::new(Point::new(10, 20), Size::new(3, 4));
470    ///
471    /// // Iterate over the y coordinates of the rows in reverse order.
472    /// for y in rect.rows().rev() {
473    ///     for x in rect.columns() {
474    ///         // use x, y coordinates
475    ///     }
476    /// }
477    /// ```
478    ///
479    /// [`columns`]: Rectangle::columns()
480    /// [`points`]: super::PointsIter::points
481    pub fn rows(&self) -> Range<i32> {
482        self.top_left.y
483            ..self
484                .top_left
485                .y
486                .saturating_add(self.size.height.saturating_as())
487    }
488
489    /// Returns the range of X coordinates in this rectangle.
490    ///
491    /// # Examples
492    ///
493    /// ```
494    /// use embedded_graphics::{prelude::*, primitives::Rectangle};
495    ///
496    /// let rect = Rectangle::new(Point::new(10, 20), Size::new(3, 4));
497    ///
498    /// assert_eq!(rect.columns(), 10..13);
499    /// ```
500    ///
501    /// By combining this method with [`rows`] it is possible to iterator over all pixels inside
502    /// the rectangle. This can be more flexible than using the [`points`] iterator, for example,
503    /// if a different iteration order is required or some operations should be called once per row.
504    ///
505    /// ```
506    /// use embedded_graphics::{prelude::*, primitives::Rectangle};
507    ///
508    /// let rect = Rectangle::new(Point::new(10, 20), Size::new(3, 4));
509    ///
510    /// // Iterate over all points starting from the top right corner and advancing downwards.
511    /// for x in rect.columns().rev() {
512    ///     for y in rect.rows() {
513    ///         // use x, y coordinates
514    ///     }
515    /// }
516    /// ```
517    ///
518    /// [`rows`]: Rectangle::rows()
519    /// [`points`]: super::PointsIter::points
520    pub fn columns(&self) -> Range<i32> {
521        self.top_left.x
522            ..self
523                .top_left
524                .x
525                .saturating_add(self.size.width.saturating_as())
526    }
527
528    /// Returns `true` is the rectangle is zero sized.
529    ///
530    /// A rectangle is zero sized if the width or height are zero.
531    ///
532    /// # Examples
533    /// ```
534    /// use embedded_graphics::{prelude::*, primitives::Rectangle};
535    ///
536    /// let rect = Rectangle::new(Point::new(10, 20), Size::new(10, 20));
537    /// assert_eq!(rect.is_zero_sized(), false);
538    ///
539    /// let rect = Rectangle::new(Point::new(10, 20), Size::zero());
540    /// assert_eq!(rect.is_zero_sized(), true);
541    /// ```
542    pub const fn is_zero_sized(&self) -> bool {
543        self.size.height == 0 || self.size.width == 0
544    }
545}
546
547/// Checks if the two ranges overlap.
548fn overlaps(first: RangeInclusive<i32>, second: RangeInclusive<i32>) -> bool {
549    second.contains(first.start())
550        || second.contains(first.end())
551        || first.start() < second.start() && first.end() > second.end()
552}
553
554#[cfg(test)]
555mod tests {
556    use super::*;
557    use crate::geometry::{Dimensions, Point, Size};
558
559    #[test]
560    fn dimensions() {
561        let rect = Rectangle::new(Point::new(5, 10), Size::new(10, 20));
562
563        assert_eq!(
564            rect.bounding_box(),
565            Rectangle::new(Point::new(5, 10), Size::new(10, 20))
566        );
567    }
568
569    #[test]
570    fn center() {
571        let odd = Rectangle::new(Point::new(10, 20), Size::new(5, 7));
572        assert_eq!(odd.center(), Point::new(12, 23));
573
574        let even = Rectangle::new(Point::new(20, 30), Size::new(4, 8));
575        assert_eq!(even.center(), Point::new(21, 33));
576    }
577
578    #[test]
579    fn bottom_right() {
580        let zero = Rectangle::new(Point::new(10, 20), Size::zero());
581        assert_eq!(zero.bottom_right(), None);
582
583        let odd = Rectangle::new(Point::new(10, 20), Size::new(5, 7));
584        assert_eq!(odd.bottom_right(), Some(Point::new(14, 26)));
585
586        let even = Rectangle::new(Point::new(20, 30), Size::new(4, 8));
587        assert_eq!(even.bottom_right(), Some(Point::new(23, 37)));
588    }
589
590    #[test]
591    fn rectangle_intersection() {
592        let rect1 = Rectangle::new(Point::new_equal(10), Size::new(20, 30));
593        let rect2 = Rectangle::new(Point::new_equal(25), Size::new(30, 40));
594
595        assert_eq!(
596            rect1.intersection(&rect2),
597            Rectangle::new(Point::new_equal(25), Size::new(5, 15))
598        );
599    }
600
601    #[test]
602    fn rectangle_no_intersection() {
603        let rect1 = Rectangle::new(Point::new_equal(10), Size::new(20, 30));
604        let rect2 = Rectangle::new(Point::new_equal(35), Size::new(30, 40));
605
606        assert_eq!(
607            rect1.intersection(&rect2),
608            Rectangle::new(Point::zero(), Size::zero())
609        );
610    }
611
612    #[test]
613    fn rectangle_complete_intersection() {
614        let rect1 = Rectangle::new(Point::new_equal(10), Size::new(20, 30));
615        let rect2 = rect1;
616
617        assert_eq!(rect1.intersection(&rect2), rect1);
618    }
619
620    #[test]
621    fn rectangle_contained_intersection() {
622        let rect1 = Rectangle::with_corners(Point::new_equal(10), Point::new(20, 30));
623        let rect2 = Rectangle::with_corners(Point::new_equal(5), Point::new(30, 40));
624
625        assert_eq!(rect1.intersection(&rect2), rect1);
626    }
627
628    #[test]
629    fn zero_sized_intersection() {
630        let rect1 = Rectangle::new(Point::new(1, 2), Size::new(0, 0));
631        let rect2 = Rectangle::new(Point::new(-10, -10), Size::new(20, 20));
632
633        assert_eq!(rect1.intersection(&rect2), rect1);
634
635        let rect1 = Rectangle::new(Point::new(-10, -10), Size::new(20, 20));
636        let rect2 = Rectangle::new(Point::new(2, 3), Size::new(0, 0));
637
638        assert_eq!(rect1.intersection(&rect2), rect2);
639    }
640
641    /// Test for issue #452
642    ///
643    /// Rectangles can intersect even if no corner of any rectangle is contained inside the other
644    /// rectangle.
645    ///
646    /// Example:
647    ///
648    ///     ****
649    ///     *  *
650    /// ############
651    /// #   *  *   #
652    /// #   *  *   #
653    /// ############
654    ///     *  *
655    ///     ****
656    #[test]
657    fn issue_452_broken_intersection_check() {
658        let rect1 = Rectangle::new(Point::new(50, 0), Size::new(75, 200));
659        let rect2 = Rectangle::new(Point::new(0, 75), Size::new(200, 50));
660
661        let expected = Rectangle::new(Point::new(50, 75), Size::new(75, 50));
662
663        assert_eq!(rect1.intersection(&rect2), expected);
664        assert_eq!(rect2.intersection(&rect1), expected);
665    }
666
667    #[test]
668    fn offset() {
669        let center = Point::new(10, 20);
670        let rect = Rectangle::with_center(center, Size::new(3, 4));
671
672        assert_eq!(rect.offset(0), rect);
673
674        assert_eq!(
675            rect.offset(1),
676            Rectangle::with_center(center, Size::new(5, 6))
677        );
678        assert_eq!(
679            rect.offset(2),
680            Rectangle::with_center(center, Size::new(7, 8))
681        );
682
683        assert_eq!(
684            rect.offset(-1),
685            Rectangle::with_center(center, Size::new(1, 2))
686        );
687        assert_eq!(
688            rect.offset(-2),
689            Rectangle::with_center(center, Size::new(0, 0))
690        );
691        assert_eq!(
692            rect.offset(-3),
693            Rectangle::with_center(center, Size::new(0, 0))
694        );
695    }
696
697    fn test_resized(rect: Rectangle, target_size: Size, tests: &[(AnchorPoint, Point)]) {
698        for &(anchor_point, expected_top_left) in tests {
699            let resized = rect.resized(target_size, anchor_point);
700            let expected = Rectangle::new(expected_top_left, target_size);
701
702            assert_eq!(resized, expected, "{:?}", anchor_point);
703
704            let resized_x = rect.resized_width(target_size.width, anchor_point.x());
705            assert_eq!(
706                resized_x.top_left,
707                Point::new(resized.top_left.x, rect.top_left.y)
708            );
709            assert_eq!(
710                resized_x.size,
711                Size::new(resized.size.width, rect.size.height)
712            );
713
714            let resized_y = rect.resized_height(target_size.height, anchor_point.y());
715            assert_eq!(
716                resized_y.top_left,
717                Point::new(rect.top_left.x, resized.top_left.y)
718            );
719            assert_eq!(
720                resized_y.size,
721                Size::new(rect.size.width, resized.size.height)
722            );
723        }
724    }
725
726    #[test]
727    fn resized_smaller() {
728        test_resized(
729            Rectangle::new(Point::new(10, 20), Size::new(30, 40)),
730            Size::new(10, 20),
731            &[
732                (AnchorPoint::TopLeft, Point::new(10, 20)),
733                (AnchorPoint::TopCenter, Point::new(20, 20)),
734                (AnchorPoint::TopRight, Point::new(30, 20)),
735                (AnchorPoint::CenterLeft, Point::new(10, 30)),
736                (AnchorPoint::Center, Point::new(20, 30)),
737                (AnchorPoint::CenterRight, Point::new(30, 30)),
738                (AnchorPoint::BottomLeft, Point::new(10, 40)),
739                (AnchorPoint::BottomCenter, Point::new(20, 40)),
740                (AnchorPoint::BottomRight, Point::new(30, 40)),
741            ],
742        );
743    }
744
745    #[test]
746    fn resized_larger() {
747        test_resized(
748            Rectangle::new(Point::new(10, 20), Size::new(30, 40)),
749            Size::new(40, 50),
750            &[
751                (AnchorPoint::TopLeft, Point::new(10, 20)),
752                (AnchorPoint::TopCenter, Point::new(5, 20)),
753                (AnchorPoint::TopRight, Point::new(0, 20)),
754                (AnchorPoint::CenterLeft, Point::new(10, 15)),
755                (AnchorPoint::Center, Point::new(5, 15)),
756                (AnchorPoint::CenterRight, Point::new(0, 15)),
757                (AnchorPoint::BottomLeft, Point::new(10, 10)),
758                (AnchorPoint::BottomCenter, Point::new(5, 10)),
759                (AnchorPoint::BottomRight, Point::new(0, 10)),
760            ],
761        );
762    }
763
764    #[test]
765    fn resized_zero_sized() {
766        test_resized(
767            Rectangle::new(Point::new(10, 20), Size::zero()),
768            Size::new(5, 7),
769            &[
770                (AnchorPoint::TopLeft, Point::new(10, 20)),
771                (AnchorPoint::TopCenter, Point::new(8, 20)),
772                (AnchorPoint::TopRight, Point::new(6, 20)),
773                (AnchorPoint::CenterLeft, Point::new(10, 17)),
774                (AnchorPoint::Center, Point::new(8, 17)),
775                (AnchorPoint::CenterRight, Point::new(6, 17)),
776                (AnchorPoint::BottomLeft, Point::new(10, 14)),
777                (AnchorPoint::BottomCenter, Point::new(8, 14)),
778                (AnchorPoint::BottomRight, Point::new(6, 14)),
779            ],
780        );
781    }
782
783    #[test]
784    fn resized_to_zero_sized() {
785        test_resized(
786            Rectangle::new(Point::new(10, 20), Size::new(21, 31)),
787            Size::zero(),
788            &[
789                (AnchorPoint::TopLeft, Point::new(10, 20)),
790                (AnchorPoint::TopCenter, Point::new(20, 20)),
791                (AnchorPoint::TopRight, Point::new(30, 20)),
792                (AnchorPoint::CenterLeft, Point::new(10, 35)),
793                (AnchorPoint::Center, Point::new(20, 35)),
794                (AnchorPoint::CenterRight, Point::new(30, 35)),
795                (AnchorPoint::BottomLeft, Point::new(10, 50)),
796                (AnchorPoint::BottomCenter, Point::new(20, 50)),
797                (AnchorPoint::BottomRight, Point::new(30, 50)),
798            ],
799        );
800    }
801
802    #[test]
803    fn anchor_point() {
804        let rect = Rectangle::new(Point::new(10, 20), Size::new(21, 31));
805
806        for &(anchor_point, expected) in &[
807            (AnchorPoint::TopLeft, Point::new(10, 20)),
808            (AnchorPoint::TopCenter, Point::new(20, 20)),
809            (AnchorPoint::TopRight, Point::new(30, 20)),
810            (AnchorPoint::CenterLeft, Point::new(10, 35)),
811            (AnchorPoint::Center, Point::new(20, 35)),
812            (AnchorPoint::CenterRight, Point::new(30, 35)),
813            (AnchorPoint::BottomLeft, Point::new(10, 50)),
814            (AnchorPoint::BottomCenter, Point::new(20, 50)),
815            (AnchorPoint::BottomRight, Point::new(30, 50)),
816        ] {
817            assert_eq!(
818                rect.anchor_point(anchor_point),
819                expected,
820                "{:?}",
821                anchor_point,
822            );
823
824            assert_eq!(
825                rect.anchor_x(anchor_point.x()),
826                expected.x,
827                "{:?}.x()",
828                anchor_point
829            );
830
831            assert_eq!(
832                rect.anchor_y(anchor_point.y()),
833                expected.y,
834                "{:?}.y()",
835                anchor_point
836            );
837        }
838    }
839
840    #[test]
841    fn rows_and_columns_zero_sized() {
842        let rect = Rectangle::zero();
843
844        assert_eq!(
845            rect.rows().next(),
846            None,
847            "the rows iterator for a zero sized rectangle shouldn't return any items"
848        );
849
850        assert_eq!(
851            rect.columns().next(),
852            None,
853            "the columns iterator for a zero sized rectangle shouldn't return any items"
854        );
855    }
856}