Improve GH simplification example

This commit is contained in:
Mael Rouxel-Labbé 2019-09-19 14:30:16 +02:00
parent cb3c68eca2
commit a835744ff7
1 changed files with 94 additions and 39 deletions

View File

@ -1,65 +1,120 @@
#include <iostream>
#include <fstream>
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Polyhedron_3.h>
// Simplification function
#include <CGAL/Surface_mesh_simplification/edge_collapse.h>
#include <CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Count_ratio_stop_predicate.h>
// Stop-condition policy
#include <CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Edge_length_cost.h>
#include <CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Edge_length_stop_predicate.h>
#include <CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Midpoint_placement.h>
#include <CGAL/IO/STL_reader.h>
#include <CGAL/IO/PLY_reader.h>
#include <CGAL/Surface_mesh_simplification/GarlandHeckbert_edge_collapse_visitor_base.h>
#include <CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Bounded_normal_change_placement.h>
#include <CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_cost.h>
#include <CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_placement.h>
#include <CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_cost_stop_predicate.h>
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef CGAL::Polyhedron_3<Kernel> Surface_mesh;
// @tmp only required for STL reading
#include <CGAL/Polygon_mesh_processing/orient_polygon_soup.h>
#include <CGAL/Polygon_mesh_processing/polygon_soup_to_polygon_mesh.h>
#include <chrono>
#include <iostream>
#include <fstream>
#include <vector>
typedef CGAL::Simple_cartesian<double> Kernel;
typedef Kernel::FT FT;
typedef Kernel::Point_3 Point_3;
typedef CGAL::Surface_mesh<Point_3> Surface_mesh;
namespace SMS = CGAL::Surface_mesh_simplification;
template <typename K, typename Mesh>
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<Point> points;
std::vector<std::array<int, 3> > 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<Kernel>(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<Surface_mesh>::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<double>(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 <Surface_mesh>(state))
.get_placement(SMS::GarlandHeckbert_placement<Surface_mesh>(state))
.visitor(SMS::GarlandHeckbert_edge_collapse_visitor_base<Surface_mesh>(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<Surface_mesh> stop(stop_threshold);
// SMS::GarlandHeckbert_cost_stop_predicate<FT> 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<Surface_mesh>::type Cost_matrix;
typedef CGAL::dynamic_vertex_property_t<Cost_matrix> Cost_property;
typedef typename boost::property_map<Surface_mesh, Cost_property>::type Vertex_cost_map;
typedef SMS::GarlandHeckbert_placement<Surface_mesh, Vertex_cost_map> GH_placement;
Vertex_cost_map vcm = get(Cost_property(), surface_mesh);
SMS::GarlandHeckbert_cost<Surface_mesh, Vertex_cost_map> cost(vcm);
GH_placement gh_placement(vcm);
SMS::Bounded_normal_change_placement<GH_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<std::chrono::milliseconds>(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);