mesh_graph/ops/
subdivide.rs

1use hashbrown::{HashMap, HashSet};
2use tracing::{error, instrument};
3
4use crate::{
5    HalfedgeId, MeshGraph, Selection, SelectionOps, VertexId, error_none, utils::unwrap_or_return,
6};
7
8#[cfg(feature = "rerun")]
9use crate::utils::vec3_array;
10
11impl MeshGraph {
12    /// Subdivides an edge by computing it's center vertex. This also subdivides any adjacent triangles and
13    /// makes sure everything is properly reconnected. Works only on triangle meshes.
14    ///
15    /// Returns the id of the new halfedge which goes from the center vertex to the original edge's end vertex.
16    /// And also return the halfedges that are created by subdividing the adjacent faces. Only one of the two twin
17    /// halfedges per face subdivision is returned. In total the number `n` of halfedges returned is `1 <= n <= 3`.
18    /// (The one from dividing the halfedge and at most 2 from dividing the two adjacent faces).
19    #[instrument(skip(self))]
20    pub fn subdivide_edge(&mut self, halfedge_id: HalfedgeId) -> Vec<HalfedgeId> {
21        let mut new_halfedges = Vec::with_capacity(3);
22
23        let he = unwrap_or_return!(
24            self.halfedges.get(halfedge_id),
25            "Halfedge not found",
26            new_halfedges
27        );
28        let twin_id = unwrap_or_return!(he.twin, "Twin halfedge not found", new_halfedges);
29
30        let start_v = unwrap_or_return!(
31            he.start_vertex(self),
32            "Start vertex not found",
33            new_halfedges
34        );
35        let end_v = he.end_vertex;
36
37        let start_pos = self.positions[start_v];
38        let end_pos = self.positions[end_v];
39
40        let center_pos = (start_pos + end_pos) * 0.5;
41
42        #[cfg(feature = "rerun")]
43        {
44            crate::RR
45                .log(
46                    "meshgraph/subdivide/edge",
47                    &rerun::Arrows3D::from_vectors([vec3_array(end_pos - start_pos)])
48                        .with_origins([vec3_array(start_pos)]),
49                )
50                .unwrap();
51
52            crate::RR
53                .log(
54                    "meshgraph/subdivide/center",
55                    &rerun::Points3D::new([vec3_array(center_pos)]),
56                )
57                .unwrap();
58        }
59
60        let center_v = self.insert_vertex(center_pos);
61        if let Some(normals) = &mut self.vertex_normals {
62            let start_normal = unwrap_or_return!(
63                normals.get(start_v),
64                "Start normal not found",
65                new_halfedges
66            );
67            let end_normal =
68                unwrap_or_return!(normals.get(end_v), "End normal not found", new_halfedges);
69            normals[center_v] = (start_normal + end_normal).normalize();
70        }
71
72        let new_he = self.insert_halfedge(end_v);
73        // inserted just above
74        self.vertices[center_v].outgoing_halfedge = Some(new_he);
75
76        new_halfedges.push(new_he);
77
78        if let Some(new_face_he) = self.subdivide_face(halfedge_id, new_he, center_v) {
79            new_halfedges.push(new_face_he);
80        }
81
82        let new_twin = self.insert_halfedge(start_v);
83
84        if let Some(new_face_he) = self.subdivide_face(twin_id, new_twin, center_v) {
85            new_halfedges.push(new_face_he);
86        }
87
88        // inserted above
89        self.halfedges[new_he].twin = Some(twin_id);
90        unwrap_or_return!(
91            self.halfedges.get_mut(twin_id),
92            "Twin halfedge not found",
93            new_halfedges
94        )
95        .twin = Some(new_he);
96
97        // checked in the beginning of the function
98        self.halfedges[halfedge_id].twin = Some(new_twin);
99        // inserted above
100        self.halfedges[new_twin].twin = Some(halfedge_id);
101
102        // self.vertices[end_v].outgoing_halfedge = Some(new_twin);
103        // self.vertices[start_v].outgoing_halfedge = Some(new_he);
104
105        new_halfedges
106    }
107
108    /// Subdivides a triangle into two halves. Used in [Self::subdivide_edge].
109    #[instrument(skip(self))]
110    fn subdivide_face(
111        &mut self,
112        existing_halfedge_id: HalfedgeId,
113        new_halfedge_id: HalfedgeId,
114        center_v: VertexId,
115    ) -> Option<HalfedgeId> {
116        let he = self
117            .halfedges
118            .get(existing_halfedge_id)
119            .or_else(error_none!("Halfedge not found"))?;
120
121        let face_id = he.face?;
122        self.faces
123            .get_mut(face_id)
124            .or_else(error_none!("Facee not found"))?
125            .halfedge = existing_halfedge_id;
126
127        // checked above
128        let next_he = self.halfedges[existing_halfedge_id]
129            .next
130            .or_else(error_none!("Next halfedge missing"))?;
131        let last_he = self
132            .halfedges
133            .get(next_he)
134            .or_else(error_none!("Next halfedge not found"))?
135            .next
136            .or_else(error_none!("Last halfedge not found"))?;
137
138        // rewire existing face
139        let new_he = self.insert_halfedge(self.halfedges[next_he].end_vertex);
140
141        self.halfedges[existing_halfedge_id].next = Some(new_he);
142        self.halfedges[new_he].next = Some(last_he);
143        self.halfedges[new_he].face = Some(face_id);
144
145        // insert new face
146        let new_face_id = self.insert_face(new_halfedge_id);
147
148        // checked above
149        let face = self.faces[face_id];
150        // freshly inserted
151        let new_face = self.faces[new_face_id];
152        self.bvh
153            .insert_or_update_partially(face.aabb(self), face.index, 0.0);
154        self.bvh
155            .insert_or_update_partially(new_face.aabb(self), new_face.index, 0.0);
156
157        let new_twin = self.insert_halfedge(center_v);
158
159        self.halfedges[new_twin].next = Some(new_halfedge_id);
160        self.halfedges[new_twin].face = Some(new_face_id);
161        self.halfedges[new_twin].twin = Some(new_he);
162        self.halfedges[new_he].twin = Some(new_twin);
163
164        // inserted just before this function is called
165        self.halfedges[new_halfedge_id].next = Some(next_he);
166        self.halfedges[new_halfedge_id].face = Some(new_face_id);
167
168        // checked above
169        self.halfedges[next_he].next = Some(new_twin);
170        self.halfedges[next_he].face = Some(new_face_id);
171
172        self.halfedges[existing_halfedge_id].end_vertex = center_v;
173
174        #[cfg(feature = "rerun")]
175        {
176            self.log_he_rerun("subdivide/new_he", new_he);
177            self.log_he_rerun("subdivide/new_twin", new_twin);
178        }
179
180        Some(new_he)
181    }
182
183    /// Subdivide all edges in the selection until all of them are <= max_length.
184    /// Please note that you have to provide the squared value of max_length.
185    /// All new edges created during this process are added to the selection.
186    ///
187    /// This will schedule necessary updates to the QBVH but you have to call
188    /// `refit()` and maybe `rebalance()` after the operation.
189    #[instrument(skip(self))]
190    pub fn subdivide_until_edges_below_max_length(
191        &mut self,
192        max_length_squared: f32,
193        selection: &mut Selection,
194    ) {
195        let mut dedup_halfedges = HashSet::new();
196
197        for he_id in selection.resolve_to_halfedges(self) {
198            let he = unwrap_or_return!(self.halfedges.get(he_id), "Halfedge not found");
199            let twin_already_in = he
200                .twin
201                .map(|twin| dedup_halfedges.contains(&twin))
202                .unwrap_or_else(|| {
203                    error!("Twin missing");
204                    false
205                });
206
207            if !twin_already_in {
208                dedup_halfedges.insert(he_id);
209            }
210        }
211
212        let mut halfedges_to_subdivide = dedup_halfedges
213            .into_iter()
214            .filter_map(|he| {
215                // already checked above
216                let len = self.halfedges[he].length_squared(self);
217                (len > max_length_squared).then_some((he, len))
218            })
219            .collect::<HashMap<_, _>>();
220
221        while !halfedges_to_subdivide.is_empty() {
222            let mut max_len = 0.0;
223            let mut max_he_id = HalfedgeId::default();
224
225            #[cfg(feature = "rerun")]
226            self.log_hes_rerun(
227                "subdivide/selection",
228                &halfedges_to_subdivide
229                    .iter()
230                    .map(|(he, _)| *he)
231                    .collect::<Vec<_>>(),
232            );
233
234            for (&he, &len) in &halfedges_to_subdivide {
235                if len > max_len {
236                    max_len = len;
237                    max_he_id = he;
238                }
239            }
240
241            halfedges_to_subdivide.remove(&max_he_id);
242
243            let mut affected_faces = Selection::default();
244
245            // already checked
246            let max_he = self.halfedges[max_he_id];
247            if let Some(face_id) = max_he.face {
248                selection.insert(face_id);
249                affected_faces.insert(face_id);
250
251                #[cfg(feature = "rerun")]
252                self.log_face_rerun("subdivide/selected_new", face_id);
253            }
254
255            if let Some(twin_id) = max_he.twin.or_else(error_none!("Twin missing"))
256                && let Some(twin_he) = self
257                    .halfedges
258                    .get(twin_id)
259                    .or_else(error_none!("Halfedge not found"))
260                && let Some(twin_face_id) = twin_he.face
261            {
262                selection.insert(twin_face_id);
263                affected_faces.insert(twin_face_id);
264
265                #[cfg(feature = "rerun")]
266                self.log_face_rerun("subdivide/selected_new", twin_face_id);
267            }
268
269            let new_edges = self.subdivide_edge(max_he_id);
270
271            #[cfg(feature = "rerun")]
272            {
273                crate::RR
274                    .log("meshgraph/subdivide", &rerun::Clear::recursive())
275                    .unwrap();
276                crate::RR
277                    .log("meshgraph/halfedge/subdivide", &rerun::Clear::recursive())
278                    .unwrap();
279                crate::RR
280                    .log("meshgraph/face/subdivide", &rerun::Clear::recursive())
281                    .unwrap();
282                self.log_rerun();
283            }
284
285            for new_he_id in new_edges {
286                // newly inserted in `self.subdivide_edge`
287                let new_he = self.halfedges[new_he_id];
288
289                if let Some(face_id) = new_he.face {
290                    selection.insert(face_id);
291                    affected_faces.insert(face_id);
292                    #[cfg(feature = "rerun")]
293                    self.log_face_rerun("subdivide/selected_new", face_id);
294                }
295
296                let new_twin_id = unwrap_or_return!(new_he.twin, "New twin missing");
297                let new_twin =
298                    unwrap_or_return!(self.halfedges.get(new_twin_id), "New twin not found");
299                if let Some(face_id) = new_twin.face {
300                    selection.insert(face_id);
301                    affected_faces.insert(face_id);
302                    #[cfg(feature = "rerun")]
303                    self.log_face_rerun("subdivide/selected_new", face_id);
304                }
305            }
306
307            for he_id in affected_faces.resolve_to_halfedges(self) {
308                let he = unwrap_or_return!(self.halfedges.get(he_id), "Halfedge not found");
309                let twin = unwrap_or_return!(he.twin, "Twin missing");
310
311                if halfedges_to_subdivide.contains_key(&twin) {
312                    continue;
313                }
314
315                let len_sqr = he.length_squared(self);
316
317                if len_sqr > max_length_squared {
318                    #[cfg(feature = "rerun")]
319                    self.log_he_rerun("/subdivide/new_edge", he_id);
320                    halfedges_to_subdivide.insert(he_id, len_sqr);
321                }
322            }
323        }
324    }
325}
326
327#[cfg(test)]
328mod tests {}