1use crate::definitions::Image;
2use crate::drawing::line::{draw_antialiased_line_segment_mut, draw_line_segment_mut};
3use crate::drawing::Canvas;
4use crate::point::Point;
5use image::{GenericImage, ImageBuffer};
6use std::cmp::{max, min};
7
8#[must_use = "the function does not modify the original image"]
9fn draw_polygon_with<I, L>(
10 image: &I,
11 poly: &[Point<i32>],
12 color: I::Pixel,
13 plotter: L,
14) -> Image<I::Pixel>
15where
16 I: GenericImage,
17 L: Fn(&mut Image<I::Pixel>, (f32, f32), (f32, f32), I::Pixel),
18{
19 let mut out = ImageBuffer::new(image.width(), image.height());
20 out.copy_from(image, 0, 0).unwrap();
21 draw_polygon_with_mut(&mut out, poly, color, plotter);
22 out
23}
24
25fn draw_polygon_with_mut<C, L>(canvas: &mut C, poly: &[Point<i32>], color: C::Pixel, plotter: L)
26where
27 C: Canvas,
28 L: Fn(&mut C, (f32, f32), (f32, f32), C::Pixel),
29{
30 if poly.is_empty() {
31 return;
32 }
33 if poly[0] == poly[poly.len() - 1] {
34 panic!(
35 "First point {:?} == last point {:?}",
36 poly[0],
37 poly[poly.len() - 1]
38 );
39 }
40
41 let mut y_min = i32::MAX;
42 let mut y_max = i32::MIN;
43 for p in poly {
44 y_min = min(y_min, p.y);
45 y_max = max(y_max, p.y);
46 }
47
48 let (width, height) = canvas.dimensions();
49
50 y_min = max(0, min(y_min, height as i32 - 1));
52 y_max = max(0, min(y_max, height as i32 - 1));
53
54 let mut closed: Vec<Point<i32>> = poly.to_vec();
55 closed.push(poly[0]);
56
57 let edges: Vec<&[Point<i32>]> = closed.windows(2).collect();
58 let mut intersections = Vec::new();
59
60 for y in y_min..y_max + 1 {
61 for edge in &edges {
62 let p0 = edge[0];
63 let p1 = edge[1];
64
65 if p0.y <= y && p1.y >= y || p1.y <= y && p0.y >= y {
66 if p0.y == p1.y {
67 intersections.push(p0.x);
69 intersections.push(p1.x);
70 } else if p0.y == y || p1.y == y {
71 if p1.y > y {
72 intersections.push(p0.x);
73 }
74 if p0.y > y {
75 intersections.push(p1.x);
76 }
77 } else {
78 let fraction = (y - p0.y) as f32 / (p1.y - p0.y) as f32;
79 let inter = p0.x as f32 + fraction * (p1.x - p0.x) as f32;
80 intersections.push(inter.round() as i32);
81 }
82 }
83 }
84
85 intersections.sort_unstable();
86 intersections.chunks(2).for_each(|range| {
87 let mut from = min(range[0], width as i32);
88 let mut to = min(range[1], width as i32 - 1);
89 if from < width as i32 && to >= 0 {
90 from = max(0, from);
92 to = max(0, to);
93
94 for x in from..to + 1 {
95 canvas.draw_pixel(x as u32, y as u32, color);
96 }
97 }
98 });
99
100 intersections.clear();
101 }
102
103 for edge in &edges {
104 let start = (edge[0].x as f32, edge[0].y as f32);
105 let end = (edge[1].x as f32, edge[1].y as f32);
106 plotter(canvas, start, end, color);
107 }
108}
109
110pub fn draw_polygon<I>(image: &I, poly: &[Point<i32>], color: I::Pixel) -> Image<I::Pixel>
116where
117 I: GenericImage,
118{
119 draw_polygon_with(image, poly, color, draw_line_segment_mut)
120}
121
122pub fn draw_polygon_mut<C>(canvas: &mut C, poly: &[Point<i32>], color: C::Pixel)
128where
129 C: Canvas,
130{
131 draw_polygon_with_mut(canvas, poly, color, draw_line_segment_mut);
132}
133
134pub fn draw_antialiased_polygon<I, B>(
143 image: &I,
144 poly: &[Point<i32>],
145 color: I::Pixel,
146 blend: B,
147) -> Image<I::Pixel>
148where
149 I: GenericImage,
150 B: Fn(I::Pixel, I::Pixel, f32) -> I::Pixel,
151{
152 draw_polygon_with(image, poly, color, |image, start, end, color| {
153 draw_antialiased_line_segment_mut(
154 image,
155 (start.0 as i32, start.1 as i32),
156 (end.0 as i32, end.1 as i32),
157 color,
158 &blend,
159 )
160 })
161}
162
163pub fn draw_antialiased_polygon_mut<I, B>(
172 image: &mut I,
173 poly: &[Point<i32>],
174 color: I::Pixel,
175 blend: B,
176) where
177 I: GenericImage,
178 B: Fn(I::Pixel, I::Pixel, f32) -> I::Pixel,
179{
180 draw_polygon_with_mut(image, poly, color, |image, start, end, color| {
181 draw_antialiased_line_segment_mut(
182 image,
183 (start.0 as i32, start.1 as i32),
184 (end.0 as i32, end.1 as i32),
185 color,
186 &blend,
187 )
188 });
189}
190
191pub fn draw_hollow_polygon<I>(
199 image: &mut I,
200 poly: &[Point<f32>],
201 color: I::Pixel,
202) -> Image<I::Pixel>
203where
204 I: GenericImage,
205{
206 let mut out = ImageBuffer::new(image.width(), image.height());
207 out.copy_from(image, 0, 0).unwrap();
208 draw_hollow_polygon_mut(&mut out, poly, color);
209 out
210}
211
212pub fn draw_hollow_polygon_mut<C>(canvas: &mut C, poly: &[Point<f32>], color: C::Pixel)
220where
221 C: Canvas,
222{
223 if poly.is_empty() {
224 return;
225 }
226 if poly.len() < 2 {
227 panic!(
228 "Polygon only has {} points, but at least two are needed.",
229 poly.len(),
230 );
231 }
232 if poly[0] == poly[poly.len() - 1] {
233 panic!(
234 "First point {:?} == last point {:?}",
235 poly[0],
236 poly[poly.len() - 1]
237 );
238 }
239 for window in poly.windows(2) {
240 crate::drawing::draw_line_segment_mut(
241 canvas,
242 (window[0].x, window[0].y),
243 (window[1].x, window[1].y),
244 color,
245 );
246 }
247 let first = poly[0];
248 let last = poly.iter().last().unwrap();
249 crate::drawing::draw_line_segment_mut(canvas, (first.x, first.y), (last.x, last.y), color);
250}