1use hashbrown::HashSet;
2use itertools::Itertools;
3use tracing::{error, instrument};
4
5use crate::{FaceId, HalfedgeId, MeshGraph, VertexId, error_none};
6
7#[derive(Default)]
8pub struct VertexNeighborhoodCleanup {
9 pub removed_vertices: Vec<VertexId>,
10 pub removed_halfedges: Vec<HalfedgeId>,
11 pub removed_faces: Vec<FaceId>,
12
13 pub added_vertices: Vec<VertexId>,
14}
15
16#[derive(Default)]
17struct VertexNeighborhoodCleanupStep {
18 pub removed_vertices: Vec<VertexId>,
19 pub removed_halfedges: Vec<HalfedgeId>,
20 pub removed_faces: Vec<FaceId>,
21
22 pub added_duplicated_vertices: Vec<VertexId>,
23 pub touched_vertices: Vec<VertexId>,
24}
25
26impl MeshGraph {
27 #[instrument(skip(self))]
35 pub fn make_vertex_neighborhood_manifold(
36 &mut self,
37 vertex_id: VertexId,
38 ) -> VertexNeighborhoodCleanup {
39 #[cfg(feature = "rerun")]
40 self.log_vert_rerun("make_neigh_manifold", vertex_id);
41
42 let mut result = VertexNeighborhoodCleanup::default();
43
44 let mut vertices = vec![vertex_id];
45
46 while let Some(&v_id) = vertices.first() {
47 if !self.vertices.contains_key(v_id) {
48 vertices.swap_remove(0);
49 continue;
50 }
51
52 let VertexNeighborhoodCleanupStep {
53 added_duplicated_vertices,
54 touched_vertices,
55 removed_vertices,
56 removed_halfedges,
57 removed_faces,
58 } = self.make_vertex_neighborhood_manifold_step(v_id);
59
60 if removed_vertices.is_empty()
61 && removed_halfedges.is_empty()
62 && removed_faces.is_empty()
63 && added_duplicated_vertices.is_empty()
64 && touched_vertices.is_empty()
65 {
66 vertices.swap_remove(0);
67 }
68
69 vertices.extend(touched_vertices);
70 for added_vertex in added_duplicated_vertices {
71 vertices.push(added_vertex);
72
73 result.added_vertices.push(added_vertex);
74 }
75
76 result.removed_vertices.extend(removed_vertices);
77 result.removed_halfedges.extend(removed_halfedges);
78 result.removed_faces.extend(removed_faces);
79
80 if vertices.is_empty() {
81 break;
82 }
83 }
84
85 for &cancelled_v_id in
86 HashSet::<VertexId>::from_iter(result.removed_vertices.iter().copied())
87 .intersection(&HashSet::from_iter(result.added_vertices.iter().copied()))
88 {
89 result.added_vertices.retain(|&v_id| v_id != cancelled_v_id);
90 result
91 .removed_vertices
92 .retain(|&v_id| v_id != cancelled_v_id);
93 }
94
95 result
96 }
97
98 fn make_vertex_neighborhood_manifold_step(
99 &mut self,
100 vertex_id: VertexId,
101 ) -> VertexNeighborhoodCleanupStep {
102 let mut removed_vertices = Vec::new();
103 let mut removed_halfedges = Vec::new();
104 let mut removed_faces = Vec::new();
105
106 let added_duplicated_vertices = self
107 .make_vertex_neighborhood_manifold_inner(
108 vertex_id,
109 &mut removed_vertices,
110 &mut removed_halfedges,
111 &mut removed_faces,
112 )
113 .unwrap_or_default();
114
115 VertexNeighborhoodCleanupStep {
116 added_duplicated_vertices,
117 touched_vertices: vec![],
118 removed_vertices,
119 removed_halfedges,
120 removed_faces,
121 }
122 }
123
124 pub fn make_vertex_neighborhood_manifold_inner(
125 &mut self,
126 vertex_id: VertexId,
127 removed_vertices: &mut Vec<VertexId>,
128 removed_halfedges: &mut Vec<HalfedgeId>,
129 removed_faces: &mut Vec<FaceId>,
130 ) -> Option<Vec<VertexId>> {
131 self.vertices.get(vertex_id)?;
132
133 if self.remove_single_face(
134 vertex_id,
135 removed_vertices,
136 removed_halfedges,
137 removed_faces,
138 )? {
139 return Some(vec![]);
140 }
141
142 if self.remove_neighboring_flaps(
143 vertex_id,
144 removed_vertices,
145 removed_halfedges,
146 removed_faces,
147 )? {
148 return Some(vec![]);
149 }
150
151 if let Some(new_vertices) = self.split_disconnected_neighborhoods(vertex_id)
152 && !new_vertices.is_empty()
153 {
154 return Some(new_vertices);
155 }
156
157 if let Some(inserted_duplicated_vertex) = self.remove_degenerate_faces(
158 vertex_id,
159 removed_vertices,
160 removed_halfedges,
161 removed_faces,
162 ) {
163 return Some(vec![inserted_duplicated_vertex]);
164 }
165
166 self.remove_degenerate_edges(vertex_id).map(|v| vec![v])
167 }
168
169 fn split_disconnected_neighborhoods(&mut self, vertex_id: VertexId) -> Option<Vec<VertexId>> {
170 let mut new_vertices = Vec::new();
171
172 let mut outgoing_halfedges = HashSet::<HalfedgeId>::from_iter(
173 self.outgoing_halfedges
174 .get(vertex_id)
175 .or_else(error_none!("Outgoing halfedges not found"))?
176 .iter()
177 .copied(),
178 );
179
180 while let Some(&start_he_id) = outgoing_halfedges.iter().next() {
181 let mut current_he_id = start_he_id;
182
183 let len = outgoing_halfedges.len();
184 let mut current_outgoing_halfedges = Vec::with_capacity(len);
185
186 loop {
187 if !outgoing_halfedges.remove(¤t_he_id) {
188 return None;
189 }
190 current_outgoing_halfedges.push(current_he_id);
191 if current_outgoing_halfedges.len() == len {
192 return None;
193 }
194
195 let cur_he = self
196 .halfedges
197 .get(current_he_id)
198 .or_else(error_none!("Halfedge not found"))?;
199
200 let Some(next_he_id) = cur_he.cw_rotated_neighbour(self) else {
201 break;
203 };
204
205 if next_he_id == start_he_id {
206 break;
207 }
208
209 current_he_id = next_he_id;
210 }
211
212 if !outgoing_halfedges.is_empty() {
213 let new_vertex_id = self
214 .duplicate_vertex_and_assign_halfedges(vertex_id, current_outgoing_halfedges)?;
215
216 new_vertices.push(new_vertex_id);
217
218 self.vertices
219 .get_mut(vertex_id)
220 .or_else(error_none!("Vertex not found"))?
221 .outgoing_halfedge = Some(*outgoing_halfedges.iter().next().unwrap());
222
223 self.outgoing_halfedges
224 .insert(vertex_id, Vec::from_iter(outgoing_halfedges));
225
226 return Some(new_vertices);
227 }
228 }
229
230 Some(new_vertices)
231 }
232
233 fn duplicate_vertex_and_assign_halfedges(
234 &mut self,
235 vertex_id: VertexId,
236 outgoing_halfedges: Vec<HalfedgeId>,
237 ) -> Option<VertexId> {
238 let new_vert_id = self.add_vertex(
239 *self
240 .positions
241 .get(vertex_id)
242 .or_else(error_none!("Position not found"))?
243 + glam::Vec3::new(0.1, 0.0, 0.0),
244 );
245
246 tracing::info!("Duplicated {vertex_id:?}: {new_vert_id:?}");
247
248 for &he_id in &outgoing_halfedges {
249 let he = self
250 .halfedges
251 .get(he_id)
252 .or_else(error_none!("Halfedge not found"))?;
253
254 let twin_id = he.twin.or_else(error_none!("Twin not found"))?;
255
256 self.halfedges
257 .get_mut(twin_id)
258 .or_else(error_none!("Twin not found"))?
259 .end_vertex = new_vert_id;
260 }
261
262 self.vertices[new_vert_id].outgoing_halfedge = Some(outgoing_halfedges[0]);
264
265 self.outgoing_halfedges
266 .insert(new_vert_id, outgoing_halfedges);
267
268 Some(new_vert_id)
269 }
270
271 fn remove_degenerate_edges(&mut self, vertex_id: VertexId) -> Option<VertexId> {
272 let halfedges = self
273 .vertices
274 .get(vertex_id)
275 .or_else(error_none!("Vertex not found"))?
276 .outgoing_halfedges(self)
277 .collect_vec();
278
279 for [he_id1, he_id2] in halfedges.into_iter().array_combinations() {
280 if self.halfedges_share_all_vertices(he_id1, he_id2) {
281 let he1 = self.halfedges[he_id1];
282 let twin_id1 = he1.twin.or_else(error_none!("Twin not found"))?;
283 let face_id1 = self
284 .halfedges
285 .get(twin_id1)
286 .or_else(error_none!("Halfedge not found"))?
287 .face
288 .or_else(error_none!("Face not found"))?;
289 let face_id2 = self
290 .halfedges
291 .get(he_id2)
292 .or_else(error_none!("Halfedge not found"))?
293 .face
294 .or_else(error_none!("Face not found"))?;
295
296 let coincident_face_ids = self.vertices[vertex_id].faces(self).collect_vec();
297 let mut start_idx = 0;
298
299 for (idx, face_id) in coincident_face_ids.iter().enumerate() {
300 if *face_id == face_id1 {
301 start_idx = idx;
302 break;
303 }
304 }
305
306 let mut end_idx = start_idx;
307 let mut side_one = vec![];
308
309 loop {
310 let face_id = coincident_face_ids[end_idx];
311
312 side_one.push(face_id);
313
314 end_idx += 1;
315 end_idx %= coincident_face_ids.len();
316
317 if face_id == face_id2 {
318 break;
319 }
320 }
321
322 let mut side_two = vec![];
323
324 while end_idx != start_idx {
325 let face_id = coincident_face_ids[end_idx];
326
327 side_two.push(face_id);
328
329 end_idx += 1;
330 end_idx %= coincident_face_ids.len();
331 }
332
333 return self.split_regions_at_edge(vertex_id, he1.end_vertex, side_one, side_two);
334 }
335 }
336
337 None
338 }
339
340 #[instrument(skip(self))]
341 fn split_regions_at_edge(
342 &mut self,
343 vertex_id: VertexId,
344 other_vertex_id: VertexId,
345 side_one: Vec<FaceId>,
346 side_two: Vec<FaceId>,
347 ) -> Option<VertexId> {
348 if side_one.len() < 2 || side_two.len() < 2 {
349 error!("Not enough halfedges to split");
350 return None;
351 }
352
353 #[cfg(feature = "rerun")]
354 {
355 self.log_vert_rerun("split_regions_at_edge", vertex_id);
356 self.log_faces_rerun("split_regions_at_edge/side_one", &side_one);
357 self.log_faces_rerun("split_regions_at_edge/side_two", &side_two);
358 }
359
360 let new_vertex_id = self.add_vertex(
361 *self
362 .positions
363 .get(vertex_id)
364 .or_else(error_none!("Vertex position not found"))?,
365 );
366
367 for face_id in &side_two {
369 let face = self
370 .faces
371 .get(*face_id)
372 .or_else(error_none!("Face not found"))?;
373
374 for he_id in face.halfedges(self).collect_vec() {
375 let he = &mut self.halfedges[he_id];
377
378 if he.end_vertex == vertex_id {
379 he.end_vertex = new_vertex_id;
380 }
381 }
382 }
383
384 self.weld_faces_at(
385 vertex_id,
386 other_vertex_id,
387 side_one[side_one.len() - 1],
388 side_one[0],
389 );
390 self.weld_faces_at(
391 new_vertex_id,
392 other_vertex_id,
393 side_two[0],
394 side_two[side_two.len() - 1],
395 );
396
397 self.outgoing_halfedges[vertex_id] =
398 self.vertices[vertex_id].outgoing_halfedges(self).collect();
399 self.outgoing_halfedges[new_vertex_id] = self.vertices[new_vertex_id]
400 .outgoing_halfedges(self)
401 .collect();
402
403 Some(new_vertex_id)
404 }
405
406 #[instrument(skip_all)]
407 pub fn remove_degenerate_faces(
408 &mut self,
409 vertex_id: VertexId,
410 removed_vertices: &mut Vec<VertexId>,
411 removed_halfedges: &mut Vec<HalfedgeId>,
412 removed_faces: &mut Vec<FaceId>,
413 ) -> Option<VertexId> {
414 let faces = self
415 .vertices
416 .get(vertex_id)
417 .or_else(error_none!("Vertex not found"))?
418 .faces(self)
419 .collect_vec();
420
421 for [face_id1, face_id2] in faces.into_iter().array_combinations() {
422 if self.faces_share_all_vertices(face_id1, face_id2) {
423 let coincident_face_ids = self.vertices[vertex_id].faces(self).collect_vec();
424 let mut start_idx = 0;
425
426 for (idx, face_id) in coincident_face_ids.iter().enumerate() {
427 if *face_id == face_id1 {
428 start_idx = (idx + 1) % coincident_face_ids.len();
429 break;
430 }
431 }
432
433 let mut end_idx = start_idx;
434 let mut side_one = vec![];
435
436 loop {
437 let face_id = coincident_face_ids[end_idx];
438
439 end_idx += 1;
440 end_idx %= coincident_face_ids.len();
441
442 if face_id == face_id2 {
443 break;
444 }
445
446 side_one.push(face_id);
447 }
448
449 let mut side_two = vec![];
450
451 while end_idx != start_idx {
452 let face_id = coincident_face_ids[end_idx];
453
454 side_two.push(face_id);
455
456 end_idx += 1;
457 end_idx %= coincident_face_ids.len();
458 }
459
460 side_two.pop();
461
462 let new_vertex_id =
463 self.split_regions_at_vertex(vertex_id, side_one, side_two, removed_halfedges);
464
465 let (del_v_ids, del_he_ids) = self.remove_face(face_id1);
466 removed_vertices.extend(del_v_ids);
467 removed_halfedges.extend(del_he_ids);
468 removed_faces.push(face_id1);
469
470 let (del_v_ids, del_he_ids) = self.remove_face(face_id2);
471 removed_vertices.extend(del_v_ids);
472 removed_halfedges.extend(del_he_ids);
473 removed_faces.push(face_id2);
474
475 return new_vertex_id;
476 }
477 }
478
479 None
480 }
481
482 #[instrument(skip(self))]
483 fn split_regions_at_vertex(
484 &mut self,
485 vertex_id: VertexId,
486 side_one: Vec<FaceId>,
487 side_two: Vec<FaceId>,
488 removed_halfedges: &mut Vec<HalfedgeId>,
489 ) -> Option<VertexId> {
490 if side_one.len() < 2 || side_two.len() < 2 {
491 error!("Not enough halfedges to split");
492 return None;
493 }
494
495 #[cfg(feature = "rerun")]
496 {
497 self.log_vert_rerun("split_regions_at_vertex", vertex_id);
498 self.log_faces_rerun("split_regions_at_vertex/side_one", &side_one);
499 self.log_faces_rerun("split_regions_at_vertex/side_two", &side_two);
500 }
501
502 let new_vertex_id = self.add_vertex(
503 *self
504 .positions
505 .get(vertex_id)
506 .or_else(error_none!("Vertex position not found"))?,
507 );
508
509 for face_id in &side_two {
511 let face = self
512 .faces
513 .get(*face_id)
514 .or_else(error_none!("Face not found"))?;
515
516 for he_id in face.halfedges(self).collect_vec() {
517 let he = &mut self.halfedges[he_id];
519 if he.end_vertex == vertex_id {
520 he.end_vertex = new_vertex_id;
521 }
522 }
523 }
524
525 self.weld_faces(vertex_id, side_one[side_one.len() - 1], side_one[0]);
526 self.weld_faces(new_vertex_id, side_two[0], side_two[side_two.len() - 1]);
527
528 self.outgoing_halfedges[vertex_id] =
529 self.vertices[vertex_id].outgoing_halfedges(self).collect();
530 self.outgoing_halfedges[new_vertex_id] = self.vertices[new_vertex_id]
531 .outgoing_halfedges(self)
532 .collect();
533
534 Some(new_vertex_id)
535 }
536
537 fn weld_faces(
542 &mut self,
543 start_vertex_id: VertexId,
544 face_id1: FaceId,
545 face_id2: FaceId,
546 ) -> Option<()> {
547 let face1 = self
554 .faces
555 .get(face_id1)
556 .or_else(error_none!("Face not found"))?;
557 let face2 = self
558 .faces
559 .get(face_id2)
560 .or_else(error_none!("Face not found"))?;
561
562 let face1_vertices = face1.vertices(self).collect::<HashSet<_>>();
563 let face2_vertices = face2.vertices(self).collect::<HashSet<_>>();
564
565 let mut other_common_vertex_id = None;
566
567 for &v_id in face1_vertices.intersection(&face2_vertices) {
568 if v_id != start_vertex_id {
569 other_common_vertex_id = Some(v_id);
570 break;
571 }
572 }
573
574 let other_common_vertex_id =
575 other_common_vertex_id.or_else(error_none!("No other common vertex found"))?;
576
577 self.weld_faces_at(start_vertex_id, other_common_vertex_id, face_id1, face_id2)
578 }
579
580 #[instrument(skip(self))]
581 fn weld_faces_at(
582 &mut self,
583 start_vertex_id: VertexId,
584 other_common_vertex_id: VertexId,
585 face_id1: FaceId,
586 face_id2: FaceId,
587 ) -> Option<()> {
588 let face1 = self
589 .faces
590 .get(face_id1)
591 .or_else(error_none!("Face not found"))?;
592 let face2 = self
593 .faces
594 .get(face_id2)
595 .or_else(error_none!("Face not found"))?;
596
597 let he1_id = face1
598 .halfedge_between(start_vertex_id, other_common_vertex_id, self)
599 .or_else(error_none!("Halfedge between vertices not found"))?;
600
601 let he2_id = face2
602 .halfedge_between(start_vertex_id, other_common_vertex_id, self)
603 .or_else(error_none!("Halfedge between vertices not found"))?;
604
605 self.halfedges[he1_id].twin = Some(he2_id);
606 self.halfedges[he2_id].twin = Some(he1_id);
607
608 let (start_out_he_id, other_out_he_id) =
609 if self.halfedges[he1_id].end_vertex == start_vertex_id {
610 (he2_id, he1_id)
611 } else {
612 (he1_id, he2_id)
613 };
614
615 self.vertices
616 .get_mut(start_vertex_id)
617 .or_else(error_none!("Start vertex not found"))?
618 .outgoing_halfedge = Some(start_out_he_id);
619 self.vertices
620 .get_mut(other_common_vertex_id)
621 .or_else(error_none!("Other vertex not found"))?
622 .outgoing_halfedge = Some(other_out_he_id);
623
624 Some(())
625 }
626
627 pub(crate) fn remove_single_face(
628 &mut self,
629 vertex_id: VertexId,
630 removed_vertices: &mut Vec<VertexId>,
631 removed_halfedges: &mut Vec<HalfedgeId>,
632 removed_faces: &mut Vec<FaceId>,
633 ) -> Option<bool> {
634 let face_ids = self
635 .outgoing_halfedges
636 .get(vertex_id)
637 .or_else(error_none!(
638 "Outgoing halfedges not found for vertex {vertex_id:?}"
639 ))?
640 .iter()
641 .filter_map(|&he_id| {
642 self.halfedges
643 .get(he_id)
644 .or_else(error_none!("Halfedge not found"))
645 .and_then(|he| he.face)
646 })
647 .collect_vec();
648
649 if face_ids.len() == 1 {
650 let face_id = face_ids[0];
651
652 let (v_ids, he_ids) = self.remove_face(face_id);
653
654 removed_vertices.extend(v_ids);
655 removed_halfedges.extend(he_ids);
656 removed_faces.push(face_id);
657
658 Some(true)
659 } else {
660 Some(false)
661 }
662 }
663
664 pub fn remove_neighboring_flaps(
666 &mut self,
667 vertex_id: VertexId,
668 removed_vertices: &mut Vec<VertexId>,
669 removed_halfedges: &mut Vec<HalfedgeId>,
670 removed_faces: &mut Vec<FaceId>,
671 ) -> Option<bool> {
672 let faces = self
673 .vertices
674 .get(vertex_id)
675 .or_else(error_none!("Vertex not found"))?
676 .faces(self)
677 .collect_vec();
678
679 if faces.len() < 2 {
680 return Some(false);
681 }
682
683 let mut face_tuples = faces.into_iter().circular_array_windows().collect_vec();
684
685 while let Some([face_id1, face_id2]) = face_tuples.pop() {
686 if self.faces_share_all_vertices(face_id1, face_id2) {
687 #[cfg(feature = "rerun")]
688 {
689 self.log_vert_rerun("flap", vertex_id);
690 self.log_face_rerun("flap1", face_id1);
691 self.log_face_rerun("flap2", face_id2);
692 }
693
694 let mut halfedges_of_faces = HashSet::<HalfedgeId>::from_iter(
695 self.halfedges.iter().filter_map(|(he_id, he)| {
696 if he.face == Some(face_id1) || he.face == Some(face_id2) {
697 Some(he_id)
698 } else {
699 None
700 }
701 }),
702 );
703
704 let (vs, hes) = self.remove_face(face_id1);
705 for he_id in &hes {
706 halfedges_of_faces.remove(he_id);
707 }
708 removed_vertices.extend(vs);
709 removed_halfedges.extend(hes);
710 removed_faces.push(face_id1);
711
712 let (vs, hes) = self.remove_face(face_id2);
713 for he_id in &hes {
714 halfedges_of_faces.remove(he_id);
715 }
716 removed_vertices.extend(vs);
717 removed_halfedges.extend(hes);
718 removed_faces.push(face_id2);
719
720 if halfedges_of_faces.len() >= 2 {
722 for [he_id1, he_id2] in halfedges_of_faces.iter().copied().array_combinations()
723 {
724 let Some(he1) = self.halfedges.get(he_id1) else {
725 continue;
727 };
728 let twin_id1 = he1.twin.or_else(error_none!("Twin 1 missing"))?;
729
730 let Some(he2) = self.halfedges.get(he_id2) else {
731 continue;
732 };
733 let twin_id2 = he2.twin.or_else(error_none!("Twin 2 missing"))?;
734
735 let start_v_id1 = he1
736 .start_vertex(self)
737 .or_else(error_none!("Start vertex 1 missing"))?;
738 let start_v_id2 = he2
739 .start_vertex(self)
740 .or_else(error_none!("Start vertex 2 missing"))?;
741
742 if he1.end_vertex != start_v_id2 || he2.end_vertex != start_v_id1 {
743 continue;
744 }
745
746 self.remove_only_halfedge(he_id1);
750 self.remove_only_halfedge(he_id2);
751 removed_halfedges.push(he_id1);
752 removed_halfedges.push(he_id2);
753
754 {
755 let twin1 = self
756 .halfedges
757 .get_mut(twin_id1)
758 .or_else(error_none!("Twin 1 missing"))?;
759 twin1.twin = Some(twin_id2);
760 };
761
762 {
763 let twin2 = self
764 .halfedges
765 .get_mut(twin_id2)
766 .or_else(error_none!("Twin 2 missing"))?;
767 twin2.twin = Some(twin_id1);
768 };
769
770 self.vertices
771 .get_mut(start_v_id1)
772 .or_else(error_none!("Start vertex 1 missing"))?
773 .outgoing_halfedge = Some(twin_id2);
774
775 self.vertices
776 .get_mut(start_v_id2)
777 .or_else(error_none!("Start vertex 2 missing"))?
778 .outgoing_halfedge = Some(twin_id1);
779 }
780 } else {
781 tracing::warn!("There's only one halfedge left");
782 }
783
784 return Some(true);
785 }
786 }
787
788 Some(false)
789 }
790}
791
792#[cfg(test)]
793mod tests {
794 use crate::ops::AddOrGetEdge;
795
796 use super::*;
797 use glam::Vec3;
798
799 #[test]
800 fn test_remove_degenerate_faces() {
801 crate::utils::get_tracing_subscriber();
802 let mut meshgraph = MeshGraph::new();
803
804 let center_v_id = meshgraph.add_vertex(Vec3::new(0.0, 0.0, 1.0));
805
806 let v1_id = meshgraph.add_vertex(Vec3::new(-0.2, 0.0, 0.0));
807 let he_c_1_id = meshgraph
808 .add_or_get_edge(center_v_id, v1_id)
809 .unwrap()
810 .start_to_end_he_id;
811 let v1p_id = meshgraph.add_vertex(Vec3::new(-0.2, 0.0, 0.0));
812 let AddOrGetEdge {
813 start_to_end_he_id: he_c_1p_id,
814 twin_he_id: he_1p_c_id,
815 ..
816 } = meshgraph.add_or_get_edge(center_v_id, v1p_id).unwrap();
817
818 let v2_id = meshgraph.add_vertex(Vec3::new(-1.0, 1.0, 0.0));
819 let he_c_2_id = meshgraph
820 .add_or_get_edge(center_v_id, v2_id)
821 .unwrap()
822 .start_to_end_he_id;
823
824 let v3_id = meshgraph.add_vertex(Vec3::new(-1.0, -1.0, 0.0));
825 let he_c_3_id = meshgraph
826 .add_or_get_edge(center_v_id, v3_id)
827 .unwrap()
828 .start_to_end_he_id;
829
830 let v4_id = meshgraph.add_vertex(Vec3::new(0.2, 0.0, 0.0));
831 let he_c_4_id = meshgraph
832 .add_or_get_edge(center_v_id, v4_id)
833 .unwrap()
834 .start_to_end_he_id;
835
836 let v4p_id = meshgraph.add_vertex(Vec3::new(0.2, 0.0, 0.0));
837 let AddOrGetEdge {
838 start_to_end_he_id: he_c_4p_id,
839 twin_he_id: he_4p_c_id,
840 ..
841 } = meshgraph.add_or_get_edge(center_v_id, v4p_id).unwrap();
842
843 let v5_id = meshgraph.add_vertex(Vec3::new(1.0, -1.0, 0.0));
844 let he_c_5_id = meshgraph
845 .add_or_get_edge(center_v_id, v5_id)
846 .unwrap()
847 .start_to_end_he_id;
848
849 let v6_id = meshgraph.add_vertex(Vec3::new(1.0, 1.0, 0.0));
850 let he_c_6_id = meshgraph
851 .add_or_get_edge(center_v_id, v6_id)
852 .unwrap()
853 .start_to_end_he_id;
854
855 meshgraph
856 .add_face_from_halfedges(he_c_1_id, he_c_2_id)
857 .unwrap();
858 meshgraph
859 .add_face_from_halfedges(he_c_2_id, he_c_3_id)
860 .unwrap();
861 meshgraph
862 .add_face_from_halfedges(he_c_3_id, he_c_1p_id)
863 .unwrap();
864
865 meshgraph
866 .add_face_from_halfedges(he_c_1p_id, he_c_4p_id)
867 .unwrap();
868
869 meshgraph
870 .add_face_from_halfedges(he_c_4p_id, he_c_5_id)
871 .unwrap();
872 meshgraph
873 .add_face_from_halfedges(he_c_5_id, he_c_6_id)
874 .unwrap();
875 meshgraph
876 .add_face_from_halfedges(he_c_6_id, he_c_4_id)
877 .unwrap();
878
879 meshgraph
880 .add_face_from_halfedges(he_c_1_id, he_c_4_id)
881 .unwrap();
882
883 meshgraph.halfedges[he_c_1p_id].end_vertex = v1_id;
884 meshgraph.halfedges[he_c_4p_id].end_vertex = v4_id;
885
886 let AddOrGetEdge {
888 start_to_end_he_id: he_1p_4p_id,
889 twin_he_id: he_4p_1p_id,
890 ..
891 } = meshgraph.add_or_get_edge(v1p_id, v4p_id).unwrap();
892 meshgraph.halfedges[he_1p_4p_id].end_vertex = v4_id;
893 meshgraph.halfedges[he_4p_1p_id].end_vertex = v1_id;
894
895 let AddOrGetEdge {
896 start_to_end_he_id: he_3_1p_id,
897 twin_he_id: he_1p_3_id,
898 ..
899 } = meshgraph.add_or_get_edge(v3_id, v1p_id).unwrap();
900 meshgraph.halfedges[he_3_1p_id].end_vertex = v1_id;
901
902 let AddOrGetEdge {
903 start_to_end_he_id: he_4p_5_id,
904 twin_he_id: he_5_4p_id,
905 ..
906 } = meshgraph.add_or_get_edge(v4p_id, v5_id).unwrap();
907 meshgraph.halfedges[he_5_4p_id].end_vertex = v4_id;
908
909 meshgraph.outgoing_halfedges[v1_id].push(he_1p_4p_id);
910 meshgraph.outgoing_halfedges[v1_id].push(he_1p_c_id);
911 meshgraph.outgoing_halfedges[v1_id].push(he_1p_3_id);
912 meshgraph.outgoing_halfedges[v4_id].push(he_4p_1p_id);
913 meshgraph.outgoing_halfedges[v4_id].push(he_4p_c_id);
914 meshgraph.outgoing_halfedges[v4_id].push(he_4p_5_id);
915
916 meshgraph.remove_only_vertex(v1p_id);
917 meshgraph.remove_only_vertex(v4p_id);
918
919 #[cfg(feature = "rerun")]
920 meshgraph.log_rerun();
921
922 let mut removed_vertices = vec![];
923 let mut removed_halfedges = vec![];
924 let mut removed_faces = vec![];
925
926 meshgraph.remove_degenerate_faces(
927 center_v_id,
928 &mut removed_vertices,
929 &mut removed_halfedges,
930 &mut removed_faces,
931 );
932
933 #[cfg(feature = "rerun")]
934 {
935 meshgraph.log_rerun();
936 crate::RR.flush_blocking().unwrap();
937 }
938 }
939
940 #[test]
941 fn test_remove_degenerate_edges() {
942 crate::utils::get_tracing_subscriber();
943
944 let mut meshgraph = MeshGraph::new();
945
946 let center_v_id = meshgraph.add_vertex(Vec3::new(0.0, 0.0, 1.0));
947
948 let v1_id = meshgraph.add_vertex(Vec3::new(0.0, 0.0, 0.0));
949 let he_c_1_id = meshgraph
950 .add_or_get_edge(center_v_id, v1_id)
951 .unwrap()
952 .start_to_end_he_id;
953
954 let v1p_id = meshgraph.add_vertex(Vec3::new(0.0, 0.0, 0.0));
955 let AddOrGetEdge {
956 start_to_end_he_id: he_c_1p_id,
957 twin_he_id: he_1p_c_id,
958 ..
959 } = meshgraph.add_or_get_edge(center_v_id, v1p_id).unwrap();
960
961 let v2_id = meshgraph.add_vertex(Vec3::new(-1.0, 1.0, 0.0));
962 let he_c_2_id = meshgraph
963 .add_or_get_edge(center_v_id, v2_id)
964 .unwrap()
965 .start_to_end_he_id;
966
967 let v3_id = meshgraph.add_vertex(Vec3::new(-1.0, -1.0, 0.0));
968 let he_c_3_id = meshgraph
969 .add_or_get_edge(center_v_id, v3_id)
970 .unwrap()
971 .start_to_end_he_id;
972
973 let v5_id = meshgraph.add_vertex(Vec3::new(1.0, -1.0, 0.0));
974 let he_c_5_id = meshgraph
975 .add_or_get_edge(center_v_id, v5_id)
976 .unwrap()
977 .start_to_end_he_id;
978
979 let v6_id = meshgraph.add_vertex(Vec3::new(1.0, 1.0, 0.0));
980 let he_c_6_id = meshgraph
981 .add_or_get_edge(center_v_id, v6_id)
982 .unwrap()
983 .start_to_end_he_id;
984
985 meshgraph
986 .add_face_from_halfedges(he_c_1_id, he_c_2_id)
987 .unwrap();
988 meshgraph
989 .add_face_from_halfedges(he_c_2_id, he_c_3_id)
990 .unwrap();
991 meshgraph
992 .add_face_from_halfedges(he_c_3_id, he_c_1p_id)
993 .unwrap();
994
995 meshgraph
996 .add_face_from_halfedges(he_c_1p_id, he_c_5_id)
997 .unwrap();
998
999 meshgraph
1000 .add_face_from_halfedges(he_c_5_id, he_c_6_id)
1001 .unwrap();
1002 meshgraph
1003 .add_face_from_halfedges(he_c_6_id, he_c_1_id)
1004 .unwrap();
1005
1006 meshgraph.halfedges[he_c_1p_id].end_vertex = v1_id;
1007
1008 let AddOrGetEdge {
1010 start_to_end_he_id: he_3_1p_id,
1011 twin_he_id: he_1p_3_id,
1012 ..
1013 } = meshgraph.add_or_get_edge(v3_id, v1p_id).unwrap();
1014 meshgraph.halfedges[he_3_1p_id].end_vertex = v1_id;
1015
1016 let AddOrGetEdge {
1017 start_to_end_he_id: he_1p_5_id,
1018 twin_he_id: he_5_1p_id,
1019 ..
1020 } = meshgraph.add_or_get_edge(v1p_id, v5_id).unwrap();
1021 meshgraph.halfedges[he_5_1p_id].end_vertex = v1_id;
1022
1023 meshgraph.outgoing_halfedges[v1_id].push(he_1p_c_id);
1024 meshgraph.outgoing_halfedges[v1_id].push(he_1p_5_id);
1025 meshgraph.outgoing_halfedges[v1_id].push(he_1p_3_id);
1026
1027 meshgraph.remove_only_vertex(v1p_id);
1028
1029 #[cfg(feature = "rerun")]
1030 meshgraph.log_rerun();
1031
1032 meshgraph.remove_degenerate_edges(center_v_id);
1033
1034 #[cfg(feature = "rerun")]
1035 {
1036 meshgraph.log_rerun();
1037 crate::RR.flush_blocking().unwrap();
1038 }
1039 }
1040
1041 #[test]
1042 fn test_remove_flap() {
1043 crate::utils::get_tracing_subscriber();
1044
1045 let mut mesh_graph = MeshGraph::new();
1046
1047 let v1 = mesh_graph.add_vertex(Vec3::new(0.0, 0.0, 0.0));
1048 let v2 = mesh_graph.add_vertex(Vec3::new(1.0, 0.0, 0.0));
1049 let v3 = mesh_graph.add_vertex(Vec3::new(0.0, 1.0, 0.0));
1050
1051 let v4 = mesh_graph.add_vertex(Vec3::new(1.0, 1.0, 0.5));
1052 let v5 = mesh_graph.add_vertex(Vec3::new(1.0, 1.0, -0.5));
1053
1054 let edge1 = mesh_graph.add_edge(v1, v2).unwrap();
1055 let edge2 = mesh_graph.add_edge(v2, v3).unwrap();
1056 let edge2_d = mesh_graph.add_edge(v2, v3).unwrap();
1057
1058 mesh_graph
1059 .add_face_from_halfedges(edge1.start_to_end_he_id, edge2.start_to_end_he_id)
1060 .unwrap();
1061 mesh_graph
1062 .add_face_from_halfedges(edge2_d.twin_he_id, edge1.twin_he_id)
1063 .unwrap();
1064
1065 mesh_graph
1066 .add_face_from_halfedge_and_vertex(edge2.twin_he_id, v4)
1067 .unwrap();
1068 mesh_graph
1069 .add_face_from_halfedge_and_vertex(edge2_d.start_to_end_he_id, v5)
1070 .unwrap();
1071
1072 #[cfg(feature = "rerun")]
1073 mesh_graph.log_rerun();
1074
1075 let mut removed_vertices = Vec::new();
1076 let mut removed_halfedges = Vec::new();
1077 let mut removed_faces = Vec::new();
1078
1079 mesh_graph.remove_neighboring_flaps(
1080 v1,
1081 &mut removed_vertices,
1082 &mut removed_halfedges,
1083 &mut removed_faces,
1084 );
1085
1086 #[cfg(feature = "rerun")]
1087 {
1088 mesh_graph.log_rerun();
1089 crate::RR.flush_blocking().unwrap();
1090 }
1091
1092 assert_eq!(removed_vertices.len(), 1);
1093 assert_eq!(removed_halfedges.len(), 6);
1094 assert_eq!(removed_faces.len(), 2);
1095 }
1096
1097 #[test]
1098 fn test_remove_double_flaps() {
1099 crate::utils::get_tracing_subscriber();
1100
1101 let mut mesh_graph = MeshGraph::new();
1102
1103 let v1 = mesh_graph.add_vertex(Vec3::new(0.0, 0.0, 0.0));
1104 let v2 = mesh_graph.add_vertex(Vec3::new(1.0, 0.0, 0.0));
1105 let v3 = mesh_graph.add_vertex(Vec3::new(0.0, 1.0, 0.0));
1106 let v4 = mesh_graph.add_vertex(Vec3::new(1.0, 1.0, 0.0));
1107
1108 let v5 = mesh_graph.add_vertex(Vec3::new(0.0, -1.0, 0.0));
1109
1110 let edge1 = mesh_graph.add_edge(v1, v2).unwrap();
1111 let edge1_d = mesh_graph.add_edge(v1, v2).unwrap();
1112 let edge2 = mesh_graph.add_edge(v2, v3).unwrap();
1113 let edge2_d = mesh_graph.add_edge(v2, v3).unwrap();
1114
1115 mesh_graph
1116 .add_face_from_halfedges(edge1.start_to_end_he_id, edge2.start_to_end_he_id)
1117 .unwrap();
1118 mesh_graph
1119 .add_face_from_halfedge_and_vertex(edge2.twin_he_id, v4)
1120 .unwrap();
1121
1122 mesh_graph
1123 .add_face_from_halfedge_and_vertex(edge2_d.start_to_end_he_id, v4)
1124 .unwrap();
1125 mesh_graph
1126 .add_face_from_halfedges(edge2_d.twin_he_id, edge1_d.twin_he_id)
1127 .unwrap();
1128
1129 mesh_graph
1130 .add_face_from_halfedge_and_vertex(edge1_d.start_to_end_he_id, v5)
1131 .unwrap();
1132
1133 #[cfg(feature = "rerun")]
1134 mesh_graph.log_rerun();
1135
1136 let mut removed_vertices = Vec::new();
1137 let mut removed_halfedges = Vec::new();
1138 let mut removed_faces = Vec::new();
1139
1140 mesh_graph.remove_neighboring_flaps(
1141 v1,
1142 &mut removed_vertices,
1143 &mut removed_halfedges,
1144 &mut removed_faces,
1145 );
1146
1147 #[cfg(feature = "rerun")]
1148 {
1149 mesh_graph.log_rerun();
1150 crate::RR.flush_blocking().unwrap();
1151 }
1152
1153 assert_eq!(removed_vertices.len(), 0);
1154 assert_eq!(removed_halfedges.len(), 6);
1155 assert_eq!(removed_faces.len(), 2);
1156 }
1157}