test remesh on the fly

This commit is contained in:
Lingjie Zhu 2018-09-28 16:22:56 +08:00
parent a6c32b6279
commit ebad196840
9 changed files with 303 additions and 187 deletions

View File

@ -2,29 +2,46 @@
#include <fstream> #include <fstream>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h> #include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Polyhedron_3.h> #include <CGAL/Surface_mesh.h>
#include <CGAL/boost/graph/graph_traits_Polyhedron_3.h>
#include <CGAL/IO/Polyhedron_iostream.h> #include <CGAL/Polygon_mesh_processing/remesh.h>
#include <CGAL/Surface_mesh_approximation/approximate_triangle_mesh.h> #include <CGAL/Surface_mesh_approximation/approximate_triangle_mesh.h>
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef CGAL::Polyhedron_3<Kernel> Polyhedron; typedef CGAL::Surface_mesh<Kernel::Point_3> Mesh;
typedef boost::graph_traits<Mesh>::face_descriptor face_descriptor;
namespace PMP = CGAL::Polygon_mesh_processing;
/** /**
* This file tests the free function CGAL::Surface_mesh_approximation::approximate_triangle_mesh. * This file tests the free function CGAL::Surface_mesh_approximation::approximate_triangle_mesh.
*/ */
int main() int main()
{ {
Polyhedron mesh; Mesh mesh;
std::ifstream input("./data/cube_meshed.off"); std::ifstream input("./data/cube.off");
if (!input || !(input >> mesh) || mesh.empty()) { if (!input || !(input >> mesh) || !CGAL::is_triangle_mesh(mesh)) {
std::cerr << "Invalid off file." << std::endl; std::cerr << "Invalid input file." << std::endl;
return EXIT_FAILURE; return EXIT_FAILURE;
} }
Polyhedron out_mesh; const double target_edge_length = 0.05;
std::map<Polyhedron::Facet_handle, std::size_t> fidxmap; const unsigned int nb_iter = 3;
boost::associative_property_map<std::map<Polyhedron::Facet_handle, std::size_t> > fpxmap(fidxmap);
std::cout << "Start remeshing. "
<< " (" << num_faces(mesh) << " faces)..." << std::endl;
PMP::isotropic_remeshing(
faces(mesh),
target_edge_length,
mesh,
PMP::parameters::number_of_iterations(nb_iter));
std::cout << "Remeshing done. "
<< " (" << num_faces(mesh) << " faces)..." << std::endl;
Mesh out_mesh;
std::map<face_descriptor, std::size_t> fidxmap;
boost::associative_property_map<std::map<face_descriptor, std::size_t> > fpxmap(fidxmap);
std::vector<Kernel::Vector_3> proxies; std::vector<Kernel::Vector_3> proxies;
std::vector<Kernel::Point_3> points; std::vector<Kernel::Point_3> points;
std::vector<CGAL::cpp11::array<std::size_t, 3> > triangles; std::vector<CGAL::cpp11::array<std::size_t, 3> > triangles;

View File

@ -2,52 +2,65 @@
#include <fstream> #include <fstream>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h> #include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Polyhedron_3.h> #include <CGAL/Surface_mesh.h>
#include <CGAL/IO/Polyhedron_iostream.h>
#include <CGAL/Polygon_mesh_processing/remesh.h>
#include <CGAL/boost/graph/graph_traits_Polyhedron_3.h>
#include <CGAL/Variational_shape_approximation.h> #include <CGAL/Variational_shape_approximation.h>
#include <CGAL/Surface_mesh_approximation/L2_metric_plane_proxy.h> #include <CGAL/Surface_mesh_approximation/L2_metric_plane_proxy.h>
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef Kernel::FT FT; typedef CGAL::Surface_mesh<Kernel::Point_3> Mesh;
typedef Kernel::Point_3 Point; typedef boost::graph_traits<Mesh>::vertex_descriptor vertex_descriptor;
typedef boost::graph_traits<Mesh>::face_descriptor face_descriptor;
typedef CGAL::Polyhedron_3<Kernel> Polyhedron; typedef boost::associative_property_map<std::map<face_descriptor, std::size_t> > Face_proxy_map;
typedef Polyhedron::Facet_handle Facet_handle; typedef boost::property_map<Mesh, boost::vertex_point_t>::type Vertex_point_map;
typedef boost::associative_property_map<std::map<Facet_handle, std::size_t> > Face_proxy_map;
typedef boost::property_map<Polyhedron, boost::vertex_point_t>::type Vertex_point_map;
typedef CGAL::Surface_mesh_approximation::L2_metric_plane_proxy<Polyhedron> L2_metric_plane_proxy; typedef CGAL::Surface_mesh_approximation::L2_metric_plane_proxy<Mesh> L2_metric_plane_proxy;
typedef CGAL::Variational_shape_approximation<Polyhedron, Vertex_point_map, L2_metric_plane_proxy> L2_approx; typedef CGAL::Variational_shape_approximation<Mesh, Vertex_point_map, L2_metric_plane_proxy> L2_approx;
typedef L2_approx::Proxy Plane_proxy; typedef L2_approx::Proxy Plane_proxy;
namespace PMP = CGAL::Polygon_mesh_processing;
/** /**
* This file tests the main class API and the L2 metric. * This file tests the main class API and the L2 metric.
* It should cover all the APIs. * It should cover all the APIs.
*/ */
int main() int main()
{ {
Polyhedron mesh; Mesh mesh;
std::ifstream input("./data/sphere_iso.off"); std::ifstream input("./data/sphere.off");
if (!input || !(input >> mesh) || mesh.empty()) { if (!input || !(input >> mesh) || !CGAL::is_triangle_mesh(mesh)) {
std::cerr << "Invalid off file." << std::endl; std::cerr << "Invalid input file." << std::endl;
return EXIT_FAILURE; return EXIT_FAILURE;
} }
const double target_edge_length = 0.05;
const unsigned int nb_iter = 3;
std::cout << "Start remeshing. "
<< " (" << num_faces(mesh) << " faces)..." << std::endl;
PMP::isotropic_remeshing(
faces(mesh),
target_edge_length,
mesh,
PMP::parameters::number_of_iterations(nb_iter));
std::cout << "Remeshing done. "
<< " (" << num_faces(mesh) << " faces)..." << std::endl;
// face area map // face area map
std::map<Facet_handle, std::size_t> face_index; std::map<face_descriptor, std::size_t> face_index;
for (Polyhedron::Facet_iterator fitr = mesh.facets_begin(); BOOST_FOREACH(face_descriptor f, faces(mesh))
fitr != mesh.facets_end(); ++fitr) face_index.insert(std::pair<face_descriptor, std::size_t>(f, 0));
face_index.insert(std::pair<Facet_handle, std::size_t>(fitr, 0));
Face_proxy_map proxy_pmap(face_index); Face_proxy_map proxy_pmap(face_index);
// create L2_approx L2 metric approximation algorithm instance // create L2_approx L2 metric approximation algorithm instance
std::cout << "setup algorithm instance" << std::endl; std::cout << "setup algorithm instance" << std::endl;
L2_metric_plane_proxy error_metric(mesh, L2_metric_plane_proxy error_metric(mesh,
get(boost::vertex_point, const_cast<Polyhedron &>(mesh))); get(boost::vertex_point, const_cast<Mesh &>(mesh)));
L2_approx approx(mesh, L2_approx approx(mesh,
get(boost::vertex_point, const_cast<Polyhedron &>(mesh)), get(boost::vertex_point, const_cast<Mesh &>(mesh)),
error_metric); error_metric);
// random seeding and run // random seeding and run
@ -87,7 +100,7 @@ int main()
if (approx.number_of_proxies() != 17) if (approx.number_of_proxies() != 17)
return EXIT_FAILURE; return EXIT_FAILURE;
// extract the approximation polyhedron // extract the approximation Mesh
std::cout << "meshing" << std::endl; std::cout << "meshing" << std::endl;
if (approx.extract_mesh(CGAL::parameters::subdivision_ratio(1.0))) if (approx.extract_mesh(CGAL::parameters::subdivision_ratio(1.0)))
std::cout << "manifold." << std::endl; std::cout << "manifold." << std::endl;
@ -99,17 +112,17 @@ int main()
approx.proxy_map(proxy_pmap); approx.proxy_map(proxy_pmap);
for (std::size_t i = 0; i < approx.number_of_proxies(); ++i) { for (std::size_t i = 0; i < approx.number_of_proxies(); ++i) {
std::list<Facet_handle> patch; std::list<face_descriptor> patch;
approx.proxy_region(i, std::back_inserter(patch)); approx.proxy_region(i, std::back_inserter(patch));
} }
std::vector<Plane_proxy> proxies; std::vector<Plane_proxy> proxies;
approx.proxies(std::back_inserter(proxies)); approx.proxies(std::back_inserter(proxies));
std::vector<Point> anchor_pos; std::vector<Kernel::Point_3> anchor_pos;
approx.anchor_points(std::back_inserter(anchor_pos)); approx.anchor_points(std::back_inserter(anchor_pos));
std::vector<Polyhedron::Vertex_handle> anchor_vtx; std::vector<vertex_descriptor> anchor_vtx;
approx.anchor_vertices(std::back_inserter(anchor_vtx)); approx.anchor_vertices(std::back_inserter(anchor_vtx));
std::vector<CGAL::cpp11::array<std::size_t, 3> > tris; std::vector<CGAL::cpp11::array<std::size_t, 3> > tris;
@ -118,7 +131,7 @@ int main()
std::vector<std::vector<std::size_t> > boundary; std::vector<std::vector<std::size_t> > boundary;
approx.indexed_boundary_polygons(std::back_inserter(boundary)); approx.indexed_boundary_polygons(std::back_inserter(boundary));
const FT drop(0.001); const Kernel::FT drop(0.001);
const std::size_t iterations = 5; const std::size_t iterations = 5;
std::cout << "re-initialize and hierarchical seeding" << std::endl; std::cout << "re-initialize and hierarchical seeding" << std::endl;
approx.initialize_seeds(CGAL::parameters::seeding_method(CGAL::Surface_mesh_approximation::HIERARCHICAL) approx.initialize_seeds(CGAL::parameters::seeding_method(CGAL::Surface_mesh_approximation::HIERARCHICAL)
@ -134,7 +147,7 @@ int main()
approx.run(10); approx.run(10);
std::cout << "#proxies " << approx.number_of_proxies() << std::endl; std::cout << "#proxies " << approx.number_of_proxies() << std::endl;
// extract the approximation polyhedron // extract the approximation Mesh
std::cout << "meshing" << std::endl; std::cout << "meshing" << std::endl;
if (approx.extract_mesh(CGAL::parameters::subdivision_ratio(1.0))) if (approx.extract_mesh(CGAL::parameters::subdivision_ratio(1.0)))
std::cout << "manifold." << std::endl; std::cout << "manifold." << std::endl;

View File

@ -2,40 +2,40 @@
#include <fstream> #include <fstream>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h> #include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Polyhedron_3.h> #include <CGAL/Surface_mesh.h>
#include <CGAL/IO/Polyhedron_iostream.h>
#include <CGAL/Polygon_mesh_processing/remesh.h>
#include <CGAL/boost/graph/graph_traits_Polyhedron_3.h>
#include <CGAL/Variational_shape_approximation.h> #include <CGAL/Variational_shape_approximation.h>
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef Kernel::FT FT; typedef CGAL::Surface_mesh<Kernel::Point_3> Mesh;
typedef CGAL::Polyhedron_3<Kernel> Polyhedron; typedef boost::graph_traits<Mesh>::face_descriptor face_descriptor;
typedef boost::property_map<Polyhedron, boost::vertex_point_t>::type Vertex_point_map;
typedef CGAL::Variational_shape_approximation<Polyhedron, Vertex_point_map> L21_approx; typedef boost::property_map<Mesh, boost::vertex_point_t>::type Vertex_point_map;
typedef CGAL::Variational_shape_approximation<Mesh, Vertex_point_map> L21_approx;
typedef L21_approx::Error_metric L21_metric; typedef L21_approx::Error_metric L21_metric;
bool test_shape(const char *file_name, const std::size_t target_num_proxies) bool test_shape(const char *file_name, const std::size_t target_num_proxies)
{ {
Polyhedron mesh; Mesh mesh;
std::ifstream input(file_name); std::ifstream input(file_name);
if (!input || !(input >> mesh) || mesh.empty()) { if (!input || !(input >> mesh) || !CGAL::is_triangle_mesh(mesh)) {
std::cout << "Invalid off file." << std::endl; std::cout << "Invalid input file." << std::endl;
return false; return false;
} }
std::cout << "Testing \"" << file_name << '\"' << std::endl; std::cout << "Testing \"" << file_name << '\"' << std::endl;
// algorithm instance // algorithm instance
L21_metric error_metric(mesh, L21_metric error_metric(mesh,
get(boost::vertex_point, const_cast<Polyhedron &>(mesh))); get(boost::vertex_point, const_cast<Mesh &>(mesh)));
L21_approx approx(mesh, L21_approx approx(mesh,
get(boost::vertex_point, const_cast<Polyhedron &>(mesh)), get(boost::vertex_point, const_cast<Mesh &>(mesh)),
error_metric); error_metric);
// approximation, seeding from error, drop to the target error incrementally // approximation, seeding from error, drop to the target error incrementally
// should reach targeted number of proxies gradually // should reach targeted number of proxies gradually
const FT drop(1e-8); const Kernel::FT drop(1e-8);
const std::size_t num_iterations = 20; const std::size_t num_iterations = 20;
const std::size_t inner_iterations = 10; const std::size_t inner_iterations = 10;
approx.initialize_seeds(CGAL::parameters::seeding_method(CGAL::Surface_mesh_approximation::INCREMENTAL) approx.initialize_seeds(CGAL::parameters::seeding_method(CGAL::Surface_mesh_approximation::INCREMENTAL)
@ -45,8 +45,7 @@ bool test_shape(const char *file_name, const std::size_t target_num_proxies)
// eliminate redundant area (local minima) by merging // eliminate redundant area (local minima) by merging
boost::optional<std::pair<std::size_t, std::size_t> > best_pair = boost::none; boost::optional<std::pair<std::size_t, std::size_t> > best_pair = boost::none;
while ( ( best_pair = approx.find_best_merge(true) ) != boost::none ) while ((best_pair = approx.find_best_merge(true)) != boost::none) {
{
approx.merge(best_pair->first, best_pair->second); approx.merge(best_pair->first, best_pair->second);
approx.run(num_iterations); approx.run(num_iterations);
} }
@ -73,14 +72,14 @@ bool test_shape(const char *file_name, const std::size_t target_num_proxies)
int main() int main()
{ {
std::cout << "Correctness test." << std::endl; std::cout << "Correctness test." << std::endl;
if (!test_shape("./data/cube_meshed.off", 6)) if (!test_shape("./data/cube.off", 6))
return EXIT_FAILURE; return EXIT_FAILURE;
if (!test_shape("./data/cube_meshed_open.off", 5)) if (!test_shape("./data/cube-ouvert.off", 5))
return EXIT_FAILURE; return EXIT_FAILURE;
std::cout << "Surface with disconnected components test." << std::endl; std::cout << "Surface with disconnected components test." << std::endl;
if (!test_shape("./data/cubes_disconnected.off", 11)) if (!test_shape("./data/cubes-merged.off", 11))
return EXIT_FAILURE; return EXIT_FAILURE;
return EXIT_SUCCESS; return EXIT_SUCCESS;

View File

@ -2,20 +2,23 @@
#include <fstream> #include <fstream>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h> #include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Polyhedron_3.h> #include <CGAL/Surface_mesh.h>
#include <CGAL/IO/Polyhedron_iostream.h>
#include <CGAL/Polygon_mesh_processing/remesh.h>
#include <CGAL/boost/graph/graph_traits_Polyhedron_3.h>
#include <CGAL/Variational_shape_approximation.h> #include <CGAL/Variational_shape_approximation.h>
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef Kernel::FT FT; typedef Kernel::FT FT;
typedef CGAL::Polyhedron_3<Kernel> Polyhedron;
typedef boost::property_map<Polyhedron, boost::vertex_point_t>::type Vertex_point_map;
typedef CGAL::Variational_shape_approximation<Polyhedron, Vertex_point_map> L21_approx; typedef CGAL::Surface_mesh<Kernel::Point_3> Mesh;
typedef boost::property_map<Mesh, boost::vertex_point_t>::type Vertex_point_map;
typedef CGAL::Variational_shape_approximation<Mesh, Vertex_point_map> L21_approx;
typedef L21_approx::Error_metric L21_metric; typedef L21_approx::Error_metric L21_metric;
namespace PMP = CGAL::Polygon_mesh_processing;
bool check_strict_ordering(const std::vector<FT> &error) bool check_strict_ordering(const std::vector<FT> &error)
{ {
if (error.empty()) { if (error.empty()) {
@ -35,18 +38,31 @@ bool check_strict_ordering(const std::vector<FT> &error)
*/ */
int main() int main()
{ {
Polyhedron mesh; Mesh mesh;
std::ifstream input("./data/sphere_iso.off"); std::ifstream input("./data/sphere.off");
if (!input || !(input >> mesh) || mesh.empty()) { if (!input || !(input >> mesh) || !CGAL::is_triangle_mesh(mesh)) {
std::cerr << "Invalid off file." << std::endl; std::cerr << "Invalid input file." << std::endl;
return EXIT_FAILURE; return EXIT_FAILURE;
} }
const double target_edge_length = 0.05;
const unsigned int nb_iter = 3;
std::cout << "Start remeshing. "
<< " (" << num_faces(mesh) << " faces)..." << std::endl;
PMP::isotropic_remeshing(
faces(mesh),
target_edge_length,
mesh,
PMP::parameters::number_of_iterations(nb_iter));
std::cout << "Remeshing done. "
<< " (" << num_faces(mesh) << " faces)..." << std::endl;
// algorithm instance // algorithm instance
L21_metric error_metric(mesh, L21_metric error_metric(mesh,
get(boost::vertex_point, const_cast<Polyhedron &>(mesh))); get(boost::vertex_point, const_cast<Mesh &>(mesh)));
L21_approx approx(mesh, L21_approx approx(mesh,
get(boost::vertex_point, const_cast<Polyhedron &>(mesh)), get(boost::vertex_point, const_cast<Mesh &>(mesh)),
error_metric); error_metric);
approx.initialize_seeds(CGAL::parameters::seeding_method(CGAL::Surface_mesh_approximation::RANDOM) approx.initialize_seeds(CGAL::parameters::seeding_method(CGAL::Surface_mesh_approximation::RANDOM)

View File

@ -10,33 +10,93 @@
#include <CGAL/Surface_mesh.h> #include <CGAL/Surface_mesh.h>
#include <CGAL/Polygon_mesh_processing/remesh.h>
#include <CGAL/Surface_mesh_approximation/approximate_triangle_mesh.h> #include <CGAL/Surface_mesh_approximation/approximate_triangle_mesh.h>
typedef CGAL::Exact_predicates_inexact_constructions_kernel Epic; typedef CGAL::Exact_predicates_inexact_constructions_kernel Epic;
typedef CGAL::Simple_cartesian<double> Sckernel; typedef CGAL::Simple_cartesian<double> Sckernel;
template <typename K, typename TM> namespace PMP = CGAL::Polygon_mesh_processing;
int test() {
TM tm; template <typename TM>
std::ifstream input("./data/cube_meshed.off"); int load_and_remesh_sm(TM &mesh) {
if (!input || !(input >> tm) || num_vertices(tm) == 0) { std::ifstream input("./data/cube.off");
std::cerr << "Invalid off file." << std::endl; if (!input || !(input >> mesh) || !CGAL::is_triangle_mesh(mesh)) {
std::cerr << "Invalid input file." << std::endl;
return EXIT_FAILURE; return EXIT_FAILURE;
} }
typedef CGAL::Polyhedron_3<K> Polyhedron; const double target_edge_length = 0.05;
Polyhedron out_mesh; const unsigned int nb_iter = 3;
std::cout << "Start remeshing. "
<< " (" << num_faces(mesh) << " faces)..." << std::endl;
PMP::isotropic_remeshing(
faces(mesh),
target_edge_length,
mesh,
PMP::parameters::number_of_iterations(nb_iter));
std::cout << "Remeshing done. "
<< " (" << num_faces(mesh) << " faces)..." << std::endl;
return EXIT_SUCCESS;
}
template <typename TM>
int load_and_remesh_poly(TM &mesh) {
std::ifstream input("./data/cube.off");
if (!input || !(input >> mesh) || !CGAL::is_triangle_mesh(mesh)) {
std::cerr << "Invalid input file." << std::endl;
return EXIT_FAILURE;
}
const double target_edge_length = 0.05;
const unsigned int nb_iter = 3;
std::cout << "Start remeshing. "
<< " (" << num_faces(mesh) << " faces)..." << std::endl;
PMP::isotropic_remeshing(
faces(mesh),
target_edge_length,
mesh,
PMP::parameters::number_of_iterations(nb_iter).
face_index_map(get(boost::face_external_index, mesh)));
std::cout << "Remeshing done. "
<< " (" << num_faces(mesh) << " faces)..." << std::endl;
return EXIT_SUCCESS;
}
template <typename K, typename TM>
void run_approximation(const TM &mesh) {
std::vector<typename K::Point_3> points; std::vector<typename K::Point_3> points;
std::vector<CGAL::cpp11::array<std::size_t, 3> > triangles; std::vector<CGAL::cpp11::array<std::size_t, 3> > triangles;
CGAL::Surface_mesh_approximation::approximate_triangle_mesh(tm, CGAL::Surface_mesh_approximation::approximate_triangle_mesh(mesh,
CGAL::parameters::max_number_of_proxies(6). CGAL::parameters::max_number_of_proxies(6).
number_of_iterations(30). number_of_iterations(30).
number_of_relaxations(5). number_of_relaxations(5).
subdivision_ratio(0.5). subdivision_ratio(0.5).
anchors(std::back_inserter(points)). anchors(std::back_inserter(points)).
triangles(std::back_inserter(triangles))); triangles(std::back_inserter(triangles)));
}
template <typename K, typename TM>
int test_sm() {
TM mesh;
if (load_and_remesh_sm(mesh) == EXIT_FAILURE)
return EXIT_FAILURE;
run_approximation<K, TM>(mesh);
return EXIT_SUCCESS;
}
template <typename K, typename TM>
int test_poly() {
TM mesh;
if (load_and_remesh_poly(mesh) == EXIT_FAILURE)
return EXIT_FAILURE;
run_approximation<K, TM>(mesh);
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
@ -45,16 +105,16 @@ int test() {
*/ */
int main() int main()
{ {
if (test<Epic, CGAL::Polyhedron_3<Epic> >() == EXIT_FAILURE) if (test_poly<Epic, CGAL::Polyhedron_3<Epic> >() == EXIT_FAILURE)
return EXIT_FAILURE; return EXIT_FAILURE;
if (test<Epic, CGAL::Surface_mesh<Epic::Point_3> >() == EXIT_FAILURE) if (test_sm<Epic, CGAL::Surface_mesh<Epic::Point_3> >() == EXIT_FAILURE)
return EXIT_FAILURE; return EXIT_FAILURE;
if (test<Sckernel, CGAL::Polyhedron_3<Sckernel> >() == EXIT_FAILURE) if (test_poly<Sckernel, CGAL::Polyhedron_3<Sckernel> >() == EXIT_FAILURE)
return EXIT_FAILURE; return EXIT_FAILURE;
if (test<Sckernel, CGAL::Surface_mesh<Sckernel::Point_3> >() == EXIT_FAILURE) if (test_sm<Sckernel, CGAL::Surface_mesh<Sckernel::Point_3> >() == EXIT_FAILURE)
return EXIT_FAILURE; return EXIT_FAILURE;
return EXIT_SUCCESS; return EXIT_SUCCESS;

View File

@ -2,35 +2,50 @@
#include <fstream> #include <fstream>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h> #include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Polyhedron_3.h> #include <CGAL/Surface_mesh.h>
#include <CGAL/IO/Polyhedron_iostream.h>
#include <CGAL/Polygon_mesh_processing/remesh.h>
#include <CGAL/boost/graph/graph_traits_Polyhedron_3.h>
#include <CGAL/Variational_shape_approximation.h> #include <CGAL/Variational_shape_approximation.h>
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef Kernel::FT FT; typedef Kernel::FT FT;
typedef CGAL::Polyhedron_3<Kernel> Polyhedron; typedef CGAL::Surface_mesh<Kernel::Point_3> Mesh;
typedef boost::property_map<Polyhedron, boost::vertex_point_t>::type Vertex_point_map; typedef boost::property_map<Mesh, boost::vertex_point_t>::type Vertex_point_map;
typedef CGAL::Variational_shape_approximation<Polyhedron, Vertex_point_map> L21_approx; typedef CGAL::Variational_shape_approximation<Mesh, Vertex_point_map> L21_approx;
typedef L21_approx::Error_metric L21_metric; typedef L21_approx::Error_metric L21_metric;
namespace PMP = CGAL::Polygon_mesh_processing;
bool test_manifold(const char *file_name, const FT drop = FT(1e-8)) bool test_manifold(const char *file_name, const FT drop = FT(1e-8))
{ {
Polyhedron mesh; Mesh mesh;
std::ifstream input(file_name); std::ifstream input(file_name);
if (!input || !(input >> mesh) || mesh.empty()) { if (!input || !(input >> mesh) || !CGAL::is_triangle_mesh(mesh)) {
std::cout << "Invalid off file." << std::endl; std::cout << "Invalid input file." << std::endl;
return false; return false;
} }
const double target_edge_length = 0.05;
const unsigned int nb_iter = 3;
std::cout << "Start remeshing. "
<< " (" << num_faces(mesh) << " faces)..." << std::endl;
PMP::isotropic_remeshing(
faces(mesh),
target_edge_length,
mesh,
PMP::parameters::number_of_iterations(nb_iter));
std::cout << "Remeshing done. "
<< " (" << num_faces(mesh) << " faces)..." << std::endl;
std::cout << "Testing \"" << file_name << '\"' << std::endl; std::cout << "Testing \"" << file_name << '\"' << std::endl;
// algorithm instance // algorithm instance
L21_metric error_metric(mesh, L21_metric error_metric(mesh,
get(boost::vertex_point, const_cast<Polyhedron &>(mesh))); get(boost::vertex_point, const_cast<Mesh &>(mesh)));
L21_approx approx(mesh, L21_approx approx(mesh,
get(boost::vertex_point, const_cast<Polyhedron &>(mesh)), get(boost::vertex_point, const_cast<Mesh &>(mesh)),
error_metric); error_metric);
// approximation, seeding from error, drop to the target error incrementally // approximation, seeding from error, drop to the target error incrementally
@ -59,13 +74,13 @@ bool test_manifold(const char *file_name, const FT drop = FT(1e-8))
int main() int main()
{ {
std::cout << "Meshing manifold test." << std::endl; std::cout << "Meshing manifold test." << std::endl;
if (!test_manifold("./data/cube_meshed.off")) if (!test_manifold("./data/cube.off"))
return EXIT_FAILURE; return EXIT_FAILURE;
if (!test_manifold("./data/cube_meshed_open.off")) if (!test_manifold("./data/cube-ouvert.off"))
return EXIT_FAILURE; return EXIT_FAILURE;
if (!test_manifold("./data/sphere_iso.off", FT(1e-2))) if (!test_manifold("./data/sphere.off", FT(1e-2)))
return EXIT_FAILURE; return EXIT_FAILURE;
return EXIT_SUCCESS; return EXIT_SUCCESS;

View File

@ -2,30 +2,31 @@
#include <fstream> #include <fstream>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h> #include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Polyhedron_3.h> #include <CGAL/Surface_mesh.h>
#include <CGAL/IO/Polyhedron_iostream.h>
#include <CGAL/Polygon_mesh_processing/remesh.h>
#include <CGAL/boost/graph/graph_traits_Polyhedron_3.h>
#include <CGAL/property_map.h>
#include <CGAL/Variational_shape_approximation.h> #include <CGAL/Variational_shape_approximation.h>
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef Kernel::FT FT; typedef Kernel::FT FT;
typedef Kernel::Vector_3 Vector; typedef Kernel::Vector_3 Vector_3;
typedef Kernel::Point_3 Point; typedef Kernel::Point_3 Point_3;
typedef CGAL::Polyhedron_3<Kernel> Polyhedron; typedef CGAL::Surface_mesh<Point_3> Mesh;
typedef Polyhedron::Facet_handle Facet_handle; typedef boost::graph_traits<Mesh>::face_descriptor face_descriptor;
typedef Polyhedron::Halfedge_handle Halfedge_handle; typedef boost::graph_traits<Mesh>::halfedge_descriptor halfedge_descriptor;
typedef Polyhedron::Facet_iterator Facet_iterator;
typedef boost::associative_property_map<std::map<Facet_handle, FT> > Face_area_map; typedef Mesh::Property_map<face_descriptor, FT> Face_area_map;
typedef boost::associative_property_map<std::map<Facet_handle, Point> > Face_center_map; typedef Mesh::Property_map<face_descriptor, Point_3> Face_center_map;
typedef boost::property_map<Polyhedron, boost::vertex_point_t>::type Vertex_point_map; typedef boost::property_map<Mesh, boost::vertex_point_t>::type Vertex_point_map;
namespace PMP = CGAL::Polygon_mesh_processing;
// user defined point-wise compact metric // user defined point-wise compact metric
struct Compact_metric_point_proxy { struct Compact_metric_point_proxy {
// use point as proxy // use point as proxy
typedef Point Proxy; typedef Point_3 Proxy;
// we keep a precomputed property map to speed up computations // we keep a precomputed property map to speed up computations
Compact_metric_point_proxy(const Face_center_map &_center_pmap, const Face_area_map &_area_pmap) Compact_metric_point_proxy(const Face_center_map &_center_pmap, const Face_area_map &_area_pmap)
@ -34,8 +35,7 @@ struct Compact_metric_point_proxy {
// compute and return error from a face to a proxy, // compute and return error from a face to a proxy,
// defined as the Euclidean distance between // defined as the Euclidean distance between
// the face center of mass and proxy point. // the face center of mass and proxy point.
FT compute_error(const Facet_handle &f, const Polyhedron &tm, const Proxy &px) const { FT compute_error(const face_descriptor &f, const Mesh &, const Proxy &px) const {
(void)(tm);
return FT(std::sqrt(CGAL::to_double( return FT(std::sqrt(CGAL::to_double(
CGAL::squared_distance(center_pmap[f], px)))); CGAL::squared_distance(center_pmap[f], px))));
} }
@ -43,12 +43,11 @@ struct Compact_metric_point_proxy {
// template functor to compute a best-fit // template functor to compute a best-fit
// proxy from a range of faces // proxy from a range of faces
template <typename FaceRange> template <typename FaceRange>
Proxy fit_proxy(const FaceRange &faces, const Polyhedron &tm) const { Proxy fit_proxy(const FaceRange &faces, const Mesh &) const {
(void)(tm);
// fitting center // fitting center
Vector center = CGAL::NULL_VECTOR; Vector_3 center = CGAL::NULL_VECTOR;
FT sum_areas = FT(0.0); FT sum_areas = FT(0.0);
BOOST_FOREACH(const Facet_handle &f, faces) { BOOST_FOREACH(const face_descriptor &f, faces) {
center = center + (center_pmap[f] - CGAL::ORIGIN) * area_pmap[f]; center = center + (center_pmap[f] - CGAL::ORIGIN) * area_pmap[f];
sum_areas += area_pmap[f]; sum_areas += area_pmap[f];
} }
@ -61,42 +60,40 @@ struct Compact_metric_point_proxy {
}; };
typedef CGAL::Variational_shape_approximation< typedef CGAL::Variational_shape_approximation<
Polyhedron, Vertex_point_map, Compact_metric_point_proxy> Compact_approx; Mesh, Vertex_point_map, Compact_metric_point_proxy> Compact_approx;
/** /**
* This file tests the user defined metric. * This file tests the user defined metric.
*/ */
int main() int main()
{ {
Polyhedron mesh; Mesh mesh;
std::ifstream input("./data/cube_meshed_open.off"); std::ifstream input("./data/cube-ouvert.off");
if (!input || !(input >> mesh) || mesh.empty()) { if (!input || !(input >> mesh) || !CGAL::is_triangle_mesh(mesh)) {
std::cerr << "Invalid off file." << std::endl; std::cerr << "Invalid input file." << std::endl;
return EXIT_FAILURE; return EXIT_FAILURE;
} }
// construct face normal & area map // construct face normal and area map
std::map<Facet_handle, FT> face_areas; Vertex_point_map vpmap = get(boost::vertex_point, const_cast<Mesh &>(mesh));
std::map<Facet_handle, Point> face_centers; Face_area_map area_pmap =
for(Facet_iterator fitr = mesh.facets_begin(); fitr != mesh.facets_end(); ++fitr) { mesh.add_property_map<face_descriptor, FT>("f:area", FT(0.0)).first;
const Halfedge_handle he = fitr->halfedge(); Face_center_map center_pmap =
const Point &p0 = he->opposite()->vertex()->point(); mesh.add_property_map<face_descriptor, Point_3>("f:center", CGAL::ORIGIN).first;
const Point &p1 = he->vertex()->point(); BOOST_FOREACH (face_descriptor f, faces(mesh)) {
const Point &p2 = he->next()->vertex()->point(); const halfedge_descriptor he = halfedge(f, mesh);
FT area(std::sqrt(CGAL::to_double(CGAL::squared_area(p0, p1, p2)))); const Point_3 &p0 = vpmap[source(he, mesh)];
face_areas.insert(std::pair<Facet_handle, FT>(fitr, area)); const Point_3 &p1 = vpmap[target(he, mesh)];
face_centers.insert(std::pair<Facet_handle, Point>(fitr, CGAL::centroid(p0, p1, p2))); const Point_3 &p2 = vpmap[target(next(he, mesh), mesh)];
put(area_pmap, f, FT(std::sqrt(CGAL::to_double(CGAL::squared_area(p0, p1, p2)))));
put(center_pmap, f, CGAL::centroid(p0, p1, p2));
} }
Face_area_map area_pmap(face_areas);
Face_center_map center_pmap(face_centers);
// create compact metric approximation algorithm instance // create compact metric approximation algorithm instance
std::cout << "create compact vas instance" << std::endl; std::cout << "create compact vas instance" << std::endl;
Compact_metric_point_proxy error_metric(center_pmap, area_pmap); Compact_metric_point_proxy error_metric(center_pmap, area_pmap);
Compact_approx approx(mesh, Compact_approx approx(mesh, vpmap, error_metric);
get(boost::vertex_point, const_cast<Polyhedron &>(mesh)),
error_metric);
std::cout << "random seeding and run" << std::endl; std::cout << "random seeding and run" << std::endl;
approx.initialize_seeds(CGAL::parameters::seeding_method(CGAL::Surface_mesh_approximation::RANDOM) approx.initialize_seeds(CGAL::parameters::seeding_method(CGAL::Surface_mesh_approximation::RANDOM)

View File

@ -2,36 +2,35 @@
#include <fstream> #include <fstream>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h> #include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Polyhedron_3.h> #include <CGAL/Surface_mesh.h>
#include <CGAL/Polygon_mesh_processing/remesh.h>
#include <CGAL/Surface_mesh_approximation/approximate_triangle_mesh.h> #include <CGAL/Surface_mesh_approximation/approximate_triangle_mesh.h>
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef CGAL::Polyhedron_3<Kernel> Polyhedron; typedef CGAL::Surface_mesh<Kernel::Point_3> Mesh;
typedef typename boost::graph_traits<Polyhedron>::face_descriptor face_descriptor; typedef typename boost::graph_traits<Mesh>::face_descriptor face_descriptor;
typedef boost::unordered_map<face_descriptor, std::size_t> Face_index_map; typedef Mesh::Property_map<face_descriptor, std::size_t> Face_proxy_pmap;
typedef boost::associative_property_map<Face_index_map> Face_proxy_pmap;
/** /**
* This file tests the free function CGAL::Surface_mesh_approximation::approximate_triangle_mesh. * This file tests the free function CGAL::Surface_mesh_approximation::approximate_triangle_mesh.
*/ */
int main() int main()
{ {
Polyhedron input; Mesh mesh;
std::ifstream file("data/sphere_iso.off"); std::ifstream file("data/sphere.off");
if (!file || !(file >> input) || input.empty()) { if (!file || !(file >> mesh) || !CGAL::is_triangle_mesh(mesh)) {
std::cerr << "Invalid off file." << std::endl; std::cerr << "Invalid input file." << std::endl;
return EXIT_FAILURE; return EXIT_FAILURE;
} }
Face_index_map fidx_map; Face_proxy_pmap fpxmap =
BOOST_FOREACH(face_descriptor f, faces(input)) mesh.add_property_map<face_descriptor, std::size_t>("f:proxy_id", 0).first;
fidx_map[f] = 0;
Face_proxy_pmap fpxmap(fidx_map);
std::vector<Kernel::Vector_3> proxies; std::vector<Kernel::Vector_3> proxies;
// free function interface with named parameters // free function interface with named parameters
CGAL::Surface_mesh_approximation::approximate_triangle_mesh(input, CGAL::Surface_mesh_approximation::approximate_triangle_mesh(mesh,
CGAL::parameters::seeding_method(CGAL::Surface_mesh_approximation::HIERARCHICAL). // hierarchical seeding CGAL::parameters::seeding_method(CGAL::Surface_mesh_approximation::HIERARCHICAL). // hierarchical seeding
max_number_of_proxies(200). // both maximum number of proxies stop criterion, max_number_of_proxies(200). // both maximum number of proxies stop criterion,
min_error_drop(0.05). // and minimum error drop stop criterion are specified min_error_drop(0.05). // and minimum error drop stop criterion are specified

View File

@ -3,27 +3,27 @@
#include <ctime> #include <ctime>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h> #include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Polyhedron_3.h> #include <CGAL/Surface_mesh.h>
#include <CGAL/IO/Polyhedron_iostream.h>
#include <CGAL/Bbox_3.h> #include <CGAL/Bbox_3.h>
#include <CGAL/boost/graph/graph_traits_Polyhedron_3.h> #include <CGAL/Polygon_mesh_processing/remesh.h>
#include <CGAL/Variational_shape_approximation.h> #include <CGAL/Variational_shape_approximation.h>
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef Kernel::FT FT; typedef Kernel::FT FT;
typedef Kernel::Point_3 Point; typedef Kernel::Point_3 Point_3;
typedef Kernel::Vector_3 Vector; typedef Kernel::Vector_3 Vector_3;
typedef CGAL::Polyhedron_3<Kernel> Polyhedron; typedef CGAL::Surface_mesh<Kernel::Point_3> Mesh;
typedef Polyhedron::Facet_handle Facet_handle; typedef boost::graph_traits<Mesh>::face_descriptor face_descriptor;
typedef Polyhedron::Facet_iterator Facet_iterator; typedef boost::graph_traits<Mesh>::vertex_descriptor vertex_descriptor;
typedef Polyhedron::Halfedge_handle Halfedge_handle; typedef boost::graph_traits<Mesh>::halfedge_descriptor halfedge_descriptor;
typedef boost::property_map<Polyhedron, boost::vertex_point_t>::type Vertex_point_map; typedef boost::property_map<Mesh, boost::vertex_point_t>::type Vertex_point_map;
typedef boost::associative_property_map<std::map<Facet_handle, std::size_t> > Face_proxy_map; typedef Mesh::Property_map<face_descriptor, std::size_t> Face_proxy_map;
typedef CGAL::Variational_shape_approximation<Polyhedron, Vertex_point_map> L21_approx; typedef CGAL::Variational_shape_approximation<Mesh, Vertex_point_map> L21_approx;
typedef L21_approx::Error_metric L21_metric; typedef L21_approx::Error_metric L21_metric;
typedef L21_approx::Proxy Plane_proxies; typedef L21_approx::Proxy Plane_proxies;
@ -35,10 +35,12 @@ bool check_strict_ordering(const std::vector<FT> &error)
std::cout << "Empty error sequence." << std::endl; std::cout << "Empty error sequence." << std::endl;
return false; return false;
} }
FT pre = error.front(); FT pre = error.front();
for (std::vector<FT>::const_iterator itr = error.begin(); itr != error.end(); ++itr) BOOST_FOREACH(const FT &e, error) {
if (pre < *itr) if (pre < e)
return false; return false;
}
return true; return true;
} }
@ -50,20 +52,18 @@ bool check_strict_ordering(const std::vector<FT> &error)
*/ */
int main() int main()
{ {
Polyhedron mesh; Mesh mesh;
std::ifstream input("./data/plane-sphere-high.off"); std::ifstream input("./data/plane-sphere-high.off");
if (!input || !(input >> mesh) || mesh.empty()) { if (!input || !(input >> mesh) || !CGAL::is_triangle_mesh(mesh)) {
std::cerr << "Invalid off file." << std::endl; std::cerr << "Invalid input file." << std::endl;
return EXIT_FAILURE; return EXIT_FAILURE;
} }
std::cout << "Teleportation test." << std::endl; std::cout << "Teleportation test." << std::endl;
// algorithm instance // algorithm instance
L21_metric error_metric(mesh, Vertex_point_map vpmap = get(boost::vertex_point, const_cast<Mesh &>(mesh));
get(boost::vertex_point, const_cast<Polyhedron &>(mesh))); L21_metric error_metric(mesh, vpmap);
L21_approx approx(mesh, L21_approx approx(mesh, vpmap, error_metric);
get(boost::vertex_point, const_cast<Polyhedron &>(mesh)),
error_metric);
std::cout << "Random seeding by number." << std::endl; std::cout << "Random seeding by number." << std::endl;
std::srand(static_cast<unsigned int>(std::time(0))); std::srand(static_cast<unsigned int>(std::time(0)));
@ -92,15 +92,16 @@ int main()
// test partition placement // test partition placement
std::cout << "Test partition placement." << std::endl; std::cout << "Test partition placement." << std::endl;
std::map<Facet_handle, std::size_t> internal_fidxmap; Face_proxy_map fproxymap =
for (Facet_iterator fitr = mesh.facets_begin(); fitr != mesh.facets_end(); ++fitr) mesh.add_property_map<face_descriptor, std::size_t>("f:porxy_id", 0).first;
internal_fidxmap[fitr] = 0;
Face_proxy_map fproxymap(internal_fidxmap);
approx.proxy_map(fproxymap); approx.proxy_map(fproxymap);
std::vector<Plane_proxies> proxies; std::vector<Plane_proxies> proxies;
approx.proxies(std::back_inserter(proxies)); approx.proxies(std::back_inserter(proxies));
CGAL::Bbox_3 bbox = CGAL::bbox_3(mesh.points_begin(), mesh.points_end());
CGAL::Bbox_3 bbox;
BOOST_FOREACH(const vertex_descriptor v, vertices(mesh))
bbox += vpmap[v].bbox();
const FT ymin = bbox.ymin(), ymax = bbox.ymax(), yrange = ymax - ymin; const FT ymin = bbox.ymin(), ymax = bbox.ymax(), yrange = ymax - ymin;
std::cout << "Range along y axis: [" << ymin << ", " << ymax << "]" << std::endl; std::cout << "Range along y axis: [" << ymin << ", " << ymax << "]" << std::endl;
@ -108,21 +109,20 @@ int main()
std::size_t planar_pxidx = static_cast<std::size_t>(-1); std::size_t planar_pxidx = static_cast<std::size_t>(-1);
std::size_t num_planar_faces = 0; std::size_t num_planar_faces = 0;
bool first = true; bool first = true;
for (Facet_iterator fitr = mesh.facets_begin(); fitr != mesh.facets_end(); ++fitr) { BOOST_FOREACH(const face_descriptor f, faces(mesh)) {
Halfedge_handle he = fitr->halfedge(); const halfedge_descriptor he = halfedge(f, mesh);
const Point &p0 = he->opposite()->vertex()->point(); const Point_3 &p0 = vpmap[source(he, mesh)];
const Point &p1 = he->vertex()->point(); const Point_3 &p1 = vpmap[target(he, mesh)];
const Point &p2 = he->next()->vertex()->point(); const Point_3 &p2 = vpmap[target(next(he, mesh), mesh)];
const Point fcenter = CGAL::centroid(p0, p1, p2); const Point_3 fcenter = CGAL::centroid(p0, p1, p2);
Vector fnormal = CGAL::normal(p0, p1, p2); const Vector_3 fnormal = CGAL::unit_normal(p0, p1, p2);
fnormal = fnormal / FT(std::sqrt(CGAL::to_double(fnormal.squared_length())));
// check the face center and normal to see if it is on the planar part of the geometry // check the face center and normal to see if it is on the planar part of the geometry
double dis_var = std::abs(CGAL::to_double((fcenter.y() - ymin) / yrange)); double dis_var = std::abs(CGAL::to_double((fcenter.y() - ymin) / yrange));
double dir_var = std::abs(CGAL::to_double(fnormal.y()) - 1.0); double dir_var = std::abs(CGAL::to_double(fnormal.y()) - 1.0);
if (dis_var < CGAL_VSA_TEST_TOLERANCE && dir_var < CGAL_VSA_TEST_TOLERANCE) { if (dis_var < CGAL_VSA_TEST_TOLERANCE && dir_var < CGAL_VSA_TEST_TOLERANCE) {
++num_planar_faces; ++num_planar_faces;
const std::size_t pxidx = fproxymap[fitr]; const std::size_t pxidx = fproxymap[f];
if (first) { if (first) {
first = false; first = false;
planar_pxidx = pxidx; planar_pxidx = pxidx;