mesh_graph/ops/
delete.rs

1use hashbrown::HashSet;
2use tracing::instrument;
3
4use crate::{FaceId, HalfedgeId, MeshGraph, VertexId, error_none, utils::unwrap_or_return};
5
6impl MeshGraph {
7    /// Deletes a face from the mesh graph.
8    ///
9    /// It also deletes the vertices and halfedges that are no
10    /// longer connected to any other faces.
11    ///
12    /// Returns the ids of the removed vertices and halfedges.
13    #[instrument(skip(self))]
14    pub fn delete_face(&mut self, face_id: FaceId) -> (Vec<VertexId>, Vec<HalfedgeId>) {
15        let face = unwrap_or_return!(self.faces.get(face_id), "Face not found", (vec![], vec![]));
16
17        let vertices = face.vertices(self).collect::<Vec<_>>();
18        let halfedges = face.halfedges(self).collect::<Vec<_>>();
19
20        let mut deleted_halfedges = HashSet::with_capacity(4);
21
22        for he_id in halfedges {
23            let he = unwrap_or_return!(
24                self.halfedges.get(he_id),
25                "Halfedge not found",
26                (vec![], vec![])
27            );
28            let twin_id = unwrap_or_return!(he.twin, "Twin not found", (vec![], vec![]));
29
30            if unwrap_or_return!(
31                self.halfedges.get(twin_id),
32                "Twin halfedge not found",
33                (vec![], vec![])
34            )
35            .is_boundary()
36            {
37                deleted_halfedges.insert(he_id);
38                deleted_halfedges.insert(twin_id);
39            } else {
40                // already checked above
41                self.halfedges[he_id].face = None;
42                self.halfedges[he_id].next = None;
43            }
44        }
45
46        #[cfg(feature = "rerun")]
47        self.log_hes_rerun(
48            "deleted_by_face_deletion",
49            &deleted_halfedges.iter().copied().collect::<Vec<_>>(),
50        );
51
52        let mut deleted_vertices = Vec::with_capacity(3);
53
54        for &vertex_id in &vertices {
55            let mut all_deleted = true;
56            for he_id in unwrap_or_return!(
57                self.vertices.get(vertex_id),
58                "Vertex not found",
59                (vec![], vec![])
60            )
61            .outgoing_halfedges(self)
62            {
63                if !deleted_halfedges.contains(&he_id) {
64                    all_deleted = false;
65                    break;
66                }
67            }
68
69            if all_deleted {
70                self.positions.remove(vertex_id);
71                if let Some(normals) = &mut self.vertex_normals {
72                    normals.remove(vertex_id);
73                }
74                self.vertices.remove(vertex_id);
75
76                deleted_vertices.push(vertex_id);
77            }
78        }
79
80        // Update connections from vertices to deleted halfedges
81        for &he_id in &deleted_halfedges {
82            // checked when inserted into deleted_halfedges
83            let start_v_id = unwrap_or_return!(
84                self.halfedges[he_id].start_vertex(self),
85                "Start vertex not found",
86                (vec![], vec![])
87            );
88            if let Some(v) = self.vertices.get(start_v_id) {
89                self.vertices[start_v_id].outgoing_halfedge = v
90                    .outgoing_halfedges(self)
91                    .into_iter()
92                    .find(|id| !deleted_halfedges.contains(id))
93                    .or_else(error_none!("No new outgoing halfedge found"));
94            }
95        }
96
97        for &he_id in &deleted_halfedges {
98            self.halfedges.remove(he_id);
99        }
100
101        // already checked at the start of the function
102        self.bvh.remove(self.faces[face_id].index);
103        self.faces.remove(face_id);
104
105        (deleted_vertices, Vec::from_iter(deleted_halfedges))
106    }
107}