embedded_graphics/primitives/rounded_rectangle/
points.rs

1use crate::{
2    geometry::Point,
3    primitives::{
4        common::Scanline,
5        rounded_rectangle::{RoundedRectangle, RoundedRectangleContains},
6        ContainsPoint,
7    },
8};
9
10/// Iterator over all points inside the rounded rectangle.
11#[derive(Clone, Eq, PartialEq, Hash, Debug)]
12#[cfg_attr(feature = "defmt", derive(::defmt::Format))]
13pub struct Points {
14    scanlines: Scanlines,
15    current_scanline: Scanline,
16}
17
18impl Points {
19    pub(in crate::primitives) fn new(rounded_rectangle: &RoundedRectangle) -> Self {
20        Self {
21            scanlines: Scanlines::new(rounded_rectangle),
22            current_scanline: Scanline::new_empty(0),
23        }
24    }
25}
26
27impl Iterator for Points {
28    type Item = Point;
29
30    fn next(&mut self) -> Option<Self::Item> {
31        self.current_scanline.next().or_else(|| {
32            self.current_scanline = self.scanlines.next()?;
33            self.current_scanline.next()
34        })
35    }
36}
37
38#[derive(Clone, Eq, PartialEq, Hash, Debug)]
39#[cfg_attr(feature = "defmt", derive(::defmt::Format))]
40pub struct Scanlines {
41    rounded_rectangle: RoundedRectangleContains,
42}
43
44impl Scanlines {
45    pub fn new(rounded_rectangle: &RoundedRectangle) -> Self {
46        Self {
47            rounded_rectangle: RoundedRectangleContains::new(rounded_rectangle),
48        }
49    }
50}
51
52impl Iterator for Scanlines {
53    type Item = Scanline;
54
55    fn next(&mut self) -> Option<Self::Item> {
56        let columns = self.rounded_rectangle.columns.clone();
57        let y = self.rounded_rectangle.rows.next()?;
58
59        let x_start = if y < self.rounded_rectangle.straight_rows_left.start {
60            columns
61                .clone()
62                .find(|x| self.rounded_rectangle.top_left.contains(Point::new(*x, y)))
63        } else if y >= self.rounded_rectangle.straight_rows_left.end {
64            columns.clone().find(|x| {
65                self.rounded_rectangle
66                    .bottom_left
67                    .contains(Point::new(*x, y))
68            })
69        } else {
70            None
71        }
72        .unwrap_or(columns.start);
73
74        let x_end = if y < self.rounded_rectangle.straight_rows_right.start {
75            columns
76                .clone()
77                .rfind(|x| self.rounded_rectangle.top_right.contains(Point::new(*x, y)))
78        } else if y >= self.rounded_rectangle.straight_rows_right.end {
79            columns.clone().rfind(|x| {
80                self.rounded_rectangle
81                    .bottom_right
82                    .contains(Point::new(*x, y))
83            })
84        } else {
85            None
86        }
87        .map(|x| x + 1)
88        .unwrap_or(columns.end);
89
90        Some(Scanline::new(y, x_start..x_end))
91    }
92}
93
94#[cfg(test)]
95mod tests {
96    use super::*;
97    use crate::{
98        geometry::Size,
99        mock_display::MockDisplay,
100        pixelcolor::BinaryColor,
101        primitives::{PointsIter, Primitive, PrimitiveStyle, Rectangle},
102        Drawable,
103    };
104
105    #[test]
106    fn points_equals_filled() {
107        let rounded_rect = RoundedRectangle::with_equal_corners(
108            Rectangle::new(Point::zero(), Size::new(10, 20)),
109            Size::new(4, 8),
110        );
111
112        let mut expected = MockDisplay::new();
113        rounded_rect
114            .into_styled(PrimitiveStyle::with_fill(BinaryColor::On))
115            .draw(&mut expected)
116            .unwrap();
117
118        MockDisplay::from_points(rounded_rect.points(), BinaryColor::On).assert_eq(&expected);
119    }
120}