| 235 | } // namespace |
| 236 | |
| 237 | PlyMesh SimplifyMesh(const PlyMesh& mesh, |
| 238 | const MeshSimplificationOptions& options) { |
| 239 | THROW_CHECK(options.Check()); |
| 240 | |
| 241 | if (mesh.faces.empty() || mesh.vertices.empty()) { |
| 242 | return mesh; |
| 243 | } |
| 244 | |
| 245 | // Validate that all face vertex indices are within bounds. |
| 246 | const size_t num_verts = mesh.vertices.size(); |
| 247 | for (size_t fi = 0; fi < mesh.faces.size(); ++fi) { |
| 248 | const auto& face = mesh.faces[fi]; |
| 249 | THROW_CHECK_LT(face.vertex_idx1, num_verts) |
| 250 | << "Face " << fi << " has out-of-bounds vertex index"; |
| 251 | THROW_CHECK_LT(face.vertex_idx2, num_verts) |
| 252 | << "Face " << fi << " has out-of-bounds vertex index"; |
| 253 | THROW_CHECK_LT(face.vertex_idx3, num_verts) |
| 254 | << "Face " << fi << " has out-of-bounds vertex index"; |
| 255 | } |
| 256 | |
| 257 | const size_t num_faces = mesh.faces.size(); |
| 258 | const size_t target_faces = std::max( |
| 259 | static_cast<size_t>(1), |
| 260 | static_cast<size_t>(std::floor(num_faces * options.target_face_ratio))); |
| 261 | |
| 262 | if (target_faces >= num_faces) { |
| 263 | return mesh; |
| 264 | } |
| 265 | |
| 266 | const size_t num_vertices = mesh.vertices.size(); |
| 267 | std::vector<VertexData> vertex_data(num_vertices); |
| 268 | for (size_t i = 0; i < num_vertices; ++i) { |
| 269 | vertex_data[i].position = Eigen::Vector3d( |
| 270 | mesh.vertices[i].x, mesh.vertices[i].y, mesh.vertices[i].z); |
| 271 | vertex_data[i].color = Eigen::Vector3f( |
| 272 | mesh.vertices[i].r, mesh.vertices[i].g, mesh.vertices[i].b); |
| 273 | } |
| 274 | |
| 275 | // Build mutable face index array. |
| 276 | std::vector<std::array<size_t, 3>> face_indices(num_faces); |
| 277 | std::vector<bool> face_removed(num_faces, false); |
| 278 | |
| 279 | // Build topology. |
| 280 | LOG(INFO) << "Building mesh topology..."; |
| 281 | for (size_t fi = 0; fi < num_faces; ++fi) { |
| 282 | face_indices[fi] = {mesh.faces[fi].vertex_idx1, |
| 283 | mesh.faces[fi].vertex_idx2, |
| 284 | mesh.faces[fi].vertex_idx3}; |
| 285 | const auto& f = face_indices[fi]; |
| 286 | |
| 287 | // Skip degenerate faces. |
| 288 | if (f[0] == f[1] || f[0] == f[2] || f[1] == f[2]) { |
| 289 | face_removed[fi] = true; |
| 290 | continue; |
| 291 | } |
| 292 | |
| 293 | for (int j = 0; j < 3; ++j) { |
| 294 | const size_t va = f[j]; |