Skip to main content

mesh_graph/ops/
edit.rs

1use glam::Vec3;
2use hashbrown::HashSet;
3use itertools::Itertools;
4use slotmap::SparseSecondaryMap;
5use tracing::{error, instrument};
6
7use crate::{HalfedgeId, MeshGraph, VertexId, error_none, utils::unwrap_or_return};
8
9impl MeshGraph {
10    /// Flips this edge so that it represents the other diagonal described by the quad formed by the two incident triangles.
11    ///
12    /// ```text
13    ///     *                    *
14    ///    / \                  / \
15    ///   /   \                / ‖ \
16    ///  /     \              /  ‖  \
17    /// * ===== *     =>     *   ‖   *
18    ///  \     /              \  ‖  /
19    ///   \   /                \ ‖ /
20    ///    \ /                  \ /
21    ///     *                    *
22    /// ```
23    #[instrument(skip(self))]
24    pub fn flip_edge(&mut self, halfedge_id: HalfedgeId) {
25        let he = unwrap_or_return!(self.halfedges.get(halfedge_id), "Halfedge not found");
26
27        let prev_he_id = unwrap_or_return!(he.prev(self), "Prev not found");
28        let prev_he = unwrap_or_return!(self.halfedges.get(prev_he_id), "Prev not found");
29        let start_v_id = prev_he.end_vertex;
30        let prev_twin_he_id = unwrap_or_return!(prev_he.twin, "Prev twin not found");
31
32        let next_he_id = unwrap_or_return!(he.next, "Next not found");
33        let next_he = unwrap_or_return!(self.halfedges.get(next_he_id), "Next not found");
34        let opposite_v_id = next_he.end_vertex;
35        let next_twin_he_id = unwrap_or_return!(next_he.twin, "Next twin not found");
36
37        let twin_he_id = unwrap_or_return!(he.twin, "Twin not found");
38        let twin_he = unwrap_or_return!(self.halfedges.get(twin_he_id), "Twin not found");
39
40        let twin_prev_he_id = unwrap_or_return!(twin_he.prev(self), "Prev not found");
41        let twin_prev_he = unwrap_or_return!(self.halfedges.get(twin_prev_he_id), "Prev not found");
42        let twin_start_v_id = twin_prev_he.end_vertex;
43        let twin_prev_twin_he_id = unwrap_or_return!(twin_prev_he.twin, "Prev twin twin not found");
44
45        let twin_next_he_id = unwrap_or_return!(twin_he.next, "Next not found");
46        let twin_next_he = unwrap_or_return!(self.halfedges.get(twin_next_he_id), "Next not found");
47        let twin_opposite_v_id = twin_next_he.end_vertex;
48        let twin_next_twin_he_id = unwrap_or_return!(twin_next_he.twin, "Next twin twin not found");
49
50        self.halfedges[halfedge_id].end_vertex = opposite_v_id;
51
52        self.halfedges[prev_he_id].end_vertex = twin_opposite_v_id;
53        self.make_twins(prev_he_id, twin_next_twin_he_id);
54        self.halfedges[next_he_id].end_vertex = start_v_id;
55        self.make_twins(next_he_id, prev_twin_he_id);
56
57        self.remove_outgoing_halfedge(start_v_id, halfedge_id);
58        self.remove_outgoing_halfedge(start_v_id, twin_next_he_id);
59        self.add_outgoing_halfedge(start_v_id, prev_he_id);
60
61        self.remove_outgoing_halfedge(opposite_v_id, prev_he_id);
62        self.add_outgoing_halfedge(opposite_v_id, next_he_id);
63        self.add_outgoing_halfedge(opposite_v_id, twin_he_id);
64
65        self.halfedges[twin_he_id].end_vertex = twin_opposite_v_id;
66
67        self.halfedges[twin_prev_he_id].end_vertex = opposite_v_id;
68        self.make_twins(twin_prev_he_id, next_twin_he_id);
69        self.halfedges[twin_next_he_id].end_vertex = twin_start_v_id;
70        self.make_twins(twin_next_he_id, twin_prev_twin_he_id);
71
72        self.remove_outgoing_halfedge(twin_start_v_id, twin_he_id);
73        self.remove_outgoing_halfedge(twin_start_v_id, next_he_id);
74        self.add_outgoing_halfedge(twin_start_v_id, twin_prev_he_id);
75
76        self.remove_outgoing_halfedge(twin_opposite_v_id, twin_prev_he_id);
77        self.add_outgoing_halfedge(twin_opposite_v_id, twin_next_he_id);
78        self.add_outgoing_halfedge(twin_opposite_v_id, halfedge_id);
79
80        // checked if halfedge exists above
81        let face_id1 = unwrap_or_return!(self.halfedges[halfedge_id].face, "Face not found");
82        let face1 = unwrap_or_return!(self.faces.get(face_id1), "Face not found");
83        self.bvh
84            .insert_or_update_partially(face1.aabb(self), face1.index, 0.0);
85
86        // checked if halfedge exists above
87        let face_id2 = unwrap_or_return!(self.halfedges[twin_he_id].face, "Face not found");
88        let face2 = unwrap_or_return!(self.faces.get(face_id2), "Face not found");
89        self.bvh
90            .insert_or_update_partially(face2.aabb(self), face2.index, 0.0);
91    }
92
93    /// Makes two halfedges twins of each other. Doesn't change anything else
94    pub fn make_twins(&mut self, he_id1: HalfedgeId, he_id2: HalfedgeId) {
95        let he1 = unwrap_or_return!(self.halfedges.get_mut(he_id1), "Halfedge not found");
96        he1.twin = Some(he_id2);
97
98        let he2 = unwrap_or_return!(self.halfedges.get_mut(he_id2), "Halfedge not found");
99        he2.twin = Some(he_id1);
100    }
101
102    /// Removes the outgoing halfedge from a vertex. Doesn't change anything else.
103    #[instrument(skip(self))]
104    pub fn remove_outgoing_halfedge(&mut self, vertex_id: VertexId, halfedge_id: HalfedgeId) {
105        let outgoing_halfedges = unwrap_or_return!(
106            self.outgoing_halfedges.get_mut(vertex_id),
107            "No outgoing halfedges found"
108        );
109
110        outgoing_halfedges.retain(|he_id| *he_id != halfedge_id);
111    }
112
113    /// Adds the outgoing halfedge to a vertex and overrides the vertex.outgoing_halfedge
114    #[instrument(skip(self))]
115    pub fn add_outgoing_halfedge(&mut self, vertex_id: VertexId, outgoing_halfedge: HalfedgeId) {
116        let vertex = unwrap_or_return!(self.vertices.get_mut(vertex_id), "Vertex not found");
117        vertex.outgoing_halfedge = Some(outgoing_halfedge);
118
119        let v_outgoing_halfedges = unwrap_or_return!(
120            self.outgoing_halfedges.get_mut(vertex_id),
121            "No outgoing halfedges found"
122        );
123        v_outgoing_halfedges.push(outgoing_halfedge);
124    }
125
126    /// Smooths the position of the vertex by computing the average of its own and its neighbors' positions and
127    /// moving it there. Also called Laplacian Smoothing.
128    #[instrument(skip_all)]
129    pub fn smooth_vertices(&mut self, vertices: impl IntoIterator<Item = VertexId>) {
130        let mut new_positions = SparseSecondaryMap::new();
131
132        let mut affected_face_ids = HashSet::new();
133
134        for vertex_id in vertices.into_iter() {
135            let Some(pos) = self.compute_smoothed_vertex_pos(vertex_id) else {
136                continue;
137            };
138
139            new_positions.insert(vertex_id, pos);
140
141            // vertex checked if exists in `compute_smoothed_vertex_pos()`
142            affected_face_ids.extend(self.vertices[vertex_id].faces(self));
143        }
144
145        for (vertex_id, &pos) in &new_positions {
146            self.positions.insert(vertex_id, pos);
147        }
148
149        for vertex_id in new_positions.keys() {
150            self.compute_vertex_normal(vertex_id);
151        }
152
153        for face_id in affected_face_ids {
154            let Some(face) = self.faces.get(face_id) else {
155                error!("Face {:?} does not exist", face_id);
156                continue;
157            };
158
159            self.bvh
160                .insert_or_update_partially(face.aabb(self), face.index, 0.0);
161        }
162    }
163
164    /// Smooth the position of the vertex by computing the average of its own and its neighbors' positions and
165    /// moving it there. Also called Laplacian Smoothing.
166    ///
167    /// > Note: If you want to smooth multiple vertices, use the `smooth_vertices` method instead of
168    /// > calling this method multiple times.
169    #[instrument(skip(self))]
170    pub fn smooth_vertex(&mut self, vertex_id: VertexId) {
171        let pos = unwrap_or_return!(
172            self.compute_smoothed_vertex_pos(vertex_id),
173            "Couldn't compute smoothed position"
174        );
175
176        self.positions.insert(vertex_id, pos);
177        self.compute_vertex_normal(vertex_id);
178
179        // vertex checked if exists in `compute_smoothed_vertex_pos()`
180        for face_id in self.vertices[vertex_id].faces(self).collect_vec() {
181            let Some(face) = self.faces.get(face_id) else {
182                error!("Face {:?} does not exist", face_id);
183                continue;
184            };
185
186            self.bvh
187                .insert_or_update_partially(face.aabb(self), face.index, 0.0);
188        }
189    }
190
191    #[instrument(skip(self))]
192    fn compute_smoothed_vertex_pos(&mut self, vertex_id: VertexId) -> Option<Vec3> {
193        let vertex = self.vertices.get(vertex_id)?;
194
195        let mut pos = *self
196            .positions
197            .get(vertex_id)
198            .or_else(error_none!("Position not found for id {vertex_id:?}"))?;
199
200        let mut count = 1.0;
201        for neighbor_v_id in vertex.neighbours(self) {
202            let neighbor_pos = *self.positions.get(neighbor_v_id).or_else(error_none!(
203                "Neighbor position not found for id {neighbor_v_id:?}"
204            ))?;
205
206            pos += neighbor_pos;
207            count += 1.0;
208        }
209
210        pos /= count;
211
212        Some(pos)
213    }
214}
215
216#[cfg(test)]
217mod tests {
218    use glam::Vec3;
219
220    use super::*;
221
222    #[test]
223    fn test_flip_edge() {
224        let mut mesh_graph = MeshGraph::new();
225
226        let v_id1 = mesh_graph.add_vertex(Vec3::new(-1.0, 1.0, 0.0));
227        let v_id2 = mesh_graph.add_vertex(Vec3::new(-1.0, -1.0, 0.0));
228        let v_id3 = mesh_graph.add_vertex(Vec3::new(1.0, -1.0, 0.0));
229        let v_id4 = mesh_graph.add_vertex(Vec3::new(1.0, 1.0, 0.0));
230
231        mesh_graph.add_face_from_vertices(v_id1, v_id2, v_id3);
232        mesh_graph.add_face_from_vertices(v_id1, v_id3, v_id4);
233
234        #[cfg(feature = "rerun")]
235        mesh_graph.log_rerun();
236
237        assert!(mesh_graph.halfedge_from_to(v_id2, v_id4).is_none());
238
239        assert_eq!(mesh_graph.outgoing_halfedges[v_id1].len(), 3);
240        assert_eq!(mesh_graph.outgoing_halfedges[v_id2].len(), 2);
241        assert_eq!(mesh_graph.outgoing_halfedges[v_id3].len(), 3);
242        assert_eq!(mesh_graph.outgoing_halfedges[v_id4].len(), 2);
243
244        mesh_graph.flip_edge(mesh_graph.halfedge_from_to(v_id1, v_id3).unwrap());
245
246        #[cfg(feature = "rerun")]
247        {
248            mesh_graph.log_rerun();
249            crate::RR.flush_blocking().unwrap();
250        }
251
252        assert!(mesh_graph.halfedge_from_to(v_id1, v_id3).is_none());
253        assert!(mesh_graph.halfedge_from_to(v_id2, v_id4).is_some());
254
255        assert_eq!(mesh_graph.outgoing_halfedges[v_id1].len(), 2);
256        assert_eq!(mesh_graph.outgoing_halfedges[v_id2].len(), 3);
257        assert_eq!(mesh_graph.outgoing_halfedges[v_id3].len(), 2);
258        assert_eq!(mesh_graph.outgoing_halfedges[v_id4].len(), 3);
259    }
260}