tri_mesh/mesh/
traversal.rs

1use crate::mesh::connectivity_info::{ConnectivityInfo, HalfEdge};
2use crate::mesh::*;
3
4/// # Traversal
5/// Methods to construct a [Walker] which is used for easy and efficient traversal of the mesh.
6/// See [Walker] for more information and examples.
7/// Also see [Connectivity](#connectivity) for common connectivity utility functionality.
8impl Mesh {
9    /// Creates an 'empty' [Walker], ie. a walker that is associated with any half-edge.
10    pub(super) fn walker(&self) -> Walker {
11        Walker::new(&self.connectivity_info)
12    }
13
14    /// Creates a [Walker] at the half-edge pointed to by the given vertex.
15    pub fn walker_from_vertex(&self, vertex_id: VertexID) -> Walker {
16        self.walker().into_vertex_halfedge_walker(vertex_id)
17    }
18
19    /// Creates a [Walker] at the given half-edge.
20    pub fn walker_from_halfedge(&self, halfedge_id: HalfEdgeID) -> Walker {
21        self.walker().into_halfedge_walker(halfedge_id)
22    }
23
24    /// Creates a [Walker] at the half-edge pointed to by the given face.
25    pub fn walker_from_face(&self, face_id: FaceID) -> Walker {
26        self.walker().into_face_halfedge_walker(face_id)
27    }
28}
29
30///
31/// Used for easy and efficient traversal of the mesh.
32/// Also see [Connectivity](Mesh#connectivity) for common connectivity utility functionality.
33///
34/// Use [Mesh::walker_from_vertex], [Mesh::walker_from_halfedge] or [Mesh::walker_from_face] to construct a walker
35/// and the examples below for instructions on how to use a walker.
36///
37/// **Note:** If you walk outside the mesh at some point, no error will be returned,
38/// instead, all methods to extract an ID will return `None`.
39///
40/// # Examples
41///
42/// ## \# 1
43///
44/// ```
45/// # use tri_mesh::*;
46/// # let mesh: Mesh = three_d_asset::TriMesh::sphere(4).into();
47/// # let halfedge_id = mesh.halfedge_iter().next().unwrap();
48/// // Find the id of the vertex pointed to by a half-edge.
49/// let vertex_id = mesh.walker_from_halfedge(halfedge_id).vertex_id().unwrap();
50/// ```
51///
52/// ## \# 2
53///
54/// ```
55/// # use tri_mesh::*;
56/// # let mesh: Mesh = three_d_asset::TriMesh::sphere(4).into();
57/// # let halfedge_id = mesh.halfedge_iter().next().unwrap();
58/// let mut walker = mesh.walker_from_halfedge(halfedge_id);
59/// // Walk around the three sides of a face..
60/// let result_halfedge_id = walker.as_next().as_next().next_id().unwrap();
61/// // .. ending up at the same half-edge
62/// assert_eq!(halfedge_id, result_halfedge_id);
63/// ```
64/// ## \# 3
65///
66/// ```
67/// # use tri_mesh::*;
68/// # let mesh: Mesh = three_d_asset::TriMesh::sphere(4).into();
69/// # let face_id = mesh.face_iter().next().unwrap();
70/// // Find one neighbouring face to the given face
71/// let neighbour_face_id = mesh.walker_from_face(face_id).into_twin().face_id().unwrap();
72/// ```
73///
74/// ## \# 4
75///
76/// ```
77/// # use tri_mesh::*;
78/// # let mesh: Mesh = three_d_asset::TriMesh::sphere(4).into();
79/// # let face_id = mesh.face_iter().next().unwrap();
80/// // Find the circumference of a face
81/// let mut walker = mesh.walker_from_face(face_id);
82/// let mut circumference = mesh.edge_length(walker.halfedge_id().unwrap());
83/// walker.as_next();
84/// circumference += mesh.edge_length(walker.halfedge_id().unwrap());
85/// circumference += mesh.edge_length(walker.next_id().unwrap());
86/// ```
87///
88/// ## \# 5
89///
90/// ```
91/// # use tri_mesh::*;
92/// # let mesh: Mesh = three_d_asset::TriMesh::sphere(4).into();
93/// # let halfedge_id = mesh.halfedge_iter().next().unwrap();
94/// // Check if the half-edge is on the boundary of the mesh
95/// let mut walker = mesh.walker_from_halfedge(halfedge_id);
96/// let is_on_boundary = walker.face_id().is_none() || walker.as_twin().face_id().is_none();
97/// # assert!(!is_on_boundary);
98/// ```
99///
100/// ## \# 6
101///
102/// ```
103/// # use tri_mesh::*;
104/// # let mesh: Mesh = three_d_asset::TriMesh::sphere(4).into();
105/// // Compute the average edge length
106/// let mut avg_edge_length = 0.0f64;
107/// for halfedge_id in mesh.edge_iter()
108/// {
109///     let mut walker = mesh.walker_from_halfedge(halfedge_id);
110///     let p0 = mesh.vertex_position(walker.vertex_id().unwrap());
111///     let p1 = mesh.vertex_position(walker.as_twin().vertex_id().unwrap());
112///     avg_edge_length += (p0 - p1).magnitude();
113/// }
114/// avg_edge_length /= mesh.no_edges() as f64;
115/// ```
116///
117#[derive(Clone, Debug)]
118pub struct Walker<'a> {
119    connectivity_info: &'a ConnectivityInfo,
120    current: Option<HalfEdgeID>,
121    current_info: Option<HalfEdge>,
122}
123
124impl<'a> Walker<'a> {
125    pub(super) fn new(connectivity_info: &'a ConnectivityInfo) -> Self {
126        Walker {
127            current: None,
128            current_info: None,
129            connectivity_info: connectivity_info,
130        }
131    }
132
133    /// Jumps to the half-edge pointed to by the given vertex.
134    pub(super) fn into_vertex_halfedge_walker(mut self, vertex_id: VertexID) -> Self {
135        self.as_vertex_halfedge_walker(vertex_id);
136        self
137    }
138
139    /// Jumps to the given half-edge.
140    pub(super) fn into_halfedge_walker(mut self, halfedge_id: HalfEdgeID) -> Self {
141        self.as_halfedge_walker(halfedge_id);
142        self
143    }
144
145    /// Jumps to the half-edge pointed to by the given face.
146    pub(super) fn into_face_halfedge_walker(mut self, face_id: FaceID) -> Self {
147        self.as_face_halfedge_walker(face_id);
148        self
149    }
150
151    /// Jumps to the half-edge pointed to by the given vertex.
152    pub(super) fn as_vertex_halfedge_walker(&mut self, vertex_id: VertexID) -> &mut Self {
153        let halfedge_id = self.connectivity_info.vertex_halfedge(vertex_id);
154        self.set_current(halfedge_id);
155        self
156    }
157
158    /// Jumps to the given half-edge.
159    pub(super) fn as_halfedge_walker(&mut self, halfedge_id: HalfEdgeID) -> &mut Self {
160        let halfedge_id = Some(halfedge_id);
161        self.set_current(halfedge_id);
162        self
163    }
164
165    /// Jumps to the half-edge pointed to by the given face.
166    pub(super) fn as_face_halfedge_walker(&mut self, face_id: FaceID) -> &mut Self {
167        let halfedge_id = self.connectivity_info.face_halfedge(face_id);
168        self.set_current(halfedge_id);
169        self
170    }
171
172    /// Walk to the next half-edge in the adjacent face.
173    pub fn into_next(mut self) -> Self {
174        self.as_next();
175        self
176    }
177
178    /// Walk to the previous half-edge in the adjacent face.
179    pub fn into_previous(mut self) -> Self {
180        self.as_next().as_next();
181        self
182    }
183
184    /// Walk to the twin half-edge.
185    pub fn into_twin(mut self) -> Self {
186        self.as_twin();
187        self
188    }
189
190    /// Walk to the next half-edge in the adjacent face.
191    pub fn as_next(&mut self) -> &mut Self {
192        let halfedge_id = match self.current_info {
193            Some(ref current_info) => current_info.next,
194            None => None,
195        };
196        self.set_current(halfedge_id);
197        self
198    }
199
200    /// Walk to the previous half-edge in the adjacent face.
201    pub fn as_previous(&mut self) -> &mut Self {
202        self.as_next().as_next()
203    }
204
205    /// Walk to the twin half-edge.
206    pub fn as_twin(&mut self) -> &mut Self {
207        let halfedge_id = match self.current_info {
208            Some(ref current_info) => current_info.twin,
209            None => None,
210        };
211        self.set_current(halfedge_id);
212        self
213    }
214
215    /// Returns the id of the vertex pointed to by the current half-edge or `None` if the walker has walked outside of the mesh at some point.
216    pub fn vertex_id(&self) -> Option<VertexID> {
217        if let Some(ref halfedge) = self.current_info {
218            halfedge.vertex
219        } else {
220            None
221        }
222    }
223
224    /// Returns the id of the next half-edge in the adjacent face or `None` if the half-edge is at the boundary of the mesh
225    /// or if the walker has walked outside of the mesh at some point.
226    pub fn next_id(&self) -> Option<HalfEdgeID> {
227        if let Some(ref halfedge) = self.current_info {
228            halfedge.next
229        } else {
230            None
231        }
232    }
233
234    /// Returns the id of the previous half-edge in the adjacent face or `None` if the half-edge is at the boundary of the mesh
235    /// or if the walker has walked outside of the mesh at some point.
236    pub fn previous_id(&self) -> Option<HalfEdgeID> {
237        if let Some(next_id) = self.next_id() {
238            Walker::new(&self.connectivity_info)
239                .into_halfedge_walker(next_id)
240                .next_id()
241        } else {
242            None
243        }
244    }
245
246    /// Returns the id of the twin half-edge to the current half-edge or `None` if the walker has walked outside of the mesh at some point.
247    pub fn twin_id(&self) -> Option<HalfEdgeID> {
248        if let Some(ref halfedge) = self.current_info {
249            halfedge.twin
250        } else {
251            None
252        }
253    }
254
255    /// Returns the id of the current half-edge or `None` if the walker has walked outside of the mesh at some point.
256    pub fn halfedge_id(&self) -> Option<HalfEdgeID> {
257        self.current
258    }
259
260    /// Returns the id of the adjacent face or `None` if the half-edge is at the boundary of the mesh
261    /// or if the walker has walked outside of the mesh at some point.
262    pub fn face_id(&self) -> Option<FaceID> {
263        if let Some(ref halfedge) = self.current_info {
264            halfedge.face
265        } else {
266            None
267        }
268    }
269
270    fn set_current(&mut self, halfedge_id: Option<HalfEdgeID>) {
271        self.current_info = if let Some(id) = halfedge_id {
272            self.connectivity_info.halfedge(id)
273        } else {
274            None
275        };
276        self.current = halfedge_id;
277    }
278}
279
280#[cfg(test)]
281mod tests {
282    use super::*;
283
284    #[test]
285    fn test_one_face_connectivity() {
286        let mesh: Mesh = crate::test_utility::triangle();
287
288        let f1 = mesh.face_iter().next().unwrap();
289        let v1 = mesh.walker_from_face(f1).vertex_id().unwrap();
290        let v2 = mesh.walker_from_face(f1).as_next().vertex_id().unwrap();
291        let v3 = mesh.walker_from_face(f1).as_previous().vertex_id().unwrap();
292
293        let t1 = mesh.walker_from_vertex(v1).vertex_id();
294        assert_eq!(t1, Some(v2));
295
296        let t2 = mesh.walker_from_vertex(v1).as_twin().vertex_id();
297        assert_eq!(t2, Some(v1));
298
299        let t3 = mesh.walker_from_vertex(v2).as_next().as_next().vertex_id();
300        assert_eq!(t3, Some(v2));
301
302        let t4 = mesh.walker_from_face(f1).as_twin().face_id();
303        assert!(t4.is_none());
304
305        let t5 = mesh.walker_from_face(f1).as_twin().next_id();
306        assert!(t5.is_none());
307
308        let t6 = mesh
309            .walker_from_face(f1)
310            .as_previous()
311            .as_previous()
312            .as_twin()
313            .as_twin()
314            .face_id();
315        assert_eq!(t6, Some(f1));
316
317        let t7 = mesh.walker_from_vertex(v2).as_next().as_next().next_id();
318        assert_eq!(t7, mesh.walker_from_vertex(v2).halfedge_id());
319
320        let t8 = mesh.walker_from_vertex(v3).face_id();
321        assert_eq!(t8, Some(f1));
322
323        mesh.is_valid().unwrap();
324    }
325
326    #[test]
327    fn test_three_face_connectivity() {
328        let mesh = crate::test_utility::subdivided_triangle();
329        let mut id = None;
330        for vertex_id in mesh.vertex_iter() {
331            let mut round = true;
332            for halfedge_id in mesh.vertex_halfedge_iter(vertex_id) {
333                if mesh.walker_from_halfedge(halfedge_id).face_id().is_none() {
334                    round = false;
335                    break;
336                }
337            }
338            if round {
339                id = Some(vertex_id);
340                break;
341            }
342        }
343        let mut walker = mesh.walker_from_vertex(id.unwrap());
344        let start_edge = walker.halfedge_id().unwrap();
345        let one_round_edge = walker
346            .as_previous()
347            .as_twin()
348            .as_previous()
349            .as_twin()
350            .as_previous()
351            .twin_id()
352            .unwrap();
353        assert_eq!(start_edge, one_round_edge);
354    }
355}