mesh_graph/ops/
collapse.rs1use hashbrown::{HashMap, HashSet};
2use itertools::Itertools;
3
4use crate::{FaceId, HalfedgeId, MeshGraph, Selection, SelectionOps, VertexId};
5
6impl MeshGraph {
7 pub fn collapse_until_edges_above_min_length(
12 &mut self,
13 min_length_squared: f32,
14 selection: &mut Selection,
15 ) {
16 let mut dedup_halfedges = HashSet::new();
17
18 for he in selection.resolve_to_halfedges(self) {
19 let twin = self.halfedges[he].twin;
20 let twin_already_in = twin
21 .map(|twin| dedup_halfedges.contains(&twin))
22 .unwrap_or_default();
23
24 if !twin_already_in {
25 dedup_halfedges.insert(he);
26 }
27 }
28
29 let mut halfedges_to_collapse = dedup_halfedges
30 .into_iter()
31 .filter_map(|he| {
32 let len = self.halfedges[he].length_squared(self);
33 (len < min_length_squared).then_some((he, len))
34 })
35 .collect::<HashMap<_, _>>();
36
37 while !halfedges_to_collapse.is_empty() {
38 let mut min_len = f32::MAX;
39 let mut min_he = HalfedgeId::default();
40
41 for (&he, &len) in &halfedges_to_collapse {
42 if len < min_len {
43 min_len = len;
44 min_he = he;
45 }
46 }
47
48 let start_vertex = self.halfedges[min_he].start_vertex(self);
49
50 let (verts, halfedges, faces) = self.collapse_edge(min_he);
51
52 #[cfg(feature = "rerun")]
53 {
54 crate::RR
55 .log("meshgraph/face/disolve", &rerun::Clear::recursive())
56 .unwrap();
57 crate::RR
58 .log("meshgraph/halfedge/disolve", &rerun::Clear::recursive())
59 .unwrap();
60 crate::RR
61 .log("meshgraph/vertex/disolve", &rerun::Clear::recursive())
62 .unwrap();
63 self.log_rerun();
64 }
65
66 halfedges_to_collapse.remove(&min_he);
67
68 for vert in verts {
69 selection.remove(vert);
70 }
71 for halfedge in halfedges {
72 selection.remove(halfedge);
73 halfedges_to_collapse.remove(&halfedge);
74 }
75 for face in faces {
76 selection.remove(face);
77 }
78
79 for halfedge_id in self.vertices[start_vertex].outgoing_halfedges(self) {
80 let halfedge = &self.halfedges[halfedge_id];
81
82 let len = halfedge.length_squared(self);
83
84 if len < min_length_squared {
85 halfedges_to_collapse.insert(halfedge_id, len);
86 } else {
87 halfedges_to_collapse.remove(&halfedge_id);
88 }
89
90 if let Some(twin) = halfedge.twin {
91 halfedges_to_collapse.remove(&twin);
92 }
93
94 if let Some(face) = halfedge.face {
95 self.qbvh.pre_update_or_insert(self.faces[face]);
96 }
97 selection.insert(halfedge_id);
98 }
99
100 #[cfg(feature = "rerun")]
101 {
102 self.log_rerun();
103 }
104 }
105 }
106
107 pub fn collapse_edge(
113 &mut self,
114 halfedge_id: HalfedgeId,
115 ) -> (Vec<VertexId>, Vec<HalfedgeId>, Vec<FaceId>) {
116 #[cfg(feature = "rerun")]
117 {
118 self.log_he_rerun("disolve/he", halfedge_id);
119 }
120
121 let mut removed_halfedges = Vec::new();
124 let mut removed_faces = Vec::new();
125
126 let he = self.halfedges[halfedge_id];
127
128 let start_vert = he.start_vertex(self);
129 let end_vert = he.end_vertex;
130
131 #[cfg(feature = "rerun")]
132 {
133 self.log_he_rerun("disolve/remove_disolved", halfedge_id);
134 self.log_he_rerun("disolve/remove_twin", he.twin());
135 self.log_vert_rerun("disolve/remove_end", end_vert);
136 }
137
138 let end_outgoing_halfedges = self.vertices[end_vert].outgoing_halfedges(self);
139 let end_incoming_halfedges = self.vertices[end_vert].incoming_halfedges(self);
140
141 let center = (self.positions[start_vert] + self.positions[end_vert]) * 0.5;
142
143 let (face_id, halfedges) = self.remove_halfedge_face(halfedge_id);
144 removed_faces.push(face_id);
145 removed_halfedges.extend(halfedges);
146 removed_halfedges.push(halfedge_id);
147
148 let twin = he.twin();
149 if !self.halfedges[twin].is_boundary() {
150 let (face_id, halfedges) = self.remove_halfedge_face(twin);
151 removed_faces.push(face_id);
152 removed_halfedges.extend(halfedges);
153 }
154 removed_halfedges.push(twin);
155
156 for end_incoming_he in end_incoming_halfedges {
157 if let Some(end_incoming_he_mut) = self.halfedges.get_mut(end_incoming_he) {
158 end_incoming_he_mut.end_vertex = start_vert;
159 }
160 }
161
162 self.vertices.remove(end_vert);
163 self.positions.remove(end_vert);
164 if let Some(normals) = &mut self.vertex_normals {
165 normals.remove(end_vert);
166 }
167 self.halfedges.remove(halfedge_id);
168 self.halfedges.remove(twin);
169 removed_halfedges.push(twin);
170
171 self.positions[start_vert] = center;
172
173 self.vertices[start_vert].outgoing_halfedge = end_outgoing_halfedges
174 .into_iter()
175 .find(|he_id| self.halfedges.contains_key(*he_id));
176
177 #[cfg(feature = "rerun")]
178 {
179 self.log_he_rerun(
180 "disolve/outgoing",
181 self.vertices[start_vert].outgoing_halfedge.unwrap(),
182 );
183 }
184
185 let mut removed_vertices = vec![end_vert];
186
187 let mut face_tuples: Vec<_> = self.vertices[start_vert]
189 .faces(self)
190 .into_iter()
191 .circular_tuple_windows()
192 .collect();
193
194 while let Some((face_id1, face_id2)) = face_tuples.pop() {
195 if self.faces_share_all_vertices(face_id1, face_id2) {
196 let (vs, hes) = self.delete_face(face_id1);
197 removed_vertices.extend(vs);
198 removed_halfedges.extend(hes);
199 removed_faces.push(face_id1);
200
201 let (vs, hes) = self.delete_face(face_id2);
202 removed_vertices.extend(vs);
203 removed_halfedges.extend(hes);
204 removed_faces.push(face_id2);
205
206 face_tuples.pop();
208 }
209 }
210
211 (removed_vertices, removed_halfedges, removed_faces)
212 }
213
214 fn remove_halfedge_face(&mut self, halfedge_id: HalfedgeId) -> (FaceId, [HalfedgeId; 2]) {
217 let he = self.halfedges[halfedge_id];
218
219 let face_id = he
220 .face
221 .expect("only called from disolve_edge() when there is a face");
222
223 let next_he_id = he.next.unwrap();
224 let prev_he_id = he.prev(self).unwrap();
225
226 let next_twin_id = self.halfedges[next_he_id].twin;
227 let prev_twin_id = self.halfedges[prev_he_id].twin;
228
229 let next_he = self.halfedges[next_he_id];
230 let prev_he = self.halfedges[prev_he_id];
231
232 let next_end_v_id = next_he.end_vertex;
233 let prev_end_v_id = prev_he.end_vertex;
234
235 self.vertices[next_end_v_id].outgoing_halfedge = next_he.next;
236 self.vertices[prev_end_v_id].outgoing_halfedge = prev_he.next;
237
238 let prev_start_v_id = prev_he.start_vertex(self);
239 let prev_start_v = self.vertices[prev_start_v_id];
240
241 if prev_start_v.outgoing_halfedge == Some(prev_he_id) {
242 self.vertices[prev_start_v_id].outgoing_halfedge = prev_he
243 .ccw_rotated_neighbour(self)
244 .or_else(|| prev_he.cw_rotated_neighbour(self));
245 }
246
247 #[cfg(feature = "rerun")]
248 {
249 self.log_face_rerun("disolve/remove_face", face_id);
250 self.log_he_rerun("disolve/remove_next", next_he_id);
251 self.log_he_rerun("disolve/remove_prev", prev_he_id);
252 }
253
254 self.qbvh.remove(self.faces[face_id]);
255
256 self.halfedges.remove(next_he_id);
257 self.halfedges.remove(prev_he_id);
258 self.faces.remove(face_id);
259
260 if let Some(next_twin) = next_twin_id {
261 self.halfedges[next_twin].twin = prev_twin_id;
262 }
263
264 if let Some(prev_twin) = prev_twin_id {
265 self.halfedges[prev_twin].twin = next_twin_id;
266 }
267
268 (face_id, [next_he_id, prev_he_id])
269 }
270}