Skip to main content

mesh_graph/ops/cleanup/
vertex_neighborhood.rs

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    /// Ensure that the neighborhood of a vertex is manifold.
28    ///
29    /// It removes flaps (two neighboring coincident triangles) and splits the given vertex
30    /// in two if there are non-neighboring degenerate triangles or edges.
31    ///
32    /// See [Freestyle: Sculpting meshes with self-adaptive topology DOI 10.1016/j.cag.2011.03.033](https://inria.hal.science/inria-00606516v1/document)
33    /// Chapters 3.2 and 5.1
34    #[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(&current_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                    // TODO : handle boundary edges?
196                    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        // just created above
257        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        // Updating vertices
362        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                // already checked in iterator that this he exists
370                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        // Updating start vertex
504        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                // already checked in iterator that this he exists
512                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    /// This finds the common edge between the two faces and welds them together by connecting
532    /// the two `twin` relationships. The reverse `twin` pointers of the previous twins are not changed.
533    ///
534    /// `start_vertex_id` is shared by `face_id1` and `face_id2`.
535    fn weld_faces(
536        &mut self,
537        start_vertex_id: VertexId,
538        face_id1: FaceId,
539        face_id2: FaceId,
540    ) -> Option<()> {
541        // #[cfg(feature = "rerun")]
542        // {
543        //     self.log_face_rerun("face1", face_id1);
544        //     self.log_face_rerun("face2", face_id2);
545        // }
546
547        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                // TODO : Handle the case when there is only one halfedge?
714                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                            // might have been deleted by prior iteration
719                            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                        // the twin edges of the neighboring faces of the deleted faces are still there
740                        // we need to remove them and re-connect (twin) their twin edges
741
742                        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        // already created from face above
872        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        // already created from face above
989        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}