1 | use crate::{ |
2 | geometry::Point, |
3 | primitives::line::{ |
4 | bresenham::{self, Bresenham, BresenhamParameters}, |
5 | Line, |
6 | }, |
7 | }; |
8 | |
9 | /// Iterator over all points on the line. |
10 | /// |
11 | /// See the [`points`] method documentation for more details. |
12 | /// |
13 | /// [`points`]: struct.Line.html#method.points |
14 | #[derive (Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] |
15 | #[cfg_attr (feature = "defmt" , derive(::defmt::Format))] |
16 | pub struct Points { |
17 | parameters: BresenhamParameters, |
18 | bresenham: Bresenham, |
19 | points_remaining: u32, |
20 | } |
21 | |
22 | impl Points { |
23 | /// Creates an iterator over all points on the given line. |
24 | pub(in crate::primitives) fn new(line: &Line) -> Self { |
25 | let length: u32 = bresenham::major_length(line); |
26 | let parameters: BresenhamParameters = BresenhamParameters::new(line); |
27 | let bresenham: Bresenham = Bresenham::new(start_point:line.start); |
28 | |
29 | Self { |
30 | parameters, |
31 | bresenham, |
32 | points_remaining: length, |
33 | } |
34 | } |
35 | |
36 | /// Creates an empty iterator. |
37 | pub(in crate::primitives) fn empty() -> Self { |
38 | let dummy: Line = Line::new(start:Point::zero(), end:Point::zero()); |
39 | |
40 | let mut self_: Points = Self::new(&dummy); |
41 | self_.points_remaining = 0; |
42 | |
43 | self_ |
44 | } |
45 | } |
46 | |
47 | impl Iterator for Points { |
48 | type Item = Point; |
49 | |
50 | fn next(&mut self) -> Option<Self::Item> { |
51 | if self.points_remaining > 0 { |
52 | self.points_remaining -= 1; |
53 | |
54 | Some(self.bresenham.next(&self.parameters)) |
55 | } else { |
56 | None |
57 | } |
58 | } |
59 | } |
60 | |
61 | #[cfg (test)] |
62 | mod tests { |
63 | |
64 | use super::*; |
65 | use crate::{ |
66 | iterator::PixelIteratorExt, mock_display::MockDisplay, pixelcolor::BinaryColor, |
67 | primitives::PointsIter, Pixel, |
68 | }; |
69 | |
70 | fn test_points(start: Point, end: Point, expected: &[(i32, i32)]) { |
71 | let expected = expected.iter().copied().map(Point::from); |
72 | |
73 | let points = Line::new(start, end).points(); |
74 | assert!(points.eq(expected)); |
75 | } |
76 | |
77 | fn draw_lines(delta: Point) -> MockDisplay<BinaryColor> { |
78 | let mut display = MockDisplay::new(); |
79 | |
80 | for &quadrant in &[ |
81 | Point::new(-1, -1), |
82 | Point::new(1, -1), |
83 | Point::new(-1, 1), |
84 | Point::new(1, 1), |
85 | ] { |
86 | let center = delta + Point::new_equal(1); |
87 | let start = center + quadrant; |
88 | let end = start + Point::new(delta.x * quadrant.x, delta.y * quadrant.y); |
89 | |
90 | let line = Line::new(start, end); |
91 | |
92 | line.points() |
93 | .map(|point| Pixel(point, BinaryColor::On)) |
94 | .draw(&mut display) |
95 | .unwrap(); |
96 | } |
97 | |
98 | display |
99 | } |
100 | |
101 | #[test ] |
102 | fn lines_1() { |
103 | let delta = Point::new(6, 3); |
104 | |
105 | let expected = MockDisplay::from_pattern(&[ |
106 | "# #" , |
107 | " ## ## " , |
108 | " ## ## " , |
109 | " ## ## " , |
110 | " " , |
111 | " ## ## " , |
112 | " ## ## " , |
113 | " ## ## " , |
114 | "# #" , |
115 | ]); |
116 | |
117 | draw_lines(delta).assert_eq(&expected); |
118 | |
119 | let expected = expected.swap_xy(); |
120 | let delta = Point::new(delta.y, delta.x); |
121 | draw_lines(delta).assert_eq(&expected); |
122 | } |
123 | |
124 | #[test ] |
125 | fn lines_2() { |
126 | let delta = Point::new(9, 3); |
127 | |
128 | let expected = MockDisplay::from_pattern(&[ |
129 | "## ##" , |
130 | " ### ### " , |
131 | " ### ### " , |
132 | " ## ## " , |
133 | " " , |
134 | " ## ## " , |
135 | " ### ### " , |
136 | " ### ### " , |
137 | "## ##" , |
138 | ]); |
139 | draw_lines(delta).assert_eq(&expected); |
140 | |
141 | let expected = expected.swap_xy(); |
142 | let delta = Point::new(delta.y, delta.x); |
143 | draw_lines(delta).assert_eq(&expected); |
144 | } |
145 | |
146 | #[test ] |
147 | fn single_pixel() { |
148 | let start = Point::new(10, 10); |
149 | let end = Point::new(10, 10); |
150 | |
151 | let expected = [(10, 10)]; |
152 | test_points(start, end, &expected); |
153 | } |
154 | |
155 | #[test ] |
156 | fn short_correctly() { |
157 | let start = Point::new(2, 3); |
158 | let end = Point::new(3, 2); |
159 | |
160 | let expected = [(2, 3), (3, 2)]; |
161 | test_points(start, end, &expected); |
162 | } |
163 | |
164 | #[test ] |
165 | fn octant_1_correctly() { |
166 | let start = Point::new(10, 10); |
167 | let end = Point::new(15, 13); |
168 | |
169 | let expected = [(10, 10), (11, 11), (12, 11), (13, 12), (14, 12), (15, 13)]; |
170 | test_points(start, end, &expected); |
171 | } |
172 | |
173 | #[test ] |
174 | fn octant_2_correctly() { |
175 | let start = Point::new(10, 10); |
176 | let end = Point::new(13, 15); |
177 | |
178 | let expected = [(10, 10), (11, 11), (11, 12), (12, 13), (12, 14), (13, 15)]; |
179 | test_points(start, end, &expected); |
180 | } |
181 | |
182 | #[test ] |
183 | fn octant_3_correctly() { |
184 | let start = Point::new(10, 10); |
185 | let end = Point::new(7, 15); |
186 | |
187 | let expected = [(10, 10), (9, 11), (9, 12), (8, 13), (8, 14), (7, 15)]; |
188 | test_points(start, end, &expected); |
189 | } |
190 | |
191 | #[test ] |
192 | fn octant_4_correctly() { |
193 | let start = Point::new(10, 10); |
194 | let end = Point::new(5, 13); |
195 | |
196 | let expected = [(10, 10), (9, 11), (8, 11), (7, 12), (6, 12), (5, 13)]; |
197 | test_points(start, end, &expected); |
198 | } |
199 | |
200 | #[test ] |
201 | fn octant_5_correctly() { |
202 | let start = Point::new(10, 10); |
203 | let end = Point::new(5, 7); |
204 | |
205 | let expected = [(10, 10), (9, 9), (8, 9), (7, 8), (6, 8), (5, 7)]; |
206 | test_points(start, end, &expected); |
207 | } |
208 | |
209 | #[test ] |
210 | fn octant_6_correctly() { |
211 | let start = Point::new(10, 10); |
212 | let end = Point::new(7, 5); |
213 | |
214 | let expected = [(10, 10), (9, 9), (9, 8), (8, 7), (8, 6), (7, 5)]; |
215 | test_points(start, end, &expected); |
216 | } |
217 | |
218 | #[test ] |
219 | fn octant_7_correctly() { |
220 | let start = Point::new(10, 10); |
221 | let end = Point::new(13, 5); |
222 | |
223 | let expected = [(10, 10), (11, 9), (11, 8), (12, 7), (12, 6), (13, 5)]; |
224 | test_points(start, end, &expected); |
225 | } |
226 | |
227 | #[test ] |
228 | fn octant_8_correctly() { |
229 | let start = Point::new(10, 10); |
230 | let end = Point::new(15, 7); |
231 | |
232 | let expected = [(10, 10), (11, 9), (12, 9), (13, 8), (14, 8), (15, 7)]; |
233 | test_points(start, end, &expected); |
234 | } |
235 | |
236 | #[test ] |
237 | fn one_pixel_line() { |
238 | let p = Point::new(5, 6); |
239 | assert!(Line::new(p, p).points().eq(core::iter::once(p))); |
240 | } |
241 | |
242 | #[test ] |
243 | fn empty() { |
244 | assert!(Points::empty().eq(core::iter::empty())); |
245 | } |
246 | } |
247 | |