Merge pull request #6577 from sloriot/SMS-parallel_ex

add an example to simplify a mesh in parallel
This commit is contained in:
Laurent Rineau 2022-06-08 17:33:46 +02:00
commit def324a46a
2 changed files with 170 additions and 0 deletions

View File

@ -51,3 +51,16 @@ if(OpenMesh_FOUND)
create_single_source_cgal_program("edge_collapse_OpenMesh.cpp")
target_link_libraries(edge_collapse_OpenMesh PRIVATE ${OPENMESH_LIBRARIES})
endif()
find_package(METIS)
include(CGAL_METIS_support)
find_package(TBB)
include(CGAL_TBB_support)
if(TARGET CGAL::TBB_support AND TARGET CGAL::METIS_support)
create_single_source_cgal_program("collapse_small_edges_in_parallel.cpp")
target_link_libraries(collapse_small_edges_in_parallel PUBLIC CGAL::TBB_support CGAL::METIS_support)
else()
message(STATUS "collapse_small_edges_in_parallel, which use the METIS and TBB libraries will not be compiled.")
endif()

View File

@ -0,0 +1,157 @@
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/Surface_mesh_simplification/edge_collapse.h>
#include <CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Edge_length_stop_predicate.h>
#include <CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Edge_length_cost.h>
#include <CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Constrained_placement.h>
#include <CGAL/boost/graph/Face_filtered_graph.h>
#include <CGAL/boost/graph/partition.h>
#include <CGAL/Real_timer.h>
#include <CGAL/Polygon_mesh_processing/polygon_soup_to_polygon_mesh.h>
#include <CGAL/Polygon_mesh_processing/stitch_borders.h>
#include <tbb/task_group.h>
#include <iostream>
#include <fstream>
typedef CGAL::Simple_cartesian<double> Kernel;
typedef Kernel::Point_3 Point_3;
typedef CGAL::Surface_mesh<Point_3> Triangle_mesh;
namespace SMS = CGAL::Surface_mesh_simplification;
namespace PMP = CGAL::Polygon_mesh_processing;
struct Border_is_constrained_edge_map{
const Triangle_mesh& sm;
typedef Triangle_mesh::Edge_index key_type;
typedef bool value_type;
typedef value_type reference;
typedef boost::readable_property_map_tag category;
Border_is_constrained_edge_map(const Triangle_mesh& sm)
: sm(sm)
{}
friend bool get(Border_is_constrained_edge_map m, const key_type& edge) {
return CGAL::is_border(edge, m.sm);
}
};
struct Simplify
{
Triangle_mesh* tm_ptr;
double edge_length;
Simplify()
:tm_ptr(NULL), edge_length(0)
{}
Simplify(Triangle_mesh& tm, double edge_length)
: tm_ptr(&tm), edge_length(edge_length)
{}
void operator()() const
{
SMS::Edge_length_cost<Triangle_mesh> cost;
SMS::Edge_length_stop_predicate<double> stop(edge_length);
Border_is_constrained_edge_map eicm(*tm_ptr);
SMS::Constrained_placement<SMS::LindstromTurk_placement<Triangle_mesh>,
Border_is_constrained_edge_map > placement(eicm);
SMS::edge_collapse(*tm_ptr, stop,
CGAL::parameters::edge_is_constrained_map(eicm)
.get_placement(placement)
.get_cost(cost));
}
};
int main(int argc, char** argv)
{
typedef boost::graph_traits<Triangle_mesh>::face_descriptor face_descriptor;
std::ifstream in((argc>1) ? std::string(argv[1]) : CGAL::data_file_path("meshes/elephant.off"));
double edge_length = (argc>2) ? std::atof(argv[2]) : 0.02;
int number_of_parts = (argc>3) ? std::atoi(argv[3]) : 8;
Triangle_mesh tm;
in >> tm;
std::cerr << "Input: #V = "<< num_vertices(tm) << " #E = "<< num_edges(tm)
<< " #F = " << num_faces(tm) << std::endl;
CGAL::Real_timer t;
t.start();
// Partition ID map
Triangle_mesh::Property_map<face_descriptor, std::size_t> fpmap
= tm.add_property_map<face_descriptor, std::size_t>("f:partition").first;
// Set some custom options for METIS
idx_t options[METIS_NOPTIONS];
METIS_SetDefaultOptions(options);
options[METIS_OPTION_CONTIG] = 1; // need to have contiguous subdomains
options[METIS_OPTION_UFACTOR] = 1;
CGAL::METIS::partition_dual_graph(tm, number_of_parts, CGAL::parameters::METIS_options(&options)
// .vertex_index_map(get(boost::vertex_index,tm))
.face_partition_id_map(fpmap));
SMS::LindstromTurk_placement<Triangle_mesh> placement;
SMS::Edge_length_cost<Triangle_mesh> cost;
SMS::Edge_length_stop_predicate<double> stop(edge_length);
CGAL::Face_filtered_graph<Triangle_mesh> fg(tm);
std::vector<Triangle_mesh> meshes(number_of_parts);
for (int i=0; i< number_of_parts; ++i)
{
fg.set_selected_faces(i, fpmap);
CGAL::copy_face_graph(fg, meshes[i]);
}
tbb::task_group tasks;
for(int id=0; id<number_of_parts; ++id)
{
tasks.run(Simplify(meshes[id], edge_length));
}
tasks.wait();
// reassemble the mesh
Triangle_mesh final_mesh;
std::size_t nv=0, nf=0, ne=0;
for (int i=0; i< number_of_parts; ++i)
{
meshes[i].collect_garbage();
nv += num_vertices(meshes[i]);
nf += num_faces(meshes[i]);
ne += num_edges(meshes[i]);
}
final_mesh.reserve(nv, ne, nf);
for (int i=0; i< number_of_parts; ++i)
{
CGAL::copy_face_graph(meshes[i], final_mesh);
}
PMP::stitch_borders(final_mesh);
// final pass (could be applied only on interface boundaries)
SMS::edge_collapse(final_mesh, stop,
CGAL::parameters::get_placement(placement)
.get_cost(cost));
final_mesh.collect_garbage();
t.stop();
std::cerr << " Total time: " << t.time() << " sec.\n"
<< " Result: #V = " << num_vertices(final_mesh)
<< " #E = " << num_edges(final_mesh)
<< " #F = " << num_faces(final_mesh) << std::endl;
std::ofstream("simplified_mesh.off") << std::setprecision(17) << final_mesh;
return EXIT_SUCCESS;
}