Skip to main content

mesh_graph/ops/
remove.rs

1use hashbrown::HashSet;
2use itertools::Itertools;
3use tracing::instrument;
4
5use crate::{FaceId, HalfedgeId, MeshGraph, VertexId, utils::unwrap_or_return};
6
7impl MeshGraph {
8    /// Deletes a face from the mesh graph.
9    ///
10    /// It also deletes the vertices and halfedges that are no
11    /// longer connected to any other faces.
12    ///
13    /// Returns the ids of the removed vertices and halfedges.
14    #[instrument(skip(self))]
15    pub fn remove_face(&mut self, face_id: FaceId) -> (Vec<VertexId>, Vec<HalfedgeId>) {
16        if !self.faces.contains_key(face_id) {
17            return (vec![], vec![]);
18        }
19
20        let halfedges = self
21            .halfedges
22            .iter()
23            .filter_map(|(he_id, he)| {
24                if he.face == Some(face_id) {
25                    Some((he_id, *he))
26                } else {
27                    None
28                }
29            })
30            .collect_vec();
31
32        let mut removed_halfedges = HashSet::with_capacity(4);
33
34        for (he_id, he) in halfedges {
35            let twin_id = unwrap_or_return!(he.twin, "Twin not found", (vec![], vec![]));
36
37            let twin = unwrap_or_return!(
38                self.halfedges.get(twin_id),
39                "Twin halfedge not found",
40                (vec![], vec![])
41            );
42            if twin.is_boundary() {
43                removed_halfedges.insert(he_id);
44                removed_halfedges.insert(twin_id);
45            } else if twin.twin != Some(he_id) {
46                removed_halfedges.insert(he_id);
47            } else {
48                // already checked above
49                self.halfedges[he_id].face = None;
50                self.halfedges[he_id].next = None;
51            }
52        }
53
54        #[cfg(feature = "rerun")]
55        self.log_hes_rerun(
56            "deleted_by_face_deletion",
57            &removed_halfedges.iter().copied().collect::<Vec<_>>(),
58        );
59
60        let mut removed_vertices = Vec::with_capacity(3);
61
62        // Update connections from vertices to deleted halfedges
63        for &he_id in &removed_halfedges {
64            // checked when inserted into deleted_halfedges
65            let start_v_id = unwrap_or_return!(
66                self.halfedges[he_id].start_vertex(self),
67                "Start vertex not found",
68                (vec![], vec![])
69            );
70            if let Some(out_he_ids) = self.outgoing_halfedges.get_mut(start_v_id) {
71                out_he_ids.retain(|&id| id != he_id);
72            }
73
74            if let Some(out_he_ids) = self.outgoing_halfedges.get(start_v_id)
75                && !out_he_ids.is_empty()
76            {
77                let v = unwrap_or_return!(
78                    self.vertices.get_mut(start_v_id),
79                    "Vertex not found",
80                    (vec![], vec![])
81                );
82
83                v.outgoing_halfedge = Some(self.outgoing_halfedges[start_v_id][0]);
84            } else {
85                self.remove_only_vertex(start_v_id);
86                removed_vertices.push(start_v_id);
87            }
88        }
89
90        for he_id in &removed_halfedges {
91            self.halfedges.remove(*he_id);
92        }
93
94        // already checked at the start of the function
95        self.bvh.remove(self.faces[face_id].index);
96        self.faces.remove(face_id);
97
98        (removed_vertices, Vec::from_iter(removed_halfedges))
99    }
100
101    /// Deletes only a vertex, without deleting any faces or halfedges connected to it.
102    pub fn remove_only_vertex(&mut self, vertex_id: VertexId) {
103        self.outgoing_halfedges.remove(vertex_id);
104        self.positions.remove(vertex_id);
105        if let Some(normals) = &mut self.vertex_normals {
106            normals.remove(vertex_id);
107        }
108        self.vertices.remove(vertex_id);
109    }
110
111    /// Deletes only a halfedge, without deleting any faces or vertices connected to it.
112    /// This also doesn't delete or update any twin
113    pub fn remove_only_halfedge(&mut self, he_id: HalfedgeId) {
114        if let Some(he) = self.halfedges.get(he_id) {
115            if let Some(start_v_id) = he.start_vertex(self)
116                && let Some(hes) = self.outgoing_halfedges.get_mut(start_v_id)
117            {
118                hes.retain(|out_he_id| *out_he_id != he_id);
119            }
120
121            self.halfedges.remove(he_id);
122        }
123    }
124
125    pub fn remove_only_halfedge_and_twin(&mut self, he_id: HalfedgeId) {
126        if let Some(he) = self.halfedges.get(he_id) {
127            if let Some(start_v_id) = he.start_vertex(self)
128                && let Some(hes) = self.outgoing_halfedges.get_mut(start_v_id)
129            {
130                hes.retain(|out_he_id| *out_he_id != he_id);
131            }
132
133            if let Some(twin_he_id) = he.twin {
134                self.remove_only_halfedge(twin_he_id);
135            }
136
137            self.halfedges.remove(he_id);
138        }
139    }
140}
141
142#[cfg(test)]
143mod tests {
144    use glam::{Mat4, vec3};
145
146    use crate::{
147        utils::{extend_with, get_tracing_subscriber},
148        *,
149    };
150
151    #[test]
152    fn test_remove_face() {
153        get_tracing_subscriber();
154        let mut meshgraph = MeshGraph::new();
155        let p_c = vec3(0.0, 0.0, 0.0);
156        let p_1 = vec3(0.0, 1.0, 0.0);
157        let p_2 = vec3(-1.0, 0.5, 0.0);
158        let p_3 = vec3(-1.0, -0.5, 0.0);
159        let p_4 = vec3(0.0, -1.0, 0.0);
160        let p_5 = vec3(1.0, -0.5, 0.0);
161        let p_6 = vec3(1.0, 0.5, 0.0);
162
163        let points = vec![p_c, p_1, p_2, p_3, p_4, p_5, p_6];
164        let vertex_ids = extend_with(&mut meshgraph, &points.clone(), Mat4::default(), 5.0, 0);
165
166        #[cfg(feature = "rerun")]
167        {
168            meshgraph.log_rerun();
169            RR.flush_blocking().unwrap();
170        }
171
172        let face_count = meshgraph.faces.len();
173        let face_id = meshgraph.vertices[vertex_ids[6]]
174            .faces(&meshgraph)
175            .next()
176            .unwrap();
177        meshgraph.remove_face(face_id);
178        #[cfg(feature = "rerun")]
179        {
180            meshgraph.log_rerun();
181            RR.flush_blocking().unwrap();
182        }
183
184        assert_eq!(meshgraph.faces.len(), face_count - 1);
185    }
186}