1use crate::{
2 geometry::Point,
3 primitives::line::{
4 bresenham::{self, Bresenham, BresenhamParameters},
5 Line,
6 },
7};
8
9#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
15#[cfg_attr(feature = "defmt", derive(::defmt::Format))]
16pub struct Points {
17 parameters: BresenhamParameters,
18 bresenham: Bresenham,
19 points_remaining: u32,
20}
21
22impl Points {
23 pub(in crate::primitives) fn new(line: &Line) -> Self {
25 let length = bresenham::major_length(line);
26 let parameters = BresenhamParameters::new(line);
27 let bresenham = Bresenham::new(line.start);
28
29 Self {
30 parameters,
31 bresenham,
32 points_remaining: length,
33 }
34 }
35
36 pub(in crate::primitives) fn empty() -> Self {
38 let dummy = Line::new(Point::zero(), Point::zero());
39
40 let mut self_ = Self::new(&dummy);
41 self_.points_remaining = 0;
42
43 self_
44 }
45}
46
47impl 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)]
62mod 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}