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_id = None;
50
51 for (&he_id, &len) in &halfedges_to_collapse {
52 if len < min_len && self.can_collapse_edge(he_id, min_length_squared) {
53 min_len = len;
54 min_he_id = Some(he_id);
55 }
56 }
57
58 if min_he_id.is_none() {
59 break;
61 }
62 let min_he_id = min_he_id.unwrap();
63
64 let start_vertex = self.halfedges[min_he_id].start_vertex(self);
65
66 let (verts, halfedges, faces) = self.collapse_edge(min_he_id);
67
68 #[cfg(feature = "rerun")]
69 {
70 crate::RR
71 .log("meshgraph/face/collapse", &rerun::Clear::recursive())
72 .unwrap();
73 crate::RR
74 .log("meshgraph/halfedge/collapse", &rerun::Clear::recursive())
75 .unwrap();
76 crate::RR
77 .log("meshgraph/vertex/collapse", &rerun::Clear::recursive())
78 .unwrap();
79 self.log_rerun();
80 }
81
82 halfedges_to_collapse.remove(&min_he_id);
83
84 for vert in verts {
85 selection.remove(vert);
86 }
87 for halfedge in halfedges {
88 selection.remove(halfedge);
89 halfedges_to_collapse.remove(&halfedge);
90 }
91 for face in faces {
92 selection.remove(face);
93 }
94
95 if let Some(start_vertex) = start_vertex {
96 let outgoing_halfedges = self
97 .vertices
98 .get(start_vertex)
99 .or_else(error_none!("Vertex for start vertex not found"))
100 .map(|vertex| vertex.outgoing_halfedges(self).collect::<Vec<_>>())
101 .unwrap_or_default();
102
103 for halfedge_id in outgoing_halfedges {
104 if let Some(halfedge) = self.halfedges.get(halfedge_id) {
105 let len = halfedge.length_squared(self);
106
107 if len < min_length_squared {
108 halfedges_to_collapse.insert(halfedge_id, len);
109 } else {
110 halfedges_to_collapse.remove(&halfedge_id);
111 }
112
113 if let Some(twin) = halfedge.twin {
114 halfedges_to_collapse.remove(&twin);
115 }
116
117 if let Some(face_id) = halfedge.face {
118 if let Some(face) = self.faces.get(face_id) {
119 self.bvh.insert_or_update_partially(
120 face.aabb(self),
121 face.index,
122 0.0,
123 );
124 } else {
125 error!("Face not found. BVH will not be updated.");
126 }
127 }
128 selection.insert(halfedge_id);
129 } else {
130 error!("Halfedge not found");
131 }
132 }
133 } else {
134 error!("Start vertex not found")
135 }
136
137 #[cfg(feature = "rerun")]
138 {
139 self.log_rerun();
140 }
141 }
142 }
143
144 #[inline]
145 fn can_collapse_edge(&mut self, halfedge_id: HalfedgeId, min_length_squared: f32) -> bool {
146 self.can_collapse_edge_inner(halfedge_id, min_length_squared)
147 .is_some()
148 }
149
150 #[instrument(skip(self))]
151 fn can_collapse_edge_inner(
152 &mut self,
153 halfedge_id: HalfedgeId,
154 min_length_squared: f32,
155 ) -> Option<()> {
156 let he = self
181 .halfedges
182 .get(halfedge_id)
183 .or_else(error_none!("Halfedge not found"))?;
184
185 let start_vertex_id = he.start_vertex(self)?;
186 self.vertices
187 .get_mut(start_vertex_id)
188 .or_else(error_none!("Start vertex not found"))?
189 .outgoing_halfedge = Some(halfedge_id);
190
191 let start_outgoing_vertex_ids = self.vertices[start_vertex_id]
193 .outgoing_halfedges(self)
194 .skip(2)
195 .filter_map(|he_id| {
196 Some(
197 self.halfedges
198 .get(he_id)
199 .or_else(error_none!("Halfedge not found"))?
200 .end_vertex,
201 )
202 })
203 .collect_vec();
204
205 let twin_id = he.twin.or_else(error_none!("Twin halfedge not found"))?;
206
207 let end_vertex_id = he.end_vertex;
208 self.vertices
209 .get_mut(end_vertex_id)
210 .or_else(error_none!("End vertex not found"))?
211 .outgoing_halfedge = Some(twin_id);
212
213 let end_outgoing_vertex_ids = self.vertices[end_vertex_id]
215 .outgoing_halfedges(self)
216 .skip(2)
217 .filter_map(|he_id| {
218 Some(
219 self.halfedges
220 .get(he_id)
221 .or_else(error_none!("Halfedge not found"))?
222 .end_vertex,
223 )
224 })
225 .collect_vec();
226
227 let neighbours = start_outgoing_vertex_ids
228 .into_iter()
229 .chain(end_outgoing_vertex_ids)
230 .collect_vec();
231
232 if neighbours.is_empty() {
233 error!("Vertex has no neighbours");
234 return None;
235 }
236
237 let start_pos = self
238 .positions
239 .get(start_vertex_id)
240 .or_else(error_none!("Start position not found"))?;
241
242 let end_pos = self
243 .positions
244 .get(end_vertex_id)
245 .or_else(error_none!("End position not found"))?;
246
247 let center = (start_pos + end_pos) * 0.5;
248
249 let mut prev_diff = (self
250 .positions
251 .get(neighbours[neighbours.len() - 1])
252 .or_else(error_none!("Last neighbour position not found"))?
253 - center)
254 .normalize();
255
256 let mut normal = Vec3::ZERO;
257
258 if let Some(face_id) = he.face {
259 let face = self
260 .faces
261 .get(face_id)
262 .or_else(error_none!("Face not found"))?;
263 normal += face.normal(self)?;
264 }
265
266 if let Some(face_id) = self
267 .halfedges
268 .get(twin_id)
269 .or_else(error_none!("Face not found"))?
270 .face
271 {
272 let face = self
273 .faces
274 .get(face_id)
275 .or_else(error_none!("Face not found"))?;
276 normal += face.normal(self)?;
277 }
278
279 if normal == Vec3::ZERO {
280 error!("Halfedge as no adjacent faces");
281 return None;
282 }
283
284 normal = normal.normalize();
285
286 let max_length_squared = min_length_squared * 5.0;
288
289 for neighbour_id in neighbours {
290 let diff = self
291 .positions
292 .get(neighbour_id)
293 .or_else(error_none!("Neighbour position not found"))?
294 - center;
295
296 if diff.length_squared() > max_length_squared {
297 return None;
299 }
300
301 if diff.normalize().cross(prev_diff).dot(normal) < 0.1 {
302 return None;
304 }
305
306 prev_diff = diff;
307 }
308
309 Some(())
310 }
311
312 #[instrument(skip(self))]
321 pub fn collapse_edge(
322 &mut self,
323 halfedge_id: HalfedgeId,
324 ) -> (Vec<VertexId>, Vec<HalfedgeId>, Vec<FaceId>) {
325 #[cfg(feature = "rerun")]
326 {
327 self.log_he_rerun("collapse/he", halfedge_id);
328 }
329
330 let mut removed_vertices = Vec::new();
333 let mut removed_halfedges = Vec::new();
334 let mut removed_faces = Vec::new();
335
336 let he = *unwrap_or_return!(
337 self.halfedges.get(halfedge_id),
338 "Halfedge not found",
339 (removed_vertices, removed_halfedges, removed_faces)
340 );
341
342 let start_vert_id = unwrap_or_return!(
343 he.start_vertex(self),
344 "Start vertex not found",
345 (removed_vertices, removed_halfedges, removed_faces)
346 );
347 let end_vert_id = he.end_vertex;
348
349 #[cfg(feature = "rerun")]
350 {
351 self.log_he_rerun("collapse/remove_collapsed", halfedge_id);
352 if let Some(twin) = he.twin {
353 self.log_he_rerun("collapse/remove_twin", twin);
354 }
355 self.log_vert_rerun("collapse/remove_end", end_vert_id);
356 }
357
358 let end_outgoing_halfedges = self.vertices[end_vert_id]
359 .outgoing_halfedges(self)
360 .collect::<Vec<_>>();
361 let end_incoming_halfedges = self.vertices[end_vert_id]
362 .incoming_halfedges(self)
363 .collect::<Vec<_>>();
364
365 let start_pos = *unwrap_or_return!(
366 self.positions.get(start_vert_id),
367 "Start position not found",
368 (removed_vertices, removed_halfedges, removed_faces)
369 );
370 let end_pos = *unwrap_or_return!(
371 self.positions.get(end_vert_id),
372 "End position not found",
373 (removed_vertices, removed_halfedges, removed_faces)
374 );
375
376 let center_pos = (start_pos + end_pos) * 0.5;
377
378 if !he.is_boundary() {
379 let (face_id, halfedges) = unwrap_or_return!(
380 self.remove_halfedge_face(halfedge_id),
381 "Could not remove face",
382 (removed_vertices, removed_halfedges, removed_faces)
383 );
384 removed_faces.push(face_id);
385 removed_halfedges.extend(halfedges);
386 }
387 removed_halfedges.push(halfedge_id);
388
389 let twin_id = unwrap_or_return!(
390 he.twin,
391 "Twin missing",
392 (removed_vertices, removed_halfedges, removed_faces)
393 );
394 let twin = unwrap_or_return!(
395 self.halfedges.get(twin_id),
396 "Halfedge not found",
397 (removed_vertices, removed_halfedges, removed_faces)
398 );
399
400 if !twin.is_boundary() {
401 let (face_id, halfedges) = unwrap_or_return!(
402 self.remove_halfedge_face(twin_id),
403 "Failed to remove halfedge face",
404 (removed_vertices, removed_halfedges, removed_faces)
405 );
406
407 removed_faces.push(face_id);
408 removed_halfedges.extend(halfedges);
409 }
410 removed_halfedges.push(twin_id);
411
412 for end_incoming_he in end_incoming_halfedges {
413 if let Some(end_incoming_he_mut) = self.halfedges.get_mut(end_incoming_he) {
414 end_incoming_he_mut.end_vertex = start_vert_id;
415 }
416 }
417
418 self.vertices.remove(end_vert_id);
419 self.positions.remove(end_vert_id);
420 if let Some(normals) = &mut self.vertex_normals {
421 normals.remove(end_vert_id);
422 }
423 self.halfedges.remove(halfedge_id);
424 self.halfedges.remove(twin_id);
425 removed_halfedges.push(twin_id);
426
427 self.positions[start_vert_id] = center_pos;
428
429 self.vertices[start_vert_id].outgoing_halfedge = end_outgoing_halfedges
430 .into_iter()
431 .find(|he_id| self.halfedges.contains_key(*he_id))
432 .or_else(error_none!("No new outgoing halfedge found"));
433
434 #[cfg(feature = "rerun")]
435 {
436 self.log_he_rerun(
437 "collapse/outgoing",
438 self.vertices[start_vert_id].outgoing_halfedge.unwrap(),
439 );
440 }
441
442 removed_vertices.push(end_vert_id);
443
444 let mut face_tuples: Vec<_> = unwrap_or_return!(
446 self.vertices.get(start_vert_id),
447 "Start vertex not found",
448 (removed_vertices, removed_halfedges, removed_faces)
449 )
450 .faces(self)
451 .collect::<Vec<_>>()
452 .into_iter()
453 .circular_tuple_windows()
454 .collect();
455
456 let mut first = true;
457
458 while let Some((face_id1, face_id2)) = face_tuples.pop() {
459 #[cfg(feature = "rerun")]
460 {
461 self.log_rerun();
462 }
463
464 if self.faces_share_all_vertices(face_id1, face_id2) {
465 #[cfg(feature = "rerun")]
466 {
467 if self.vertices[start_vert_id].faces(self).count() == 1 {
468 self.log_vert_rerun("cleanup_delete", start_vert_id);
469 }
470
471 self.log_face_rerun("cleanup_delete/1", face_id1);
472 self.log_face_rerun("cleanup_delete/2", face_id2);
473 }
474
475 let mut halfedges_of_faces = HashSet::new();
476 halfedges_of_faces.extend(self.faces[face_id1].halfedges(self));
478 halfedges_of_faces.extend(self.faces[face_id2].halfedges(self));
479
480 let (vs, hes) = self.delete_face(face_id1);
481 for he_id in &hes {
482 halfedges_of_faces.remove(he_id);
483 }
484 removed_vertices.extend(vs);
485 removed_halfedges.extend(hes);
486 removed_faces.push(face_id1);
487
488 let (vs, hes) = self.delete_face(face_id2);
489 for he_id in &hes {
490 halfedges_of_faces.remove(he_id);
491 }
492 removed_vertices.extend(vs);
493 removed_halfedges.extend(hes);
494 removed_faces.push(face_id2);
495
496 debug_assert_eq!(halfedges_of_faces.len(), 2);
499 let mut halfedges_of_faces = halfedges_of_faces.into_iter();
500 let he_id1 = halfedges_of_faces.next().unwrap();
501 let he_id2 = halfedges_of_faces.next().unwrap();
502
503 let he1 = unwrap_or_return!(
504 self.halfedges.get(he_id1),
505 "Halfedge 1 missing",
506 (removed_vertices, removed_halfedges, removed_faces)
507 );
508 let twin_id1 = unwrap_or_return!(
509 he1.twin,
510 "Twin 1 missing",
511 (removed_vertices, removed_halfedges, removed_faces)
512 );
513 let he2 = unwrap_or_return!(
514 self.halfedges.get(he_id2),
515 "Halfedge 2 missing",
516 (removed_vertices, removed_halfedges, removed_faces)
517 );
518 let twin_id2 = unwrap_or_return!(
519 he2.twin,
520 "Twin 2 missing",
521 (removed_vertices, removed_halfedges, removed_faces)
522 );
523
524 {
525 let twin1 = unwrap_or_return!(
526 self.halfedges.get_mut(twin_id1),
527 "Twin 1 missing",
528 (removed_vertices, removed_halfedges, removed_faces)
529 );
530 twin1.twin = Some(twin_id2);
531 }
532
533 {
534 let twin2 = unwrap_or_return!(
535 self.halfedges.get_mut(twin_id2),
536 "Twin 2 missing",
537 (removed_vertices, removed_halfedges, removed_faces)
538 );
539 twin2.twin = Some(twin_id1);
540 }
541
542 self.halfedges.remove(he_id1);
543 self.halfedges.remove(he_id2);
544 removed_halfedges.push(he_id1);
545 removed_halfedges.push(he_id2);
546
547 let new_outgoing_he_id = if self.halfedges[twin_id1].end_vertex == start_vert_id {
548 twin_id2
549 } else {
550 twin_id1
551 };
552
553 unwrap_or_return!(
555 self.vertices.get_mut(start_vert_id),
556 "Start vertex not found",
557 (removed_vertices, removed_halfedges, removed_faces)
558 )
559 .outgoing_halfedge = Some(new_outgoing_he_id);
560
561 let new_outgoing_he = unwrap_or_return!(
562 self.halfedges.get(new_outgoing_he_id),
563 "New outgoing halfedge not found",
564 (removed_vertices, removed_halfedges, removed_faces)
565 );
566 unwrap_or_return!(
567 self.vertices.get_mut(new_outgoing_he.end_vertex),
568 "End vertex not found",
569 (removed_vertices, removed_halfedges, removed_faces)
570 )
571 .outgoing_halfedge = new_outgoing_he
572 .twin
573 .or_else(error_none!("New outgoing twin missing"));
574
575 face_tuples.pop();
577
578 if first {
580 face_tuples.remove(0);
581 }
582 }
583
584 first = false;
585 }
586
587 (removed_vertices, removed_halfedges, removed_faces)
588 }
589
590 #[instrument(skip(self))]
593 fn remove_halfedge_face(
594 &mut self,
595 halfedge_id: HalfedgeId,
596 ) -> Option<(FaceId, [HalfedgeId; 2])> {
597 let he = self
598 .halfedges
599 .get(halfedge_id)
600 .or_else(error_none!("Halfedge not found"))?;
601
602 let face_id = he.face.or_else(error_none!("Face not found"))?;
603
604 let next_he_id = he.next.or_else(error_none!("Next halfedge is None"))?;
605 let prev_he_id = he
606 .prev(self)
607 .or_else(error_none!("Previous halfedge is None"))?;
608
609 let next_twin_id = self.halfedges[next_he_id]
610 .twin
611 .or_else(error_none!("Next twin halfedge not found"))?;
612 let prev_twin_id = self.halfedges[prev_he_id]
613 .twin
614 .or_else(error_none!("Previous twin halfedge not found"))?;
615
616 let next_he = self
617 .halfedges
618 .get(next_he_id)
619 .or_else(error_none!("Next halfedge not found"))?;
620 let prev_he = self
621 .halfedges
622 .get(prev_he_id)
623 .or_else(error_none!("Previous halfedge not found"))?;
624
625 let next_end_v_id = next_he.end_vertex;
626 let prev_end_v_id = prev_he.end_vertex;
627
628 self.vertices
629 .get_mut(next_end_v_id)
630 .or_else(error_none!("Next end vertex not found"))?
631 .outgoing_halfedge = next_he.next.or_else(error_none!("Next next is None"));
632 self.vertices
633 .get_mut(prev_end_v_id)
634 .or_else(error_none!("Previous end vertex not found"))?
635 .outgoing_halfedge = prev_he.next.or_else(error_none!("Previous next is None"));
636
637 let prev_start_v_id = prev_he
638 .start_vertex(self)
639 .or_else(error_none!("Previous start vertex ID not found"))?;
640 let prev_start_v = self
641 .vertices
642 .get(prev_start_v_id)
643 .or_else(error_none!("Previous start vertex not found"))?;
644
645 if prev_start_v.outgoing_halfedge == Some(prev_he_id) {
646 self.vertices[prev_start_v_id].outgoing_halfedge = prev_he
647 .ccw_rotated_neighbour(self)
648 .or_else(|| prev_he.cw_rotated_neighbour(self))
649 .or_else(error_none!(
650 "Previous start vertex new outgoing halfedge not found"
651 ));
652 }
653
654 #[cfg(feature = "rerun")]
655 {
656 self.log_face_rerun("collapse/remove_face", face_id);
657 self.log_he_rerun("collapse/remove_next", next_he_id);
658 self.log_he_rerun("collapse/remove_prev", prev_he_id);
659 }
660
661 self.bvh.remove(
662 self.faces
663 .get(face_id)
664 .or_else(error_none!("Face not found"))?
665 .index,
666 );
667
668 self.halfedges.remove(next_he_id);
669 self.halfedges.remove(prev_he_id);
670 self.faces.remove(face_id);
671
672 self.halfedges
673 .get_mut(next_twin_id)
674 .or_else(error_none!("Next twin halfedge not found"))?
675 .twin = Some(prev_twin_id);
676
677 self.halfedges
678 .get_mut(prev_twin_id)
679 .or_else(error_none!("Previous twin halfedge not found"))?
680 .twin = Some(next_twin_id);
681
682 Some((face_id, [next_he_id, prev_he_id]))
683 }
684}
685
686