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); }
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; } }
void TilerEngine::remove_duplicated_vertices(WireNetwork& wire_network, Float tol) { const size_t num_input_vertices = wire_network.get_num_vertices(); DuplicatedVertexRemoval remover(wire_network.get_vertices(), wire_network.get_edges()); remover.run(tol); MatrixFr vertices = remover.get_vertices(); MatrixIr edges = remover.get_faces(); VectorI index_map = remover.get_index_map(); assert(num_input_vertices == index_map.size()); wire_network.set_vertices(vertices); wire_network.set_edges(edges); const size_t num_output_vertices = wire_network.get_num_vertices(); std::vector<std::string> attr_names = wire_network.get_attribute_names(); for (auto itr : attr_names) { const std::string& name = itr; if (wire_network.is_vertex_attribute(name)) { MatrixFr values = wire_network.get_attribute(name); MatrixFr updated_values = MatrixFr::Zero(num_output_vertices, values.cols()); VectorF count = VectorF::Zero(num_output_vertices); for (size_t i=0; i<num_input_vertices; i++) { size_t j = index_map[i]; updated_values.row(j) += values.row(i); count[j] += 1; } for (size_t i=0; i<num_output_vertices; i++) { assert(count[i] > 0); updated_values.row(i) /= count[i]; } wire_network.set_attribute(name, updated_values); } } }
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)); }
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; }
void save_mesh(const std::string& filename, const MatrixFr& vertices, const MatrixIr& faces) { auto flattened_vertices = MatrixUtils::flatten<VectorF>(vertices); auto flattened_faces = MatrixUtils::flatten<VectorI>(faces); VectorI voxels = VectorI::Zero(0); MeshWriter::Ptr writer = MeshWriter::create(filename); writer->write(flattened_vertices, flattened_faces, voxels, vertices.cols(), faces.cols(), 0); }
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); }
BoundaryRemesher::BoundaryRemesher(const MatrixFr& vertices, const MatrixIr& faces) : m_vertices(vertices), m_faces(faces) { if (vertices.cols() != 3) { throw NotImplementedError( "Only 3D meshes are supported for remeshing"); } if (faces.cols() != 3) { throw NotImplementedError( "Only triangle meshes are supported for remeshing"); } assert_faces_are_valid(m_faces); }
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(); }
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); }
void reorientate_triangles(const MatrixFr& vertices, MatrixIr& faces, const VectorF& n) { assert(vertices.cols() == 3); assert(faces.cols() == 3); const VectorI& f = faces.row(0); const Vector3F& v0 = vertices.row(f[0]); const Vector3F& v1 = vertices.row(f[1]); const Vector3F& v2 = vertices.row(f[2]); Float projected_area = (v1-v0).cross(v2-v0).dot(n); if (projected_area < 0) { faces.col(2).swap(faces.col(1)); } }
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(); } }