mirror of https://github.com/CGAL/cgal
update example and add new one using the constrained edge map
This commit is contained in:
parent
cf04e556c6
commit
235c1cc3a6
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1 @@
|
||||||
|
mesh_with_border.off
|
||||||
|
|
@ -0,0 +1,129 @@
|
||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include <CGAL/Simple_cartesian.h>
|
||||||
|
#include <CGAL/Polyhedron_3.h>
|
||||||
|
#include <CGAL/IO/Polyhedron_iostream.h>
|
||||||
|
|
||||||
|
// Adaptor for Polyhedron_3
|
||||||
|
#include <CGAL/Surface_mesh_simplification/HalfedgeGraph_Polyhedron_3.h>
|
||||||
|
|
||||||
|
// Simplification function
|
||||||
|
#include <CGAL/Surface_mesh_simplification/edge_collapse.h>
|
||||||
|
|
||||||
|
// Midpoint placement policy
|
||||||
|
#include <CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Midpoint_placement.h>
|
||||||
|
|
||||||
|
//Placement wrapper
|
||||||
|
#include <CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Constrained_placement_wrapper.h>
|
||||||
|
|
||||||
|
typedef CGAL::Simple_cartesian<double> Kernel;
|
||||||
|
typedef Kernel::Point_3 Point_3;
|
||||||
|
typedef CGAL::Polyhedron_3<Kernel> Surface;
|
||||||
|
|
||||||
|
namespace SMS = CGAL::Surface_mesh_simplification ;
|
||||||
|
|
||||||
|
//
|
||||||
|
// BGL property map which indicates whether an edge is marked as non-removable
|
||||||
|
//
|
||||||
|
struct Border_is_constrained_edge_map{
|
||||||
|
typedef boost::graph_traits<Surface>::edge_descriptor key_type;
|
||||||
|
typedef bool value_type;
|
||||||
|
typedef value_type reference;
|
||||||
|
typedef boost::readable_property_map_tag category;
|
||||||
|
friend bool get(Border_is_constrained_edge_map, key_type edge) {
|
||||||
|
return edge->is_border_edge();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// A stop predicate that never says to stop.
|
||||||
|
//
|
||||||
|
struct No_stop_predicate
|
||||||
|
{
|
||||||
|
typedef Surface ECM;
|
||||||
|
typedef double FT;
|
||||||
|
typedef boost::graph_traits<ECM>::edges_size_type size_type;
|
||||||
|
typedef SMS::Edge_profile<Surface> Profile;
|
||||||
|
|
||||||
|
bool operator()( FT const&, Profile const&, size_type, size_type) const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// Placement class
|
||||||
|
//
|
||||||
|
typedef SMS::Constrained_placement_wrapper<SMS::Midpoint_placement<Surface>,
|
||||||
|
Border_is_constrained_edge_map >
|
||||||
|
Placement;
|
||||||
|
|
||||||
|
int main( int argc, char** argv )
|
||||||
|
{
|
||||||
|
Surface surface;
|
||||||
|
|
||||||
|
if (argc!=2){
|
||||||
|
std::cerr<< "Usage: " << argv[0] << " input.off\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ifstream is(argv[1]);
|
||||||
|
if(!is){
|
||||||
|
std::cerr<< "Filename provided is invalid\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
is >> surface ;
|
||||||
|
|
||||||
|
// map used to check that constrained_edges and the points of its vertices
|
||||||
|
// are preserved at the end of the simplification
|
||||||
|
std::map<Surface::Halfedge_handle,std::pair<Point_3, Point_3> >constrained_edges;
|
||||||
|
std::size_t nb_border_edges=0;
|
||||||
|
|
||||||
|
for (Surface::Halfedge_iterator hit=surface.halfedges_begin(),
|
||||||
|
hit_end=surface.halfedges_end(); hit!=hit_end;
|
||||||
|
++hit )
|
||||||
|
{
|
||||||
|
if ( hit->is_border() ){
|
||||||
|
constrained_edges[hit]=std::make_pair( hit->opposite()->vertex()->point(),
|
||||||
|
hit->vertex()->point() );
|
||||||
|
++nb_border_edges;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This the actual call to the simplification algorithm.
|
||||||
|
// The surface and stop conditions are mandatory arguments.
|
||||||
|
// The index maps are needed because the vertices and edges
|
||||||
|
// of this surface lack an "id()" field.
|
||||||
|
int r = SMS::edge_collapse
|
||||||
|
(surface
|
||||||
|
,No_stop_predicate()
|
||||||
|
,CGAL::vertex_index_map(boost::get(CGAL::vertex_external_index,surface))
|
||||||
|
.edge_index_map (boost::get(CGAL::edge_external_index ,surface))
|
||||||
|
.edge_is_constrained_map(Border_is_constrained_edge_map())
|
||||||
|
.get_placement(Placement())
|
||||||
|
);
|
||||||
|
|
||||||
|
std::cout << "\nFinished...\n" << r << " edges removed.\n"
|
||||||
|
<< (surface.size_of_halfedges()/2) << " final edges.\n" ;
|
||||||
|
|
||||||
|
std::ofstream os( argc > 2 ? argv[2] : "out.off" ) ; os << surface ;
|
||||||
|
|
||||||
|
// now check!
|
||||||
|
for (Surface::Halfedge_iterator hit=surface.halfedges_begin(),
|
||||||
|
hit_end=surface.halfedges_end(); hit!=hit_end;
|
||||||
|
++hit )
|
||||||
|
{
|
||||||
|
if (hit->is_border()){
|
||||||
|
--nb_border_edges;
|
||||||
|
assert( constrained_edges[hit] ==
|
||||||
|
std::make_pair( hit->opposite()->vertex()->point(),
|
||||||
|
hit->vertex()->point() ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert( nb_border_edges==0 );
|
||||||
|
|
||||||
|
return 0 ;
|
||||||
|
}
|
||||||
|
|
@ -18,54 +18,50 @@
|
||||||
#include <CGAL/Unique_hash_map.h>
|
#include <CGAL/Unique_hash_map.h>
|
||||||
|
|
||||||
typedef CGAL::Simple_cartesian<double> Kernel;
|
typedef CGAL::Simple_cartesian<double> Kernel;
|
||||||
typedef CGAL::Polyhedron_3<Kernel> Surface;
|
typedef CGAL::Polyhedron_3<Kernel> Surface;
|
||||||
|
typedef boost::graph_traits<Surface const>::edge_descriptor edge_descriptor;
|
||||||
namespace SMS = CGAL::Surface_mesh_simplification ;
|
namespace SMS = CGAL::Surface_mesh_simplification ;
|
||||||
|
|
||||||
//
|
//
|
||||||
// BGL property map which indicates whether an edge is border OR is marked as non-removable
|
// BGL property map which indicates whether an edge is marked as non-removable
|
||||||
//
|
//
|
||||||
class Constrains_map : public boost::put_get_helper<bool,Constrains_map>
|
struct Constrained_edge_map : public boost::put_get_helper<bool,Constrained_edge_map>
|
||||||
{
|
{
|
||||||
public:
|
typedef boost::readable_property_map_tag category;
|
||||||
|
typedef bool value_type;
|
||||||
|
typedef bool reference;
|
||||||
|
typedef edge_descriptor key_type;
|
||||||
|
|
||||||
typedef boost::readable_property_map_tag category;
|
Constrained_edge_map(const CGAL::Unique_hash_map<key_type,bool>& aConstraints)
|
||||||
typedef bool value_type;
|
: mConstraints(aConstraints) {}
|
||||||
typedef bool reference;
|
|
||||||
typedef boost::graph_traits<Surface const>::edge_descriptor key_type;
|
|
||||||
|
|
||||||
Constrains_map() : mConstrains(false) {}
|
reference operator[](key_type const& e) const { return is_constrained(e); }
|
||||||
|
|
||||||
|
bool is_constrained( key_type const& e ) const {
|
||||||
|
return mConstraints.is_defined(e) ? mConstraints[e] : false ; }
|
||||||
|
|
||||||
reference operator[](key_type const& e) const { return e->is_border() || is_constrained(e) ; }
|
|
||||||
|
|
||||||
void set_is_constrained ( key_type const& e, bool is ) { mConstrains[e]=is; }
|
|
||||||
|
|
||||||
bool is_constrained( key_type const& e ) const { return mConstrains.is_defined(e) ? mConstrains[e] : false ; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
const CGAL::Unique_hash_map<key_type,bool>& mConstraints;
|
||||||
CGAL::Unique_hash_map<key_type,bool> mConstrains ;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
int main( int argc, char** argv )
|
int main( int argc, char** argv )
|
||||||
{
|
{
|
||||||
Surface surface;
|
Surface surface;
|
||||||
|
|
||||||
std::ifstream is(argv[1]) ; is >> surface ;
|
std::ifstream is(argv[1]) ; is >> surface ;
|
||||||
|
|
||||||
// This is a stop predicate (defines when the algorithm terminates).
|
// This is a stop predicate (defines when the algorithm terminates).
|
||||||
// In this example, the simplification stops when the number of undirected edges
|
// In this example, the simplification stops when the number of undirected edges
|
||||||
// left in the surface drops below the specified number (1000)
|
// left in the surface drops below the specified number (1000)
|
||||||
SMS::Count_stop_predicate<Surface> stop(10);
|
SMS::Count_stop_predicate<Surface> stop(10);
|
||||||
|
|
||||||
Constrains_map constrains_map ;
|
// This example marks ALL edges as non-removable, but a real world application would mark only selected ones.
|
||||||
|
CGAL::Unique_hash_map<edge_descriptor,bool> constrained_edge_hmap;
|
||||||
|
for( Surface::Halfedge_iterator eb = surface.halfedges_begin(), ee = surface.halfedges_end() ; eb != ee ; ++ eb )
|
||||||
// This example marks ALL edges as non-removable, but a real world application would mark only selected ones.
|
constrained_edge_hmap[eb]=true;
|
||||||
for( Surface::Halfedge_iterator eb = surface.halfedges_begin(), ee = surface.halfedges_end() ; eb != ee ; ++ eb )
|
|
||||||
constrains_map.set_is_constrained(eb,true);
|
Constrained_edge_map constrained_edge_map(constrained_edge_hmap);
|
||||||
|
|
||||||
// This the actual call to the simplification algorithm.
|
// This the actual call to the simplification algorithm.
|
||||||
// The surface and stop conditions are mandatory arguments.
|
// The surface and stop conditions are mandatory arguments.
|
||||||
// The index maps are needed because the vertices and edges
|
// The index maps are needed because the vertices and edges
|
||||||
|
|
@ -73,15 +69,15 @@ int main( int argc, char** argv )
|
||||||
int r = SMS::edge_collapse
|
int r = SMS::edge_collapse
|
||||||
(surface
|
(surface
|
||||||
,stop
|
,stop
|
||||||
,CGAL::vertex_index_map(boost::get(CGAL::vertex_external_index,surface))
|
,CGAL::vertex_index_map(boost::get(CGAL::vertex_external_index,surface))
|
||||||
.edge_index_map (boost::get(CGAL::edge_external_index ,surface))
|
.edge_index_map (boost::get(CGAL::edge_external_index ,surface))
|
||||||
.edge_is_border_map(constrains_map)
|
.edge_is_constrained_map(constrained_edge_map)
|
||||||
);
|
);
|
||||||
|
|
||||||
std::cout << "\nFinished...\n" << r << " edges removed.\n"
|
std::cout << "\nFinished...\n" << r << " edges removed.\n"
|
||||||
<< (surface.size_of_halfedges()/2) << " final edges.\n" ;
|
<< (surface.size_of_halfedges()/2) << " final edges.\n" ;
|
||||||
|
|
||||||
std::ofstream os( argc > 2 ? argv[2] : "out.off" ) ; os << surface ;
|
std::ofstream os( argc > 2 ? argv[2] : "out.off" ) ; os << surface ;
|
||||||
|
|
||||||
return 0 ;
|
return 0 ;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
cube-meshed.off
|
||||||
|
|
@ -0,0 +1,173 @@
|
||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
#include <CGAL/Simple_cartesian.h>
|
||||||
|
#include <CGAL/Polyhedron_3.h>
|
||||||
|
#include <CGAL/IO/Polyhedron_iostream.h>
|
||||||
|
|
||||||
|
#include <CGAL/Surface_mesh_simplification/HalfedgeGraph_Polyhedron_3.h>
|
||||||
|
#include <CGAL/Surface_mesh_simplification/edge_collapse.h>
|
||||||
|
#include <CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Constrained_placement_wrapper.h>
|
||||||
|
#include <CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Midpoint_placement.h>
|
||||||
|
#include <CGAL/Unique_hash_map.h>
|
||||||
|
#include <CGAL/Mesh_3/dihedral_angle_3.h>
|
||||||
|
#include <CGAL/property_map.h>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
typedef CGAL::Simple_cartesian<double> Kernel;
|
||||||
|
typedef Kernel::Point_3 Point_3;
|
||||||
|
typedef CGAL::Polyhedron_3<Kernel> Surface;
|
||||||
|
typedef boost::graph_traits<Surface const>::edge_descriptor edge_descriptor;
|
||||||
|
|
||||||
|
namespace SMS = CGAL::Surface_mesh_simplification ;
|
||||||
|
|
||||||
|
|
||||||
|
typedef Surface::Facet_iterator Facet_iterator;
|
||||||
|
typedef Surface::Halfedge_handle Halfedge_handle;
|
||||||
|
typedef Surface::Halfedge_iterator Halfedge_iterator;
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// BGL property map which indicates whether an edge is marked as non-removable
|
||||||
|
//
|
||||||
|
struct Constrained_edge_map : public boost::put_get_helper<bool,Constrained_edge_map>
|
||||||
|
{
|
||||||
|
typedef boost::readable_property_map_tag category;
|
||||||
|
typedef bool value_type;
|
||||||
|
typedef bool reference;
|
||||||
|
typedef edge_descriptor key_type;
|
||||||
|
|
||||||
|
Constrained_edge_map(const CGAL::Unique_hash_map<key_type,bool>& aConstraints)
|
||||||
|
: mConstraints(aConstraints) {}
|
||||||
|
|
||||||
|
reference operator[](key_type const& e) const { return is_constrained(e); }
|
||||||
|
|
||||||
|
bool is_constrained( key_type const& e ) const {
|
||||||
|
return mConstraints.is_defined(e) ? mConstraints[e] : false ; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
const CGAL::Unique_hash_map<key_type,bool>& mConstraints;
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// A stop predicate that never says to stop.
|
||||||
|
//
|
||||||
|
struct No_stop_predicate
|
||||||
|
{
|
||||||
|
typedef Surface ECM;
|
||||||
|
typedef double FT;
|
||||||
|
typedef boost::graph_traits<ECM>::edges_size_type size_type;
|
||||||
|
typedef SMS::Edge_profile<Surface> Profile;
|
||||||
|
|
||||||
|
bool operator()( FT const&, Profile const&, size_type, size_type) const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
int main( int argc, char** argv )
|
||||||
|
{
|
||||||
|
CGAL::Unique_hash_map<edge_descriptor,bool> constraint_hmap(false);
|
||||||
|
|
||||||
|
Surface surface;
|
||||||
|
|
||||||
|
if (argc!=2){
|
||||||
|
std::cerr<< "Usage: " << argv[0] << " input.off\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ifstream is(argv[1]);
|
||||||
|
if(!is){
|
||||||
|
std::cerr<< "Filename provided is invalid\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
is >> surface ;
|
||||||
|
|
||||||
|
No_stop_predicate stop;
|
||||||
|
|
||||||
|
Constrained_edge_map constraints_map(constraint_hmap);
|
||||||
|
SMS::Constrained_placement_wrapper<SMS::Midpoint_placement<Surface>,
|
||||||
|
Constrained_edge_map >
|
||||||
|
placement(constraints_map);
|
||||||
|
|
||||||
|
// map used to check that constrained_edges and the points of its vertices
|
||||||
|
// are preserved at the end of the simplification
|
||||||
|
// Warning: the computation of the diedral angle is only an approximation and can
|
||||||
|
// be far from the real value and could influence the detection of sharp
|
||||||
|
// edges after the simplification
|
||||||
|
std::map<Surface::Halfedge_handle,std::pair<Point_3, Point_3> >constrained_edges;
|
||||||
|
std::size_t nb_sharp_edges=0;
|
||||||
|
|
||||||
|
// detect sharp edges
|
||||||
|
std::ofstream cst_output("constrained_edges.cgal");
|
||||||
|
for(Surface::Edge_iterator eb = surface.edges_begin(), ee = surface.edges_end() ; eb != ee ; ++eb )
|
||||||
|
{
|
||||||
|
if ( eb->is_border_edge() ){
|
||||||
|
++nb_sharp_edges;
|
||||||
|
constraint_hmap[eb]=true;
|
||||||
|
constraint_hmap[eb->opposite()]=true;
|
||||||
|
constrained_edges[eb]=std::make_pair( eb->opposite()->vertex()->point(),
|
||||||
|
eb->vertex()->point() );
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
double angle = CGAL::Mesh_3::dihedral_angle(
|
||||||
|
eb->opposite()->vertex()->point(),
|
||||||
|
eb->vertex()->point(),
|
||||||
|
eb->next()->vertex()->point(),
|
||||||
|
eb->opposite()->next()->vertex()->point() );
|
||||||
|
if ( std::abs(angle)<100 ){
|
||||||
|
++nb_sharp_edges;
|
||||||
|
constraint_hmap[eb]=true;
|
||||||
|
constraint_hmap[eb->opposite()]=true;
|
||||||
|
constrained_edges[eb]=std::make_pair( eb->opposite()->vertex()->point(),
|
||||||
|
eb->vertex()->point() );
|
||||||
|
cst_output << "2 " << eb->opposite()->vertex()->point() << " "
|
||||||
|
<< " " << eb->vertex()->point() << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cst_output.close();
|
||||||
|
|
||||||
|
int r
|
||||||
|
= SMS::edge_collapse(surface
|
||||||
|
,stop
|
||||||
|
,CGAL::vertex_index_map(boost::get(CGAL::vertex_external_index,surface))
|
||||||
|
.edge_index_map (boost::get(CGAL::edge_external_index ,surface))
|
||||||
|
.edge_is_constrained_map(constraints_map)
|
||||||
|
.get_placement(placement)
|
||||||
|
);
|
||||||
|
|
||||||
|
std::cout << "\nFinished...\n" << r << " edges removed.\n"
|
||||||
|
<< (surface.size_of_halfedges()/2) << " final edges.\n" ;
|
||||||
|
std::ofstream os(argc > 2 ? argv[2] : "out.off") ; os << surface ;
|
||||||
|
|
||||||
|
std::cout << "Checking sharped edges were preserved...\n";
|
||||||
|
// check sharp edges were preserved
|
||||||
|
for(Surface::Edge_iterator eb = surface.edges_begin(), ee = surface.edges_end() ; eb != ee ; ++eb )
|
||||||
|
{
|
||||||
|
if ( eb->is_border_edge() ){
|
||||||
|
--nb_sharp_edges;
|
||||||
|
assert(
|
||||||
|
constrained_edges[eb]==std::make_pair( eb->opposite()->vertex()->point(),
|
||||||
|
eb->vertex()->point() ) );
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
double angle = CGAL::Mesh_3::dihedral_angle(
|
||||||
|
eb->opposite()->vertex()->point(),
|
||||||
|
eb->vertex()->point(),
|
||||||
|
eb->next()->vertex()->point(),
|
||||||
|
eb->opposite()->next()->vertex()->point() );
|
||||||
|
if ( std::abs(angle)<100 ){
|
||||||
|
++nb_sharp_edges;
|
||||||
|
assert(
|
||||||
|
constrained_edges[eb]==std::make_pair( eb->opposite()->vertex()->point(),
|
||||||
|
eb->vertex()->point() ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::cout << "OK\n";
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue