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 ;
|
||||
}
|
||||
|
|
@ -19,33 +19,29 @@
|
|||
|
||||
typedef CGAL::Simple_cartesian<double> Kernel;
|
||||
typedef CGAL::Polyhedron_3<Kernel> Surface;
|
||||
|
||||
typedef boost::graph_traits<Surface const>::edge_descriptor edge_descriptor;
|
||||
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 boost::graph_traits<Surface const>::edge_descriptor key_type;
|
||||
typedef edge_descriptor key_type;
|
||||
|
||||
Constrains_map() : mConstrains(false) {}
|
||||
Constrained_edge_map(const CGAL::Unique_hash_map<key_type,bool>& aConstraints)
|
||||
: mConstraints(aConstraints) {}
|
||||
|
||||
reference operator[](key_type const& e) const { return e->is_border() || is_constrained(e) ; }
|
||||
reference operator[](key_type const& e) const { return 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 ; }
|
||||
bool is_constrained( key_type const& e ) const {
|
||||
return mConstraints.is_defined(e) ? mConstraints[e] : false ; }
|
||||
|
||||
private:
|
||||
|
||||
CGAL::Unique_hash_map<key_type,bool> mConstrains ;
|
||||
|
||||
const CGAL::Unique_hash_map<key_type,bool>& mConstraints;
|
||||
};
|
||||
|
||||
int main( int argc, char** argv )
|
||||
|
|
@ -59,12 +55,12 @@ int main( int argc, char** argv )
|
|||
// left in the surface drops below the specified number (1000)
|
||||
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 )
|
||||
constrains_map.set_is_constrained(eb,true);
|
||||
constrained_edge_hmap[eb]=true;
|
||||
|
||||
Constrained_edge_map constrained_edge_map(constrained_edge_hmap);
|
||||
|
||||
// This the actual call to the simplification algorithm.
|
||||
// The surface and stop conditions are mandatory arguments.
|
||||
|
|
@ -75,7 +71,7 @@ int main( int argc, char** argv )
|
|||
,stop
|
||||
,CGAL::vertex_index_map(boost::get(CGAL::vertex_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"
|
||||
|
|
|
|||
|
|
@ -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