1 | use core::ops::Range; |
2 | |
3 | use crate::{geometry::Point, primitives::Rectangle}; |
4 | |
5 | /// Iterator over all points inside the rectangle. |
6 | #[derive (Clone, Eq, PartialEq, Hash, Debug)] |
7 | #[cfg_attr (feature = "defmt" , derive(::defmt::Format))] |
8 | pub struct Points { |
9 | x: Range<i32>, |
10 | y: Range<i32>, |
11 | x_start: i32, |
12 | } |
13 | |
14 | impl Points { |
15 | pub(in crate::primitives::rectangle) fn new(rectangle: &Rectangle) -> Self { |
16 | // Return `Self::empty` for all zero sized rectangles. |
17 | // The iterator would behave correctly without this check, but would loop unnecessarily for |
18 | // rectangles with zero width. |
19 | if rectangle.is_zero_sized() { |
20 | return Self::empty(); |
21 | } |
22 | |
23 | let x = rectangle.columns(); |
24 | let y = rectangle.rows(); |
25 | let x_start = x.start; |
26 | |
27 | Self { x, y, x_start } |
28 | } |
29 | |
30 | /// Create a points iterator that returns no items. |
31 | pub const fn empty() -> Self { |
32 | Self { |
33 | x: 0..0, |
34 | y: 0..0, |
35 | x_start: 0, |
36 | } |
37 | } |
38 | } |
39 | |
40 | impl Iterator for Points { |
41 | type Item = Point; |
42 | |
43 | #[inline ] |
44 | fn next(&mut self) -> Option<Self::Item> { |
45 | while !self.y.is_empty() { |
46 | if let Some(x: i32) = self.x.next() { |
47 | return Some(Point::new(x, self.y.start)); |
48 | } |
49 | |
50 | self.y.next(); |
51 | self.x.start = self.x_start; |
52 | } |
53 | |
54 | None |
55 | } |
56 | } |
57 | |
58 | #[cfg (test)] |
59 | mod tests { |
60 | use super::*; |
61 | use crate::{ |
62 | geometry::{Point, Size}, |
63 | primitives::{PointsIter, Rectangle}, |
64 | }; |
65 | |
66 | #[test ] |
67 | fn points_iter() { |
68 | let rectangle = Rectangle::new(Point::new(10, 20), Size::new(2, 3)); |
69 | |
70 | let mut points = rectangle.points(); |
71 | assert_eq!(points.next(), Some(Point::new(10, 20))); |
72 | assert_eq!(points.next(), Some(Point::new(11, 20))); |
73 | assert_eq!(points.next(), Some(Point::new(10, 21))); |
74 | assert_eq!(points.next(), Some(Point::new(11, 21))); |
75 | assert_eq!(points.next(), Some(Point::new(10, 22))); |
76 | assert_eq!(points.next(), Some(Point::new(11, 22))); |
77 | assert_eq!(points.next(), None); |
78 | } |
79 | |
80 | #[test ] |
81 | fn points_iter_zero_size() { |
82 | let rectangle = Rectangle::new(Point::new(1, 2), Size::zero()); |
83 | |
84 | let mut points = rectangle.points(); |
85 | assert_eq!(points.next(), None); |
86 | } |
87 | |
88 | #[test ] |
89 | fn points_iter_zero_size_x() { |
90 | let rectangle = Rectangle::new(Point::new(1, 2), Size::new(0, 1)); |
91 | |
92 | let mut points = rectangle.points(); |
93 | assert_eq!(points.next(), None); |
94 | } |
95 | |
96 | #[test ] |
97 | fn points_iter_zero_size_y() { |
98 | let rectangle = Rectangle::new(Point::new(1, 2), Size::new(1, 0)); |
99 | |
100 | let mut points = rectangle.points(); |
101 | assert_eq!(points.next(), None); |
102 | } |
103 | |
104 | #[test ] |
105 | fn points_iter_empty() { |
106 | let mut points = Points::empty(); |
107 | assert_eq!(points.next(), None); |
108 | } |
109 | } |
110 | |