void SimpleInflator::generate_joint( const MatrixFr& pts, const VectorI& source_ids, size_t vertex_index) { const size_t dim = m_wire_network->get_dim(); ConvexHullEngine::Ptr convex_hull = ConvexHullEngine::create(dim, "qhull"); convex_hull->run(pts); MatrixFr vertices = convex_hull->get_vertices(); MatrixIr faces = convex_hull->get_faces(); VectorI index_map = convex_hull->get_index_map(); if (dim == 2) { // Need to triangulate the loop. const size_t num_vertices = vertices.rows(); TriangleWrapper tri(vertices, faces); tri.run(std::numeric_limits<Float>::max(), false, false, false); vertices = tri.get_vertices(); faces = tri.get_faces(); assert(vertices.rows() == num_vertices); } m_vertex_list.push_back(vertices); const size_t num_faces = faces.rows(); for (size_t i=0; i<num_faces; i++) { const auto& face = faces.row(i); if (dim == 3) { auto ori_indices = map_indices(face, index_map); if (belong_to_the_same_loop(ori_indices, source_ids)) continue; } m_face_list.push_back(face.array() + m_num_vertex_accumulated); m_face_source_list.push_back(vertex_index+1); } m_num_vertex_accumulated += vertices.rows(); }
void GeometryCorrectionTable::apply_z_correction( const Vector3F& edge_dir, MatrixFr& loop) { //const Float max_z_error = 0.125; //const Float max_z_error = 0.09; const Float max_z_error = 0.00; VectorF bbox_min = loop.colwise().minCoeff(); VectorF bbox_max = loop.colwise().maxCoeff(); VectorF bbox_center = 0.5 * (bbox_min + bbox_max); Vector3F side_dir = edge_dir.cross(Vector3F::UnitZ()); Float sin_val = side_dir.norm(); if (sin_val < 1e-3) return; const size_t num_vts = loop.rows(); for (size_t i=0; i<num_vts; i++) { Vector3F v = loop.row(i) - bbox_center.transpose(); Float side_component = side_dir.dot(v) / sin_val; Vector3F proj_v = v - side_component * side_dir / sin_val; Float proj_component = proj_v.norm(); if (proj_component > 1e-3) { proj_v -= proj_v / proj_component * (sin_val * max_z_error); } loop.row(i) = bbox_center + proj_v + side_component * side_dir / sin_val; } }
VectorF FastWindingNumberEngine::run(const MatrixFr& queries) { const auto num_vertices = m_vertices.rows(); const auto num_faces = m_faces.rows(); const auto num_queries = queries.rows(); using Vector = HDK_Sample::UT_Vector3T<float>; using Engine = HDK_Sample::UT_SolidAngle<float, float>; std::vector<Vector> vertices(num_vertices); for (size_t i=0; i<num_vertices; i++) { vertices[i][0] = static_cast<float>(m_vertices(i, 0)); vertices[i][1] = static_cast<float>(m_vertices(i, 1)); vertices[i][2] = static_cast<float>(m_vertices(i, 2)); } Engine engine; engine.init(num_faces, m_faces.data(), num_vertices, vertices.data()); VectorF winding_numbers(num_queries); for (size_t i=0; i<num_queries; i++) { Vector q; q[0] = static_cast<float>(queries(i, 0)); q[1] = static_cast<float>(queries(i, 1)); q[2] = static_cast<float>(queries(i, 2)); winding_numbers[i] = engine.computeSolidAngle(q); } winding_numbers /= 4 * M_PI; return winding_numbers; }
SelfIntersection::SelfIntersection( const MatrixFr& vertices, const MatrixIr& faces) : m_faces(faces) { const size_t num_vertices = vertices.rows(); const size_t dim = vertices.cols(); const size_t num_faces = faces.rows(); const size_t vertex_per_face = faces.cols(); if (dim != 3) { throw NotImplementedError( "Self intersection check only support 3D"); } if (vertex_per_face != 3) { throw NotImplementedError( "Self intersection check only works with triangles"); } m_points.resize(num_vertices); for (size_t i=0; i<num_vertices; i++) { m_points[i] = Point_3( vertices(i,0), vertices(i,1), vertices(i,2)); } }
void GeometryCorrectionTable::apply_correction_to_in_plane_edge( const Vector3F& edge_dir, MatrixFr& loop) { VectorF bbox_min = loop.colwise().minCoeff(); VectorF bbox_max = loop.colwise().maxCoeff(); VectorF bbox_center = 0.5 * (bbox_min + bbox_max); size_t num_vts = loop.rows(); size_t dim = loop.cols(); assert(dim == 3); MatrixFr proj_loop(num_vts, dim); for (size_t i=0; i<num_vts; i++) { const VectorF& v = loop.row(i) - bbox_center.transpose(); proj_loop.row(i) = Vector3F(v[0], v[1], 0.0); } Float target_half_height = 1e3; // Something huge to represent inf Float target_half_width = proj_loop.row(0).norm(); Vector2F correction_1 = lookup(target_half_width, target_half_height); Vector2F correction_2 = lookup(target_half_height, target_half_width); Float half_width = 0.5 * (correction_1[0] + correction_2[1]) + 0.05 * num_offset_pixel; half_width = std::max(half_width, min_thickness); for (size_t i=0; i<num_vts; i++) { loop.row(i) += proj_loop.row(i) * (-target_half_width + half_width) / target_half_width; } }
GeoMeshPtr GeogramMeshUtils::wire_network_to_geomesh( const MatrixFr& vertices, const Matrix2Ir& edges) { const size_t dim = vertices.cols(); const size_t num_vertices = vertices.rows(); const size_t num_edges = edges.rows(); auto geo_mesh = std::make_shared<GeoMesh>(dim, false); geo_mesh->vertices.clear(); geo_mesh->vertices.create_vertices(num_vertices); geo_mesh->edges.clear(); geo_mesh->edges.create_edges(num_edges); for (size_t i=0; i<num_vertices; i++) { auto& p = geo_mesh->vertices.point(i); for (size_t j=0; j<dim; j++) { p[j] = vertices(i,j); } } for (size_t i=0; i<num_edges; i++) { geo_mesh->edges.set_vertex(i, 0, edges(i,0)); geo_mesh->edges.set_vertex(i, 1, edges(i,1)); } return geo_mesh; }
GeoMeshPtr GeogramMeshUtils::raw_to_geomesh( const MatrixFr& vertices, const MatrixIr& faces) { const size_t dim = vertices.cols(); const size_t vertex_per_face = faces.cols(); const size_t num_vertices = vertices.rows(); const size_t num_faces = faces.rows(); if (vertex_per_face != 3) { throw NotImplementedError("Converting non-triangle mesh to " "Geogram mesh is not yet implemented"); } auto geo_mesh = std::make_shared<GeoMesh>(dim, false); geo_mesh->vertices.clear(); geo_mesh->vertices.create_vertices(num_vertices); geo_mesh->facets.clear(); geo_mesh->facets.create_triangles(num_faces); for (size_t i=0; i<num_vertices; i++) { auto& p = geo_mesh->vertices.point(i); for (size_t j=0; j<dim; j++) { p[j] = vertices(i,j); } } for (size_t i=0; i<num_faces; i++) { geo_mesh->facets.set_vertex(i, 0, faces(i,0)); geo_mesh->facets.set_vertex(i, 1, faces(i,1)); geo_mesh->facets.set_vertex(i, 2, faces(i,2)); } return geo_mesh; }
CarveMeshPtr create_mesh(const MatrixFr& vertices, const MatrixIr& faces) { const size_t num_vertices = vertices.rows(); const size_t num_faces = faces.rows(); if (vertices.cols() != 3) { throw NotImplementedError("Only 3D mesh is supported."); } if (faces.cols() != 3) { throw NotImplementedError("Only triangle mesh is supported."); } std::vector<CarveVector> points; for (size_t i=0; i<num_vertices; i++) { const auto& v = vertices.row(i); CarveVector p; p.v[0] = v[0]; p.v[1] = v[1]; p.v[2] = v[2]; points.push_back(p); } std::vector<int> raw_faces; raw_faces.reserve(num_faces * 4); for (size_t i=0; i<num_faces; i++) { raw_faces.push_back(3); raw_faces.push_back(faces(i,0)); raw_faces.push_back(faces(i,1)); raw_faces.push_back(faces(i,2)); } return CarveMeshPtr(new CarveMesh(points, num_faces, raw_faces)); }
Polyhedron generate_polyhedron( const MatrixFr& vertices, const MatrixIr& faces) { Polyhedron P; PolyhedronBuilder<HalfedgeDS> triangle(vertices, faces); P.delegate(triangle); assert(vertices.rows() == P.size_of_vertices()); assert(faces.rows() == P.size_of_facets()); return P; }
HashGrid::Ptr compute_vertex_grid(const MatrixFr& vertices, Float cell_size) { const size_t dim = vertices.cols(); const size_t num_vertices = vertices.rows(); HashGrid::Ptr grid = HashGrid::create(cell_size, dim); for (size_t i=0; i<num_vertices; i++) { const VectorF& v = vertices.row(i); grid->insert(i, v); } return grid; }
void InflatorEngine::save_mesh(const std::string& filename, const MatrixFr& vertices, const MatrixIr& faces, VectorF debug) { VectorF flattened_vertices(vertices.rows() * vertices.cols()); std::copy(vertices.data(), vertices.data() + vertices.rows() * vertices.cols(), flattened_vertices.data()); VectorI flattened_faces(faces.rows() * faces.cols()); std::copy(faces.data(), faces.data() + faces.rows() * faces.cols(), flattened_faces.data()); VectorI voxels = VectorI::Zero(0); Mesh::Ptr mesh = MeshFactory().load_data( flattened_vertices, flattened_faces, voxels, vertices.cols(), faces.cols(), 0).create_shared(); mesh->add_attribute("debug"); mesh->set_attribute("debug", debug); MeshWriter::Ptr writer = MeshWriter::create(filename); writer->with_attribute("debug"); writer->write_mesh(*mesh); }
void CGALConvexHull3D::run(const MatrixFr& points) { std::list<Point_3> cgal_pts; const size_t num_pts = points.rows(); const size_t dim = points.cols(); if (dim != 3) { std::stringstream err_msg; err_msg << "Invalid dim: " << dim << " Expect dim=3."; throw RuntimeError(err_msg.str()); } for (size_t i=0; i<num_pts; i++) { const VectorF& p = points.row(i); cgal_pts.push_back(Point_3(p[0], p[1], p[2])); } Polyhedron_3 hull; CGAL::convex_hull_3(cgal_pts.begin(), cgal_pts.end(), hull); assert(hull.is_closed()); assert(hull.is_pure_triangle()); const size_t num_vertices = hull.size_of_vertices(); const size_t num_faces = hull.size_of_facets(); m_vertices.resize(num_vertices, dim); m_faces.resize(num_faces, 3); size_t vertex_count=0; for (auto itr=hull.vertices_begin(); itr!=hull.vertices_end(); itr++) { const Point_3& p = itr->point(); m_vertices.coeffRef(vertex_count, 0) = p.x(); m_vertices.coeffRef(vertex_count, 1) = p.y(); m_vertices.coeffRef(vertex_count, 2) = p.z(); itr->id() = vertex_count; vertex_count++; } size_t face_count=0; for (auto f_itr=hull.facets_begin(); f_itr!=hull.facets_end(); f_itr++) { size_t edge_count=0; auto h_itr = f_itr->facet_begin(); do { m_faces.coeffRef(face_count, edge_count) = h_itr->vertex()->id(); edge_count++; h_itr++; } while (h_itr != f_itr->facet_begin()); face_count++; } compute_index_map(points); reorient_faces(); }
void triangulate(MatrixFr vertices, MatrixIr edges, MatrixFr& output_vertices, MatrixIr& output_faces, Float max_area) { assert(edges.rows() >= 3); MeshCleaner cleaner; cleaner.remove_isolated_vertices(vertices, edges); cleaner.remove_duplicated_vertices(vertices, edges, 1e-12); assert(vertices.rows() >= 3); TriangleWrapper triangle(vertices, edges); triangle.run(max_area, false, true, true); output_vertices = triangle.get_vertices(); output_faces = triangle.get_faces(); }
Boundary::Ptr Boundary::extract_surface_boundary_raw( MatrixFr& vertices, MatrixIr& faces) { VectorF flattened_vertices = Eigen::Map<VectorF>(vertices.data(), vertices.rows() * vertices.cols()); VectorI flattened_faces = Eigen::Map<VectorI>(faces.data(), faces.rows() * faces.cols()); VectorI voxels = VectorI::Zero(0); MeshFactory factory; Mesh::Ptr mesh = factory.load_data(flattened_vertices, flattened_faces, voxels, vertices.cols(), faces.cols(), 0).create(); return extract_surface_boundary(*mesh); }
WireNetwork::Ptr MixedMeshTiler::tile() { const size_t num_cells = get_num_cells(); auto transforms = get_tiling_operators(); auto vars_array = extract_attributes(m_mesh); VectorI pattern_id = m_mesh->get_attribute("pattern_id").cast<int>(); assert(pattern_id.size() == num_cells); m_tiled_vertices.clear(); m_tiled_edges.clear(); m_tiled_thicknesses.clear(); m_tiled_offsets.clear(); size_t v_count = 0; auto transform_itr = transforms.begin(); for (size_t i=0; i<num_cells; i++) { set_active_wire_network(pattern_id[i]); scale_to_unit_box(); append_vertices(*transform_itr); append_edges(v_count); append_thicknesses(vars_array[i]); append_offsets(vars_array[i], *transform_itr); v_count += m_unit_wire_network->get_num_vertices(); transform_itr++; } MatrixFr vertices = vstack(m_tiled_vertices); MatrixIr edges = vstack(m_tiled_edges); MatrixFr thicknesses = vstack(m_tiled_thicknesses); MatrixFr offsets = vstack(m_tiled_offsets); assert(edges.minCoeff() >= 0); assert(edges.maxCoeff() < vertices.rows()); WireNetwork::Ptr tiled_network = WireNetwork::create_raw(vertices, edges); tiled_network->add_attribute("thickness", m_target_type == ParameterCommon::VERTEX); tiled_network->set_attribute("thickness", thicknesses); tiled_network->add_attribute("vertex_offset", true); tiled_network->set_attribute("vertex_offset", offsets); clean_up(*tiled_network); return tiled_network; }
void PointLocator::locate(const MatrixFr& points) { const Float eps = 1e-6; const size_t num_pts = points.rows(); m_voxel_idx = VectorI::Zero(num_pts); m_barycentric_coords = MatrixFr::Zero(num_pts, m_vertex_per_element); for (size_t i=0; i<num_pts; i++) { VectorF v = points.row(i); VectorI candidate_elems = m_grid->get_items_near_point(v); VectorF barycentric_coord; VectorF best_barycentric_coord; bool found = false; Float least_negative_coordinate = -std::numeric_limits<Float>::max(); const size_t num_candidates = candidate_elems.size(); for (size_t j=0; j<num_candidates; j++) { barycentric_coord = compute_barycentric_coord( v, candidate_elems[j]); Float min_barycentric_coord = barycentric_coord.minCoeff(); if (min_barycentric_coord > least_negative_coordinate) { found = true; least_negative_coordinate = min_barycentric_coord; m_voxel_idx[i] = candidate_elems[j]; best_barycentric_coord = barycentric_coord; if (min_barycentric_coord >= -eps) { break; } } } if (!found) { std::stringstream err_msg; err_msg << "Point ( "; for (size_t i=0; i<m_mesh->get_dim(); i++) { err_msg << v[i] << " "; } err_msg << ") is not inside of any voxels" << std::endl; throw RuntimeError(err_msg.str()); } m_barycentric_coords.row(i) = best_barycentric_coord; } }
bool MeshValidation::is_periodic( const MatrixFr& vertices, const MatrixIr& faces) { const Float EPS = 1e-6; HashGrid::Ptr grid = compute_vertex_grid(vertices, EPS); Vector3F bbox_min = vertices.colwise().minCoeff(); Vector3F bbox_max = vertices.colwise().maxCoeff(); Vector3F bbox_size = bbox_max - bbox_min; Vector3F offsets[] = { Vector3F( bbox_size[0], 0.0, 0.0), Vector3F(-bbox_size[0], 0.0, 0.0), Vector3F(0.0, bbox_size[1], 0.0), Vector3F(0.0,-bbox_size[1], 0.0), Vector3F(0.0, 0.0, bbox_size[2]), Vector3F(0.0, 0.0,-bbox_size[2]) }; bool result = true; const size_t num_vertices = vertices.rows(); for (size_t i=0; i<num_vertices; i++) { const VectorF& v = vertices.row(i); if (fabs(v[0] - bbox_min[0]) < EPS) { result = result && match(grid, v + offsets[0]); } if (fabs(v[0] - bbox_max[0]) < EPS) { result = result && match(grid, v + offsets[1]); } if (fabs(v[1] - bbox_min[1]) < EPS) { result = result && match(grid, v + offsets[2]); } if (fabs(v[1] - bbox_max[1]) < EPS) { result = result && match(grid, v + offsets[3]); } if (fabs(v[2] - bbox_min[2]) < EPS) { result = result && match(grid, v + offsets[4]); } if (fabs(v[2] - bbox_max[2]) < EPS) { result = result && match(grid, v + offsets[5]); } } return result; }
VectorI MeshCleaner::compute_importance_level(const MatrixFr& vertices) { VectorF bbox_min = vertices.colwise().minCoeff(); VectorF bbox_max = vertices.colwise().maxCoeff(); BoxChecker checker(bbox_min, bbox_max); const size_t num_vertices = vertices.rows(); VectorI level = VectorI::Zero(num_vertices); for (size_t i=0; i<num_vertices; i++) { const VectorF& v = vertices.row(i); if (checker.is_on_boundary_corners(v)) { level[i] = 3; } else if (checker.is_on_boundary_edges(v)) { level[i] = 2; } else if (checker.is_on_boundary(v)) { level[i] = 1; } } return level; }
bool PeriodicExploration::run_tetgen(Float max_tet_vol) { const size_t dim = m_vertices.cols(); const size_t num_vertices = m_vertices.rows(); TetgenWrapper tetgen(m_vertices, m_faces); std::stringstream flags; if (max_tet_vol == 0.0) { max_tet_vol = pow(m_default_thickness * pow(0.5, m_refine_order), dim); } flags << "pqYQa" << max_tet_vol; try { tetgen.run(flags.str()); } catch (TetgenException& e) { save_mesh("tetgen_debug.msh"); std::cerr << "Tetgen failed! Flags: " << flags.str() << std::endl; std::cerr << e.what() << std::endl; std::cerr << "Data saved in tetgen_debug.msh" << std::endl; return false; } // Important note: // // The following code is based on rather shaky the observation that tetgen // will only append to the existing list of vertices. Therefore, the face // arrays are still valid given the "Y" flag is used. MatrixFr vertices = tetgen.get_vertices(); assert(vertices.rows() > 0); assert((vertices.block(0, 0, num_vertices, dim).array()==m_vertices.array()).all()); m_vertices = vertices; m_voxels = tetgen.get_voxels(); const size_t num_vol_vertices = m_vertices.rows(); for (auto& velocity : m_shape_velocities) { velocity.conservativeResize(num_vol_vertices, dim); velocity.block(num_vertices, 0, num_vol_vertices-num_vertices, dim).setZero(); } update_mesh(); return true; }
Boundary::Ptr Boundary::extract_volume_boundary_raw( MatrixFr& vertices, MatrixIr& voxels) { VectorF flattened_vertices = Eigen::Map<VectorF>(vertices.data(), vertices.rows() * vertices.cols()); VectorI faces = VectorI::Zero(0); VectorI flattened_voxels = Eigen::Map<VectorI>(voxels.data(), voxels.rows() * voxels.cols()); size_t vertex_per_voxel = voxels.cols(); size_t vertex_per_face=0; if (vertex_per_voxel == 4) vertex_per_face = 3; else if (vertex_per_voxel == 8) vertex_per_face = 4; else { throw RuntimeError("Unknown voxel type."); } MeshFactory factory; Mesh::Ptr mesh = factory.load_data(flattened_vertices, faces, flattened_voxels, vertices.cols(), vertex_per_face, vertex_per_voxel).create(); return extract_volume_boundary(*mesh); }
VectorI get_vertex_labels(const MatrixFr& vertices, Operators& ops) { SymmetryConnectivity connectivity = compute_vertex_connectivity(vertices, ops); return label_connected_components(vertices.rows(), connectivity); }
void GeometryCorrectionTable::apply_correction_to_out_plane_edge( const Vector3F& edge_dir, MatrixFr& loop) { const Float EPS = 1e-3; assert(fabs(edge_dir[2]) > 0.0); VectorF bbox_min = loop.colwise().minCoeff(); VectorF bbox_max = loop.colwise().maxCoeff(); VectorF bbox_center = 0.5 * (bbox_min + bbox_max); size_t num_vts = loop.rows(); size_t dim = loop.cols(); assert(dim == 3); MatrixFr proj_loop(num_vts, 3); Vector3F proj_edge_dir(edge_dir[0], edge_dir[1], 0.0); if (loop.rows() != 4) { throw NotImplementedError( "Geometry correction supports only square wires"); } for (size_t i=0; i<num_vts; i++) { VectorF v = loop.row(i) - bbox_center.transpose(); Float edge_dir_offset = v[2] / edge_dir[2]; VectorF proj_v = v - edge_dir * edge_dir_offset; proj_loop.row(i) = proj_v; assert(fabs(proj_v[2]) < EPS); } Float dist_01 = (proj_loop.row(0) - proj_loop.row(1)).norm(); Float dist_12 = (proj_loop.row(1) - proj_loop.row(2)).norm(); if (dist_01 > dist_12) { proj_edge_dir = (proj_loop.row(0) - proj_loop.row(1)) / dist_01; } else { proj_edge_dir = (proj_loop.row(1) - proj_loop.row(2)) / dist_12; } const VectorF& corner = proj_loop.row(0); Float target_half_height = proj_edge_dir.dot(corner); Float target_half_width = (corner - proj_edge_dir * target_half_height).norm(); target_half_height = fabs(target_half_height); Vector2F correction_1 = lookup(target_half_width, target_half_height); Vector2F correction_2 = lookup(target_half_height, target_half_width); Float half_width = 0.5 * (correction_1[0] + correction_2[1]) + 0.05 * num_offset_pixel; Float half_height = 0.5 * (correction_1[1] + correction_2[0]) + 0.05 * num_offset_pixel; half_width = std::max(half_width, min_thickness); half_height = std::max(half_height, min_thickness); for (size_t i=0; i<num_vts; i++) { const VectorF& proj_v = proj_loop.row(i); Float height = proj_edge_dir.dot(proj_v); VectorF width_dir = (proj_v - proj_edge_dir * height).normalized(); assert(!isnan(width_dir[0])); assert(!isnan(width_dir[1])); assert(!isnan(width_dir[2])); Float height_sign = (height < 0.0)? -1: 1; proj_loop.row(i) = proj_edge_dir * height_sign * half_height + width_dir * half_width; } for (size_t i=0; i<num_vts; i++) { const VectorF& proj_v = proj_loop.row(i); loop.row(i) = (bbox_center + proj_v - edge_dir * edge_dir.dot(proj_v)).transpose(); } }
void MMG::Delaunay::refine(const MatrixFr& metric) { const size_t num_input_vertices = m_vertices.rows(); const size_t num_input_faces = m_faces.rows(); if (num_input_vertices == 0) { return; } MMG5_pMesh mmgMesh; MMG5_pSol mmgSol; mmgMesh = NULL; mmgSol = NULL; if (MMG2D_Init_mesh(MMG5_ARG_start, MMG5_ARG_ppMesh, &mmgMesh, MMG5_ARG_ppMet, &mmgSol, MMG5_ARG_end) != 1) { throw RuntimeError("MMG2D_Init_mesh failed."); } const Vector2F bbox_min = m_vertices.colwise().minCoeff(); const Vector2F bbox_max = m_vertices.colwise().maxCoeff(); const Float tol = (bbox_max - bbox_min).norm() / 20.0; if (MMG2D_Set_iparameter(mmgMesh, mmgSol, MMG2D_IPARAM_verbose, 1) != 1) { throw RuntimeError("Setting MMG2D_IPARAM_verbose failed."); } if (MMG2D_Set_dparameter(mmgMesh, mmgSol, MMG2D_DPARAM_hmax, tol) != 1) { throw RuntimeError("Setting MMG2D_DPARAM_hmax failed."); } if (MMG2D_Set_meshSize(mmgMesh,num_input_vertices,num_input_faces,0) != 1) { throw RuntimeError("MMG2D_Set_meshSize failed."); } for (size_t i=0; i<num_input_vertices; i++) { if (MMG2D_Set_vertex(mmgMesh, m_vertices(i,0), m_vertices(i, 1), i+1, i+1) != 1) { throw RuntimeError("MMG2D_Set_vertex failed for vertex " + std::to_string(i) + "."); } } for (size_t i=0; i<num_input_faces; i++) { if (MMG2D_Set_triangle(mmgMesh, m_faces(i, 0) + 1, m_faces(i, 1) + 1, m_faces(i, 2) + 1, i+1, i+1) != 1 ) { throw RuntimeError("MMG2D_Set_edge failed for edge " + std::to_string(i) + "."); } } // Set per-vertex metric. This must be done after mmgMesh is initialized. const size_t num_metrics = metric.rows(); if (num_metrics == 0) { if (MMG2D_Set_solSize(mmgMesh, mmgSol, MMG5_Vertex, 0, MMG5_Scalar) != 1) { throw RuntimeError("MMG2D_Set_solSize failed."); } } else if (num_metrics == num_input_vertices) { if (MMG2D_Set_solSize(mmgMesh, mmgSol, MMG5_Vertex, num_metrics, MMG5_Scalar) != 1) { throw RuntimeError("MMG2D_Set_solSize failed."); } for (size_t i=0; i<num_metrics; i++) { if (MMG2D_Set_scalarSol(mmgSol, metric(i,0), i+1) != 1 ) { throw RuntimeError("MMG2D_Set_scalarSol failed."); } } } if (MMG2D_Chk_meshData(mmgMesh, mmgSol) != 1) { throw RuntimeError("MMG2D_Chk_meshData failed"); } int r = MMG2D_mmg2dlib(mmgMesh,mmgSol); switch (r) { case MMG5_SUCCESS: break; case MMG5_LOWFAILURE: std::cerr << "Warning: MMG encountered low failure. Results may not not be valid." << std::endl; break; case MMG5_STRONGFAILURE: throw RuntimeError("MMG strong failure!"); default: throw NotImplementedError("Unknown MMG failure encountered."); } int num_vertices, num_triangles, num_edges; if (MMG2D_Get_meshSize(mmgMesh, &num_vertices, &num_triangles, &num_edges) !=1) { throw RuntimeError("MMG2D_Get_meshSize failed."); } m_vertices.resize(num_vertices, 2); int ref, is_corner, is_required; for (size_t i=0; i<num_vertices; i++) { if (MMG2D_Get_vertex(mmgMesh, &m_vertices(i, 0), &m_vertices(i, 1), &ref, &is_corner, &is_required) != 1 ) { throw RuntimeError("MMG2D_Get_vertex failed."); } } m_faces.resize(num_triangles, 3); for (size_t i=0; i<num_triangles; i++) { if (MMG2D_Get_triangle(mmgMesh, &m_faces(i, 0), &m_faces(i, 1), &m_faces(i, 2), &ref, &is_required) != 1 ) { throw RuntimeError("MMG2D_Get_triangle failed."); } } // MMG is 1 based unfortunately. m_faces.array() -= 1; //MMG2D_saveMesh(mmgMesh, "mmg_debug.mesh"); MMG2D_Free_all(MMG5_ARG_start, MMG5_ARG_ppMesh,&mmgMesh,MMG5_ARG_ppMet,&mmgSol, MMG5_ARG_end); }
bool MeshValidation::face_source_is_valid( const MatrixFr& vertices, const MatrixIr& faces, const VectorI& face_sources) { const Float EPS = 1e-6; const size_t num_vertices = vertices.rows(); const size_t num_faces = faces.rows(); Vector3F bbox_min = vertices.colwise().minCoeff(); Vector3F bbox_max = vertices.colwise().maxCoeff(); bool result = true; for (size_t i=0; i<num_faces; i++) { const Vector3I& f = faces.row(i); const Vector3F& v0 = vertices.row(f[0]); const Vector3F& v1 = vertices.row(f[1]); const Vector3F& v2 = vertices.row(f[2]); if (fabs(v0[0] - bbox_min[0]) < EPS && fabs(v1[0] - bbox_min[0]) < EPS && fabs(v2[0] - bbox_min[0]) < EPS) { result = result && (face_sources[i] == 0); continue; } if (fabs(v0[1] - bbox_min[1]) < EPS && fabs(v1[1] - bbox_min[1]) < EPS && fabs(v2[1] - bbox_min[1]) < EPS) { result = result && (face_sources[i] == 0); continue; } if (fabs(v0[2] - bbox_min[2]) < EPS && fabs(v1[2] - bbox_min[2]) < EPS && fabs(v2[2] - bbox_min[2]) < EPS) { result = result && (face_sources[i] == 0); continue; } if (fabs(v0[0] - bbox_max[0]) < EPS && fabs(v1[0] - bbox_max[0]) < EPS && fabs(v2[0] - bbox_max[0]) < EPS) { result = result && (face_sources[i] == 0); continue; } if (fabs(v0[1] - bbox_max[1]) < EPS && fabs(v1[1] - bbox_max[1]) < EPS && fabs(v2[1] - bbox_max[1]) < EPS) { result = result && (face_sources[i] == 0); continue; } if (fabs(v0[2] - bbox_max[2]) < EPS && fabs(v1[2] - bbox_max[2]) < EPS && fabs(v2[2] - bbox_max[2]) < EPS) { result = result && (face_sources[i] == 0); continue; } result = result && (face_sources[i] != 0); if (!result) { std::cout << i << ": "; std::cout << face_sources[i] << std::endl; std::cout << v0.transpose() << std::endl; std::cout << v1.transpose() << std::endl; std::cout << v2.transpose() << std::endl; return result; } } return result; }