1use glam::Vec3;
2use hashbrown::{HashMap, HashSet};
3use itertools::Itertools;
4use tracing::{error, instrument};
5
6use crate::{
7 FaceId, HalfedgeId, MeshGraph, Selection, SelectionOps, VertexId, error_none,
8 utils::unwrap_or_return,
9};
10
11impl MeshGraph {
12 #[instrument(skip(self))]
17 pub fn collapse_until_edges_above_min_length(
18 &mut self,
19 min_length_squared: f32,
20 selection: &mut Selection,
21 ) {
22 let mut dedup_halfedges = HashSet::new();
23
24 for he in selection.resolve_to_halfedges(self) {
25 let twin = self
26 .halfedges
27 .get(he)
28 .or_else(error_none!("Halfedge not found"))
29 .and_then(|he| he.twin.or_else(error_none!("Twin missing")));
30 let twin_already_in = twin
31 .map(|twin| dedup_halfedges.contains(&twin))
32 .unwrap_or_default();
33
34 if !twin_already_in {
35 dedup_halfedges.insert(he);
36 }
37 }
38
39 let mut halfedges_to_collapse = dedup_halfedges
40 .into_iter()
41 .filter_map(|he| {
42 let len = self.halfedges[he].length_squared(self);
43 (len < min_length_squared).then_some((he, len))
44 })
45 .collect::<HashMap<_, _>>();
46
47 while !halfedges_to_collapse.is_empty() {
48 let mut min_len = f32::MAX;
49 let mut min_he = HalfedgeId::default();
50
51 for (&he, &len) in &halfedges_to_collapse {
52 if len < min_len {
53 min_len = len;
54 min_he = he;
55 }
56 }
57
58 let start_vertex = self.halfedges[min_he].start_vertex(self);
59
60 let (verts, halfedges, faces) = self.collapse_edge(min_he);
61
62 #[cfg(feature = "rerun")]
63 {
64 crate::RR
65 .log("meshgraph/face/collapse", &rerun::Clear::recursive())
66 .unwrap();
67 crate::RR
68 .log("meshgraph/halfedge/collapse", &rerun::Clear::recursive())
69 .unwrap();
70 crate::RR
71 .log("meshgraph/vertex/collapse", &rerun::Clear::recursive())
72 .unwrap();
73 self.log_rerun();
74 }
75
76 halfedges_to_collapse.remove(&min_he);
77
78 for vert in verts {
79 selection.remove(vert);
80 }
81 for halfedge in halfedges {
82 selection.remove(halfedge);
83 halfedges_to_collapse.remove(&halfedge);
84 }
85 for face in faces {
86 selection.remove(face);
87 }
88
89 if let Some(start_vertex) = start_vertex {
90 let outgoing_halfedges = self
91 .vertices
92 .get(start_vertex)
93 .or_else(error_none!("Vertex for start vertex not found"))
94 .map(|vertex| vertex.outgoing_halfedges(self).collect::<Vec<_>>())
95 .unwrap_or_default();
96
97 for halfedge_id in outgoing_halfedges {
98 if let Some(halfedge) = self.halfedges.get(halfedge_id) {
99 let len = halfedge.length_squared(self);
100
101 if len < min_length_squared {
102 halfedges_to_collapse.insert(halfedge_id, len);
103 } else {
104 halfedges_to_collapse.remove(&halfedge_id);
105 }
106
107 if let Some(twin) = halfedge.twin {
108 halfedges_to_collapse.remove(&twin);
109 }
110
111 if let Some(face_id) = halfedge.face {
112 if let Some(face) = self.faces.get(face_id) {
113 self.bvh.insert_or_update_partially(
114 face.aabb(self),
115 face.index,
116 0.0,
117 );
118 } else {
119 error!("Face not found. BVH will not be updated.");
120 }
121 }
122 selection.insert(halfedge_id);
123 } else {
124 error!("Halfedge not found");
125 }
126 }
127 } else {
128 error!("Start vertex not found")
129 }
130
131 #[cfg(feature = "rerun")]
132 {
133 self.log_rerun();
134 }
135 }
136 }
137
138 #[instrument(skip(self))]
147 pub fn collapse_edge(
148 &mut self,
149 halfedge_id: HalfedgeId,
150 ) -> (Vec<VertexId>, Vec<HalfedgeId>, Vec<FaceId>) {
151 #[cfg(feature = "rerun")]
152 {
153 self.log_he_rerun("collapse/he", halfedge_id);
154 }
155
156 let mut removed_vertices = Vec::new();
159 let mut removed_halfedges = Vec::new();
160 let mut removed_faces = Vec::new();
161
162 let he = *unwrap_or_return!(
163 self.halfedges.get(halfedge_id),
164 "Halfedge not found",
165 (removed_vertices, removed_halfedges, removed_faces)
166 );
167
168 let start_vert_id = unwrap_or_return!(
169 he.start_vertex(self),
170 "Start vertex not found",
171 (removed_vertices, removed_halfedges, removed_faces)
172 );
173 let end_vert_id = he.end_vertex;
174
175 #[cfg(feature = "rerun")]
176 {
177 self.log_he_rerun("collapse/remove_collapsed", halfedge_id);
178 if let Some(twin) = he.twin {
179 self.log_he_rerun("collapse/remove_twin", twin);
180 }
181 self.log_vert_rerun("collapse/remove_end", end_vert_id);
182 }
183
184 let end_outgoing_halfedges = self.vertices[end_vert_id]
185 .outgoing_halfedges(self)
186 .collect::<Vec<_>>();
187 let end_incoming_halfedges = self.vertices[end_vert_id]
188 .incoming_halfedges(self)
189 .collect::<Vec<_>>();
190
191 let start_pos = *unwrap_or_return!(
192 self.positions.get(start_vert_id),
193 "Start position not found",
194 (removed_vertices, removed_halfedges, removed_faces)
195 );
196 let end_pos = *unwrap_or_return!(
197 self.positions.get(end_vert_id),
198 "End position not found",
199 (removed_vertices, removed_halfedges, removed_faces)
200 );
201
202 let center_pos = (start_pos + end_pos) * 0.5;
203
204 let mut normal = None;
205 if !he.is_boundary() {
206 let next_id = unwrap_or_return!(
207 he.next,
208 "Next halfedge not found",
209 (removed_vertices, removed_halfedges, removed_faces)
210 );
211 let next = unwrap_or_return!(
212 self.halfedges.get(next_id),
213 "Halfedge not found",
214 (removed_vertices, removed_halfedges, removed_faces)
215 );
216 let third_pos = unwrap_or_return!(
217 self.positions.get(next.end_vertex),
218 "Third position not found",
219 (removed_vertices, removed_halfedges, removed_faces)
220 );
221
222 normal = Some(
223 (start_pos - end_pos)
224 .cross(start_pos - third_pos)
225 .normalize(),
226 );
227
228 let (face_id, halfedges) = unwrap_or_return!(
229 self.remove_halfedge_face(halfedge_id),
230 "Could not remove face",
231 (removed_vertices, removed_halfedges, removed_faces)
232 );
233 removed_faces.push(face_id);
234 removed_halfedges.extend(halfedges);
235 }
236 removed_halfedges.push(halfedge_id);
237
238 let twin_id = unwrap_or_return!(
239 he.twin,
240 "Twin missing",
241 (removed_vertices, removed_halfedges, removed_faces)
242 );
243 let twin = unwrap_or_return!(
244 self.halfedges.get(twin_id),
245 "Halfedge not found",
246 (removed_vertices, removed_halfedges, removed_faces)
247 );
248
249 if !twin.is_boundary() {
250 if normal.is_none() {
251 let twin_id = unwrap_or_return!(
252 twin.next,
253 "Twin missing",
254 (removed_vertices, removed_halfedges, removed_faces)
255 );
256 let twin = unwrap_or_return!(
257 self.halfedges.get(twin_id),
258 "Halfedge not found",
259 (removed_vertices, removed_halfedges, removed_faces)
260 );
261 let third_pos = unwrap_or_return!(
262 self.positions.get(twin.end_vertex),
263 "Could not find third position",
264 (removed_vertices, removed_halfedges, removed_faces)
265 );
266 normal = Some((end_pos - start_pos).cross(end_pos - third_pos).normalize());
267 }
268
269 let (face_id, halfedges) = unwrap_or_return!(
270 self.remove_halfedge_face(twin_id),
271 "Failed to remove halfedge face",
272 (removed_vertices, removed_halfedges, removed_faces)
273 );
274
275 removed_faces.push(face_id);
276 removed_halfedges.extend(halfedges);
277 }
278 removed_halfedges.push(twin_id);
279
280 for end_incoming_he in end_incoming_halfedges {
281 if let Some(end_incoming_he_mut) = self.halfedges.get_mut(end_incoming_he) {
282 end_incoming_he_mut.end_vertex = start_vert_id;
283 } else {
284 error!("Halfedge not found")
285 }
286 }
287
288 self.vertices.remove(end_vert_id);
289 self.positions.remove(end_vert_id);
290 if let Some(normals) = &mut self.vertex_normals {
291 normals.remove(end_vert_id);
292 }
293 self.halfedges.remove(halfedge_id);
294 self.halfedges.remove(twin_id);
295 removed_halfedges.push(twin_id);
296
297 self.positions[start_vert_id] = center_pos;
298
299 self.vertices[start_vert_id].outgoing_halfedge = end_outgoing_halfedges
300 .into_iter()
301 .find(|he_id| self.halfedges.contains_key(*he_id))
302 .or_else(error_none!("No new outgoing halfedge found"));
303
304 #[cfg(feature = "rerun")]
305 {
306 self.log_he_rerun(
307 "collapse/outgoing",
308 self.vertices[start_vert_id].outgoing_halfedge.unwrap(),
309 );
310 }
311
312 removed_vertices.push(end_vert_id);
313
314 let mut face_tuples: Vec<_> = unwrap_or_return!(
316 self.vertices.get(start_vert_id),
317 "Start vertex not found",
318 (removed_vertices, removed_halfedges, removed_faces)
319 )
320 .faces(self)
321 .collect::<Vec<_>>()
322 .into_iter()
323 .circular_tuple_windows()
324 .collect();
325
326 let mut first = true;
327
328 while let Some((face_id1, face_id2)) = face_tuples.pop() {
329 #[cfg(feature = "rerun")]
330 {
331 self.log_rerun();
332 crate::RR.flush_blocking();
333 }
334
335 if self.faces_share_all_vertices(face_id1, face_id2) {
336 #[cfg(feature = "rerun")]
337 {
338 if self.vertices[start_vert_id].faces(self).count() == 1 {
339 self.log_vert_rerun("cleanup_delete", start_vert_id);
340 }
341
342 self.log_face_rerun("cleanup_delete/1", face_id1);
343 self.log_face_rerun("cleanup_delete/2", face_id2);
344 crate::RR.flush_blocking();
345 }
346
347 let mut halfedges_of_faces = HashSet::new();
348 halfedges_of_faces.extend(self.faces[face_id1].halfedges(self));
350 halfedges_of_faces.extend(self.faces[face_id2].halfedges(self));
351
352 let (vs, hes) = self.delete_face(face_id1);
353 for he_id in &hes {
354 halfedges_of_faces.remove(he_id);
355 }
356 removed_vertices.extend(vs);
357 removed_halfedges.extend(hes);
358 removed_faces.push(face_id1);
359
360 let (vs, hes) = self.delete_face(face_id2);
361 for he_id in &hes {
362 halfedges_of_faces.remove(he_id);
363 }
364 removed_vertices.extend(vs);
365 removed_halfedges.extend(hes);
366 removed_faces.push(face_id2);
367
368 debug_assert_eq!(halfedges_of_faces.len(), 2);
371 let mut halfedges_of_faces = halfedges_of_faces.into_iter();
372 let he_id1 = halfedges_of_faces.next().unwrap();
373 let he_id2 = halfedges_of_faces.next().unwrap();
374
375 let he1 = unwrap_or_return!(
376 self.halfedges.get(he_id1),
377 "Halfedge 1 missing",
378 (removed_vertices, removed_halfedges, removed_faces)
379 );
380 let twin_id1 = unwrap_or_return!(
381 he1.twin,
382 "Twin 1 missing",
383 (removed_vertices, removed_halfedges, removed_faces)
384 );
385 let he2 = unwrap_or_return!(
386 self.halfedges.get(he_id2),
387 "Halfedge 2 missing",
388 (removed_vertices, removed_halfedges, removed_faces)
389 );
390 let twin_id2 = unwrap_or_return!(
391 he2.twin,
392 "Twin 2 missing",
393 (removed_vertices, removed_halfedges, removed_faces)
394 );
395
396 {
397 let twin1 = unwrap_or_return!(
398 self.halfedges.get_mut(twin_id1),
399 "Twin 1 missing",
400 (removed_vertices, removed_halfedges, removed_faces)
401 );
402 twin1.twin = Some(twin_id2);
403 }
404
405 {
406 let twin2 = unwrap_or_return!(
407 self.halfedges.get_mut(twin_id2),
408 "Twin 2 missing",
409 (removed_vertices, removed_halfedges, removed_faces)
410 );
411 twin2.twin = Some(twin_id1);
412 }
413
414 self.halfedges.remove(he_id1);
415 self.halfedges.remove(he_id2);
416 removed_halfedges.push(he_id1);
417 removed_halfedges.push(he_id2);
418
419 let new_outgoing_he_id = if self.halfedges[twin_id1].end_vertex == start_vert_id {
420 twin_id2
421 } else {
422 twin_id1
423 };
424
425 unwrap_or_return!(
427 self.vertices.get_mut(start_vert_id),
428 "Start vertex not found",
429 (removed_vertices, removed_halfedges, removed_faces)
430 )
431 .outgoing_halfedge = Some(new_outgoing_he_id);
432
433 let new_outgoing_he = unwrap_or_return!(
434 self.halfedges.get(new_outgoing_he_id),
435 "New outgoing halfedge not found",
436 (removed_vertices, removed_halfedges, removed_faces)
437 );
438 unwrap_or_return!(
439 self.vertices.get_mut(new_outgoing_he.end_vertex),
440 "End vertex not found",
441 (removed_vertices, removed_halfedges, removed_faces)
442 )
443 .outgoing_halfedge = new_outgoing_he
444 .twin
445 .or_else(error_none!("New outgoing twin missing"));
446
447 face_tuples.pop();
449
450 if first {
452 face_tuples.remove(0);
453 }
454 }
455
456 first = false;
457 }
458
459 self.check_vertex_faces_for_overlapping(start_vert_id, normal.unwrap());
460
461 (removed_vertices, removed_halfedges, removed_faces)
462 }
463
464 #[instrument(skip(self))]
467 fn remove_halfedge_face(
468 &mut self,
469 halfedge_id: HalfedgeId,
470 ) -> Option<(FaceId, [HalfedgeId; 2])> {
471 let he = self
472 .halfedges
473 .get(halfedge_id)
474 .or_else(error_none!("Halfedge not found"))?;
475
476 let face_id = he.face.or_else(error_none!("Face not found"))?;
477
478 let next_he_id = he.next.or_else(error_none!("Next halfedge is None"))?;
479 let prev_he_id = he
480 .prev(self)
481 .or_else(error_none!("Previous halfedge is None"))?;
482
483 let next_twin_id = self.halfedges[next_he_id]
484 .twin
485 .or_else(error_none!("Next twin halfedge not found"))?;
486 let prev_twin_id = self.halfedges[prev_he_id]
487 .twin
488 .or_else(error_none!("Previous twin halfedge not found"))?;
489
490 let next_he = self
491 .halfedges
492 .get(next_he_id)
493 .or_else(error_none!("Next halfedge not found"))?;
494 let prev_he = self
495 .halfedges
496 .get(prev_he_id)
497 .or_else(error_none!("Previous halfedge not found"))?;
498
499 let next_end_v_id = next_he.end_vertex;
500 let prev_end_v_id = prev_he.end_vertex;
501
502 self.vertices
503 .get_mut(next_end_v_id)
504 .or_else(error_none!("Next end vertex not found"))?
505 .outgoing_halfedge = next_he.next.or_else(error_none!("Next next is None"));
506 self.vertices
507 .get_mut(prev_end_v_id)
508 .or_else(error_none!("Previous end vertex not found"))?
509 .outgoing_halfedge = prev_he.next.or_else(error_none!("Previous next is None"));
510
511 let prev_start_v_id = prev_he
512 .start_vertex(self)
513 .or_else(error_none!("Previous start vertex ID not found"))?;
514 let prev_start_v = self
515 .vertices
516 .get(prev_start_v_id)
517 .or_else(error_none!("Previous start vertex not found"))?;
518
519 if prev_start_v.outgoing_halfedge == Some(prev_he_id) {
520 self.vertices[prev_start_v_id].outgoing_halfedge = prev_he
521 .ccw_rotated_neighbour(self)
522 .or_else(|| prev_he.cw_rotated_neighbour(self))
523 .or_else(error_none!(
524 "Previous start vertex new outgoing halfedge not found"
525 ));
526 }
527
528 #[cfg(feature = "rerun")]
529 {
530 self.log_face_rerun("collapse/remove_face", face_id);
531 self.log_he_rerun("collapse/remove_next", next_he_id);
532 self.log_he_rerun("collapse/remove_prev", prev_he_id);
533 }
534
535 self.bvh.remove(
536 self.faces
537 .get(face_id)
538 .or_else(error_none!("Face not found"))?
539 .index,
540 );
541
542 self.halfedges.remove(next_he_id);
543 self.halfedges.remove(prev_he_id);
544 self.faces.remove(face_id);
545
546 self.halfedges
547 .get_mut(next_twin_id)
548 .or_else(error_none!("Next twin halfedge not found"))?
549 .twin = Some(prev_twin_id);
550
551 self.halfedges
552 .get_mut(prev_twin_id)
553 .or_else(error_none!("Previous twin halfedge not found"))?
554 .twin = Some(next_twin_id);
555
556 Some((face_id, [next_he_id, prev_he_id]))
557 }
558
559 #[instrument(skip(self))]
560 fn check_vertex_faces_for_overlapping(&mut self, vertex_id: VertexId, normal: Vec3) {
561 let vertex = *unwrap_or_return!(self.vertices.get(vertex_id), "Vertex not found");
562 let pos = *unwrap_or_return!(self.positions.get(vertex_id), "Position not found");
563
564 let neighbours = vertex.neighbours(self).collect::<Vec<_>>();
565
566 if neighbours.is_empty() {
567 error!("Vertex has no neighbours");
568 return;
569 }
570
571 let mut prev_diff = (unwrap_or_return!(
572 self.positions.get(neighbours[neighbours.len() - 1]),
573 "Last neighbour position not found"
574 ) - pos)
575 .normalize();
576
577 for neighbour_id in neighbours {
578 let mut diff = (unwrap_or_return!(
579 self.positions.get(neighbour_id),
580 "Neighbour position not found"
581 ) - pos)
582 .normalize();
583
584 if diff.cross(prev_diff).dot(normal) < 0.1 {
586 let mut avg_pos = Vec3::ZERO;
587
588 let n_neighbours = unwrap_or_return!(
589 self.vertices.get(neighbour_id),
590 "Neighbour vertex not found"
591 )
592 .neighbours(self)
593 .collect::<Vec<_>>();
594
595 let len = n_neighbours.len();
596
597 if len == 0 {
598 error!("Neighbour vertex has no neighbours");
599 continue;
600 }
601
602 for n_id in n_neighbours {
603 avg_pos += *unwrap_or_return!(
604 self.positions.get(n_id),
605 "Neighbour's neighbour position not found"
606 );
607 }
608 avg_pos /= len as f32;
609
610 self.positions[neighbour_id] = avg_pos;
612 diff = (avg_pos - pos).normalize();
613 }
614
615 prev_diff = diff;
616 }
617 }
618}
619
620