1use crate::{reference_cell, types::ReferenceCellType};
4use itertools::izip;
5
6pub fn compute_orientation(entity_type: ReferenceCellType, vertices: &[usize]) -> i32 {
12 let mut orientation = 0;
13 let mut n = 0;
14 let dim = reference_cell::dim(entity_type);
15 if dim > 1 {
16 for v in reference_cell::edges(entity_type) {
17 if vertices[v[0]] > vertices[v[1]] {
18 orientation += 1 << n;
19 }
20 n += 1;
21 }
22 }
23 if dim > 2 {
24 for (t, v) in izip!(
25 &reference_cell::entity_types(entity_type)[2],
26 reference_cell::faces(entity_type)
27 ) {
28 match t {
29 ReferenceCellType::Triangle => {
30 let m = v
31 .iter()
32 .map(|i| vertices[*i])
33 .enumerate()
34 .min_by(|(_, a), (_, b)| a.partial_cmp(b).unwrap())
35 .map(|(index, _)| index)
36 .unwrap() as i32;
37 orientation += m << n;
38 n += 2;
39 let next = vertices[v[(m as usize + 1) % 3]];
40 let prev = vertices[v[if m == 0 { 2 } else { m as usize - 1 }]];
41 if next > prev {
42 orientation += 1 << n;
43 }
44 n += 1;
45 }
46 ReferenceCellType::Quadrilateral => {
47 let m = v
48 .iter()
49 .map(|i| vertices[*i])
50 .enumerate()
51 .min_by(|(_, a), (_, b)| a.partial_cmp(b).unwrap())
52 .map(|(index, _)| index)
53 .unwrap() as i32;
54 if m == 2 {
55 orientation += 3 << n;
56 } else if m == 3 {
57 orientation += 2 << n;
58 } else {
59 orientation += m << n;
60 }
61 n += 2;
62 let next = vertices[v[[1, 3, 0, 2][m as usize]]];
63 let prev = vertices[v[[2, 0, 3, 1][m as usize]]];
64 if next > prev {
65 orientation += 1 << n;
66 }
67 n += 1;
68 }
69 _ => {
70 panic!("Unsupported face type: {t:?}");
71 }
72 }
73 }
74 }
75 orientation
76}
77
78#[cfg(test)]
79mod test {
80 use super::*;
81
82 #[test]
83 fn test_compute_orientations_interval() {
84 for (v, o) in [([0, 1], 0), ([1, 0], 0)] {
85 assert_eq!(compute_orientation(ReferenceCellType::Interval, &v), o);
86 }
87 }
88
89 #[test]
90 fn test_compute_orientations_triangle() {
91 for (v, o) in [
92 ([0, 1, 2], 0),
93 ([0, 2, 1], 1),
94 ([1, 0, 2], 4),
95 ([1, 2, 0], 3),
96 ([2, 0, 1], 6),
97 ([2, 1, 0], 7),
98 ] {
99 assert_eq!(compute_orientation(ReferenceCellType::Triangle, &v), o);
100 }
101 }
102
103 #[test]
104 fn test_compute_orientations_quadrilateral() {
105 for (v, o) in [
106 ([0, 1, 2, 3], 0),
107 ([0, 1, 3, 2], 8),
108 ([0, 2, 1, 3], 0),
109 ([0, 2, 3, 1], 12),
110 ([0, 3, 1, 2], 4),
111 ([0, 3, 2, 1], 12),
112 ([1, 0, 2, 3], 1),
113 ([1, 0, 3, 2], 9),
114 ([1, 2, 0, 3], 2),
115 ([1, 2, 3, 0], 12),
116 ([1, 3, 0, 2], 6),
117 ([1, 3, 2, 0], 12),
118 ] {
119 assert_eq!(compute_orientation(ReferenceCellType::Quadrilateral, &v), o);
120 }
121 }
122
123 #[test]
124 fn test_compute_orientations_tetrahedron() {
125 for (v, o) in [
126 ([0, 1, 2, 3], 0),
127 ([0, 3, 2, 1], 149895), ([1, 2, 0, 3], 68436), ([1, 3, 2, 0], 140687), ] {
131 assert_eq!(compute_orientation(ReferenceCellType::Tetrahedron, &v), o);
132 }
133 }
134
135 #[test]
136 fn test_compute_orientations_hexahedron() {
137 for (v, o) in [
138 ([0, 1, 2, 3, 4, 5, 6, 7], 0),
139 ([2, 5, 6, 1, 7, 0, 4, 3], 165899128), ([4, 1, 5, 0, 2, 3, 6, 7], 95215661), ([6, 5, 1, 7, 2, 4, 3, 0], 306691223), ] {
143 assert_eq!(compute_orientation(ReferenceCellType::Hexahedron, &v), o);
144 }
145 }
146}