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}