1use hashbrown::HashSet;
2use itertools::Itertools;
3use tracing::instrument;
4
5use crate::{FaceId, HalfedgeId, MeshGraph, VertexId, utils::unwrap_or_return};
6
7impl MeshGraph {
8 #[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 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 for &he_id in &removed_halfedges {
64 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 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 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 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}