1use crate::geometry::*;
2use image;
3use image::GenericImageView;
4
5pub type Grid<T> = Vec<Vec<T>>;
6
7pub struct ImagePolygon {
8 image: image::DynamicImage,
9 size: (u16, u16),
10}
11
12impl ImagePolygon {
13 pub fn new(image: image::DynamicImage) -> Self {
14 let dimensions = image.dimensions();
15 let size = (dimensions.0 as u16, dimensions.1 as u16);
16 Self { image, size }
17 }
18
19 fn get_opaque_points_grid(&self) -> Grid<bool> {
20 let rgba = &self.image.to_rgba16();
21 let mut opaque_points: Grid<bool> =
22 vec![vec![false; self.size.0 as usize]; self.size.1 as usize];
23 for y in 0..rgba.height() {
24 for x in 0..rgba.width() {
25 let pixel = rgba.get_pixel(x, y);
26 let alpha_channel = pixel.0[3];
27 opaque_points[y as usize][x as usize] = alpha_channel > 0;
28 }
29 }
30 opaque_points
31 }
32
33 fn get_edges_points(&self) -> Vec<Point> {
34 let opaque_points = self.get_opaque_points_grid();
35 let mut edge_points = Vec::new();
36
37 for (i, &is_opaque) in opaque_points.iter().flatten().enumerate() {
38 if is_opaque {
39 let x = i % self.size.0 as usize;
40 let y = i / self.size.0 as usize;
41
42 let left = opaque_points
43 .get(y)
44 .and_then(|row| row.get(x.wrapping_sub(1)));
45 let right = opaque_points.get(y).and_then(|row| row.get(x + 1));
46 let up = opaque_points
47 .get(y.wrapping_sub(1))
48 .and_then(|row| row.get(x));
49 let down = opaque_points.get(y + 1).and_then(|row| row.get(x));
50
51 if left != Some(&true)
52 || right != Some(&true)
53 || up != Some(&true)
54 || down != Some(&true)
55 {
56 edge_points.push(Point {
57 x: x as u16,
58 y: y as u16,
59 });
60 }
61 }
62 }
63
64 edge_points
65 }
66
67 fn get_first_point_of_main_polygon(&self) -> Point {
68 let grid = self.get_opaque_points_grid();
69 for (y, row) in grid.iter().enumerate() {
70 for (x, &is_opaque) in row.iter().enumerate() {
71 if is_opaque {
72 return Point {
73 x: x as u16,
74 y: y as u16,
75 };
76 }
77 }
78 }
79 panic!("No opaque points found");
80 }
81
82 pub fn to_polygon(&self) -> (Polygon, Vec<Polygon>) {
83 let mut holes: Vec<Polygon> = Vec::new();
84 let edge_points = self.get_edges_points();
85
86 let current_point = self.get_first_point_of_main_polygon();
87
88 let polygon = get_polygon_from_point(current_point, edge_points.clone());
89
90 let mut remaining_points = edge_points
92 .iter()
93 .filter(|point| !polygon.contains(point))
94 .cloned()
95 .collect::<Vec<_>>();
96
97 if edge_points.len() > polygon.len() {
98 loop {
99 if remaining_points.is_empty() {
100 break;
101 }
102
103 let hole = get_polygon_from_point(remaining_points[0], remaining_points.clone());
104
105 remaining_points = remaining_points
106 .iter()
107 .filter(|point| !hole.contains(point))
108 .cloned()
109 .collect::<Vec<_>>();
110
111 holes.push(hole);
112 }
113 }
114
115 (polygon, holes)
116 }
117}
118
119fn get_polygon_from_point(point: Point, all_points: Vec<Point>) -> Polygon {
120 let mut polygon: Polygon = Vec::new();
121 let mut current_point = point;
122 loop {
123 polygon.push(current_point);
124 let right_point = all_points
125 .iter()
126 .find(|&point| Some(point) == current_point.right().as_ref());
127 let right_up_point = all_points
128 .iter()
129 .find(|&point| Some(point) == current_point.right_up().as_ref());
130 let right_down_point = all_points
131 .iter()
132 .find(|&point| Some(point) == current_point.right_down().as_ref());
133 let up_point = all_points
134 .iter()
135 .find(|&point| Some(point) == current_point.up().as_ref());
136 let down_point = all_points
137 .iter()
138 .find(|&point| Some(point) == current_point.down().as_ref());
139 let left_point = all_points
140 .iter()
141 .find(|&point| Some(point) == current_point.left().as_ref());
142 let left_up_point = all_points
143 .iter()
144 .find(|&point| Some(point) == current_point.left_up().as_ref());
145 let left_down_point = all_points
146 .iter()
147 .find(|&point| Some(point) == current_point.left_down().as_ref());
148
149 match (
150 right_point,
151 right_up_point,
152 right_down_point,
153 up_point,
154 down_point,
155 left_point,
156 left_up_point,
157 left_down_point,
158 ) {
159 (Some(point), _, _, _, _, _, _, _) if !polygon.contains(point) => {
160 current_point = *point;
161 }
162 (_, Some(point), _, _, _, _, _, _) if !polygon.contains(point) => {
163 current_point = *point;
164 }
165 (_, _, Some(point), _, _, _, _, _) if !polygon.contains(point) => {
166 current_point = *point;
167 }
168 (_, _, _, Some(point), _, _, _, _) if !polygon.contains(point) => {
169 current_point = *point;
170 }
171 (_, _, _, _, Some(point), _, _, _) if !polygon.contains(point) => {
172 current_point = *point;
173 }
174 (_, _, _, _, _, Some(point), _, _) if !polygon.contains(point) => {
175 current_point = *point;
176 }
177 (_, _, _, _, _, _, Some(point), _) if !polygon.contains(point) => {
178 current_point = *point;
179 }
180 (_, _, _, _, _, _, _, Some(point)) if !polygon.contains(point) => {
181 current_point = *point;
182 }
183 _ => break,
184 }
185 }
186
187 polygon
188}
189impl From<Vec<u8>> for ImagePolygon {
190 fn from(data: Vec<u8>) -> Self {
191 Self::new(image::load_from_memory(&data).unwrap())
192 }
193}