mirror of https://github.com/CGAL/cgal
before switching to Surface_mesh
This commit is contained in:
parent
c1bc5b05ad
commit
0321056aff
|
|
@ -2,7 +2,7 @@
|
||||||
//this is an enriched Polyhedron with facet normals
|
//this is an enriched Polyhedron with facet normals
|
||||||
#include "PolyhedralSurf.h"
|
#include "PolyhedralSurf.h"
|
||||||
#include "PolyhedralSurf_rings.h"
|
#include "PolyhedralSurf_rings.h"
|
||||||
|
#include "compute_normals.h"
|
||||||
#include <CGAL/Ridges.h>
|
#include <CGAL/Ridges.h>
|
||||||
#include <CGAL/Umbilics.h>
|
#include <CGAL/Umbilics.h>
|
||||||
#include <CGAL/Monge_via_jet_fitting.h>
|
#include <CGAL/Monge_via_jet_fitting.h>
|
||||||
|
|
@ -24,7 +24,14 @@ typedef Kernel::Vector_3 Vector_3;
|
||||||
|
|
||||||
typedef boost::graph_traits<PolyhedralSurf>::vertex_descriptor Vertex_const_handle;
|
typedef boost::graph_traits<PolyhedralSurf>::vertex_descriptor Vertex_const_handle;
|
||||||
typedef boost::graph_traits<PolyhedralSurf>::vertex_iterator Vertex_const_iterator;
|
typedef boost::graph_traits<PolyhedralSurf>::vertex_iterator Vertex_const_iterator;
|
||||||
|
typedef boost::graph_traits<PolyhedralSurf>::face_descriptor face_descriptor;
|
||||||
|
/*
|
||||||
|
struct Face_cmp{
|
||||||
|
bool operator()(face_descriptor a, face_descriptor b) const{
|
||||||
|
return &*a < &*b;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
*/
|
||||||
typedef T_PolyhedralSurf_rings<PolyhedralSurf> Poly_rings;
|
typedef T_PolyhedralSurf_rings<PolyhedralSurf> Poly_rings;
|
||||||
typedef CGAL::Monge_via_jet_fitting<Kernel> Monge_via_jet_fitting;
|
typedef CGAL::Monge_via_jet_fitting<Kernel> Monge_via_jet_fitting;
|
||||||
typedef Monge_via_jet_fitting::Monge_form Monge_form;
|
typedef Monge_via_jet_fitting::Monge_form Monge_form;
|
||||||
|
|
@ -35,6 +42,9 @@ typedef Vertex2Data_Property_Map_with_std_map::Vertex2Vector_map Vertex2Vector_m
|
||||||
typedef Vertex2Data_Property_Map_with_std_map::Vertex2FT_property_map Vertex2FT_property_map;
|
typedef Vertex2Data_Property_Map_with_std_map::Vertex2FT_property_map Vertex2FT_property_map;
|
||||||
typedef Vertex2Data_Property_Map_with_std_map::Vertex2Vector_property_map Vertex2Vector_property_map;
|
typedef Vertex2Data_Property_Map_with_std_map::Vertex2Vector_property_map Vertex2Vector_property_map;
|
||||||
|
|
||||||
|
typedef std::map<face_descriptor, Vector_3/* , Face_cmp */ > Face2Vector_map;
|
||||||
|
typedef boost::associative_property_map< Face2Vector_map > Face2Vector_property_map;
|
||||||
|
|
||||||
//RIDGES
|
//RIDGES
|
||||||
typedef CGAL::Ridge_line<PolyhedralSurf> Ridge_line;
|
typedef CGAL::Ridge_line<PolyhedralSurf> Ridge_line;
|
||||||
typedef CGAL::Ridge_approximation < PolyhedralSurf,
|
typedef CGAL::Ridge_approximation < PolyhedralSurf,
|
||||||
|
|
@ -51,11 +61,13 @@ Vertex2FT_map vertex2k1_map, vertex2k2_map,
|
||||||
vertex2b0_map, vertex2b3_map,
|
vertex2b0_map, vertex2b3_map,
|
||||||
vertex2P1_map, vertex2P2_map;
|
vertex2P1_map, vertex2P2_map;
|
||||||
Vertex2Vector_map vertex2d1_map, vertex2d2_map;
|
Vertex2Vector_map vertex2d1_map, vertex2d2_map;
|
||||||
|
Face2Vector_map face2normal_map;
|
||||||
|
|
||||||
Vertex2FT_property_map vertex2k1_pm(vertex2k1_map), vertex2k2_pm(vertex2k2_map),
|
Vertex2FT_property_map vertex2k1_pm(vertex2k1_map), vertex2k2_pm(vertex2k2_map),
|
||||||
vertex2b0_pm(vertex2b0_map), vertex2b3_pm(vertex2b3_map),
|
vertex2b0_pm(vertex2b0_map), vertex2b3_pm(vertex2b3_map),
|
||||||
vertex2P1_pm(vertex2P1_map), vertex2P2_pm(vertex2P2_map),vertex2P2_p();
|
vertex2P1_pm(vertex2P1_map), vertex2P2_pm(vertex2P2_map),vertex2P2_p();
|
||||||
Vertex2Vector_property_map vertex2d1_pm(vertex2d1_map), vertex2d2_pm(vertex2d2_map);
|
Vertex2Vector_property_map vertex2d1_pm(vertex2d1_map), vertex2d2_pm(vertex2d2_map);
|
||||||
|
Face2Vector_property_map face2normal_pm(face2normal_map);
|
||||||
|
|
||||||
// default fct parameter values and global variables
|
// default fct parameter values and global variables
|
||||||
unsigned int d_fitting = 3;
|
unsigned int d_fitting = 3;
|
||||||
|
|
@ -73,9 +85,11 @@ unsigned int min_nb_points = (d_fitting + 1) * (d_fitting + 2) / 2;
|
||||||
2. the exact number of rings to be used
|
2. the exact number of rings to be used
|
||||||
3. nothing is specified
|
3. nothing is specified
|
||||||
*/
|
*/
|
||||||
|
template <typename VertexPointMap>
|
||||||
void gather_fitting_points(Vertex_const_handle v,
|
void gather_fitting_points(Vertex_const_handle v,
|
||||||
std::vector<Point_3> &in_points,
|
std::vector<Point_3> &in_points,
|
||||||
Poly_rings& poly_rings)
|
Poly_rings& poly_rings,
|
||||||
|
VertexPointMap vpm)
|
||||||
{
|
{
|
||||||
//container to collect vertices of v on the PolyhedralSurf
|
//container to collect vertices of v on the PolyhedralSurf
|
||||||
std::vector<Vertex_const_handle> gathered;
|
std::vector<Vertex_const_handle> gathered;
|
||||||
|
|
@ -101,7 +115,7 @@ void gather_fitting_points(Vertex_const_handle v,
|
||||||
//store the gathered points
|
//store the gathered points
|
||||||
std::vector<Vertex_const_handle>::const_iterator
|
std::vector<Vertex_const_handle>::const_iterator
|
||||||
itb = gathered.begin(), ite = gathered.end();
|
itb = gathered.begin(), ite = gathered.end();
|
||||||
CGAL_For_all(itb,ite) in_points.push_back((*itb)->point());
|
CGAL_For_all(itb,ite) in_points.push_back(get(vpm,*itb));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Use the jet_fitting package and the class Poly_rings to compute
|
/* Use the jet_fitting package and the class Poly_rings to compute
|
||||||
|
|
@ -112,6 +126,9 @@ void compute_differential_quantities(PolyhedralSurf& P, Poly_rings& poly_rings)
|
||||||
//container for approximation points
|
//container for approximation points
|
||||||
std::vector<Point_3> in_points;
|
std::vector<Point_3> in_points;
|
||||||
|
|
||||||
|
typedef boost::property_map<PolyhedralSurf,CGAL::vertex_point_t>::type VPM;
|
||||||
|
VPM vpm = get(CGAL::vertex_point,P);
|
||||||
|
|
||||||
//MAIN LOOP
|
//MAIN LOOP
|
||||||
Vertex_const_iterator vitb = P.vertices_begin(), vite = P.vertices_end();
|
Vertex_const_iterator vitb = P.vertices_begin(), vite = P.vertices_end();
|
||||||
for (; vitb != vite; vitb++) {
|
for (; vitb != vite; vitb++) {
|
||||||
|
|
@ -122,7 +139,7 @@ void compute_differential_quantities(PolyhedralSurf& P, Poly_rings& poly_rings)
|
||||||
Monge_via_jet_fitting monge_fit;
|
Monge_via_jet_fitting monge_fit;
|
||||||
|
|
||||||
//gather points around the vertex using rings
|
//gather points around the vertex using rings
|
||||||
gather_fitting_points(v, in_points, poly_rings);
|
gather_fitting_points(v, in_points, poly_rings, vpm);
|
||||||
|
|
||||||
//exit if the nb of points is too small
|
//exit if the nb of points is too small
|
||||||
if ( in_points.size() < min_nb_points )
|
if ( in_points.size() < min_nb_points )
|
||||||
|
|
@ -135,7 +152,7 @@ void compute_differential_quantities(PolyhedralSurf& P, Poly_rings& poly_rings)
|
||||||
d_fitting, d_monge);
|
d_fitting, d_monge);
|
||||||
|
|
||||||
//switch min-max ppal curv/dir wrt the mesh orientation
|
//switch min-max ppal curv/dir wrt the mesh orientation
|
||||||
const Vector_3 normal_mesh = P.computeFacetsAverageUnitNormal(v);
|
const Vector_3 normal_mesh = computeFacetsAverageUnitNormal(P,v, face2normal_pm, Kernel());
|
||||||
monge_form.comply_wrt_given_normal(normal_mesh);
|
monge_form.comply_wrt_given_normal(normal_mesh);
|
||||||
|
|
||||||
//Store monge data needed for ridge computations in property maps
|
//Store monge data needed for ridge computations in property maps
|
||||||
|
|
@ -284,7 +301,7 @@ int main()
|
||||||
{std::cerr << "not enough points in the model" << std::endl; exit(1);}
|
{std::cerr << "not enough points in the model" << std::endl; exit(1);}
|
||||||
|
|
||||||
//initialize Polyhedral data : normal of facets
|
//initialize Polyhedral data : normal of facets
|
||||||
P.compute_facets_normals();
|
compute_facets_normals(P,face2normal_pm, Kernel());
|
||||||
|
|
||||||
//create a Poly_rings object
|
//create a Poly_rings object
|
||||||
Poly_rings poly_rings(P);
|
Poly_rings poly_rings(P);
|
||||||
|
|
@ -321,13 +338,17 @@ int main()
|
||||||
std::vector<Ridge_line*>::iterator iter_lines = ridge_lines.begin(),
|
std::vector<Ridge_line*>::iterator iter_lines = ridge_lines.begin(),
|
||||||
iter_end = ridge_lines.end();
|
iter_end = ridge_lines.end();
|
||||||
//OpenGL output
|
//OpenGL output
|
||||||
for (;iter_lines!=iter_end;iter_lines++) (*iter_lines)->dump_4ogl(out_4ogl);
|
|
||||||
|
typedef boost::property_map<PolyhedralSurf,CGAL::vertex_point_t>::type VPM;
|
||||||
|
VPM vpm = get(CGAL::vertex_point,P);
|
||||||
|
|
||||||
|
for (;iter_lines!=iter_end;iter_lines++) (*iter_lines)->dump_4ogl(out_4ogl, vpm);
|
||||||
|
|
||||||
|
|
||||||
for (iter_lines = ridge_lines.begin();iter_lines!=iter_end;iter_lines++){
|
for (iter_lines = ridge_lines.begin();iter_lines!=iter_end;iter_lines++){
|
||||||
//verbose txt output
|
//verbose txt output
|
||||||
if (verbose){
|
if (verbose){
|
||||||
out_verb << **iter_lines;
|
(*iter_lines)->dump_verbose(out_verb,vpm);
|
||||||
}
|
}
|
||||||
delete *iter_lines;
|
delete *iter_lines;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
#include <CGAL/Polyhedron_3.h>
|
#include <CGAL/Polyhedron_3.h>
|
||||||
#include <CGAL/IO/Polyhedron_iostream.h>
|
#include <CGAL/IO/Polyhedron_iostream.h>
|
||||||
#include <CGAL/boost/graph/graph_traits_Polyhedron_3.h>
|
#include <CGAL/boost/graph/graph_traits_Polyhedron_3.h>
|
||||||
|
#include <CGAL/boost/graph/properties_Polyhedron_3.h>
|
||||||
#include <CGAL/boost/graph/helpers.h>
|
#include <CGAL/boost/graph/helpers.h>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
@ -30,11 +31,11 @@ public:
|
||||||
typedef typename FGeomTraits::Vector_3 Vector_3;
|
typedef typename FGeomTraits::Vector_3 Vector_3;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Vector_3 normal;
|
//Vector_3 normal;
|
||||||
public:
|
public:
|
||||||
My_facet() {}
|
My_facet() {}
|
||||||
const Vector_3 & getUnitNormal() const { return normal; }
|
//const Vector_3 & getUnitNormal() const { std::cerr << "coucou" << std::endl;return normal; }
|
||||||
void setNormal(Vector_3 n) { normal = n; }
|
//void setNormal(Vector_3 n) { normal = n; }
|
||||||
};
|
};
|
||||||
|
|
||||||
//------------------------------------------------
|
//------------------------------------------------
|
||||||
|
|
@ -68,9 +69,18 @@ class PolyhedralSurf;
|
||||||
namespace boost {
|
namespace boost {
|
||||||
template <>
|
template <>
|
||||||
struct graph_traits<PolyhedralSurf> : public boost::graph_traits<Polyhedron>
|
struct graph_traits<PolyhedralSurf> : public boost::graph_traits<Polyhedron>
|
||||||
{}; template<>
|
{};
|
||||||
|
|
||||||
|
template <>
|
||||||
struct graph_traits<PolyhedralSurf const> : public boost::graph_traits<Polyhedron>
|
struct graph_traits<PolyhedralSurf const> : public boost::graph_traits<Polyhedron>
|
||||||
{};
|
{};
|
||||||
|
|
||||||
|
template <class Tag>
|
||||||
|
struct property_map<PolyhedralSurf,Tag> : public property_map<Polyhedron,Tag>
|
||||||
|
{};
|
||||||
|
template <class Tag>
|
||||||
|
struct property_map<const PolyhedralSurf,Tag> : public property_map<const Polyhedron,Tag>
|
||||||
|
{};
|
||||||
}
|
}
|
||||||
|
|
||||||
class PolyhedralSurf : public Polyhedron {
|
class PolyhedralSurf : public Polyhedron {
|
||||||
|
|
@ -80,50 +90,9 @@ public:
|
||||||
typedef boost::graph_traits<PolyhedralSurf>::halfedge_descriptor halfedge_descriptor;
|
typedef boost::graph_traits<PolyhedralSurf>::halfedge_descriptor halfedge_descriptor;
|
||||||
|
|
||||||
PolyhedralSurf() {}
|
PolyhedralSurf() {}
|
||||||
void compute_facets_normals();
|
|
||||||
const Vector_3 computeFacetsAverageUnitNormal(const vertex_descriptor v);
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void PolyhedralSurf::compute_facets_normals()
|
|
||||||
{
|
|
||||||
BOOST_FOREACH(face_descriptor f, faces(*this)){
|
|
||||||
halfedge_descriptor h = halfedge(f,*this);
|
|
||||||
Vector_3 normal =
|
|
||||||
CGAL::cross_product(target(h,*this)->point() -
|
|
||||||
target(opposite(h,*this),*this)->point(),
|
|
||||||
target(next(h,*this),*this)->point() -
|
|
||||||
target(opposite(h,*this),*this)->point());
|
|
||||||
f->setNormal( normal / CGAL::sqrt(normal * normal));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const Vector_3 PolyhedralSurf::computeFacetsAverageUnitNormal(vertex_descriptor v)
|
|
||||||
{
|
|
||||||
halfedge_descriptor h;
|
|
||||||
face_descriptor f;
|
|
||||||
Vector_3 sum(0., 0., 0.), n;
|
|
||||||
|
|
||||||
CGAL::Halfedge_around_target_circulator<PolyhedralSurf> hedgeb(halfedge(v,*this),*this), hedgee = hedgeb;
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
h = *hedgeb;
|
|
||||||
if (is_border_edge(h,*this))
|
|
||||||
{
|
|
||||||
hedgeb++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
f = face(h,*this);
|
|
||||||
n = f->getUnitNormal();
|
|
||||||
sum = (sum + n);
|
|
||||||
hedgeb++;
|
|
||||||
}
|
|
||||||
while (hedgeb != hedgee);
|
|
||||||
sum = sum / std::sqrt(sum * sum);
|
|
||||||
return sum;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -20,17 +20,17 @@ protected:
|
||||||
//Polyhedron
|
//Polyhedron
|
||||||
typedef typename boost::graph_traits<TPoly>::vertex_descriptor Vertex_const_handle;
|
typedef typename boost::graph_traits<TPoly>::vertex_descriptor Vertex_const_handle;
|
||||||
typedef typename boost::graph_traits<TPoly>::halfedge_descriptor Halfedge_const_handle;
|
typedef typename boost::graph_traits<TPoly>::halfedge_descriptor Halfedge_const_handle;
|
||||||
typedef typename TPoly::Facet_const_handle Facet_const_handle;
|
|
||||||
typedef CGAL::Halfedge_around_target_circulator<TPoly> Halfedge_around_vertex_const_circulator;
|
|
||||||
typedef typename boost::graph_traits<TPoly>::vertex_iterator Vertex_const_iterator;
|
typedef typename boost::graph_traits<TPoly>::vertex_iterator Vertex_const_iterator;
|
||||||
|
typedef CGAL::Halfedge_around_target_circulator<TPoly> Halfedge_around_vertex_const_circulator;
|
||||||
|
/*
|
||||||
//tag to visit vertices
|
//tag to visit vertices
|
||||||
struct Vertex_cmp{//comparison is wrt vertex addresses
|
struct Vertex_cmp{//comparison is wrt vertex addresses
|
||||||
bool operator()(Vertex_const_handle a, Vertex_const_handle b) const{
|
bool operator()(Vertex_const_handle a, Vertex_const_handle b) const{
|
||||||
return &*a < &*b;
|
return &*a < &*b;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
typedef std::map<Vertex_const_handle, int, Vertex_cmp> Vertex2int_map;
|
*/
|
||||||
|
typedef std::map<Vertex_const_handle, int/*, Vertex_cmp*/> Vertex2int_map;
|
||||||
Vertex2int_map ring_index_map;
|
Vertex2int_map ring_index_map;
|
||||||
|
|
||||||
//vertex indices are initialised to -1
|
//vertex indices are initialised to -1
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
#ifndef COMPUTE_NORMALS_H
|
||||||
|
#define COMPUTE_NORMALS_H
|
||||||
|
|
||||||
|
#include <CGAL/boost/graph/helpers.h>
|
||||||
|
|
||||||
|
#include <boost/foreach.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
template <typename TriangleMesh, typename FaceVectorMap, typename Kernel>
|
||||||
|
const typename Kernel::Vector_3
|
||||||
|
computeFacetsAverageUnitNormal(const TriangleMesh& tm,
|
||||||
|
typename boost::graph_traits<TriangleMesh>::vertex_descriptor v,
|
||||||
|
FaceVectorMap fvm,
|
||||||
|
const Kernel& )
|
||||||
|
{
|
||||||
|
typename boost::graph_traits<TriangleMesh>::halfedge_descriptor h;
|
||||||
|
typename boost::graph_traits<TriangleMesh>::face_descriptor f;
|
||||||
|
typename Kernel::Vector_3 sum(0., 0., 0.), n;
|
||||||
|
|
||||||
|
CGAL::Halfedge_around_target_circulator<PolyhedralSurf> hedgeb(halfedge(v,tm),tm), hedgee = hedgeb;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
h = *hedgeb;
|
||||||
|
if (is_border_edge(h,tm))
|
||||||
|
{
|
||||||
|
hedgeb++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
f = face(h,tm);
|
||||||
|
n = get(fvm,f);
|
||||||
|
sum = (sum + n);
|
||||||
|
hedgeb++;
|
||||||
|
}
|
||||||
|
while (hedgeb != hedgee);
|
||||||
|
sum = sum / std::sqrt(sum * sum);
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TriangleMesh, typename FaceVectorMap,typename Kernel>
|
||||||
|
void compute_facets_normals(const TriangleMesh& tm,
|
||||||
|
FaceVectorMap fvm,
|
||||||
|
const Kernel& k)
|
||||||
|
{
|
||||||
|
BOOST_FOREACH(typename boost::graph_traits<TriangleMesh>::face_descriptor f, faces(tm)){
|
||||||
|
typename boost::graph_traits<TriangleMesh>::halfedge_descriptor h = halfedge(f,tm);
|
||||||
|
typename Kernel::Vector_3 normal =
|
||||||
|
CGAL::cross_product(target(h,tm)->point() -
|
||||||
|
target(opposite(h,tm),tm)->point(),
|
||||||
|
target(next(h,tm),tm)->point() -
|
||||||
|
target(opposite(h,tm),tm)->point());
|
||||||
|
put(fvm, f, normal / CGAL::sqrt(normal * normal));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -57,11 +57,8 @@ enum Ridge_order {Ridge_order_3 = 3, Ridge_order_4 = 4};
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
template < class TriangulatedSurfaceMesh > class Ridge_line
|
template < class TriangulatedSurfaceMesh > class Ridge_line
|
||||||
{
|
{
|
||||||
const TriangulatedSurfaceMesh& P;
|
|
||||||
public:
|
public:
|
||||||
typedef typename TriangulatedSurfaceMesh::Traits::FT FT;
|
typedef typename TriangulatedSurfaceMesh::Traits::FT FT;
|
||||||
typedef typename TriangulatedSurfaceMesh::Traits::Vector_3 Vector_3;
|
|
||||||
typedef typename TriangulatedSurfaceMesh::Traits::Point_3 Point_3;
|
|
||||||
typedef typename boost::graph_traits<TriangulatedSurfaceMesh>::halfedge_descriptor halfedge_descriptor;
|
typedef typename boost::graph_traits<TriangulatedSurfaceMesh>::halfedge_descriptor halfedge_descriptor;
|
||||||
typedef std::pair< halfedge_descriptor, FT> ridge_halfhedge;
|
typedef std::pair< halfedge_descriptor, FT> ridge_halfhedge;
|
||||||
|
|
||||||
|
|
@ -83,10 +80,14 @@ public:
|
||||||
/* The output is : line_type, strength, sharpness, list of points of
|
/* The output is : line_type, strength, sharpness, list of points of
|
||||||
the polyline. An insert operator << is also available.
|
the polyline. An insert operator << is also available.
|
||||||
*/
|
*/
|
||||||
void dump_4ogl(std::ostream& out_stream) const ;
|
template <class VertexPointMap>
|
||||||
void dump_verbose(std::ostream& out_stream) const ;
|
void dump_4ogl(std::ostream& out_stream, VertexPointMap vpm) const ;
|
||||||
|
|
||||||
|
template <class VertexPointMap>
|
||||||
|
void dump_verbose(std::ostream& out_stream, VertexPointMap vpm) const ;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
const TriangulatedSurfaceMesh& P;
|
||||||
//one of MAX_ELLIPTIC_RIDGE, MAX_HYPERBOLIC_RIDGE, MAX_CREST_RIDGE,
|
//one of MAX_ELLIPTIC_RIDGE, MAX_HYPERBOLIC_RIDGE, MAX_CREST_RIDGE,
|
||||||
//MIN_ELLIPTIC_RIDGE, MIN_HYPERBOLIC_RIDGE or MIN_CREST_RIDGE
|
//MIN_ELLIPTIC_RIDGE, MIN_HYPERBOLIC_RIDGE or MIN_CREST_RIDGE
|
||||||
Ridge_type m_line_type;
|
Ridge_type m_line_type;
|
||||||
|
|
@ -107,24 +108,27 @@ protected:
|
||||||
template < class TriangulatedSurfaceMesh >
|
template < class TriangulatedSurfaceMesh >
|
||||||
Ridge_line<TriangulatedSurfaceMesh>::
|
Ridge_line<TriangulatedSurfaceMesh>::
|
||||||
Ridge_line(const TriangulatedSurfaceMesh& P)
|
Ridge_line(const TriangulatedSurfaceMesh& P)
|
||||||
: P(P), m_strength(0.), m_sharpness(0.) {}
|
: P(P), m_strength(0.), m_sharpness(0.)
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
template < class TriangulatedSurfaceMesh >
|
template < class TriangulatedSurfaceMesh >
|
||||||
|
template <class VertexPointMap>
|
||||||
void Ridge_line<TriangulatedSurfaceMesh>::
|
void Ridge_line<TriangulatedSurfaceMesh>::
|
||||||
dump_4ogl(std::ostream& out_stream) const
|
dump_4ogl(std::ostream& out_stream,
|
||||||
|
VertexPointMap vpm) const
|
||||||
{
|
{
|
||||||
out_stream << line_type() << " "
|
out_stream << line_type() << " "
|
||||||
<< strength() << " "
|
<< strength() << " "
|
||||||
<< sharpness() << " ";
|
<< sharpness() << " ";
|
||||||
|
typedef typename boost::property_traits<VertexPointMap>::value_type Point_3;
|
||||||
typename std::list<ridge_halfhedge >::const_iterator
|
typename std::list<ridge_halfhedge >::const_iterator
|
||||||
iter = line()->begin(),
|
iter = line()->begin(),
|
||||||
ite = line()->end();
|
ite = line()->end();
|
||||||
for (;iter!=ite;iter++){
|
for (;iter!=ite;iter++){
|
||||||
//he: p->q, r is the crossing point
|
//he: p->q, r is the crossing point
|
||||||
Point_3 p = target(opposite(iter->first,P),P)->point(),
|
Point_3 p = get(vpm, target(opposite(iter->first,P),P)),
|
||||||
q = target(iter->first,P)->point();
|
q = get(vpm,target(iter->first,P));
|
||||||
Point_3 r = CGAL::barycenter(p, iter->second, q);
|
Point_3 r = CGAL::barycenter(p, iter->second, q);
|
||||||
out_stream << " " << r ;
|
out_stream << " " << r ;
|
||||||
}
|
}
|
||||||
|
|
@ -133,9 +137,11 @@ dump_4ogl(std::ostream& out_stream) const
|
||||||
|
|
||||||
//verbose output
|
//verbose output
|
||||||
template < class TriangulatedSurfaceMesh >
|
template < class TriangulatedSurfaceMesh >
|
||||||
|
template <class VertexPointMap>
|
||||||
void Ridge_line<TriangulatedSurfaceMesh>::
|
void Ridge_line<TriangulatedSurfaceMesh>::
|
||||||
dump_verbose(std::ostream& out_stream) const
|
dump_verbose(std::ostream& out_stream, VertexPointMap vpm) const
|
||||||
{
|
{
|
||||||
|
typedef typename boost::property_traits<VertexPointMap>::value_type Point_3;
|
||||||
out_stream << "Line type is : " << line_type() << std::endl
|
out_stream << "Line type is : " << line_type() << std::endl
|
||||||
<< "Strength is : " << strength() << std::endl
|
<< "Strength is : " << strength() << std::endl
|
||||||
<< "Sharpness is : " << sharpness() << std::endl
|
<< "Sharpness is : " << sharpness() << std::endl
|
||||||
|
|
@ -146,8 +152,8 @@ dump_verbose(std::ostream& out_stream) const
|
||||||
ite = line()->end();
|
ite = line()->end();
|
||||||
for (;iter!=ite;iter++){
|
for (;iter!=ite;iter++){
|
||||||
//he: p->q, r is the crossing point
|
//he: p->q, r is the crossing point
|
||||||
Point_3 p = target(opposite(iter->first,P),P)->point(),
|
Point_3 p = get(vpm, target(opposite(iter->first,P),P)),
|
||||||
q = target(iter->first,P)->point();
|
q = get(vpm,target(iter->first,P));
|
||||||
Point_3 r = CGAL::barycenter(p, iter->second, q);
|
Point_3 r = CGAL::barycenter(p, iter->second, q);
|
||||||
out_stream << r << std::endl;
|
out_stream << r << std::endl;
|
||||||
}
|
}
|
||||||
|
|
@ -172,17 +178,17 @@ class Vertex2Data_Property_Map_with_std_map
|
||||||
typedef typename TriangulatedSurfaceMesh::Traits::FT FT;
|
typedef typename TriangulatedSurfaceMesh::Traits::FT FT;
|
||||||
typedef typename TriangulatedSurfaceMesh::Traits::Vector_3 Vector_3;
|
typedef typename TriangulatedSurfaceMesh::Traits::Vector_3 Vector_3;
|
||||||
typedef typename boost::graph_traits<TriangulatedSurfaceMesh>::vertex_descriptor vertex_descriptor;
|
typedef typename boost::graph_traits<TriangulatedSurfaceMesh>::vertex_descriptor vertex_descriptor;
|
||||||
|
/*
|
||||||
struct Vertex_cmp{
|
struct Vertex_cmp{
|
||||||
bool operator()(vertex_descriptor a, vertex_descriptor b) const{
|
bool operator()(vertex_descriptor a, vertex_descriptor b) const{
|
||||||
return &*a < &*b;
|
return &*a < &*b;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
*/
|
||||||
typedef std::map<vertex_descriptor, FT, Vertex_cmp> Vertex2FT_map;
|
typedef std::map<vertex_descriptor, FT /* , Vertex_cmp */ > Vertex2FT_map;
|
||||||
typedef boost::associative_property_map< Vertex2FT_map > Vertex2FT_property_map;
|
typedef boost::associative_property_map< Vertex2FT_map > Vertex2FT_property_map;
|
||||||
|
|
||||||
typedef std::map<vertex_descriptor, Vector_3, Vertex_cmp> Vertex2Vector_map;
|
typedef std::map<vertex_descriptor, Vector_3/* , Vertex_cmp*/ > Vertex2Vector_map;
|
||||||
typedef boost::associative_property_map< Vertex2Vector_map > Vertex2Vector_property_map;
|
typedef boost::associative_property_map< Vertex2Vector_map > Vertex2Vector_property_map;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -195,14 +201,18 @@ template < class TriangulatedSurfaceMesh,
|
||||||
class Vertex2VectorPropertyMap >
|
class Vertex2VectorPropertyMap >
|
||||||
class Ridge_approximation
|
class Ridge_approximation
|
||||||
{
|
{
|
||||||
|
typedef typename boost::property_map<TriangulatedSurfaceMesh,vertex_point_t>::const_type VPM;
|
||||||
|
typedef typename boost::property_traits<VPM>::value_type Point_3;
|
||||||
|
typedef typename Kernel_traits<Point_3>::Kernel Kernel;
|
||||||
public:
|
public:
|
||||||
typedef typename TriangulatedSurfaceMesh::Traits::FT FT;
|
typedef typename Kernel::FT FT;
|
||||||
typedef typename TriangulatedSurfaceMesh::Traits::Vector_3 Vector_3;
|
typedef typename Kernel::Vector_3 Vector_3;
|
||||||
typedef typename boost::graph_traits<TriangulatedSurfaceMesh>::vertex_descriptor vertex_descriptor;
|
typedef typename boost::graph_traits<TriangulatedSurfaceMesh>::vertex_descriptor vertex_descriptor;
|
||||||
typedef typename boost::graph_traits<TriangulatedSurfaceMesh>::halfedge_descriptor halfedge_descriptor;
|
typedef typename boost::graph_traits<TriangulatedSurfaceMesh>::halfedge_descriptor halfedge_descriptor;
|
||||||
typedef typename boost::graph_traits<TriangulatedSurfaceMesh>::face_descriptor Facet_const_handle;
|
typedef typename boost::graph_traits<TriangulatedSurfaceMesh>::face_descriptor Facet_const_handle;
|
||||||
typedef typename boost::graph_traits<TriangulatedSurfaceMesh>::face_iterator Facet_const_iterator;
|
typedef typename boost::graph_traits<TriangulatedSurfaceMesh>::face_iterator Facet_const_iterator;
|
||||||
|
|
||||||
|
|
||||||
//requirements for the templates TriangulatedSurfaceMesh and Vertex2FTPropertyMap or Vertex2VectorPropertyMap
|
//requirements for the templates TriangulatedSurfaceMesh and Vertex2FTPropertyMap or Vertex2VectorPropertyMap
|
||||||
CGAL_static_assertion((boost::is_same<vertex_descriptor, typename Vertex2FTPropertyMap::key_type>::value));
|
CGAL_static_assertion((boost::is_same<vertex_descriptor, typename Vertex2FTPropertyMap::key_type>::value));
|
||||||
CGAL_static_assertion((boost::is_same<vertex_descriptor, typename Vertex2VectorPropertyMap::key_type>::value));
|
CGAL_static_assertion((boost::is_same<vertex_descriptor, typename Vertex2VectorPropertyMap::key_type>::value));
|
||||||
|
|
@ -246,19 +256,23 @@ class Ridge_approximation
|
||||||
//used to make the sharpness scale independant and iso indep
|
//used to make the sharpness scale independant and iso indep
|
||||||
Ridge_order tag_order;
|
Ridge_order tag_order;
|
||||||
|
|
||||||
|
/*
|
||||||
//tag to visit faces
|
//tag to visit faces
|
||||||
struct Facet_cmp{ //comparison is wrt facet addresses
|
struct Facet_cmp{ //comparison is wrt facet addresses
|
||||||
bool operator()(Facet_const_handle a, Facet_const_handle b) const{
|
bool operator()(Facet_const_handle a, Facet_const_handle b) const{
|
||||||
return &*a < &*b;
|
return &*a < &*b;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
typedef std::map<Facet_const_handle, bool, Facet_cmp> Facet2bool_map_type;
|
*/
|
||||||
|
typedef std::map<Facet_const_handle, bool/*, Facet_cmp*/> Facet2bool_map_type;
|
||||||
Facet2bool_map_type is_visited_map;
|
Facet2bool_map_type is_visited_map;
|
||||||
|
|
||||||
//Property maps
|
//Property maps
|
||||||
const Vertex2FTPropertyMap &k1, &k2, &b0, &b3, &P1, &P2;
|
const Vertex2FTPropertyMap &k1, &k2, &b0, &b3, &P1, &P2;
|
||||||
const Vertex2VectorPropertyMap &d1, &d2;
|
const Vertex2VectorPropertyMap &d1, &d2;
|
||||||
|
|
||||||
|
VPM vpm;
|
||||||
|
|
||||||
//is a facet crossed by a BLUE, RED or CREST_RIDGE ridge? if so, return
|
//is a facet crossed by a BLUE, RED or CREST_RIDGE ridge? if so, return
|
||||||
//the crossed edges and more precise type from MAX_ELLIPTIC_RIDGE,
|
//the crossed edges and more precise type from MAX_ELLIPTIC_RIDGE,
|
||||||
//MAX_HYPERBOLIC_RIDGE, MAX_CREST_RIDGE, MIN_ELLIPTIC_RIDGE,
|
//MAX_HYPERBOLIC_RIDGE, MAX_CREST_RIDGE, MIN_ELLIPTIC_RIDGE,
|
||||||
|
|
@ -348,7 +362,8 @@ template < class TriangulatedSurfaceMesh,
|
||||||
const Vertex2FTPropertyMap& vertex2P1_pm,
|
const Vertex2FTPropertyMap& vertex2P1_pm,
|
||||||
const Vertex2FTPropertyMap& vertex2P2_pm)
|
const Vertex2FTPropertyMap& vertex2P2_pm)
|
||||||
: P(p), k1(vertex2k1_pm), k2(vertex2k2_pm), b0(vertex2b0_pm), b3(vertex2b3_pm),
|
: P(p), k1(vertex2k1_pm), k2(vertex2k2_pm), b0(vertex2b0_pm), b3(vertex2b3_pm),
|
||||||
P1(vertex2P1_pm), P2(vertex2P2_pm), d1(vertex2d1_pm), d2(vertex2d2_pm)
|
P1(vertex2P1_pm), P2(vertex2P2_pm), d1(vertex2d1_pm), d2(vertex2d2_pm),
|
||||||
|
vpm(get(CGAL::vertex_point,p))
|
||||||
{
|
{
|
||||||
//init the is_visited_map and check that the mesh is a triangular one.
|
//init the is_visited_map and check that the mesh is a triangular one.
|
||||||
Facet_const_iterator itb,ite;
|
Facet_const_iterator itb,ite;
|
||||||
|
|
@ -358,8 +373,13 @@ template < class TriangulatedSurfaceMesh,
|
||||||
}
|
}
|
||||||
CGAL_precondition( is_pure_triangle(p) );
|
CGAL_precondition( is_pure_triangle(p) );
|
||||||
|
|
||||||
|
std::vector<Point_3> points;
|
||||||
|
BOOST_FOREACH(vertex_descriptor v, vertices(p)){
|
||||||
|
points.push_back(get(vpm,v));
|
||||||
|
}
|
||||||
|
|
||||||
CGAL::Min_sphere_d<CGAL::Optimisation_d_traits_3<typename TriangulatedSurfaceMesh::Traits> >
|
CGAL::Min_sphere_d<CGAL::Optimisation_d_traits_3<typename TriangulatedSurfaceMesh::Traits> >
|
||||||
min_sphere(P.points_begin(), P.points_end());
|
min_sphere(points.begin(), points.end());
|
||||||
squared_model_size = min_sphere.squared_radius();
|
squared_model_size = min_sphere.squared_radius();
|
||||||
//maybe better to use CGAL::Min_sphere_of_spheres_d ?? but need to create spheres?
|
//maybe better to use CGAL::Min_sphere_of_spheres_d ?? but need to create spheres?
|
||||||
|
|
||||||
|
|
@ -617,8 +637,8 @@ bool Ridge_approximation< TriangulatedSurfaceMesh, Vertex2FTPropertyMap , Vertex
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( tag_order == Ridge_order_3 ) {
|
if ( tag_order == Ridge_order_3 ) {
|
||||||
Vector_3 r1 = CGAL::barycenter(v_p1->point(), coord1, v_q1->point()) - ORIGIN,
|
Vector_3 r1 = CGAL::barycenter(get(vpm, v_p1), coord1, get(vpm, v_q1)) - ORIGIN,
|
||||||
r2 = CGAL::barycenter(v_p2->point(), coord2, v_q2->point()) - ORIGIN;
|
r2 = CGAL::barycenter(get(vpm,v_p2), coord2, get(vpm,v_q2)) - ORIGIN;
|
||||||
//identify the 3 different vertices v_p1, v_q1 and v3 = v_p2 or v_q2
|
//identify the 3 different vertices v_p1, v_q1 and v3 = v_p2 or v_q2
|
||||||
vertex_descriptor v3;
|
vertex_descriptor v3;
|
||||||
if (v_p2 == v_p1 || v_p2 == v_q1) v3 = v_q2;
|
if (v_p2 == v_p1 || v_p2 == v_q1) v3 = v_q2;
|
||||||
|
|
@ -675,9 +695,9 @@ int Ridge_approximation< TriangulatedSurfaceMesh, Vertex2FTPropertyMap , Vertex2
|
||||||
}
|
}
|
||||||
if ( r != CGAL::NULL_VECTOR ) r = r/CGAL::sqrt(r*r);
|
if ( r != CGAL::NULL_VECTOR ) r = r/CGAL::sqrt(r*r);
|
||||||
FT sign1, sign2, sign3;
|
FT sign1, sign2, sign3;
|
||||||
sign1 = bv1*(r1 - (v1->point()-ORIGIN) + (((v1->point()-ORIGIN)-r1)*r)*r )*dv1;
|
sign1 = bv1*(r1 - (get(vpm, v1)-ORIGIN) + (((get(vpm, v1)-ORIGIN)-r1)*r)*r )*dv1;
|
||||||
sign2 = bv2*(r1 - (v2->point()-ORIGIN) + (((v2->point()-ORIGIN)-r1)*r)*r )*dv2;
|
sign2 = bv2*(r1 - (get(vpm, v2)-ORIGIN) + (((get(vpm, v2)-ORIGIN)-r1)*r)*r )*dv2;
|
||||||
sign3 = bv3*(r1 - (v3->point()-ORIGIN) + (((v3->point()-ORIGIN)-r1)*r)*r )*dv3;
|
sign3 = bv3*(r1 - (get(vpm, v3)-ORIGIN) + (((get(vpm, v3)-ORIGIN)-r1)*r)*r )*dv3;
|
||||||
|
|
||||||
int compt = 0;
|
int compt = 0;
|
||||||
if ( sign1 > 0 ) compt++; else if (sign1 < 0) compt--;
|
if ( sign1 > 0 ) compt++; else if (sign1 < 0) compt--;
|
||||||
|
|
@ -713,8 +733,8 @@ addback(Ridge_line* ridge_line, const halfedge_descriptor he,
|
||||||
FT coord = bary_coord(he,r_type);
|
FT coord = bary_coord(he,r_type);
|
||||||
vertex_descriptor v_p = target(opposite(he,P),P), v_q = target(he,P),
|
vertex_descriptor v_p = target(opposite(he,P),P), v_q = target(he,P),
|
||||||
v_p_cur = target(opposite(he_cur,P),P), v_q_cur = target(he_cur,P); // he: p->q
|
v_p_cur = target(opposite(he_cur,P),P), v_q_cur = target(he_cur,P); // he: p->q
|
||||||
Vector_3 segment = CGAL::barycenter(v_p->point(), coord, v_q->point()) -
|
Vector_3 segment = CGAL::barycenter(get(vpm, v_p), coord, get(vpm, v_q)) -
|
||||||
CGAL::barycenter(v_p_cur->point(), coord_cur, v_q_cur->point());
|
CGAL::barycenter(get(vpm, v_p_cur), coord_cur, get(vpm, v_q_cur));
|
||||||
|
|
||||||
FT k1x, k2x; //abs value of the ppal curvatures at the Xing point on he.
|
FT k1x, k2x; //abs value of the ppal curvatures at the Xing point on he.
|
||||||
FT k_second = 0; // abs value of the second derivative of the curvature
|
FT k_second = 0; // abs value of the second derivative of the curvature
|
||||||
|
|
@ -756,8 +776,8 @@ addfront(Ridge_line* ridge_line,
|
||||||
FT coord = bary_coord(he,r_type);
|
FT coord = bary_coord(he,r_type);
|
||||||
vertex_descriptor v_p = target(opposite(he,P),P), v_q = target(he,P),
|
vertex_descriptor v_p = target(opposite(he,P),P), v_q = target(he,P),
|
||||||
v_p_cur = target(opposite(he_cur,P),P), v_q_cur = target(he_cur,P); // he: p->q
|
v_p_cur = target(opposite(he_cur,P),P), v_q_cur = target(he_cur,P); // he: p->q
|
||||||
Vector_3 segment = CGAL::barycenter(v_p->point(), coord, v_q->point()) -
|
Vector_3 segment = CGAL::barycenter(get(vpm, v_p), coord, get(vpm, v_q)) -
|
||||||
CGAL::barycenter(v_p_cur->point(), coord_cur, v_q_cur->point());
|
CGAL::barycenter(get(vpm, v_p_cur), coord_cur, get(vpm, v_q_cur));
|
||||||
|
|
||||||
FT k1x, k2x; //abs value of the ppal curvatures at the Xing point on he.
|
FT k1x, k2x; //abs value of the ppal curvatures at the Xing point on he.
|
||||||
FT k_second = 0.; // abs value of the second derivative of the curvature
|
FT k_second = 0.; // abs value of the second derivative of the curvature
|
||||||
|
|
@ -789,7 +809,7 @@ addfront(Ridge_line* ridge_line,
|
||||||
template < class TriangulatedSurfaceMesh,
|
template < class TriangulatedSurfaceMesh,
|
||||||
class Vertex2FTPropertyMap,
|
class Vertex2FTPropertyMap,
|
||||||
class Vertex2VectorPropertyMap >
|
class Vertex2VectorPropertyMap >
|
||||||
typename TriangulatedSurfaceMesh::Traits::FT
|
typename Ridge_approximation< TriangulatedSurfaceMesh, Vertex2FTPropertyMap , Vertex2VectorPropertyMap>::FT
|
||||||
Ridge_approximation< TriangulatedSurfaceMesh, Vertex2FTPropertyMap , Vertex2VectorPropertyMap>::
|
Ridge_approximation< TriangulatedSurfaceMesh, Vertex2FTPropertyMap , Vertex2VectorPropertyMap>::
|
||||||
bary_coord(const halfedge_descriptor he, const Ridge_type r_type)
|
bary_coord(const halfedge_descriptor he, const Ridge_type r_type)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@ template <class TriangulatedSurfaceMesh>
|
||||||
std::ostream&
|
std::ostream&
|
||||||
operator<<(std::ostream& out_stream, const Umbilic<TriangulatedSurfaceMesh>& umbilic)
|
operator<<(std::ostream& out_stream, const Umbilic<TriangulatedSurfaceMesh>& umbilic)
|
||||||
{
|
{
|
||||||
out_stream << "Umbilic at location (" << umbilic.vertex()->point() << ") of type ";
|
out_stream << "Umbilic at location (" << /* umbilic.vertex()->point() << */ ") of type ";
|
||||||
switch (umbilic.umbilic_type())
|
switch (umbilic.umbilic_type())
|
||||||
{
|
{
|
||||||
case CGAL::NON_GENERIC_UMBILIC: out_stream << "non generic" << std::endl; break;
|
case CGAL::NON_GENERIC_UMBILIC: out_stream << "non generic" << std::endl; break;
|
||||||
|
|
@ -90,9 +90,13 @@ template < class TriangulatedSurfaceMesh,
|
||||||
class Vertex2FTPropertyMap, class Vertex2VectorPropertyMap >
|
class Vertex2FTPropertyMap, class Vertex2VectorPropertyMap >
|
||||||
class Umbilic_approximation
|
class Umbilic_approximation
|
||||||
{
|
{
|
||||||
|
|
||||||
|
typedef typename boost::property_map<TriangulatedSurfaceMesh,vertex_point_t>::const_type VPM;
|
||||||
|
typedef typename boost::property_traits<VPM>::value_type Point_3;
|
||||||
|
typedef typename Kernel_traits<Point_3>::Kernel Kernel;
|
||||||
public:
|
public:
|
||||||
typedef typename TriangulatedSurfaceMesh::Traits::FT FT;
|
typedef typename Kernel::FT FT;
|
||||||
typedef typename TriangulatedSurfaceMesh::Traits::Vector_3 Vector_3;
|
typedef typename Kernel::Vector_3 Vector_3;
|
||||||
typedef typename boost::graph_traits<TriangulatedSurfaceMesh>::vertex_descriptor Vertex_const_handle;
|
typedef typename boost::graph_traits<TriangulatedSurfaceMesh>::vertex_descriptor Vertex_const_handle;
|
||||||
typedef typename boost::graph_traits<TriangulatedSurfaceMesh>::halfedge_descriptor Halfedge_const_handle;
|
typedef typename boost::graph_traits<TriangulatedSurfaceMesh>::halfedge_descriptor Halfedge_const_handle;
|
||||||
typedef typename boost::graph_traits<TriangulatedSurfaceMesh>::face_iterator Facet_const_iterator;
|
typedef typename boost::graph_traits<TriangulatedSurfaceMesh>::face_iterator Facet_const_iterator;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue