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 len = outgoing_halfedges.len();
184            let mut current_outgoing_halfedges = Vec::with_capacity(len);
185
186            loop {
187                if !outgoing_halfedges.remove(&current_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                    // TODO : handle boundary edges?
202                    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        // just created above
263        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        // Updating vertices
368        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                // already checked in iterator that this he exists
376                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        // Updating start vertex
510        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                // already checked in iterator that this he exists
518                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    /// This finds the common edge between the two faces and welds them together by connecting
538    /// the two `twin` relationships. The reverse `twin` pointers of the previous twins are not changed.
539    ///
540    /// `start_vertex_id` is shared by `face_id1` and `face_id2`.
541    fn weld_faces(
542        &mut self,
543        start_vertex_id: VertexId,
544        face_id1: FaceId,
545        face_id2: FaceId,
546    ) -> Option<()> {
547        // #[cfg(feature = "rerun")]
548        // {
549        //     self.log_face_rerun("face1", face_id1);
550        //     self.log_face_rerun("face2", face_id2);
551        // }
552
553        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    /// Removes all neighboring flaps (triangles that share all the same vertices) connected to the given vertex.
665    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                // TODO : Handle the case when there is only one halfedge?
721                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                            // might have been deleted by prior iteration
726                            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                        // the twin edges of the neighboring faces of the deleted faces are still there
747                        // we need to remove them and re-connect (twin) their twin edges
748
749                        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        // already created from face above
887        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        // already created from face above
1009        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}