tri_mesh/operations/
connectivity.rs

1//! See [Mesh](crate::mesh::Mesh).
2
3use crate::mesh::*;
4
5/// # Connectivity
6impl Mesh {
7    /// Returns whether or not the mesh is closed, ie. contains no holes.
8    pub fn is_closed(&self) -> bool {
9        for halfedge_id in self.edge_iter() {
10            if self.is_edge_on_boundary(halfedge_id) {
11                return false;
12            }
13        }
14        true
15    }
16    ///
17    /// Returns the connecting edge between the two vertices or `None` if no edge is found.
18    ///
19    /// **Note:** This method assumes that the mesh is properly connected.
20    /// See [vertex_halfedge_iter](#method.vertex_halfedge_iter) for more information.
21    ///
22    pub fn connecting_edge(
23        &self,
24        vertex_id1: VertexID,
25        vertex_id2: VertexID,
26    ) -> Option<HalfEdgeID> {
27        for halfedge_id in self.vertex_halfedge_iter(vertex_id1) {
28            if self.walker_from_halfedge(halfedge_id).vertex_id().unwrap() == vertex_id2 {
29                return Some(halfedge_id);
30            }
31        }
32        None
33    }
34
35    /// Returns whether or not the vertex is on a boundary.
36    pub fn is_vertex_on_boundary(&self, vertex_id: VertexID) -> bool {
37        for halfedge_id in self.vertex_halfedge_iter(vertex_id) {
38            let mut walker = self.walker_from_halfedge(halfedge_id);
39            if walker.face_id().is_none() || walker.as_twin().face_id().is_none() {
40                return true;
41            }
42        }
43        false
44    }
45
46    /// Returns whether or not the edge is on a boundary.
47    pub fn is_edge_on_boundary(&self, halfedge_id: HalfEdgeID) -> bool {
48        let mut walker = self.walker_from_halfedge(halfedge_id);
49        walker.face_id().is_none() || walker.as_twin().face_id().is_none()
50    }
51
52    /// Returns the vertex id of the two adjacent vertices to the given edge.
53    pub fn edge_vertices(&self, halfedge_id: HalfEdgeID) -> (VertexID, VertexID) {
54        let mut walker = self.walker_from_halfedge(halfedge_id);
55        let v1 = walker.vertex_id().unwrap();
56        let v2 = walker.as_twin().vertex_id().unwrap();
57        (v1, v2)
58    }
59
60    /// Returns the vertex id of the two adjacent vertices to the given edge
61    /// and ordered such that `ordered_edge_vertices.0 < ordered_edge_vertices.1`.
62    pub fn ordered_edge_vertices(&self, halfedge_id: HalfEdgeID) -> (VertexID, VertexID) {
63        let mut walker = self.walker_from_halfedge(halfedge_id);
64        let v1 = walker.vertex_id().unwrap();
65        let v2 = walker.as_twin().vertex_id().unwrap();
66        if v1 < v2 {
67            (v1, v2)
68        } else {
69            (v2, v1)
70        }
71    }
72
73    /// Returns the vertex id of the three connected vertices to the given face.
74    pub fn face_vertices(&self, face_id: FaceID) -> (VertexID, VertexID, VertexID) {
75        let mut walker = self.walker_from_face(face_id);
76        let v1 = walker.vertex_id().unwrap();
77        walker.as_next();
78        let v2 = walker.vertex_id().unwrap();
79        walker.as_next();
80        let v3 = walker.vertex_id().unwrap();
81        (v1, v2, v3)
82    }
83
84    /// Returns the vertex id of the three connected vertices to the given face
85    /// and ordered such that `ordered_face_vertices.0 < ordered_face_vertices.1 < ordered_face_vertices.2`.
86    pub fn ordered_face_vertices(&self, face_id: FaceID) -> (VertexID, VertexID, VertexID) {
87        let mut walker = self.walker_from_face(face_id);
88        let v1 = walker.vertex_id().unwrap();
89        walker.as_next();
90        let v2 = walker.vertex_id().unwrap();
91        walker.as_next();
92        let v3 = walker.vertex_id().unwrap();
93        if v1 < v2 {
94            if v2 < v3 {
95                (v1, v2, v3)
96            } else {
97                if v1 < v3 {
98                    (v1, v3, v2)
99                } else {
100                    (v3, v1, v2)
101                }
102            }
103        } else {
104            if v1 < v3 {
105                (v2, v1, v3)
106            } else {
107                if v2 < v3 {
108                    (v2, v3, v1)
109                } else {
110                    (v3, v2, v1)
111                }
112            }
113        }
114    }
115}
116
117#[cfg(test)]
118mod tests {
119    use super::*;
120    use three_d_asset::TriMesh;
121    #[test]
122    fn test_is_closed_when_not_closed() {
123        let mesh = crate::test_utility::subdivided_triangle();
124        assert!(!mesh.is_closed());
125    }
126
127    #[test]
128    fn test_is_closed_when_closed() {
129        let mesh: Mesh = TriMesh::sphere(4).into();
130        assert!(mesh.is_closed());
131    }
132}