tri_mesh/mesh/
orientation.rs1use crate::mesh::*;
4
5impl Mesh {
7 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 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}