1use crate::prelude::Point;
5use core::iter::Iterator;
6
7pub struct Bresenham {
9 x: i32,
10 y: i32,
11 dx: i32,
12 dy: i32,
13 x1: i32,
14 diff: i32,
15 octant: Octant,
16}
17
18struct Octant(u8);
19
20impl Octant {
21 #[inline]
23 fn from_points(start: Point, end: Point) -> Octant {
24 let mut dx = end.x - start.x;
25 let mut dy = end.y - start.y;
26
27 let mut octant = 0;
28
29 if dy < 0 {
30 dx = -dx;
31 dy = -dy;
32 octant += 4;
33 }
34
35 if dx < 0 {
36 let tmp = dx;
37 dx = dy;
38 dy = -tmp;
39 octant += 2;
40 }
41
42 if dx < dy {
43 octant += 1;
44 }
45
46 Octant(octant)
47 }
48
49 #[inline]
50 fn to_octant0(&self, p: Point) -> Point {
51 match self.0 {
52 0 => Point::new(p.x, p.y),
53 1 => Point::new(p.y, p.x),
54 2 => Point::new(p.y, -p.x),
55 3 => Point::new(-p.x, p.y),
56 4 => Point::new(-p.x, -p.y),
57 5 => Point::new(-p.y, -p.x),
58 6 => Point::new(-p.y, p.x),
59 7 => Point::new(p.x, -p.y),
60 _ => unreachable!(),
61 }
62 }
63
64 #[inline]
65 fn from_octant0(&self, p: Point) -> Point {
66 match self.0 {
67 0 => Point::new(p.x, p.y),
68 1 => Point::new(p.y, p.x),
69 2 => Point::new(-p.y, p.x),
70 3 => Point::new(-p.x, p.y),
71 4 => Point::new(-p.x, -p.y),
72 5 => Point::new(-p.y, -p.x),
73 6 => Point::new(p.y, -p.x),
74 7 => Point::new(p.x, -p.y),
75 _ => unreachable!(),
76 }
77 }
78}
79
80impl Bresenham {
81 #[inline]
84 pub fn new(start: Point, end: Point) -> Bresenham {
85 let octant = Octant::from_points(start, end);
86
87 let start = octant.to_octant0(start);
88 let end = octant.to_octant0(end);
89
90 let dx = end.x - start.x;
91 let dy = end.y - start.y;
92
93 Bresenham {
94 x: start.x,
95 y: start.y,
96 dx,
97 dy,
98 x1: end.x,
99 diff: dy - dx,
100 octant,
101 }
102 }
103
104 #[inline]
106 pub fn advance(&mut self) -> Point {
107 let p = Point::new(self.x, self.y);
108
109 if self.diff >= 0 {
110 self.y += 1;
111 self.diff -= self.dx;
112 }
113
114 self.diff += self.dy;
115
116 self.x += 1;
118
119 self.octant.from_octant0(p)
120 }
121}
122
123impl Iterator for Bresenham {
124 type Item = Point;
125
126 #[inline]
127 fn next(&mut self) -> Option<Self::Item> {
128 if self.x >= self.x1 {
129 None
130 } else {
131 Some(self.advance())
132 }
133 }
134}
135
136pub struct BresenhamInclusive(Bresenham);
138impl BresenhamInclusive {
139 #[inline]
141 pub fn new(start: Point, end: Point) -> Self {
142 Self(Bresenham::new(start, end))
143 }
144
145 #[inline]
147 pub fn advance(&mut self) -> Point {
148 self.0.advance()
149 }
150}
151impl Iterator for BresenhamInclusive {
152 type Item = Point;
153
154 #[inline]
155 fn next(&mut self) -> Option<Self::Item> {
156 if self.0.x > self.0.x1 {
157 None
158 } else {
159 Some(self.0.advance())
160 }
161 }
162}
163
164#[cfg(test)]
165mod tests {
166 use super::*;
167 use std::vec::Vec;
168
169 #[test]
170 fn test_empty() {
171 let bi = Bresenham::new(Point::new(0, 0), Point::new(0, 0));
172 let res: Vec<_> = bi.collect();
173 assert_eq!(res, []);
174
175 let bi = BresenhamInclusive::new(Point::new(0, 0), Point::new(0, 0));
176 let res: Vec<_> = bi.collect();
177 assert_eq!(res, [Point::new(0, 0)]);
178
179 let mut bi = BresenhamInclusive::new(Point::new(0, 0), Point::new(0, 0));
180 bi.advance();
181 let res: Vec<_> = bi.collect();
182 assert_eq!(res, []);
183 }
184
185 #[test]
186 fn test_wp_example() {
187 let start = Point::new(0, 1);
188 let end = Point::new(6, 4);
189
190 let bi = Bresenham::new(start, end);
191 let res: Vec<_> = bi.collect();
192 let mut expected = vec![
193 Point::new(0, 1),
194 Point::new(1, 1),
195 Point::new(2, 2),
196 Point::new(3, 2),
197 Point::new(4, 3),
198 Point::new(5, 3)
199 ];
200 assert_eq!(res, expected);
201
202 let bi = BresenhamInclusive::new(start, end);
203 let res: Vec<_> = bi.collect();
204 expected.push(end);
205 assert_eq!(res, expected);
206 }
207
208 #[test]
209 fn test_inverse_wp() {
210 let start = Point::new(6, 4);
211 let end = Point::new(0, 1);
212
213 let bi = Bresenham::new(start, end);
214 let res: Vec<_> = bi.collect();
215 let mut expected = vec![
216 Point::new(6, 4),
217 Point::new(5, 4),
218 Point::new(4, 3),
219 Point::new(3, 3),
220 Point::new(2, 2),
221 Point::new(1, 2)
222 ];
223 assert_eq!(res, expected);
224
225 let bi = BresenhamInclusive::new(start, end);
226 let res: Vec<_> = bi.collect();
227 expected.push(end);
228 assert_eq!(res, expected);
229 }
230
231 #[test]
232 fn test_straight_hline() {
233 let start = Point::new(2, 3);
234 let end = Point::new(5, 3);
235
236 let bi = Bresenham::new(start, end);
237 let res: Vec<_> = bi.collect();
238 let mut expected = vec![Point::new(2, 3), Point::new(3, 3), Point::new(4, 3)];
239 assert_eq!(res, expected);
240
241 let bi = BresenhamInclusive::new(start, end);
242 let res: Vec<_> = bi.collect();
243 expected.push(end);
244 assert_eq!(res, expected);
245 }
246
247 #[test]
248 fn test_straight_vline() {
249 let start = Point::new(2, 3);
250 let end = Point::new(2, 6);
251
252 let bi = Bresenham::new(start, end);
253 let res: Vec<_> = bi.collect();
254 let mut expected = vec![Point::new(2, 3), Point::new(2, 4), Point::new(2, 5)];
255 assert_eq!(res, expected);
256
257 let bi = BresenhamInclusive::new(start, end);
258 let res: Vec<_> = bi.collect();
259 expected.push(end);
260 assert_eq!(res, expected);
261 }
262
263 #[test]
264 fn test_issue135_line() {
265 let line = Bresenham::new(Point::new(0, 6), Point::new(6, 0));
266 let res: Vec<Point> = line.collect();
267 assert!(res.len() == 6);
268 res.iter().for_each(|p| {
269 assert!(p.x >= 0);
270 assert!(p.x < 7);
271 assert!(p.y >= 0);
272 assert!(p.y < 7);
273 });
274 }
275
276 #[test]
277 fn test_line_sweep() {
278 use crate::prelude::*;
279 let mut angle = Degrees::new(0.0);
280 let start_point = Point::new(20, 20);
281 while angle.0 < 360.0 {
282 let end_point = project_angle(Point::new(0, 0), 8.0, angle) + start_point;
283 let line = Bresenham::new(start_point, end_point);
284 let res: Vec<Point> = line.collect();
285 assert!(res.len() > 0);
286 res.iter().for_each(|p| {
287 assert!(p.x >= 10);
288 assert!(p.x < 30);
289 assert!(p.y >= 10);
290 assert!(p.y < 30);
291 });
292 angle.0 += 1.0;
293 }
294 }
295}