| 87 | } |
| 88 | |
| 89 | Mesh::Ptr MeshCutter::cut_at_uv_discontinuity() const { |
| 90 | const size_t dim = m_mesh->get_dim(); |
| 91 | const size_t num_vertices = m_mesh->get_num_vertices(); |
| 92 | const size_t num_faces = m_mesh->get_num_faces(); |
| 93 | const size_t vertex_per_face = m_mesh->get_vertex_per_face(); |
| 94 | const auto& vertices = m_mesh->get_vertices(); |
| 95 | const auto& faces = m_mesh->get_faces(); |
| 96 | |
| 97 | if (!m_mesh->has_attribute("corner_texture")) { |
| 98 | throw RuntimeError("Mesh does not have texture"); |
| 99 | } |
| 100 | const auto& uv = m_mesh->get_attribute("corner_texture"); |
| 101 | if (uv.size() != num_faces * vertex_per_face * 2) { |
| 102 | throw RuntimeError("Comp ids size does not match the number of faces in mesh"); |
| 103 | } |
| 104 | |
| 105 | struct Vector2FHash { |
| 106 | size_t operator()(const Vector2F& p) const { |
| 107 | return std::hash<Float>()(p[0] * 524287) ^ std::hash<Float>()(p[1]); |
| 108 | } |
| 109 | }; |
| 110 | |
| 111 | auto get_corner_index = [&faces, vertex_per_face](size_t fid, size_t vid) { |
| 112 | for (size_t i=0; i<vertex_per_face; i++) { |
| 113 | if (faces[fid*vertex_per_face+i] == vid) return i; |
| 114 | } |
| 115 | throw RuntimeError("Vertex " + std::to_string(vid) |
| 116 | + " is not adjacent to face " + std::to_string(fid)); |
| 117 | }; |
| 118 | |
| 119 | std::vector<size_t> added_vertices; |
| 120 | using UVMap = std::unordered_map<Vector2F, size_t, Vector2FHash>; |
| 121 | std::vector<UVMap> index_map(num_vertices, UVMap(8)); |
| 122 | for (size_t i=0; i<num_vertices; i++) { |
| 123 | const auto& adj_faces = m_mesh->get_vertex_adjacent_faces(i); |
| 124 | const size_t num_adj_faces = adj_faces.size(); |
| 125 | if (num_adj_faces == 0) continue; |
| 126 | |
| 127 | MatrixFr local_uv(num_adj_faces, 2); |
| 128 | for (size_t j=0; j<num_adj_faces; j++) { |
| 129 | auto corner_id = get_corner_index(adj_faces[j], i); |
| 130 | local_uv.row(j) = uv.segment<2>( |
| 131 | (adj_faces[j]*vertex_per_face + corner_id)*2); |
| 132 | } |
| 133 | |
| 134 | bool is_interior_vtx = true; |
| 135 | for (size_t j=1; is_interior_vtx && j<num_adj_faces; j++) { |
| 136 | is_interior_vtx &= (local_uv.row(0) == local_uv.row(j)); |
| 137 | } |
| 138 | if (is_interior_vtx) continue; |
| 139 | |
| 140 | Vector2F min_uv = local_uv.row(0); |
| 141 | auto& m = index_map[i]; |
| 142 | m[min_uv] = i; |
| 143 | for (size_t j=0; j<num_adj_faces; j++) { |
| 144 | const auto itr = m.find(local_uv.row(j)); |
| 145 | if (itr == m.end()) { |
| 146 | m[local_uv.row(j)] = num_vertices + added_vertices.size(); |