tri_mesh/mesh/
orientation.rs

1//! See [Mesh](crate::mesh::Mesh).
2
3use crate::mesh::*;
4
5/// # Orientation
6impl Mesh {
7    /// Flip the orientation of all faces in the mesh, ie. such that the normal points in the opposite direction.
8    pub fn flip_orientation(&mut self) {
9        for face_id in self.face_iter() {
10            self.flip_orientation_of_face(face_id);
11        }
12    }
13
14    /// Fix the orientation of all faces in the mesh such that the orientation of each pair of neighbouring faces is aligned.
15    pub fn fix_orientation(&mut self) {
16        let mut visited_faces = std::collections::HashMap::new();
17        for face_id in self.face_iter() {
18            self.find_faces_to_flip_orientation(face_id, &mut visited_faces, false);
19        }
20        for (face_id, should_flip) in visited_faces {
21            if should_flip {
22                self.flip_orientation_of_face(face_id)
23            }
24        }
25    }
26
27    fn flip_orientation_of_face(&mut self, face_id: FaceID) {
28        let mut update_list = [(None, None, None); 3];
29
30        let mut i = 0;
31        for halfedge_id in self.face_halfedge_iter(face_id) {
32            let mut walker = self.walker_from_halfedge(halfedge_id);
33            let vertex_id = walker.vertex_id();
34            walker.as_previous();
35            update_list[i] = (Some(halfedge_id), walker.vertex_id(), walker.halfedge_id());
36            i += 1;
37
38            self.connectivity_info
39                .set_vertex_halfedge(walker.vertex_id().unwrap(), walker.halfedge_id());
40
41            walker.as_next().as_twin();
42            if walker.face_id().is_none() {
43                self.connectivity_info
44                    .set_vertex_halfedge(walker.vertex_id().unwrap(), walker.halfedge_id());
45                self.connectivity_info
46                    .set_halfedge_vertex(walker.halfedge_id().unwrap(), vertex_id.unwrap());
47            }
48        }
49
50        for (halfedge_id, new_vertex_id, new_next_id) in update_list.iter() {
51            self.connectivity_info
52                .set_halfedge_vertex(halfedge_id.unwrap(), new_vertex_id.unwrap());
53            self.connectivity_info
54                .set_halfedge_next(halfedge_id.unwrap(), *new_next_id);
55        }
56    }
57
58    fn find_faces_to_flip_orientation(
59        &self,
60        face_id: FaceID,
61        visited_faces: &mut std::collections::HashMap<FaceID, bool>,
62        should_flip: bool,
63    ) {
64        if !visited_faces.contains_key(&face_id) {
65            visited_faces.insert(face_id, should_flip);
66            for halfedge_id in self.face_halfedge_iter(face_id) {
67                let mut walker = self.walker_from_halfedge(halfedge_id);
68                let vertex_id = walker.vertex_id();
69                if let Some(face_id_to_test) = walker.as_twin().face_id() {
70                    let is_opposite = vertex_id == walker.vertex_id();
71                    self.find_faces_to_flip_orientation(
72                        face_id_to_test,
73                        visited_faces,
74                        is_opposite && !should_flip || !is_opposite && should_flip,
75                    );
76                }
77            }
78        }
79    }
80}
81
82#[cfg(test)]
83mod tests {
84    use super::*;
85    use three_d_asset::TriMesh;
86
87    #[test]
88    fn test_fix_orientation() {
89        let mut mesh = crate::test_utility::subdivided_triangle();
90
91        mesh.flip_orientation_of_face(mesh.face_iter().next().unwrap());
92        mesh.fix_orientation();
93
94        mesh.is_valid().unwrap();
95    }
96
97    #[test]
98    fn test_flip_orientation() {
99        let mut mesh: Mesh = TriMesh::sphere(4).into();
100
101        let mut map = std::collections::HashMap::new();
102        for face_id in mesh.face_iter() {
103            map.insert(face_id, mesh.face_normal(face_id));
104        }
105        mesh.flip_orientation();
106
107        mesh.is_valid().unwrap();
108        for face_id in mesh.face_iter() {
109            assert!((mesh.face_normal(face_id) - -*map.get(&face_id).unwrap()).magnitude() < 0.001);
110        }
111    }
112}