Skip to main content

polyanya/
mesh_cleanup.rs

1use glam::Vec2;
2#[cfg(feature = "tracing")]
3use tracing::instrument;
4
5use crate::{instance::U32Layer, Layer, Mesh};
6
7impl Mesh {
8    /// Reorder all the neighboring polygons of all the vertices so that they are CCW ordered, and correctly mark corners.
9    pub fn reorder_neighbors_ccw_and_fix_corners(&mut self) {
10        let mut reordered_neighbors = vec![];
11        for layer in self.layers.iter() {
12            let mut reordered_neighbors_in_layer = vec![];
13            for vertex in &layer.vertices {
14                let vertex_coords = vertex.coords + layer.offset;
15                // For each polygon using a vertex, sort them in CCW order
16                let mut polygons = vertex
17                    .polygons
18                    .iter()
19                    .filter(|p| **p != u32::MAX)
20                    .cloned()
21                    .collect::<Vec<_>>();
22                // Sort by the angle between the Y axis and the direction from the vertex to the center of the polygon
23                polygons.sort_unstable_by_key(|p| {
24                    let vertices =
25                        &self.layers[p.layer() as usize].polygons[p.polygon() as usize].vertices;
26                    let center = vertices
27                        .iter()
28                        .map(|v| self.layers[p.layer() as usize].vertices[*v as usize].coords)
29                        .sum::<Vec2>()
30                        / vertices.len() as f32
31                        + self.layers[p.layer() as usize].offset;
32                    let direction = center - vertex_coords;
33                    let angle = Vec2::Y.angle_to(direction);
34                    (angle * 100000.0) as i32
35                });
36                polygons.dedup_by_key(|p| *p);
37                if polygons.is_empty() {
38                    reordered_neighbors_in_layer.push(vec![u32::MAX]);
39                } else {
40                    // Reintroduce empty markers
41                    // For two following polygons on a vertex, check their previous / next vertices
42                    // If they are different, there is a hole between them
43                    let first = polygons[0];
44                    let last = *polygons.last().unwrap();
45                    if first == last {
46                        polygons.push(u32::MAX);
47                    } else {
48                        polygons = polygons
49                            .windows(2)
50                            .map(|pair| [pair[0], pair[1]])
51                            .chain(std::iter::once([last, first]))
52                            .flat_map(|[pair0, pair1]| {
53                                let layer0 = &self.layers[pair0.layer() as usize];
54                                let layer1 = &self.layers[pair1.layer() as usize];
55                                let mut polygon0 =
56                                    layer0.polygons[pair0.polygon() as usize].vertices.clone();
57                                polygon0.reverse();
58                                let mut found = false;
59                                let Some(previous0) =
60                                    polygon0.iter().cycle().take(polygon0.len() * 2).find(|v| {
61                                        if found {
62                                            return true;
63                                        }
64                                        if (layer0.vertices[**v as usize].coords + layer0.offset)
65                                            .distance_squared(vertex_coords)
66                                            < 0.0001
67                                        {
68                                            found = true;
69                                        }
70                                        false
71                                    })
72                                else {
73                                    return vec![pair0, u32::MAX];
74                                };
75                                let polygon1 = &layer1.polygons[pair1.polygon() as usize].vertices;
76                                let mut found = false;
77                                let Some(next1) =
78                                    polygon1.iter().cycle().take(polygon1.len() * 2).find(|v| {
79                                        if found {
80                                            return true;
81                                        }
82                                        if (layer1.vertices[**v as usize].coords + layer1.offset)
83                                            .distance_squared(vertex_coords)
84                                            < 0.0001
85                                        {
86                                            found = true;
87                                        }
88                                        false
89                                    })
90                                else {
91                                    return vec![pair0, u32::MAX];
92                                };
93
94                                if layer0.vertices[*previous0 as usize].coords + layer0.offset
95                                    != layer1.vertices[*next1 as usize].coords + layer1.offset
96                                {
97                                    vec![pair0, u32::MAX]
98                                } else {
99                                    vec![pair0]
100                                }
101                            })
102                            .collect();
103                    }
104                    reordered_neighbors_in_layer.push(polygons);
105                }
106            }
107
108            reordered_neighbors.push(reordered_neighbors_in_layer);
109        }
110        for (layer, new) in self.layers.iter_mut().zip(reordered_neighbors.into_iter()) {
111            for (vertex, new) in layer.vertices.iter_mut().zip(new.into_iter()) {
112                vertex.is_corner = new.contains(&u32::MAX);
113                vertex.polygons = new;
114            }
115        }
116    }
117
118    /// Remove vertices that are not used by any polygon, and update indexes.
119    #[cfg_attr(feature = "tracing", instrument(skip_all))]
120    pub fn remove_useless_vertices(&mut self) -> bool {
121        !self
122            .layers
123            .iter_mut()
124            .map(|layer| layer.remove_useless_vertices())
125            .all(|m| !m)
126    }
127
128    /// Update the `is_one_way` flag for each polygon.
129    #[cfg_attr(feature = "tracing", instrument(skip_all))]
130    pub fn update_is_one_way(&mut self) {
131        self.layers
132            .iter_mut()
133            .for_each(|layer| layer.update_is_one_way());
134    }
135}
136
137impl Layer {
138    /// Remove vertices that are not used by any polygon, and update indexes.
139    #[cfg_attr(feature = "tracing", instrument(skip_all))]
140    pub fn remove_useless_vertices(&mut self) -> bool {
141        let mut removed = false;
142        let mut new_indexes = vec![u32::MAX; self.vertices.len()];
143        let mut kept = 0;
144        for (i, vertex) in self.vertices.iter().enumerate() {
145            if vertex.polygons.is_empty() || vertex.polygons == [u32::MAX] {
146                removed = true;
147            } else {
148                new_indexes[i] = kept;
149                kept += 1;
150            }
151        }
152        for polygon in self.polygons.iter_mut() {
153            for vertex in polygon.vertices.iter_mut() {
154                *vertex = new_indexes[*vertex as usize];
155            }
156        }
157        self.vertices = self
158            .vertices
159            .iter()
160            .enumerate()
161            .filter_map(|(i, _)| {
162                if new_indexes[i] != u32::MAX {
163                    Some(self.vertices[i].clone())
164                } else {
165                    None
166                }
167            })
168            .collect();
169        if !self.height.is_empty() {
170            self.height = self
171                .height
172                .iter()
173                .enumerate()
174                .filter_map(|(i, _)| {
175                    if new_indexes[i] != u32::MAX {
176                        Some(self.height[i])
177                    } else {
178                        None
179                    }
180                })
181                .collect();
182        }
183        removed
184    }
185
186    /// Update the `is_one_way` flag for each polygon.
187    #[cfg_attr(feature = "tracing", instrument(skip_all))]
188    pub fn update_is_one_way(&mut self) {
189        for polygon in self.polygons.iter_mut() {
190            if polygon.vertices.len() == 3 {
191                polygon.is_one_way = polygon
192                    .vertices
193                    .iter()
194                    .any(|vertex| self.vertices[*vertex as usize].polygons.len() == 2);
195            } else {
196                polygon.is_one_way = polygon
197                    .vertices
198                    .iter()
199                    .filter(|vertex| self.vertices[**vertex as usize].polygons.len() == 2)
200                    .count()
201                    == polygon.vertices.len() - 2;
202            }
203        }
204    }
205}