From a835744ff7dca3920b78e10c50b076c4792c858e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Thu, 19 Sep 2019 14:30:16 +0200 Subject: [PATCH] Improve GH simplification example --- .../edge_collapse_garland_heckbert.cpp | 133 +++++++++++++----- 1 file changed, 94 insertions(+), 39 deletions(-) diff --git a/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_garland_heckbert.cpp b/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_garland_heckbert.cpp index 889740a4b2d..d4d34a38261 100644 --- a/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_garland_heckbert.cpp +++ b/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_garland_heckbert.cpp @@ -1,65 +1,120 @@ -#include -#include +#include +#include -#include -#include - -// Simplification function #include +#include -// Stop-condition policy -#include -#include -#include +#include +#include -#include +#include #include #include #include -typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; -typedef CGAL::Polyhedron_3 Surface_mesh; +// @tmp only required for STL reading +#include +#include + +#include +#include +#include +#include + +typedef CGAL::Simple_cartesian Kernel; +typedef Kernel::FT FT; +typedef Kernel::Point_3 Point_3; +typedef CGAL::Surface_mesh Surface_mesh; namespace SMS = CGAL::Surface_mesh_simplification; +template +void read_mesh(const char* filename, + Mesh& sm) +{ + typedef typename K::Point_3 Point; + + std::ifstream in(filename, std::ios::binary); + if(!in.good()) + { + std::cerr << "Error: can't read file: " << filename << std::endl; + std::exit(1); + } + + std::string fn(filename); + if(fn.substr(fn.find_last_of(".") + 1) == "stl") + { + std::vector points; + std::vector > faces; + CGAL::read_STL(in, points, faces); + + if(!CGAL::Polygon_mesh_processing::orient_polygon_soup(points, faces)) + std::cerr << "W: File does not describe a polygon mesh" << std::endl; + + CGAL::Polygon_mesh_processing::polygon_soup_to_polygon_mesh(points, faces, sm); + } + else if(fn.substr(fn.find_last_of(".") + 1) == "off") + { + if(!in || !(in >> sm)) + { + std::cerr << "Error: cannot OFF open mesh\n"; + return; + } + } + else + { + std::cerr << "Unknown file type" << std::endl; + return; + } +} + int main(int argc, char** argv) { - if(argc<3) - { - std::cerr << "Usage: " << argv[0] << " input.off minimal_quadric_error [out.off]\n"; - return EXIT_FAILURE; - } - Surface_mesh surface_mesh; - std::ifstream is(argv[1]); - if(is >> surface_mesh) - { - std::cerr << "Error: could not read input file" << std::endl; - return EXIT_FAILURE; - } - const double threshold = atof(argv[2]); - - std::cout << num_vertices(surface_mesh) << " vertices and " << num_edges(surface_mesh) << " edges (input)" << std::endl; + const char* filename = argv[1]; + read_mesh(filename, surface_mesh); if(!CGAL::is_triangle_mesh(surface_mesh)) { - std::cerr << "Error: Input geometry is not triangulated." << std::endl; + std::cerr << "Input geometry is not triangulated." << std::endl; return EXIT_FAILURE; } - SMS::GarlandHeckbert_edge_collapse_visitor_base::garland_heckbert_state_type state; + std::cout << "Input mesh has " << num_vertices(surface_mesh) << " nv " + << num_edges(surface_mesh) << " ne " + << num_faces(surface_mesh) << " nf" << std::endl; - int r = SMS::edge_collapse(surface_mesh, - CGAL::Surface_mesh_simplification::GarlandHeckbert_cost_stop_predicate(threshold), - CGAL::parameters::vertex_index_map(get(CGAL::vertex_external_index, surface_mesh)) - .halfedge_index_map(get(CGAL::halfedge_external_index, surface_mesh)) - .get_cost(SMS::GarlandHeckbert_cost (state)) - .get_placement(SMS::GarlandHeckbert_placement(state)) - .visitor(SMS::GarlandHeckbert_edge_collapse_visitor_base(state))); + const double stop_threshold = (argc > 2) ? std::stod(argv[2]) : 0.1; - std::cout << "\nFinished...\n" << r << " edges removed.\n" - << (surface_mesh.size_of_halfedges()/2) << " final edges.\n"; + std::chrono::steady_clock::time_point start_time = std::chrono::steady_clock::now(); + + SMS::Count_ratio_stop_predicate stop(stop_threshold); + // SMS::GarlandHeckbert_cost_stop_predicate stop(stop_threshold); + + // Garland&Heckbert simplification maintains an error matrix at each vertex, + // which must be accessible for the cost and placement evaluations. + typedef typename SMS::GarlandHeckbert_cost_matrix::type Cost_matrix; + typedef CGAL::dynamic_vertex_property_t Cost_property; + typedef typename boost::property_map::type Vertex_cost_map; + typedef SMS::GarlandHeckbert_placement GH_placement; + + Vertex_cost_map vcm = get(Cost_property(), surface_mesh); + SMS::GarlandHeckbert_cost cost(vcm); + + GH_placement gh_placement(vcm); + SMS::Bounded_normal_change_placement placement(gh_placement); + + int r = SMS::edge_collapse(surface_mesh, stop, CGAL::parameters::get_cost(cost) + .get_placement(placement)); + + std::chrono::steady_clock::time_point end_time = std::chrono::steady_clock::now(); + + std::cout << "Time elapsed: " + << std::chrono::duration_cast(end_time - start_time).count() + << "ms" << std::endl; + + std::cout << "\nFinished...\n" << r << " edges removed.\n" << surface_mesh.number_of_edges() << " final edges.\n"; std::ofstream os(argc > 3 ? argv[3] : "out.off"); os.precision(17);