update example and add new one using the constrained edge map

This commit is contained in:
Sébastien Loriot 2014-01-29 19:00:46 +01:00
parent cf04e556c6
commit 235c1cc3a6
7 changed files with 4502 additions and 38 deletions

File diff suppressed because it is too large Load Diff

View File

@ -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 ;
}

View File

@ -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 ;
} }

View File

@ -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;
}