1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 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;
}
|