1use crate::{BinaryImage, PointI32};
2
3pub fn bresenham(p0: PointI32, p1: PointI32) -> BresenhamIterator {
6 let dx = p1.x - p0.x;
7 let dy = p1.y - p0.y;
8 let adx = dx.abs();
9 let ady = dy.abs();
10 let eps = 0;
11 let sx = if dx > 0 { 1 } else { -1 };
12 let sy = if dy > 0 { 1 } else { -1 };
13 BresenhamIterator { x: p0.x, y: p0.y, sx, sy, eps, adx, ady, p: p1, horizontal: adx > ady }
14}
15
16pub struct BresenhamIterator {
17 x: i32,
18 y: i32,
19 sx: i32,
20 sy: i32,
21 eps: i32,
22 adx: i32,
23 ady: i32,
24 p: PointI32,
25 horizontal: bool,
26}
27
28impl Iterator for BresenhamIterator {
29 type Item = PointI32;
30
31 fn next(&mut self) -> Option<Self::Item> {
32 if self.horizontal {
33 if if self.sx < 0 { self.x >= self.p.x } else { self.x <= self.p.x } {
34 let pp = PointI32::new(self.x, self.y);
35 self.eps += self.ady;
36 if (self.eps << 1) >= self.adx {
37 self.y += self.sy;
38 self.eps -= self.adx;
39 }
40 self.x += self.sx;
41 return Some(pp);
42 }
43 None
44 } else {
45 if if self.sy < 0 { self.y >= self.p.y } else { self.y <= self.p.y } {
46 let pp = PointI32::new(self.x, self.y);
47 self.eps += self.adx;
48 if (self.eps << 1) >= self.ady {
49 self.x += self.sx;
50 self.eps -= self.ady;
51 }
52 self.y += self.sy;
53 return Some(pp);
54 }
55 None
56 }
57 }
58}
59
60pub fn walk_triangle(triangle: &[PointI32; 3]) -> TriangleRasterizer {
63 let mut points: Vec<PointI32> =
65 bresenham(triangle[1], triangle[2])
66 .chain(&mut bresenham(triangle[0], triangle[2]))
67 .chain(&mut bresenham(triangle[0], triangle[1]))
68 .collect();
69
70 points.sort_by(|a, b| if a.y == b.y { a.x.cmp(&b.x) } else { a.y.cmp(&b.y) });
72
73 TriangleRasterizer {
74 points,
75 counter: 0,
76 span: None,
77 }
78}
79
80pub fn rasterize_triangle(triangle: &[PointI32; 3], image: &mut BinaryImage) {
82 for p in walk_triangle(triangle) {
83 image.set_pixel_safe(p.x, p.y, true);
84 }
85}
86
87pub struct TriangleRasterizer {
88 points: Vec<PointI32>,
89 counter: usize,
90 span: Option<SpanRasterizer>,
91}
92
93impl Iterator for TriangleRasterizer {
94 type Item = PointI32;
95
96 fn next(&mut self) -> Option<Self::Item> {
97 if self.span.is_some() {
98 if let Some(p) = self.span.as_mut().unwrap().next() {
99 return Some(p);
100 } else {
101 self.span = None;
102 self.counter += 1;
103 }
105 }
106 if self.counter >= self.points.len() {
107 return None;
108 }
109 let point = self.points[self.counter];
110 if self.counter + 1 < self.points.len() {
111 let next = self.points[self.counter + 1];
112
113 if point.y == next.y {
114 self.span = Some(SpanRasterizer {
115 x: point.x,
116 x1: next.x,
117 y: point.y,
118 });
119 return self.next();
121 }
122 }
123 self.counter += 1;
124 Some(PointI32::new(point.x, point.y))
125 }
126}
127
128struct SpanRasterizer {
129 x: i32,
130 x1: i32,
131 y: i32,
132}
133
134impl Iterator for SpanRasterizer {
135 type Item = PointI32;
136
137 fn next(&mut self) -> Option<Self::Item> {
138 if self.x < self.x1 {
139 let p = PointI32::new(self.x, self.y);
140 self.x += 1;
141 Some(p)
142 } else {
143 None
144 }
145 }
146}
147
148#[cfg(test)]
149mod tests {
150 use super::*;
151
152 #[test]
153 fn test_triangle_1() {
154 assert_eq!(
155 walk_triangle(&[PointI32::new(0, 0), PointI32::new(4, 4), PointI32::new(4, 0)])
156 .collect::<Vec<_>>(),
157 vec![
158 PointI32::new(0, 0),
159 PointI32::new(1, 0),
160 PointI32::new(2, 0),
161 PointI32::new(3, 0),
162 PointI32::new(4, 0),
163 PointI32::new(1, 1),
164 PointI32::new(2, 1),
165 PointI32::new(3, 1),
166 PointI32::new(4, 1),
167 PointI32::new(2, 2),
168 PointI32::new(3, 2),
169 PointI32::new(4, 2),
170 PointI32::new(3, 3),
171 PointI32::new(4, 3),
172 PointI32::new(4, 4),
173 ]
174 );
175 }
176
177 #[test]
178 fn test_triangle_2() {
179 assert_eq!(
180 walk_triangle(&[PointI32::new(1, 1), PointI32::new(8, 4), PointI32::new(4, 8)])
181 .collect::<Vec<_>>(),
182 vec![
183 PointI32::new(1, 1),
184 PointI32::new(2, 1),
185 PointI32::new(1, 2),
186 PointI32::new(2, 2),
187 PointI32::new(3, 2),
188 PointI32::new(4, 2),
189 PointI32::new(2, 3),
190 PointI32::new(3, 3),
191 PointI32::new(4, 3),
192 PointI32::new(5, 3),
193 PointI32::new(6, 3),
194 PointI32::new(2, 4),
195 PointI32::new(3, 4),
196 PointI32::new(4, 4),
197 PointI32::new(5, 4),
198 PointI32::new(6, 4),
199 PointI32::new(7, 4),
200 PointI32::new(8, 4),
201 PointI32::new(3, 5),
202 PointI32::new(4, 5),
203 PointI32::new(5, 5),
204 PointI32::new(6, 5),
205 PointI32::new(7, 5),
206 PointI32::new(3, 6),
207 PointI32::new(4, 6),
208 PointI32::new(5, 6),
209 PointI32::new(6, 6),
210 PointI32::new(4, 7),
211 PointI32::new(5, 7),
212 PointI32::new(4, 8),
213 ]
214 );
215 }
216
217 #[test]
218 fn rasterize_triangle_1() {
219 let mut image = BinaryImage::new_w_h(5, 5);
220 rasterize_triangle(&[PointI32::new(0, 0), PointI32::new(4, 4), PointI32::new(4, 0)], &mut image);
221 assert_eq!(image.to_string(),
222 "*****\n".to_owned() +
223 "-****\n" +
224 "--***\n" +
225 "---**\n" +
226 "----*\n"
227 );
228 }
229
230 #[test]
231 fn rasterize_triangle_2() {
232 let mut image = BinaryImage::new_w_h(5, 5);
233 rasterize_triangle(&[PointI32::new(0, 0), PointI32::new(0, 4), PointI32::new(4, 4)], &mut image);
234 assert_eq!(image.to_string(),
235 "*----\n".to_owned() +
236 "**---\n" +
237 "***--\n" +
238 "****-\n" +
239 "*****\n"
240 );
241 }
242
243 #[test]
244 fn rasterize_triangle_3() {
245 let mut image = BinaryImage::new_w_h(6, 11);
246 rasterize_triangle(&[PointI32::new(0, 0), PointI32::new(5, 5), PointI32::new(0, 10)], &mut image);
247 assert_eq!(image.to_string(),
248 "*-----\n".to_owned() +
249 "**----\n" +
250 "***---\n" +
251 "****--\n" +
252 "*****-\n" +
253 "******\n" +
254 "*****-\n" +
255 "****--\n" +
256 "***---\n" +
257 "**----\n" +
258 "*-----\n"
259 );
260 }
261
262}