| 80 | } |
| 81 | |
| 82 | bool MeshChecker::is_oriented() const { |
| 83 | // For each edge (s, d), check to see if the number of faces containing |
| 84 | // (s, d) as an edge and the number of faces containing (d, s) as an edge |
| 85 | // are equal. |
| 86 | // |
| 87 | // Boundary edges are skipped. |
| 88 | const size_t num_vertex_per_face = m_faces.cols(); |
| 89 | for (auto adj : m_edge_face_adjacency) { |
| 90 | if (adj.second.size() == 1) continue; |
| 91 | |
| 92 | const auto& e = adj.first.get_ori_data(); |
| 93 | if (e[0] == e[1]) { |
| 94 | // It is impossible to determine the orientaiton of faces such as |
| 95 | // [a, b, b] or [a, a, a]. |
| 96 | return false; |
| 97 | } else { |
| 98 | int consistent_count = 0; |
| 99 | for (auto fid : adj.second) { |
| 100 | VectorI f = m_faces.row(fid); |
| 101 | for (size_t i=0; i<num_vertex_per_face; i++) { |
| 102 | if (f[i] == e[0] && f[(i+1)%num_vertex_per_face] == e[1]) { |
| 103 | consistent_count++; |
| 104 | } else if (f[i] == e[1] && |
| 105 | f[(i+1)%num_vertex_per_face] == e[0]) { |
| 106 | consistent_count--; |
| 107 | } |
| 108 | } |
| 109 | } |
| 110 | if (consistent_count != 0) return false; |
| 111 | } |
| 112 | } |
| 113 | return true; |
| 114 | } |
| 115 | |
| 116 | bool MeshChecker::is_closed() const { |
| 117 | return m_boundary_edges.rows() == 0; |