Skip to main content

cazan_common/
image.rs

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        // If there's some points that are in the edge_points list but not in the polygon list, it means that there's holes
91        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}