Added small tutorial on custom properties
This commit is contained in:
119
Doc/Tutorial/10-persistence/fill_props.hh
Normal file
119
Doc/Tutorial/10-persistence/fill_props.hh
Normal file
@@ -0,0 +1,119 @@
|
||||
#ifndef FILL_PROPS_HH
|
||||
#define FILL_PROPS_HH
|
||||
|
||||
#include <OpenMesh/Core/Utils/Property.hh>
|
||||
#include "int2roman.hh"
|
||||
|
||||
|
||||
template <typename Mesh>
|
||||
bool
|
||||
fill_props( Mesh& _m, OpenMesh::VPropHandleT<float> _ph, bool _check=false)
|
||||
{
|
||||
static float a[9] = { 1.1f, 2.2f, 3.3f, 4.4f, 5.5f, 6.6f, 7.7f, 8.8f, 9.9f };
|
||||
|
||||
for(typename Mesh::VertexIter it=_m.vertices_begin();
|
||||
it != _m.vertices_end(); ++it)
|
||||
{
|
||||
const float v = a[it->idx()%9];
|
||||
if ( _check && !(_m.property( _ph, *it ) == v) )
|
||||
return false;
|
||||
else
|
||||
_m.property( _ph, *it ) = v;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
template <typename Mesh>
|
||||
bool
|
||||
fill_props( Mesh& _m, OpenMesh::EPropHandleT<bool> _ph, bool _check=false )
|
||||
{
|
||||
|
||||
for( typename Mesh::EdgeIter it=_m.edges_begin();
|
||||
it != _m.edges_end(); ++it)
|
||||
{
|
||||
const size_t n = it->idx();
|
||||
const bool v = ((n&(n-1))==0); // true for 0,1,2,4,8,..
|
||||
|
||||
if (_check && _m.property( _ph, *it ) != v)
|
||||
{
|
||||
std::cout << " eprop_bool: " << n << " -> "
|
||||
<< _m.property(_ph, *it ) << " != " << v << std::endl;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
_m.property( _ph, *it ) = v;
|
||||
std::cout << " eprop_bool: " << n << " -> " << v << std::endl;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename Mesh>
|
||||
bool
|
||||
fill_props(Mesh& _m, OpenMesh::FPropHandleT<std::string> _ph, bool _check=false)
|
||||
{
|
||||
|
||||
for( typename Mesh::FaceIter it=_m.faces_begin();
|
||||
it != _m.faces_end(); ++it)
|
||||
{
|
||||
const int n = (it->idx()) + 1;
|
||||
_m.property( _ph, *it ) = int2roman(n);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
template <typename Mesh, typename T>
|
||||
bool
|
||||
fill_props( Mesh& _m, OpenMesh::HPropHandleT<T> _ph, bool _check=false)
|
||||
{
|
||||
T v;
|
||||
static float a[9] = { 1.1f, 2.2f, 3.3f, 4.4f, 5.5f, 6.6f, 7.7f, 8.8f, 9.9f };
|
||||
static float b[9] = { 2.2f, 3.3f, 4.4f, 5.5f, 6.6f, 7.7f, 8.8f, 9.9f, 1.1f };
|
||||
static float c[9] = { 3.3f, 4.4f, 5.5f, 6.6f, 7.7f, 8.8f, 9.9f, 1.1f, 2.2f };
|
||||
static float d[9] = { 4.4f, 5.5f, 6.6f, 7.7f, 8.8f, 9.9f, 1.1f, 2.2f, 3.3f };
|
||||
static double values[9] = { 0.1, 0.02, 0.003, 0.0004, 0.00005, 0.000006,
|
||||
0.0000007, 0.00000008, 0.000000009 };
|
||||
|
||||
for( typename Mesh::HalfedgeIter it=_m.halfedges_begin();
|
||||
it != _m.halfedges_end(); ++it)
|
||||
{
|
||||
const int n = it->idx();
|
||||
|
||||
v = it->idx()+1; // ival
|
||||
v = values[n%9]; // dval
|
||||
v = ((n&(n-1))==0); // bval
|
||||
v.vec4fval[0] = a[n%9];
|
||||
v.vec4fval[1] = b[n%9];
|
||||
v.vec4fval[2] = c[n%9];
|
||||
v.vec4fval[3] = d[n%9];
|
||||
|
||||
if ( _check && _m.property( _ph, *it ) != v )
|
||||
return false;
|
||||
else
|
||||
_m.property( _ph, *it ) = v;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Mesh, typename T>
|
||||
bool
|
||||
fill_props( Mesh& _m, OpenMesh::MPropHandleT<T> _ph, bool _check=false)
|
||||
{
|
||||
for( typename Mesh::FaceIter it=_m.faces_begin(); it != _m.faces_end(); ++it)
|
||||
{
|
||||
const size_t idx = it->idx();
|
||||
if ( _check && _m.property( _ph )[int2roman(idx+1)] != idx )
|
||||
return false;
|
||||
else
|
||||
_m.property( _ph )[int2roman(idx+1)] = idx;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
70
Doc/Tutorial/10-persistence/generate_cube.hh
Normal file
70
Doc/Tutorial/10-persistence/generate_cube.hh
Normal file
@@ -0,0 +1,70 @@
|
||||
#ifndef GENERATE_CUBE_HH
|
||||
#define GENERATE_CUBE_HH
|
||||
|
||||
template <typename MeshType>
|
||||
size_t generate_cube( MeshType& mesh )
|
||||
{
|
||||
typedef typename MeshType::VertexHandle VertexHandle;
|
||||
typedef typename MeshType::Point Point;
|
||||
|
||||
typename MeshType::VertexHandle vhandle[8];
|
||||
|
||||
vhandle[0] = mesh.add_vertex(Point(-1, -1, 1));
|
||||
vhandle[1] = mesh.add_vertex(Point( 1, -1, 1));
|
||||
vhandle[2] = mesh.add_vertex(Point( 1, 1, 1));
|
||||
vhandle[3] = mesh.add_vertex(Point(-1, 1, 1));
|
||||
vhandle[4] = mesh.add_vertex(Point(-1, -1, -1));
|
||||
vhandle[5] = mesh.add_vertex(Point( 1, -1, -1));
|
||||
vhandle[6] = mesh.add_vertex(Point( 1, 1, -1));
|
||||
vhandle[7] = mesh.add_vertex(Point(-1, 1, -1));
|
||||
|
||||
// generate (quadrilateral) faces
|
||||
|
||||
std::vector< VertexHandle > face_vhandles;
|
||||
|
||||
face_vhandles.clear();
|
||||
face_vhandles.push_back(vhandle[0]);
|
||||
face_vhandles.push_back(vhandle[1]);
|
||||
face_vhandles.push_back(vhandle[2]);
|
||||
face_vhandles.push_back(vhandle[3]);
|
||||
mesh.add_face(face_vhandles);
|
||||
|
||||
face_vhandles.clear();
|
||||
face_vhandles.push_back(vhandle[7]);
|
||||
face_vhandles.push_back(vhandle[6]);
|
||||
face_vhandles.push_back(vhandle[5]);
|
||||
face_vhandles.push_back(vhandle[4]);
|
||||
mesh.add_face(face_vhandles);
|
||||
|
||||
face_vhandles.clear();
|
||||
face_vhandles.push_back(vhandle[1]);
|
||||
face_vhandles.push_back(vhandle[0]);
|
||||
face_vhandles.push_back(vhandle[4]);
|
||||
face_vhandles.push_back(vhandle[5]);
|
||||
mesh.add_face(face_vhandles);
|
||||
|
||||
face_vhandles.clear();
|
||||
face_vhandles.push_back(vhandle[2]);
|
||||
face_vhandles.push_back(vhandle[1]);
|
||||
face_vhandles.push_back(vhandle[5]);
|
||||
face_vhandles.push_back(vhandle[6]);
|
||||
mesh.add_face(face_vhandles);
|
||||
|
||||
face_vhandles.clear();
|
||||
face_vhandles.push_back(vhandle[3]);
|
||||
face_vhandles.push_back(vhandle[2]);
|
||||
face_vhandles.push_back(vhandle[6]);
|
||||
face_vhandles.push_back(vhandle[7]);
|
||||
mesh.add_face(face_vhandles);
|
||||
|
||||
face_vhandles.clear();
|
||||
face_vhandles.push_back(vhandle[0]);
|
||||
face_vhandles.push_back(vhandle[3]);
|
||||
face_vhandles.push_back(vhandle[7]);
|
||||
face_vhandles.push_back(vhandle[4]);
|
||||
mesh.add_face(face_vhandles);
|
||||
|
||||
return mesh.n_vertices();
|
||||
};
|
||||
|
||||
#endif
|
||||
42
Doc/Tutorial/10-persistence/int2roman.cc
Normal file
42
Doc/Tutorial/10-persistence/int2roman.cc
Normal file
@@ -0,0 +1,42 @@
|
||||
#include <OpenMesh/Core/System/config.hh>
|
||||
#if defined(OM_CC_MIPS)
|
||||
# include <assert.h>
|
||||
#else
|
||||
# include <cassert>
|
||||
#endif
|
||||
#include "int2roman.hh"
|
||||
|
||||
|
||||
std::string int2roman( size_t decimal, size_t length )
|
||||
{
|
||||
assert( decimal > 0 && decimal < 1000 );
|
||||
|
||||
const size_t nrows = 4;
|
||||
const size_t ncols = 4;
|
||||
|
||||
static size_t table_arabs[ nrows ][ ncols ] = { { 1000, 1000, 1000, 1000 },
|
||||
{ 900, 500, 400, 100 },
|
||||
{ 90, 50, 40, 10 },
|
||||
{ 9, 5, 4, 1 } };
|
||||
|
||||
static char *table_romans[ nrows ][ ncols ] = { { "M", "M", "M", "M" },
|
||||
{ "CM", "D", "CD", "C" },
|
||||
{ "XC", "L", "XL", "X" },
|
||||
{ "IX", "V", "IV", "I" } };
|
||||
|
||||
size_t power; // power of ten
|
||||
size_t index; // Indexes thru values to subtract
|
||||
|
||||
std::string roman = "";
|
||||
roman.reserve(length);
|
||||
|
||||
for ( power = 0; power < nrows; power++ )
|
||||
for ( index = 0; index < ncols; index++ )
|
||||
while ( decimal >= table_arabs[ power ][ index ] )
|
||||
{
|
||||
roman += table_romans[ power ][ index ];
|
||||
decimal -= table_arabs[ power ][ index ];
|
||||
}
|
||||
|
||||
return roman;
|
||||
}
|
||||
8
Doc/Tutorial/10-persistence/int2roman.hh
Normal file
8
Doc/Tutorial/10-persistence/int2roman.hh
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef INT2ROMAN_HH
|
||||
#define INT2ROMAN_HH
|
||||
|
||||
#include <string>
|
||||
|
||||
std::string int2roman( size_t decimal, size_t length=30 );
|
||||
|
||||
#endif
|
||||
345
Doc/Tutorial/10-persistence/persistence.cc
Normal file
345
Doc/Tutorial/10-persistence/persistence.cc
Normal file
@@ -0,0 +1,345 @@
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <map>
|
||||
// -------------------- OpenMesh
|
||||
#include <OpenMesh/Core/IO/MeshIO.hh>
|
||||
#include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
|
||||
#include <OpenMesh/Core/Mesh/PolyMesh_ArrayKernelT.hh>
|
||||
// -------------------- little helper
|
||||
#include "generate_cube.hh"
|
||||
#include "stats.hh"
|
||||
#include "fill_props.hh"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// Set to 1 to use an PolyMesh type.
|
||||
#define UsePolyMesh 1
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
using namespace OpenMesh;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
typedef TriMesh_ArrayKernelT<> TriMesh;
|
||||
typedef PolyMesh_ArrayKernelT<> PolyMesh;
|
||||
|
||||
#if UsePolyMesh
|
||||
typedef PolyMesh Mesh;
|
||||
#else
|
||||
typedef TriMesh Mesh;
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#ifndef DOXY_IGNORE_THIS
|
||||
|
||||
struct MyData
|
||||
{
|
||||
int ival;
|
||||
double dval;
|
||||
bool bval;
|
||||
OpenMesh::Vec4f vec4fval;
|
||||
|
||||
MyData()
|
||||
: ival(0), dval(0.0), bval(false)
|
||||
{ }
|
||||
|
||||
MyData( const MyData& _cpy )
|
||||
: ival(_cpy.ival), dval(_cpy.dval), bval(_cpy.bval),
|
||||
vec4fval(_cpy.vec4fval)
|
||||
{ }
|
||||
|
||||
|
||||
// ---------- assignment
|
||||
|
||||
MyData& operator = (const MyData& _rhs)
|
||||
{
|
||||
ival = _rhs.ival;
|
||||
dval = _rhs.dval;
|
||||
bval = _rhs.bval;
|
||||
vec4fval = _rhs.vec4fval;
|
||||
return *this;
|
||||
}
|
||||
|
||||
MyData& operator = (int _rhs) { ival = _rhs; return *this; }
|
||||
MyData& operator = (double _rhs) { dval = _rhs; return *this; }
|
||||
MyData& operator = (bool _rhs) { bval = _rhs; return *this; }
|
||||
MyData& operator = (const OpenMesh::Vec4f& _rhs)
|
||||
{ vec4fval = _rhs; return *this; }
|
||||
|
||||
|
||||
// ---------- comparison
|
||||
|
||||
bool operator == (const MyData& _rhs) const
|
||||
{
|
||||
return ival == _rhs.ival
|
||||
&& dval == _rhs.dval
|
||||
&& bval == _rhs.bval
|
||||
&& vec4fval == _rhs.vec4fval;
|
||||
}
|
||||
|
||||
bool operator != (const MyData& _rhs) const { return !(*this == _rhs); }
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
typedef std::map< std::string, unsigned int > MyMap;
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#ifndef DOXY_IGNORE_THIS
|
||||
|
||||
namespace OpenMesh {
|
||||
namespace IO {
|
||||
|
||||
// support persistence for struct MyData
|
||||
|
||||
template <> struct binary<MyData>
|
||||
{
|
||||
typedef MyData value_type;
|
||||
|
||||
static const bool is_streamable = true;
|
||||
|
||||
// return binary size of the value
|
||||
|
||||
static size_t size_of(void)
|
||||
{
|
||||
return sizeof(int)+sizeof(double)+sizeof(bool)+sizeof(OpenMesh::Vec4f);
|
||||
}
|
||||
|
||||
static size_t size_of(const value_type&)
|
||||
{
|
||||
return size_of();
|
||||
}
|
||||
|
||||
static size_t store(std::ostream& _os, const value_type& _v, bool _swap=false)
|
||||
{
|
||||
size_t bytes;
|
||||
bytes = IO::store( _os, _v.ival, _swap );
|
||||
bytes += IO::store( _os, _v.dval, _swap );
|
||||
bytes += IO::store( _os, _v.bval, _swap );
|
||||
bytes += IO::store( _os, _v.vec4fval, _swap );
|
||||
return _os.good() ? bytes : 0;
|
||||
}
|
||||
|
||||
static size_t restore( std::istream& _is, value_type& _v, bool _swap=false)
|
||||
{
|
||||
size_t bytes;
|
||||
bytes = IO::restore( _is, _v.ival, _swap );
|
||||
bytes += IO::restore( _is, _v.dval, _swap );
|
||||
bytes += IO::restore( _is, _v.bval, _swap );
|
||||
bytes += IO::restore( _is, _v.vec4fval, _swap );
|
||||
return _is.good() ? bytes : 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <> struct binary< MyMap >
|
||||
{
|
||||
typedef MyMap value_type;
|
||||
|
||||
static const bool is_streamable = true;
|
||||
|
||||
// return generic binary size of self, if known
|
||||
static size_t size_of(void) { return UnknownSize; }
|
||||
|
||||
// return binary size of the value
|
||||
static size_t size_of(const value_type& _v)
|
||||
{
|
||||
if (_v.empty())
|
||||
return sizeof(unsigned int);
|
||||
|
||||
value_type::const_iterator it = _v.begin();
|
||||
unsigned int N = _v.size();
|
||||
size_t bytes = IO::size_of(N);
|
||||
|
||||
for(;it!=_v.end(); ++it)
|
||||
{
|
||||
bytes += IO::size_of( it->first );
|
||||
bytes += IO::size_of( it->second );
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
static
|
||||
size_t store(std::ostream& _os, const value_type& _v, bool _swap=false)
|
||||
{
|
||||
size_t bytes = 0;
|
||||
unsigned int N = _v.size();
|
||||
|
||||
value_type::const_iterator it = _v.begin();
|
||||
|
||||
bytes += IO::store( _os, N, _swap );
|
||||
|
||||
for (; it != _v.end() && _os.good(); ++it)
|
||||
{
|
||||
bytes += IO::store( _os, it->first, _swap );
|
||||
bytes += IO::store( _os, it->second, _swap );
|
||||
}
|
||||
return _os.good() ? bytes : 0;
|
||||
}
|
||||
|
||||
static
|
||||
size_t restore( std::istream& _is, value_type& _v, bool _swap=false)
|
||||
{
|
||||
size_t bytes = 0;
|
||||
unsigned int N = 0;
|
||||
|
||||
_v.clear();
|
||||
|
||||
bytes += IO::restore( _is, N, _swap );
|
||||
value_type::key_type key;
|
||||
value_type::mapped_type val;
|
||||
|
||||
for (size_t i=0; i<N && _is.good(); ++i)
|
||||
{
|
||||
bytes += IO::restore( _is, key, _swap );
|
||||
bytes += IO::restore( _is, val, _swap );
|
||||
_v[key] = val;
|
||||
}
|
||||
return _is.good() ? bytes : 0;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
int main(void)
|
||||
{
|
||||
//
|
||||
Mesh mesh;
|
||||
|
||||
|
||||
// generate a geometry
|
||||
generate_cube<Mesh>(mesh);
|
||||
|
||||
|
||||
// should display 8 vertices, 18/12 edges, 12/6 faces (Tri/Poly)
|
||||
mesh_stats(mesh);
|
||||
|
||||
|
||||
// print out information about properties
|
||||
mesh_property_stats(mesh);
|
||||
|
||||
|
||||
std::cout << "Define some custom properties..\n";
|
||||
|
||||
OpenMesh::VPropHandleT<float> vprop_float;
|
||||
OpenMesh::EPropHandleT<bool> eprop_bool;
|
||||
OpenMesh::FPropHandleT<std::string> fprop_string;
|
||||
OpenMesh::HPropHandleT<MyData> hprop_mydata;
|
||||
OpenMesh::MPropHandleT<MyMap> mprop_map;
|
||||
|
||||
std::cout << ".. and registrate them at the mesh object.\n";
|
||||
|
||||
mesh.add_property(vprop_float, "vprop_float");
|
||||
mesh.add_property(eprop_bool, "eprop_bool");
|
||||
mesh.add_property(fprop_string, "fprop_string");
|
||||
mesh.add_property(hprop_mydata, "hprop_mydata");
|
||||
mesh.add_property(mprop_map, "mprop_map");
|
||||
|
||||
|
||||
mesh_property_stats(mesh);
|
||||
|
||||
|
||||
std::cout << "Now let's fill the props..\n";
|
||||
|
||||
fill_props(mesh, vprop_float);
|
||||
fill_props(mesh, eprop_bool);
|
||||
fill_props(mesh, fprop_string);
|
||||
fill_props(mesh, hprop_mydata);
|
||||
fill_props(mesh, mprop_map);
|
||||
|
||||
|
||||
std::cout << "Check props..\n";
|
||||
#define CHK_PROP( PH ) \
|
||||
std::cout << " " << #PH << " " \
|
||||
<< (fill_props(mesh, PH, true)?"ok\n":"error\n")
|
||||
|
||||
CHK_PROP(vprop_float);
|
||||
CHK_PROP(eprop_bool);
|
||||
CHK_PROP(fprop_string);
|
||||
CHK_PROP(hprop_mydata);
|
||||
CHK_PROP(mprop_map);
|
||||
#undef CHK_PROP
|
||||
|
||||
|
||||
std::cout << "Set persistent flag..\n";
|
||||
#define SET_PERS( PH ) \
|
||||
mesh.property(PH).set_persistent(true); \
|
||||
std::cout << " " << #PH << " " \
|
||||
<< (mesh.property(PH).persistent()?"ok\n":"failed!\n")
|
||||
|
||||
mesh.property(vprop_float).set_persistent(true);
|
||||
std::cout << " vprop_float "
|
||||
<< (mesh.property(vprop_float).persistent()?"ok\n":"failed!\n");
|
||||
|
||||
SET_PERS( eprop_bool );
|
||||
SET_PERS( fprop_string );
|
||||
SET_PERS( hprop_mydata );
|
||||
mesh.mproperty(mprop_map).set_persistent(true);
|
||||
std::cout << " mprop_map "
|
||||
<< (mesh.mproperty(mprop_map).persistent()?"ok\n":"failed!\n");
|
||||
|
||||
|
||||
std::cout << "Write mesh..";
|
||||
if (IO::write_mesh( mesh, "persistence-check.om" ))
|
||||
std::cout << " ok\n";
|
||||
else
|
||||
{
|
||||
std::cout << " failed\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
std::cout << "Clear mesh\n";
|
||||
mesh.clear();
|
||||
mesh_stats(mesh, " ");
|
||||
|
||||
|
||||
std::cout << "Read back mesh..";
|
||||
try
|
||||
{
|
||||
if (IO::read_mesh( mesh, "persistence-check.om" ))
|
||||
std::cout << " ok\n";
|
||||
else
|
||||
{
|
||||
std::cout << " failed!\n";
|
||||
return 1;
|
||||
}
|
||||
mesh_stats(mesh, " ");
|
||||
}
|
||||
catch( std::exception &x )
|
||||
{
|
||||
std::cerr << x.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
std::cout << "Check props..\n";
|
||||
#define CHK_PROP( PH ) \
|
||||
std::cout << " " << #PH << " " \
|
||||
<< (fill_props(mesh, PH, true)?"ok\n":"error\n")
|
||||
CHK_PROP(vprop_float);
|
||||
CHK_PROP(eprop_bool);
|
||||
CHK_PROP(fprop_string);
|
||||
CHK_PROP(hprop_mydata);
|
||||
CHK_PROP(mprop_map);
|
||||
#undef CHK_PROP
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// end of file
|
||||
// ============================================================================
|
||||
20
Doc/Tutorial/10-persistence/stats.hh
Normal file
20
Doc/Tutorial/10-persistence/stats.hh
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef STATS_HH
|
||||
#define STATS_HH
|
||||
|
||||
template <typename Mesh>
|
||||
void mesh_stats( Mesh& _m, const std::string& prefix = "" )
|
||||
{
|
||||
std::cout << prefix
|
||||
<< _m.n_vertices() << " vertices, "
|
||||
<< _m.n_edges() << " edges, "
|
||||
<< _m.n_faces() << " faces\n";
|
||||
}
|
||||
|
||||
template <typename Mesh>
|
||||
void mesh_property_stats(Mesh& _m)
|
||||
{
|
||||
std::cout << "Current set of properties:\n";
|
||||
_m.property_stats(std::cout);
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user