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 mut current_outgoing_halfedges = Vec::with_capacity(outgoing_halfedges.len());
184
185 loop {
186 outgoing_halfedges.remove(¤t_he_id);
187 current_outgoing_halfedges.push(current_he_id);
188
189 let cur_he = self
190 .halfedges
191 .get(current_he_id)
192 .or_else(error_none!("Halfedge not found"))?;
193
194 let Some(next_he_id) = cur_he.cw_rotated_neighbour(self) else {
195 break;
197 };
198
199 if next_he_id == start_he_id {
200 break;
201 }
202
203 current_he_id = next_he_id;
204 }
205
206 if !outgoing_halfedges.is_empty() {
207 let new_vertex_id = self
208 .duplicate_vertex_and_assign_halfedges(vertex_id, current_outgoing_halfedges)?;
209
210 new_vertices.push(new_vertex_id);
211
212 self.vertices
213 .get_mut(vertex_id)
214 .or_else(error_none!("Vertex not found"))?
215 .outgoing_halfedge = Some(*outgoing_halfedges.iter().next().unwrap());
216
217 self.outgoing_halfedges
218 .insert(vertex_id, Vec::from_iter(outgoing_halfedges));
219
220 return Some(new_vertices);
221 }
222 }
223
224 Some(new_vertices)
225 }
226
227 fn duplicate_vertex_and_assign_halfedges(
228 &mut self,
229 vertex_id: VertexId,
230 outgoing_halfedges: Vec<HalfedgeId>,
231 ) -> Option<VertexId> {
232 let new_vert_id = self.add_vertex(
233 *self
234 .positions
235 .get(vertex_id)
236 .or_else(error_none!("Position not found"))?
237 + glam::Vec3::new(0.1, 0.0, 0.0),
238 );
239
240 tracing::info!("Duplicated {vertex_id:?}: {new_vert_id:?}");
241
242 for &he_id in &outgoing_halfedges {
243 let he = self
244 .halfedges
245 .get(he_id)
246 .or_else(error_none!("Halfedge not found"))?;
247
248 let twin_id = he.twin.or_else(error_none!("Twin not found"))?;
249
250 self.halfedges
251 .get_mut(twin_id)
252 .or_else(error_none!("Twin not found"))?
253 .end_vertex = new_vert_id;
254 }
255
256 self.vertices[new_vert_id].outgoing_halfedge = Some(outgoing_halfedges[0]);
258
259 self.outgoing_halfedges
260 .insert(new_vert_id, outgoing_halfedges);
261
262 Some(new_vert_id)
263 }
264
265 fn remove_degenerate_edges(&mut self, vertex_id: VertexId) -> Option<VertexId> {
266 let halfedges = self
267 .vertices
268 .get(vertex_id)
269 .or_else(error_none!("Vertex not found"))?
270 .outgoing_halfedges(self)
271 .collect_vec();
272
273 for (he_id1, he_id2) in halfedges.into_iter().tuple_combinations() {
274 if self.halfedges_share_all_vertices(he_id1, he_id2) {
275 let he1 = self.halfedges[he_id1];
276 let twin_id1 = he1.twin.or_else(error_none!("Twin not found"))?;
277 let face_id1 = self
278 .halfedges
279 .get(twin_id1)
280 .or_else(error_none!("Halfedge not found"))?
281 .face
282 .or_else(error_none!("Face not found"))?;
283 let face_id2 = self
284 .halfedges
285 .get(he_id2)
286 .or_else(error_none!("Halfedge not found"))?
287 .face
288 .or_else(error_none!("Face not found"))?;
289
290 let coincident_face_ids = self.vertices[vertex_id].faces(self).collect_vec();
291 let mut start_idx = 0;
292
293 for (idx, face_id) in coincident_face_ids.iter().enumerate() {
294 if *face_id == face_id1 {
295 start_idx = idx;
296 break;
297 }
298 }
299
300 let mut end_idx = start_idx;
301 let mut side_one = vec![];
302
303 loop {
304 let face_id = coincident_face_ids[end_idx];
305
306 side_one.push(face_id);
307
308 end_idx += 1;
309 end_idx %= coincident_face_ids.len();
310
311 if face_id == face_id2 {
312 break;
313 }
314 }
315
316 let mut side_two = vec![];
317
318 while end_idx != start_idx {
319 let face_id = coincident_face_ids[end_idx];
320
321 side_two.push(face_id);
322
323 end_idx += 1;
324 end_idx %= coincident_face_ids.len();
325 }
326
327 return self.split_regions_at_edge(vertex_id, he1.end_vertex, side_one, side_two);
328 }
329 }
330
331 None
332 }
333
334 #[instrument(skip(self))]
335 fn split_regions_at_edge(
336 &mut self,
337 vertex_id: VertexId,
338 other_vertex_id: VertexId,
339 side_one: Vec<FaceId>,
340 side_two: Vec<FaceId>,
341 ) -> Option<VertexId> {
342 if side_one.len() < 2 || side_two.len() < 2 {
343 error!("Not enough halfedges to split");
344 return None;
345 }
346
347 #[cfg(feature = "rerun")]
348 {
349 self.log_vert_rerun("split_regions_at_edge", vertex_id);
350 self.log_faces_rerun("split_regions_at_edge/side_one", &side_one);
351 self.log_faces_rerun("split_regions_at_edge/side_two", &side_two);
352 }
353
354 let new_vertex_id = self.add_vertex(
355 *self
356 .positions
357 .get(vertex_id)
358 .or_else(error_none!("Vertex position not found"))?,
359 );
360
361 for face_id in &side_two {
363 let face = self
364 .faces
365 .get(*face_id)
366 .or_else(error_none!("Face not found"))?;
367
368 for he_id in face.halfedges(self).collect_vec() {
369 let he = &mut self.halfedges[he_id];
371
372 if he.end_vertex == vertex_id {
373 he.end_vertex = new_vertex_id;
374 }
375 }
376 }
377
378 self.weld_faces_at(
379 vertex_id,
380 other_vertex_id,
381 side_one[side_one.len() - 1],
382 side_one[0],
383 );
384 self.weld_faces_at(
385 new_vertex_id,
386 other_vertex_id,
387 side_two[0],
388 side_two[side_two.len() - 1],
389 );
390
391 self.outgoing_halfedges[vertex_id] =
392 self.vertices[vertex_id].outgoing_halfedges(self).collect();
393 self.outgoing_halfedges[new_vertex_id] = self.vertices[new_vertex_id]
394 .outgoing_halfedges(self)
395 .collect();
396
397 Some(new_vertex_id)
398 }
399
400 #[instrument(skip_all)]
401 pub fn remove_degenerate_faces(
402 &mut self,
403 vertex_id: VertexId,
404 removed_vertices: &mut Vec<VertexId>,
405 removed_halfedges: &mut Vec<HalfedgeId>,
406 removed_faces: &mut Vec<FaceId>,
407 ) -> Option<VertexId> {
408 let faces = self
409 .vertices
410 .get(vertex_id)
411 .or_else(error_none!("Vertex not found"))?
412 .faces(self)
413 .collect_vec();
414
415 for (face_id1, face_id2) in faces.into_iter().tuple_combinations() {
416 if self.faces_share_all_vertices(face_id1, face_id2) {
417 let coincident_face_ids = self.vertices[vertex_id].faces(self).collect_vec();
418 let mut start_idx = 0;
419
420 for (idx, face_id) in coincident_face_ids.iter().enumerate() {
421 if *face_id == face_id1 {
422 start_idx = (idx + 1) % coincident_face_ids.len();
423 break;
424 }
425 }
426
427 let mut end_idx = start_idx;
428 let mut side_one = vec![];
429
430 loop {
431 let face_id = coincident_face_ids[end_idx];
432
433 end_idx += 1;
434 end_idx %= coincident_face_ids.len();
435
436 if face_id == face_id2 {
437 break;
438 }
439
440 side_one.push(face_id);
441 }
442
443 let mut side_two = vec![];
444
445 while end_idx != start_idx {
446 let face_id = coincident_face_ids[end_idx];
447
448 side_two.push(face_id);
449
450 end_idx += 1;
451 end_idx %= coincident_face_ids.len();
452 }
453
454 side_two.pop();
455
456 let new_vertex_id =
457 self.split_regions_at_vertex(vertex_id, side_one, side_two, removed_halfedges);
458
459 let (del_v_ids, del_he_ids) = self.remove_face(face_id1);
460 removed_vertices.extend(del_v_ids);
461 removed_halfedges.extend(del_he_ids);
462 removed_faces.push(face_id1);
463
464 let (del_v_ids, del_he_ids) = self.remove_face(face_id2);
465 removed_vertices.extend(del_v_ids);
466 removed_halfedges.extend(del_he_ids);
467 removed_faces.push(face_id2);
468
469 return new_vertex_id;
470 }
471 }
472
473 None
474 }
475
476 #[instrument(skip(self))]
477 fn split_regions_at_vertex(
478 &mut self,
479 vertex_id: VertexId,
480 side_one: Vec<FaceId>,
481 side_two: Vec<FaceId>,
482 removed_halfedges: &mut Vec<HalfedgeId>,
483 ) -> Option<VertexId> {
484 if side_one.len() < 2 || side_two.len() < 2 {
485 error!("Not enough halfedges to split");
486 return None;
487 }
488
489 #[cfg(feature = "rerun")]
490 {
491 self.log_vert_rerun("split_regions_at_vertex", vertex_id);
492 self.log_faces_rerun("split_regions_at_vertex/side_one", &side_one);
493 self.log_faces_rerun("split_regions_at_vertex/side_two", &side_two);
494 }
495
496 let new_vertex_id = self.add_vertex(
497 *self
498 .positions
499 .get(vertex_id)
500 .or_else(error_none!("Vertex position not found"))?,
501 );
502
503 for face_id in &side_two {
505 let face = self
506 .faces
507 .get(*face_id)
508 .or_else(error_none!("Face not found"))?;
509
510 for he_id in face.halfedges(self).collect_vec() {
511 let he = &mut self.halfedges[he_id];
513 if he.end_vertex == vertex_id {
514 he.end_vertex = new_vertex_id;
515 }
516 }
517 }
518
519 self.weld_faces(vertex_id, side_one[side_one.len() - 1], side_one[0]);
520 self.weld_faces(new_vertex_id, side_two[0], side_two[side_two.len() - 1]);
521
522 self.outgoing_halfedges[vertex_id] =
523 self.vertices[vertex_id].outgoing_halfedges(self).collect();
524 self.outgoing_halfedges[new_vertex_id] = self.vertices[new_vertex_id]
525 .outgoing_halfedges(self)
526 .collect();
527
528 Some(new_vertex_id)
529 }
530
531 fn weld_faces(
536 &mut self,
537 start_vertex_id: VertexId,
538 face_id1: FaceId,
539 face_id2: FaceId,
540 ) -> Option<()> {
541 let face1 = self
548 .faces
549 .get(face_id1)
550 .or_else(error_none!("Face not found"))?;
551 let face2 = self
552 .faces
553 .get(face_id2)
554 .or_else(error_none!("Face not found"))?;
555
556 let face1_vertices = face1.vertices(self).collect::<HashSet<_>>();
557 let face2_vertices = face2.vertices(self).collect::<HashSet<_>>();
558
559 let mut other_common_vertex_id = None;
560
561 for &v_id in face1_vertices.intersection(&face2_vertices) {
562 if v_id != start_vertex_id {
563 other_common_vertex_id = Some(v_id);
564 break;
565 }
566 }
567
568 let other_common_vertex_id =
569 other_common_vertex_id.or_else(error_none!("No other common vertex found"))?;
570
571 self.weld_faces_at(start_vertex_id, other_common_vertex_id, face_id1, face_id2)
572 }
573
574 #[instrument(skip(self))]
575 fn weld_faces_at(
576 &mut self,
577 start_vertex_id: VertexId,
578 other_common_vertex_id: VertexId,
579 face_id1: FaceId,
580 face_id2: FaceId,
581 ) -> Option<()> {
582 let face1 = self
583 .faces
584 .get(face_id1)
585 .or_else(error_none!("Face not found"))?;
586 let face2 = self
587 .faces
588 .get(face_id2)
589 .or_else(error_none!("Face not found"))?;
590
591 let he1_id = face1
592 .halfedge_between(start_vertex_id, other_common_vertex_id, self)
593 .or_else(error_none!("Halfedge between vertices not found"))?;
594
595 let he2_id = face2
596 .halfedge_between(start_vertex_id, other_common_vertex_id, self)
597 .or_else(error_none!("Halfedge between vertices not found"))?;
598
599 self.halfedges[he1_id].twin = Some(he2_id);
600 self.halfedges[he2_id].twin = Some(he1_id);
601
602 let (start_out_he_id, other_out_he_id) =
603 if self.halfedges[he1_id].end_vertex == start_vertex_id {
604 (he2_id, he1_id)
605 } else {
606 (he1_id, he2_id)
607 };
608
609 self.vertices
610 .get_mut(start_vertex_id)
611 .or_else(error_none!("Start vertex not found"))?
612 .outgoing_halfedge = Some(start_out_he_id);
613 self.vertices
614 .get_mut(other_common_vertex_id)
615 .or_else(error_none!("Other vertex not found"))?
616 .outgoing_halfedge = Some(other_out_he_id);
617
618 Some(())
619 }
620
621 pub(crate) fn remove_single_face(
622 &mut self,
623 vertex_id: VertexId,
624 removed_vertices: &mut Vec<VertexId>,
625 removed_halfedges: &mut Vec<HalfedgeId>,
626 removed_faces: &mut Vec<FaceId>,
627 ) -> Option<bool> {
628 let face_ids = self
629 .outgoing_halfedges
630 .get(vertex_id)
631 .or_else(error_none!(
632 "Outgoing halfedges not found for vertex {vertex_id:?}"
633 ))?
634 .iter()
635 .filter_map(|&he_id| {
636 self.halfedges
637 .get(he_id)
638 .or_else(error_none!("Halfedge not found"))
639 .and_then(|he| he.face)
640 })
641 .collect_vec();
642
643 if face_ids.len() == 1 {
644 let face_id = face_ids[0];
645
646 let (v_ids, he_ids) = self.remove_face(face_id);
647
648 removed_vertices.extend(v_ids);
649 removed_halfedges.extend(he_ids);
650 removed_faces.push(face_id);
651
652 Some(true)
653 } else {
654 Some(false)
655 }
656 }
657
658 fn remove_neighboring_flaps(
659 &mut self,
660 vertex_id: VertexId,
661 removed_vertices: &mut Vec<VertexId>,
662 removed_halfedges: &mut Vec<HalfedgeId>,
663 removed_faces: &mut Vec<FaceId>,
664 ) -> Option<bool> {
665 let faces = self
666 .vertices
667 .get(vertex_id)
668 .or_else(error_none!("Vertex not found"))?
669 .faces(self)
670 .collect_vec();
671
672 if faces.len() < 2 {
673 return Some(false);
674 }
675
676 let mut face_tuples = faces.into_iter().circular_tuple_windows().collect_vec();
677
678 while let Some((face_id1, face_id2)) = face_tuples.pop() {
679 if self.faces_share_all_vertices(face_id1, face_id2) {
680 #[cfg(feature = "rerun")]
681 {
682 self.log_vert_rerun("flap", vertex_id);
683 self.log_face_rerun("flap1", face_id1);
684 self.log_face_rerun("flap2", face_id2);
685 }
686
687 let mut halfedges_of_faces = HashSet::<HalfedgeId>::from_iter(
688 self.halfedges.iter().filter_map(|(he_id, he)| {
689 if he.face == Some(face_id1) || he.face == Some(face_id2) {
690 Some(he_id)
691 } else {
692 None
693 }
694 }),
695 );
696
697 let (vs, hes) = self.remove_face(face_id1);
698 for he_id in &hes {
699 halfedges_of_faces.remove(he_id);
700 }
701 removed_vertices.extend(vs);
702 removed_halfedges.extend(hes);
703 removed_faces.push(face_id1);
704
705 let (vs, hes) = self.remove_face(face_id2);
706 for he_id in &hes {
707 halfedges_of_faces.remove(he_id);
708 }
709 removed_vertices.extend(vs);
710 removed_halfedges.extend(hes);
711 removed_faces.push(face_id2);
712
713 if halfedges_of_faces.len() >= 2 {
715 for (he_id1, he_id2) in halfedges_of_faces.iter().copied().tuple_combinations()
716 {
717 let Some(he1) = self.halfedges.get(he_id1) else {
718 continue;
720 };
721 let twin_id1 = he1.twin.or_else(error_none!("Twin 1 missing"))?;
722
723 let Some(he2) = self.halfedges.get(he_id2) else {
724 continue;
725 };
726 let twin_id2 = he2.twin.or_else(error_none!("Twin 2 missing"))?;
727
728 let start_v_id1 = he1
729 .start_vertex(self)
730 .or_else(error_none!("Start vertex 1 missing"))?;
731 let start_v_id2 = he2
732 .start_vertex(self)
733 .or_else(error_none!("Start vertex 2 missing"))?;
734
735 if he1.end_vertex != start_v_id2 || he2.end_vertex != start_v_id1 {
736 continue;
737 }
738
739 self.remove_only_halfedge(he_id1);
743 self.remove_only_halfedge(he_id2);
744 removed_halfedges.push(he_id1);
745 removed_halfedges.push(he_id2);
746
747 {
748 let twin1 = self
749 .halfedges
750 .get_mut(twin_id1)
751 .or_else(error_none!("Twin 1 missing"))?;
752 twin1.twin = Some(twin_id2);
753 };
754
755 {
756 let twin2 = self
757 .halfedges
758 .get_mut(twin_id2)
759 .or_else(error_none!("Twin 2 missing"))?;
760 twin2.twin = Some(twin_id1);
761 };
762
763 self.vertices
764 .get_mut(start_v_id1)
765 .or_else(error_none!("Start vertex 1 missing"))?
766 .outgoing_halfedge = Some(twin_id2);
767
768 self.vertices
769 .get_mut(start_v_id2)
770 .or_else(error_none!("Start vertex 2 missing"))?
771 .outgoing_halfedge = Some(twin_id1);
772 }
773 }
774
775 return Some(true);
776 }
777 }
778
779 Some(false)
780 }
781}
782
783#[cfg(test)]
784mod tests {
785 use crate::ops::AddOrGetEdge;
786
787 use super::*;
788 use glam::Vec3;
789
790 #[test]
791 fn test_remove_degenerate_faces() {
792 crate::utils::get_tracing_subscriber();
793 let mut meshgraph = MeshGraph::new();
794
795 let center_v_id = meshgraph.add_vertex(Vec3::new(0.0, 0.0, 1.0));
796
797 let v1_id = meshgraph.add_vertex(Vec3::new(-0.2, 0.0, 0.0));
798 let he_c_1_id = meshgraph
799 .add_or_get_edge(center_v_id, v1_id)
800 .start_to_end_he_id;
801 let v1p_id = meshgraph.add_vertex(Vec3::new(-0.2, 0.0, 0.0));
802 let AddOrGetEdge {
803 start_to_end_he_id: he_c_1p_id,
804 twin_he_id: he_1p_c_id,
805 ..
806 } = meshgraph.add_or_get_edge(center_v_id, v1p_id);
807
808 let v2_id = meshgraph.add_vertex(Vec3::new(-1.0, 1.0, 0.0));
809 let he_c_2_id = meshgraph
810 .add_or_get_edge(center_v_id, v2_id)
811 .start_to_end_he_id;
812
813 let v3_id = meshgraph.add_vertex(Vec3::new(-1.0, -1.0, 0.0));
814 let he_c_3_id = meshgraph
815 .add_or_get_edge(center_v_id, v3_id)
816 .start_to_end_he_id;
817
818 let v4_id = meshgraph.add_vertex(Vec3::new(0.2, 0.0, 0.0));
819 let he_c_4_id = meshgraph
820 .add_or_get_edge(center_v_id, v4_id)
821 .start_to_end_he_id;
822
823 let v4p_id = meshgraph.add_vertex(Vec3::new(0.2, 0.0, 0.0));
824 let AddOrGetEdge {
825 start_to_end_he_id: he_c_4p_id,
826 twin_he_id: he_4p_c_id,
827 ..
828 } = meshgraph.add_or_get_edge(center_v_id, v4p_id);
829
830 let v5_id = meshgraph.add_vertex(Vec3::new(1.0, -1.0, 0.0));
831 let he_c_5_id = meshgraph
832 .add_or_get_edge(center_v_id, v5_id)
833 .start_to_end_he_id;
834
835 let v6_id = meshgraph.add_vertex(Vec3::new(1.0, 1.0, 0.0));
836 let he_c_6_id = meshgraph
837 .add_or_get_edge(center_v_id, v6_id)
838 .start_to_end_he_id;
839
840 meshgraph
841 .add_face_from_halfedges(he_c_1_id, he_c_2_id)
842 .unwrap();
843 meshgraph
844 .add_face_from_halfedges(he_c_2_id, he_c_3_id)
845 .unwrap();
846 meshgraph
847 .add_face_from_halfedges(he_c_3_id, he_c_1p_id)
848 .unwrap();
849
850 meshgraph
851 .add_face_from_halfedges(he_c_1p_id, he_c_4p_id)
852 .unwrap();
853
854 meshgraph
855 .add_face_from_halfedges(he_c_4p_id, he_c_5_id)
856 .unwrap();
857 meshgraph
858 .add_face_from_halfedges(he_c_5_id, he_c_6_id)
859 .unwrap();
860 meshgraph
861 .add_face_from_halfedges(he_c_6_id, he_c_4_id)
862 .unwrap();
863
864 meshgraph
865 .add_face_from_halfedges(he_c_1_id, he_c_4_id)
866 .unwrap();
867
868 meshgraph.halfedges[he_c_1p_id].end_vertex = v1_id;
869 meshgraph.halfedges[he_c_4p_id].end_vertex = v4_id;
870
871 let AddOrGetEdge {
873 start_to_end_he_id: he_1p_4p_id,
874 twin_he_id: he_4p_1p_id,
875 ..
876 } = meshgraph.add_or_get_edge(v1p_id, v4p_id);
877 meshgraph.halfedges[he_1p_4p_id].end_vertex = v4_id;
878 meshgraph.halfedges[he_4p_1p_id].end_vertex = v1_id;
879
880 let AddOrGetEdge {
881 start_to_end_he_id: he_3_1p_id,
882 twin_he_id: he_1p_3_id,
883 ..
884 } = meshgraph.add_or_get_edge(v3_id, v1p_id);
885 meshgraph.halfedges[he_3_1p_id].end_vertex = v1_id;
886
887 let AddOrGetEdge {
888 start_to_end_he_id: he_4p_5_id,
889 twin_he_id: he_5_4p_id,
890 ..
891 } = meshgraph.add_or_get_edge(v4p_id, v5_id);
892 meshgraph.halfedges[he_5_4p_id].end_vertex = v4_id;
893
894 meshgraph.outgoing_halfedges[v1_id].push(he_1p_4p_id);
895 meshgraph.outgoing_halfedges[v1_id].push(he_1p_c_id);
896 meshgraph.outgoing_halfedges[v1_id].push(he_1p_3_id);
897 meshgraph.outgoing_halfedges[v4_id].push(he_4p_1p_id);
898 meshgraph.outgoing_halfedges[v4_id].push(he_4p_c_id);
899 meshgraph.outgoing_halfedges[v4_id].push(he_4p_5_id);
900
901 meshgraph.remove_only_vertex(v1p_id);
902 meshgraph.remove_only_vertex(v4p_id);
903
904 #[cfg(feature = "rerun")]
905 meshgraph.log_rerun();
906
907 let mut removed_vertices = vec![];
908 let mut removed_halfedges = vec![];
909 let mut removed_faces = vec![];
910
911 meshgraph.remove_degenerate_faces(
912 center_v_id,
913 &mut removed_vertices,
914 &mut removed_halfedges,
915 &mut removed_faces,
916 );
917
918 #[cfg(feature = "rerun")]
919 {
920 meshgraph.log_rerun();
921 crate::RR.flush_blocking().unwrap();
922 }
923 }
924
925 #[test]
926 fn test_remove_degenerate_edges() {
927 crate::utils::get_tracing_subscriber();
928
929 let mut meshgraph = MeshGraph::new();
930
931 let center_v_id = meshgraph.add_vertex(Vec3::new(0.0, 0.0, 1.0));
932
933 let v1_id = meshgraph.add_vertex(Vec3::new(0.0, 0.0, 0.0));
934 let he_c_1_id = meshgraph
935 .add_or_get_edge(center_v_id, v1_id)
936 .start_to_end_he_id;
937
938 let v1p_id = meshgraph.add_vertex(Vec3::new(0.0, 0.0, 0.0));
939 let AddOrGetEdge {
940 start_to_end_he_id: he_c_1p_id,
941 twin_he_id: he_1p_c_id,
942 ..
943 } = meshgraph.add_or_get_edge(center_v_id, v1p_id);
944
945 let v2_id = meshgraph.add_vertex(Vec3::new(-1.0, 1.0, 0.0));
946 let he_c_2_id = meshgraph
947 .add_or_get_edge(center_v_id, v2_id)
948 .start_to_end_he_id;
949
950 let v3_id = meshgraph.add_vertex(Vec3::new(-1.0, -1.0, 0.0));
951 let he_c_3_id = meshgraph
952 .add_or_get_edge(center_v_id, v3_id)
953 .start_to_end_he_id;
954
955 let v5_id = meshgraph.add_vertex(Vec3::new(1.0, -1.0, 0.0));
956 let he_c_5_id = meshgraph
957 .add_or_get_edge(center_v_id, v5_id)
958 .start_to_end_he_id;
959
960 let v6_id = meshgraph.add_vertex(Vec3::new(1.0, 1.0, 0.0));
961 let he_c_6_id = meshgraph
962 .add_or_get_edge(center_v_id, v6_id)
963 .start_to_end_he_id;
964
965 meshgraph
966 .add_face_from_halfedges(he_c_1_id, he_c_2_id)
967 .unwrap();
968 meshgraph
969 .add_face_from_halfedges(he_c_2_id, he_c_3_id)
970 .unwrap();
971 meshgraph
972 .add_face_from_halfedges(he_c_3_id, he_c_1p_id)
973 .unwrap();
974
975 meshgraph
976 .add_face_from_halfedges(he_c_1p_id, he_c_5_id)
977 .unwrap();
978
979 meshgraph
980 .add_face_from_halfedges(he_c_5_id, he_c_6_id)
981 .unwrap();
982 meshgraph
983 .add_face_from_halfedges(he_c_6_id, he_c_1_id)
984 .unwrap();
985
986 meshgraph.halfedges[he_c_1p_id].end_vertex = v1_id;
987
988 let AddOrGetEdge {
990 start_to_end_he_id: he_3_1p_id,
991 twin_he_id: he_1p_3_id,
992 ..
993 } = meshgraph.add_or_get_edge(v3_id, v1p_id);
994 meshgraph.halfedges[he_3_1p_id].end_vertex = v1_id;
995
996 let AddOrGetEdge {
997 start_to_end_he_id: he_1p_5_id,
998 twin_he_id: he_5_1p_id,
999 ..
1000 } = meshgraph.add_or_get_edge(v1p_id, v5_id);
1001 meshgraph.halfedges[he_5_1p_id].end_vertex = v1_id;
1002
1003 meshgraph.outgoing_halfedges[v1_id].push(he_1p_c_id);
1004 meshgraph.outgoing_halfedges[v1_id].push(he_1p_5_id);
1005 meshgraph.outgoing_halfedges[v1_id].push(he_1p_3_id);
1006
1007 meshgraph.remove_only_vertex(v1p_id);
1008
1009 #[cfg(feature = "rerun")]
1010 meshgraph.log_rerun();
1011
1012 meshgraph.remove_degenerate_edges(center_v_id);
1013
1014 #[cfg(feature = "rerun")]
1015 {
1016 meshgraph.log_rerun();
1017 crate::RR.flush_blocking().unwrap();
1018 }
1019 }
1020
1021 #[test]
1022 fn test_remove_flap() {
1023 crate::utils::get_tracing_subscriber();
1024
1025 let mut mesh_graph = MeshGraph::new();
1026
1027 let v1 = mesh_graph.add_vertex(Vec3::new(0.0, 0.0, 0.0));
1028 let v2 = mesh_graph.add_vertex(Vec3::new(1.0, 0.0, 0.0));
1029 let v3 = mesh_graph.add_vertex(Vec3::new(0.0, 1.0, 0.0));
1030
1031 let v4 = mesh_graph.add_vertex(Vec3::new(1.0, 1.0, 0.5));
1032 let v5 = mesh_graph.add_vertex(Vec3::new(1.0, 1.0, -0.5));
1033
1034 let edge1 = mesh_graph.add_edge(v1, v2);
1035 let edge2 = mesh_graph.add_edge(v2, v3);
1036 let edge2_d = mesh_graph.add_edge(v2, v3);
1037
1038 mesh_graph.add_face_from_halfedges(edge1.start_to_end_he_id, edge2.start_to_end_he_id);
1039 mesh_graph.add_face_from_halfedges(edge2_d.twin_he_id, edge1.twin_he_id);
1040
1041 mesh_graph.add_face_from_halfedge_and_vertex(edge2.twin_he_id, v4);
1042 mesh_graph.add_face_from_halfedge_and_vertex(edge2_d.start_to_end_he_id, v5);
1043
1044 #[cfg(feature = "rerun")]
1045 mesh_graph.log_rerun();
1046
1047 let mut removed_vertices = Vec::new();
1048 let mut removed_halfedges = Vec::new();
1049 let mut removed_faces = Vec::new();
1050
1051 mesh_graph.remove_neighboring_flaps(
1052 v1,
1053 &mut removed_vertices,
1054 &mut removed_halfedges,
1055 &mut removed_faces,
1056 );
1057
1058 #[cfg(feature = "rerun")]
1059 {
1060 mesh_graph.log_rerun();
1061 crate::RR.flush_blocking().unwrap();
1062 }
1063
1064 assert_eq!(removed_vertices.len(), 1);
1065 assert_eq!(removed_halfedges.len(), 6);
1066 assert_eq!(removed_faces.len(), 2);
1067 }
1068
1069 #[test]
1070 fn test_remove_double_flaps() {
1071 crate::utils::get_tracing_subscriber();
1072
1073 let mut mesh_graph = MeshGraph::new();
1074
1075 let v1 = mesh_graph.add_vertex(Vec3::new(0.0, 0.0, 0.0));
1076 let v2 = mesh_graph.add_vertex(Vec3::new(1.0, 0.0, 0.0));
1077 let v3 = mesh_graph.add_vertex(Vec3::new(0.0, 1.0, 0.0));
1078 let v4 = mesh_graph.add_vertex(Vec3::new(1.0, 1.0, 0.0));
1079
1080 let v5 = mesh_graph.add_vertex(Vec3::new(0.0, -1.0, 0.0));
1081
1082 let edge1 = mesh_graph.add_edge(v1, v2);
1083 let edge1_d = mesh_graph.add_edge(v1, v2);
1084 let edge2 = mesh_graph.add_edge(v2, v3);
1085 let edge2_d = mesh_graph.add_edge(v2, v3);
1086
1087 mesh_graph.add_face_from_halfedges(edge1.start_to_end_he_id, edge2.start_to_end_he_id);
1088 mesh_graph.add_face_from_halfedge_and_vertex(edge2.twin_he_id, v4);
1089
1090 mesh_graph.add_face_from_halfedge_and_vertex(edge2_d.start_to_end_he_id, v4);
1091 mesh_graph.add_face_from_halfedges(edge2_d.twin_he_id, edge1_d.twin_he_id);
1092
1093 mesh_graph.add_face_from_halfedge_and_vertex(edge1_d.start_to_end_he_id, v5);
1094
1095 #[cfg(feature = "rerun")]
1096 mesh_graph.log_rerun();
1097
1098 let mut removed_vertices = Vec::new();
1099 let mut removed_halfedges = Vec::new();
1100 let mut removed_faces = Vec::new();
1101
1102 mesh_graph.remove_neighboring_flaps(
1103 v1,
1104 &mut removed_vertices,
1105 &mut removed_halfedges,
1106 &mut removed_faces,
1107 );
1108
1109 #[cfg(feature = "rerun")]
1110 {
1111 mesh_graph.log_rerun();
1112 crate::RR.flush_blocking().unwrap();
1113 }
1114
1115 assert_eq!(removed_vertices.len(), 0);
1116 assert_eq!(removed_halfedges.len(), 6);
1117 assert_eq!(removed_faces.len(), 2);
1118 }
1119}