imageproc/drawing/
polygon.rs1use crate::definitions::Image;
2use crate::drawing::line::draw_line_segment_mut;
3use crate::drawing::Canvas;
4use crate::point::Point;
5use image::{GenericImage, ImageBuffer};
6use std::cmp::{max, min};
7use std::f32;
8use std::i32;
9
10#[must_use = "the function does not modify the original image"]
16pub fn draw_polygon<I>(image: &I, poly: &[Point<i32>], color: I::Pixel) -> Image<I::Pixel>
17where
18 I: GenericImage,
19{
20 let mut out = ImageBuffer::new(image.width(), image.height());
21 out.copy_from(image, 0, 0).unwrap();
22 draw_polygon_mut(&mut out, poly, color);
23 out
24}
25
26pub fn draw_polygon_mut<C>(canvas: &mut C, poly: &[Point<i32>], color: C::Pixel)
32where
33 C: Canvas,
34{
35 if poly.is_empty() {
36 return;
37 }
38 if poly[0] == poly[poly.len() - 1] {
39 panic!(
40 "First point {:?} == last point {:?}",
41 poly[0],
42 poly[poly.len() - 1]
43 );
44 }
45
46 let mut y_min = i32::MAX;
47 let mut y_max = i32::MIN;
48 for p in poly {
49 y_min = min(y_min, p.y);
50 y_max = max(y_max, p.y);
51 }
52
53 let (width, height) = canvas.dimensions();
54
55 y_min = max(0, min(y_min, height as i32 - 1));
57 y_max = max(0, min(y_max, height as i32 - 1));
58
59 let mut closed: Vec<Point<i32>> = poly.to_vec();
60 closed.push(poly[0]);
61
62 let edges: Vec<&[Point<i32>]> = closed.windows(2).collect();
63 let mut intersections = Vec::new();
64
65 for y in y_min..y_max + 1 {
66 for edge in &edges {
67 let p0 = edge[0];
68 let p1 = edge[1];
69
70 if p0.y <= y && p1.y >= y || p1.y <= y && p0.y >= y {
71 if p0.y == p1.y {
72 intersections.push(p0.x);
74 intersections.push(p1.x);
75 } else if p0.y == y || p1.y == y {
76 if p1.y > y {
77 intersections.push(p0.x);
78 }
79 if p0.y > y {
80 intersections.push(p1.x);
81 }
82 } else {
83 let fraction = (y - p0.y) as f32 / (p1.y - p0.y) as f32;
84 let inter = p0.x as f32 + fraction * (p1.x - p0.x) as f32;
85 intersections.push(inter.round() as i32);
86 }
87 }
88 }
89
90 intersections.sort_unstable();
91 intersections.chunks(2).for_each(|range| {
92 let mut from = min(range[0], width as i32);
93 let mut to = min(range[1], width as i32 - 1);
94 if from < width as i32 && to >= 0 {
95 from = max(0, from);
97 to = max(0, to);
98
99 for x in from..to + 1 {
100 canvas.draw_pixel(x as u32, y as u32, color);
101 }
102 }
103 });
104
105 intersections.clear();
106 }
107
108 for edge in &edges {
109 let start = (edge[0].x as f32, edge[0].y as f32);
110 let end = (edge[1].x as f32, edge[1].y as f32);
111 draw_line_segment_mut(canvas, start, end, color);
112 }
113}