25 static constexpr std::array<std::array<edge_index, 3>, 6> EdgeIndices{
26 {{0, 1, 4}, {0, 4, 3}, {0, 3, 9}, {0, 9, 12}, {0, 12, 13}, {0, 13, 1}}};
36 static constexpr std::array<std::array<edge_index, 3>, 6> OuterEdgeIndices{
37 {{2, 6, 12}, {5, 9, 13}, {6, 11, 1}, {8, 13, 4}, {11, 2, 3}, {10, 4, 9}}};
40 template <binary_sign s, binary_sign s0, binary_sign s1, binary_sign s2>
41 static constexpr int tetrahedron_type() {
42 return (s2 << 3) | (s1 << 2) | (s0 << 1) | s;
49 template <
class OutputIterator>
50 void get_faces(OutputIterator faces)
const {
51 auto ei0 = EdgeIndices.at(index_)[0];
52 auto ei1 = EdgeIndices.at(index_)[1];
53 auto ei2 = EdgeIndices.at(index_)[2];
55 const auto& node0 = node_.neighbor(ei0);
56 const auto& node1 = node_.neighbor(ei1);
57 const auto& node2 = node_.neighbor(ei2);
59 if (degenerate(node_, node0, node1, node2)) {
63 auto oei0 = OuterEdgeIndices.at(index_)[0];
64 auto oei1 = OuterEdgeIndices.at(index_)[1];
65 auto oei2 = OuterEdgeIndices.at(index_)[2];
69 auto v0 = vertex_on_edge(node_, ei0, node0);
70 auto v1 = vertex_on_edge(node_, ei1, node1);
71 auto v2 = vertex_on_edge(node_, ei2, node2);
72 auto v3 = vertex_on_edge(node0, oei0, node1);
73 auto v4 = vertex_on_edge(node1, oei1, node2);
74 auto v5 = vertex_on_edge(node2, oei2, node0);
76 auto tetra = tetrahedron_type(node_.value_sign(), node0.value_sign(), node1.value_sign(),
80 case tetrahedron_type<Pos, Pos, Pos, Pos>():
81 case tetrahedron_type<Neg, Neg, Neg, Neg>():
84 case tetrahedron_type<Neg, Pos, Pos, Pos>():
86 *faces++ = {v0.value(), v1.value(), v2.value()};
88 case tetrahedron_type<Pos, Neg, Neg, Neg>():
90 *faces++ = {v0.value(), v2.value(), v1.value()};
92 case tetrahedron_type<Pos, Neg, Pos, Pos>():
94 *faces++ = {v0.value(), v5.value(), v3.value()};
96 case tetrahedron_type<Neg, Pos, Neg, Neg>():
98 *faces++ = {v0.value(), v3.value(), v5.value()};
100 case tetrahedron_type<Pos, Pos, Neg, Pos>():
102 *faces++ = {v1.value(), v3.value(), v4.value()};
104 case tetrahedron_type<Neg, Neg, Pos, Neg>():
106 *faces++ = {v1.value(), v4.value(), v3.value()};
108 case tetrahedron_type<Pos, Pos, Pos, Neg>():
110 *faces++ = {v2.value(), v4.value(), v5.value()};
112 case tetrahedron_type<Neg, Neg, Neg, Pos>():
114 *faces++ = {v2.value(), v5.value(), v4.value()};
116 case tetrahedron_type<Neg, Neg, Pos, Pos>():
118 *faces++ = {v5.value(), v3.value(), v1.value()};
119 *faces++ = {v5.value(), v1.value(), v2.value()};
121 case tetrahedron_type<Pos, Pos, Neg, Neg>():
123 *faces++ = {v5.value(), v1.value(), v3.value()};
124 *faces++ = {v5.value(), v2.value(), v1.value()};
126 case tetrahedron_type<Neg, Pos, Neg, Pos>():
128 *faces++ = {v0.value(), v3.value(), v4.value()};
129 *faces++ = {v0.value(), v4.value(), v2.value()};
131 case tetrahedron_type<Pos, Neg, Pos, Neg>():
133 *faces++ = {v0.value(), v4.value(), v3.value()};
134 *faces++ = {v0.value(), v2.value(), v4.value()};
136 case tetrahedron_type<Neg, Pos, Pos, Neg>():
138 *faces++ = {v5.value(), v0.value(), v1.value()};
139 *faces++ = {v5.value(), v1.value(), v4.value()};
141 case tetrahedron_type<Pos, Neg, Neg, Pos>():
143 *faces++ = {v5.value(), v1.value(), v0.value()};
144 *faces++ = {v5.value(), v4.value(), v1.value()};
147 RSMESH_UNREACHABLE();
158 const auto& p = node.position();
159 const auto& p0 = node0.position();
160 const auto& p1 = node1.position();
161 const auto& p2 = node2.position();
163 return (p.array() == p0.array() && p.array() == p1.array() && p.array() == p2.array()).any();
166 static int tetrahedron_type(binary_sign s, binary_sign s0, binary_sign s1, binary_sign s2) {
167 return (s2 << 3) | (s1 << 2) | (s0 << 1) | s;
170 static std::optional<vertex_index> vertex_on_edge(
const rmt_node& node, edge_index edge_idx,
172 if (node.has_intersection(edge_idx)) {
173 return node.vertex_on_edge(edge_idx);
176 auto opp_edge_idx = OppositeEdge.at(edge_idx);
177 if (opp_node.has_intersection(opp_edge_idx)) {
178 return opp_node.vertex_on_edge(opp_edge_idx);