diff --git a/Doc/Tutorial/03-properties/smooth.cc b/Doc/Tutorial/03-properties/smooth.cc index 207a619b..8756c492 100644 --- a/Doc/Tutorial/03-properties/smooth.cc +++ b/Doc/Tutorial/03-properties/smooth.cc @@ -46,20 +46,20 @@ int main(int argc, char **argv) { for (v_it=mesh.vertices_begin(); v_it!=v_end; ++v_it) { - mesh.property(cogs,v_it).vectorize(0.0f); - valence = 0; + mesh.property(cogs,*v_it).vectorize(0.0f); + valence = 0.0; - for (vv_it=mesh.vv_iter( v_it ); vv_it; ++vv_it) + for (vv_it=mesh.vv_iter( *v_it ); vv_it; ++vv_it) { - mesh.property(cogs,v_it) += mesh.point( vv_it ); + mesh.property(cogs,*v_it) += mesh.point( *vv_it ); ++valence; } - mesh.property(cogs,v_it) /= valence; + mesh.property(cogs,*v_it) /= valence; } for (v_it=mesh.vertices_begin(); v_it!=v_end; ++v_it) - if ( !mesh.is_boundary( v_it ) ) - mesh.set_point( v_it, mesh.property(cogs,v_it) ); + if ( !mesh.is_boundary( *v_it ) ) + mesh.set_point( *v_it, mesh.property(cogs,*v_it) ); } diff --git a/Doc/Tutorial/04-stl_algorithms/smooth_algo.hh b/Doc/Tutorial/04-stl_algorithms/smooth_algo.hh index 9c564427..b39fd82f 100644 --- a/Doc/Tutorial/04-stl_algorithms/smooth_algo.hh +++ b/Doc/Tutorial/04-stl_algorithms/smooth_algo.hh @@ -52,21 +52,20 @@ private: : mesh_(_mesh), cog_(_cog) {} - void operator()(typename Mesh::Vertex& _v) + void operator()(const typename Mesh::VertexHandle& _vh) { - typename Mesh::VertexHandle vh( mesh_.handle(_v) ); typename Mesh::VertexVertexIter vv_it; typename Mesh::Scalar valence(0.0); - mesh_.property(cog_, vh) = typename Mesh::Point(0.0, 0.0, 0.0); + mesh_.property(cog_, _vh) = typename Mesh::Point(0.0, 0.0, 0.0); - for (vv_it=mesh_.vv_iter(vh); vv_it; ++vv_it) + for (vv_it=mesh_.vv_iter(_vh); vv_it.is_valid(); ++vv_it) { - mesh_.property(cog_, vh) += mesh_.point( vv_it ); + mesh_.property(cog_, _vh) += mesh_.point( *vv_it ); ++valence; } - mesh_.property(cog_, mesh_.handle(_v) ) /= valence; + mesh_.property(cog_, _vh ) /= valence; } private: @@ -82,12 +81,11 @@ private: : mesh_(_mesh), cog_(_cog) {} - void operator()(typename Mesh::Vertex& _v) + void operator()(const typename Mesh::VertexHandle& _vh) { - typename Mesh::VertexHandle vh(mesh_.handle(_v)); - if (!mesh_.is_boundary(vh)) - mesh_.set_point( vh, mesh_.property(cog_, vh) ); + if (!mesh_.is_boundary(_vh)) + mesh_.set_point( _vh, mesh_.property(cog_, _vh) ); } private: diff --git a/Doc/Tutorial/05-std_properties/properties.cc b/Doc/Tutorial/05-std_properties/properties.cc index 7fc05288..545e8d30 100644 --- a/Doc/Tutorial/05-std_properties/properties.cc +++ b/Doc/Tutorial/05-std_properties/properties.cc @@ -52,9 +52,9 @@ int main(int argc, char **argv) for (MyMesh::VertexIter v_it = mesh.vertices_begin(); v_it != mesh.vertices_end(); ++v_it) { - std::cout << "Vertex #" << v_it << ": " << mesh.point( v_it ); - mesh.set_point( v_it, mesh.point(v_it)+mesh.normal(v_it) ); - std::cout << " moved to " << mesh.point( v_it ) << std::endl; + std::cout << "Vertex #" << *v_it << ": " << mesh.point( *v_it ); + mesh.set_point( *v_it, mesh.point(*v_it)+mesh.normal(*v_it) ); + std::cout << " moved to " << mesh.point( *v_it ) << std::endl; } // don't need the normals anymore? Remove them! diff --git a/Doc/Tutorial/06-attributes/attributes.cc b/Doc/Tutorial/06-attributes/attributes.cc index 8d446f72..1e93567e 100644 --- a/Doc/Tutorial/06-attributes/attributes.cc +++ b/Doc/Tutorial/06-attributes/attributes.cc @@ -85,9 +85,9 @@ int main(int argc, char **argv) for (MyMesh::VertexIter v_it = mesh.vertices_begin(); v_it != mesh.vertices_end(); ++v_it) { - std::cout << "Vertex #" << v_it << ": " << mesh.point( v_it ); - mesh.set_point( v_it, mesh.point(v_it)+mesh.normal(v_it) ); - std::cout << " moved to " << mesh.point( v_it ) << std::endl; + std::cout << "Vertex #" << *v_it << ": " << mesh.point( *v_it ); + mesh.set_point( *v_it, mesh.point(*v_it)+mesh.normal(*v_it) ); + std::cout << " moved to " << mesh.point( *v_it ) << std::endl; } return 0; diff --git a/Doc/Tutorial/07-traits/smooth.cc b/Doc/Tutorial/07-traits/smooth.cc index a68a1a33..85d3db27 100644 --- a/Doc/Tutorial/07-traits/smooth.cc +++ b/Doc/Tutorial/07-traits/smooth.cc @@ -100,13 +100,13 @@ int main(int argc, char **argv) { cog[0] = cog[1] = cog[2] = valence = 0.0; - for (vv_it=mesh.vv_iter(*v_it); vv_it; ++vv_it) + for (vv_it=mesh.vv_iter(*v_it); vv_it.is_valid(); ++vv_it) { cog += mesh.point( *vv_it ); ++valence; } - mesh.data(v_it).set_cog(cog / valence); + mesh.data(*v_it).set_cog(cog / valence); } for (v_it=mesh.vertices_begin(); v_it!=v_end; ++v_it) diff --git a/Doc/Tutorial/09-persistence/fill_props.hh b/Doc/Tutorial/09-persistence/fill_props.hh index 5f2b4f45..6c7d4f38 100644 --- a/Doc/Tutorial/09-persistence/fill_props.hh +++ b/Doc/Tutorial/09-persistence/fill_props.hh @@ -15,10 +15,10 @@ fill_props( Mesh& _m, OpenMesh::VPropHandleT _ph, bool _check=false) it != _m.vertices_end(); ++it) { const float v = a[it->idx()%9]; - if ( _check && !(_m.property( _ph, it ) == v) ) + if ( _check && !(_m.property( _ph, *it ) == v) ) return false; else - _m.property( _ph, it ) = v; + _m.property( _ph, *it ) = v; } return true; } @@ -35,15 +35,15 @@ fill_props( Mesh& _m, OpenMesh::EPropHandleT _ph, bool _check=false ) 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) + if (_check && _m.property( _ph, *it ) != v) { std::cout << " eprop_bool: " << n << " -> " - << _m.property(_ph, it ) << " != " << v << std::endl; + << _m.property(_ph, *it ) << " != " << v << std::endl; return false; } else { - _m.property( _ph, it ) = v; + _m.property( _ph, *it ) = v; std::cout << " eprop_bool: " << n << " -> " << v << std::endl; } } @@ -60,8 +60,8 @@ fill_props(Mesh& _m, OpenMesh::FPropHandleT _ph, bool _check=false) for( typename Mesh::FaceIter it=_m.faces_begin(); it != _m.faces_end(); ++it) { - const int n = ++(it->idx()); - _m.property( _ph, it ) = int2roman(n); + const int n = (it->idx()) + 1; + _m.property( _ph, *it ) = int2roman(n); } return true; } @@ -92,10 +92,10 @@ fill_props( Mesh& _m, OpenMesh::HPropHandleT _ph, bool _check=false) v.vec4fval[2] = c[n%9]; v.vec4fval[3] = d[n%9]; - if ( _check && _m.property( _ph, it ) != v ) + if ( _check && _m.property( _ph, *it ) != v ) return false; else - _m.property( _ph, it ) = v; + _m.property( _ph, *it ) = v; } return true; } diff --git a/src/Unittests/fill_props.hh b/src/Unittests/fill_props.hh new file mode 100644 index 00000000..0309f2d6 --- /dev/null +++ b/src/Unittests/fill_props.hh @@ -0,0 +1,116 @@ +#ifndef FILL_PROPS_HH +#define FILL_PROPS_HH + +#include +#include "int2roman.hh" + + +template +bool +fill_props( Mesh& _m, OpenMesh::VPropHandleT _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 +bool +fill_props( Mesh& _m, OpenMesh::EPropHandleT _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) + { + return false; + } + else + { + _m.property( _ph, *it ) = v; + } + } + return true; +} + + + +template +bool +fill_props(Mesh& _m, OpenMesh::FPropHandleT _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 +bool +fill_props( Mesh& _m, OpenMesh::HPropHandleT _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 +bool +fill_props( Mesh& _m, OpenMesh::MPropHandleT _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 diff --git a/src/Unittests/generate_cube.hh b/src/Unittests/generate_cube.hh new file mode 100644 index 00000000..1582a3de --- /dev/null +++ b/src/Unittests/generate_cube.hh @@ -0,0 +1,70 @@ +#ifndef GENERATE_CUBE_HH +#define GENERATE_CUBE_HH + +template +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 diff --git a/src/Unittests/int2roman.hh b/src/Unittests/int2roman.hh new file mode 100644 index 00000000..356578be --- /dev/null +++ b/src/Unittests/int2roman.hh @@ -0,0 +1,43 @@ +#ifndef INT2ROMAN_HH +#define INT2ROMAN_HH + +#include + +std::string int2roman( size_t decimal, size_t length = 30 ) +{ + 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 const 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); + + roman[ 0 ] = '\0'; + + 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; +} + +#endif diff --git a/src/Unittests/unittests_tutorials.cc b/src/Unittests/unittests_tutorials.cc new file mode 100644 index 00000000..a8c847dc --- /dev/null +++ b/src/Unittests/unittests_tutorials.cc @@ -0,0 +1,795 @@ + +#include +#include +#include +#include +#include "generate_cube.hh" +#include "fill_props.hh" + +/* + * ==================================================================== + * Definition of custom properties related classes + * ==================================================================== + */ + +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); } +}; + +typedef std::map< std::string, unsigned int > MyMap; + +namespace OpenMesh { + namespace IO { + // support persistence for struct MyData + template <> struct binary + { + 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 ); + std::string key; + size_t val; + for (size_t i=0; i class SmootherT +{ +public: + typedef typename Mesh::Point cog_t; + typedef OpenMesh::VPropHandleT< cog_t > Property_cog; + +public: + // construct with a given mesh + SmootherT(Mesh& _mesh) + : mesh_(_mesh) + { + mesh_.add_property( cog_ ); + } + ~SmootherT() + { + mesh_.remove_property( cog_ ); + } + // smooth mesh _iterations times + void smooth(unsigned int _iterations) + { + for (unsigned int i=0; i < _iterations; ++i) + { + std::for_each(mesh_.vertices_begin(), + mesh_.vertices_end(), + ComputeCOG(mesh_, cog_)); + std::for_each(mesh_.vertices_begin(), + mesh_.vertices_end(), + SetCOG(mesh_, cog_)); + } + } + +private: + //--- private classes --- + class ComputeCOG + { + public: + ComputeCOG(Mesh& _mesh, Property_cog& _cog) + : mesh_(_mesh), cog_(_cog) + {} + void operator()(const typename Mesh::VertexHandle& _vh) + { + typename Mesh::VertexVertexIter vv_it; + typename Mesh::Scalar valence(0.0); + + mesh_.property(cog_, _vh) = typename Mesh::Point(0.0, 0.0, 0.0); + for (vv_it=mesh_.vv_iter(_vh); vv_it.is_valid(); ++vv_it) + { + mesh_.property(cog_, _vh) += mesh_.point( *vv_it ); + ++valence; + } + mesh_.property(cog_, _vh ) /= valence; + } + private: + Mesh& mesh_; + Property_cog& cog_; + }; + + class SetCOG + { + public: + SetCOG(Mesh& _mesh, Property_cog& _cog) + : mesh_(_mesh), cog_(_cog) + {} + void operator()(const typename Mesh::VertexHandle& _vh) + { + if (!mesh_.is_boundary(_vh)) + mesh_.set_point( _vh, mesh_.property(cog_, _vh) ); + } + private: + Mesh& mesh_; + Property_cog& cog_; + }; + + //--- private elements --- + Mesh& mesh_; + Property_cog cog_; +}; + + +/* + * ==================================================================== + * Specify our traits + * ==================================================================== + */ + +struct MyTraits : public OpenMesh::DefaultTraits +{ + HalfedgeAttributes(OpenMesh::Attributes::PrevHalfedge); +}; + +// Define my personal fancy traits +struct MyFancyTraits : OpenMesh::DefaultTraits +{ + // Let Point and Normal be a vector of doubles + typedef OpenMesh::Vec3d Point; + typedef OpenMesh::Vec3d Normal; + // Already defined in OpenMesh::DefaultTraits + // HalfedgeAttributes( OpenMesh::Attributes::PrevHalfedge ); + + // Uncomment next line to disable attribute PrevHalfedge + // HalfedgeAttributes( OpenMesh::Attributes::None ); + // + // or + // + // HalfedgeAttributes( 0 ); +}; + +struct MyTraitsWithCOG : public OpenMesh::DefaultTraits +{ + // store barycenter of neighbors in this member + VertexTraits + { + private: + Point cog_; + public: + VertexT() : cog_( Point(0.0f, 0.0f, 0.0f ) ) { } + const Point& cog() const { return cog_; } + void set_cog(const Point& _p) { cog_ = _p; } + }; +}; + +struct MyTraitsWithStatus : public OpenMesh::DefaultTraits +{ + VertexAttributes(OpenMesh::Attributes::Status); + FaceAttributes(OpenMesh::Attributes::Status); + EdgeAttributes(OpenMesh::Attributes::Status); +}; + +/* + * ==================================================================== + * Specify our meshes + * ==================================================================== + */ +typedef OpenMesh::PolyMesh_ArrayKernelT<> MyMesh; +typedef OpenMesh::TriMesh_ArrayKernelT MyMeshWithTraits; +typedef OpenMesh::TriMesh_ArrayKernelT MyTriMesh; +typedef OpenMesh::TriMesh_ArrayKernelT MyFancyTriMesh; +typedef OpenMesh::TriMesh_ArrayKernelT MyTriMeshWithCOG; +typedef OpenMesh::PolyMesh_ArrayKernelT MyMeshWithStatus; + +/* + * ==================================================================== + * Define tests below + * ==================================================================== + */ + +/* + */ +TEST_F(OpenMeshTutorials, building_a_cube) { + + MyMesh mesh; + + // generate vertices + MyMesh::VertexHandle vhandle[8]; + vhandle[0] = mesh.add_vertex(MyMesh::Point(-1, -1, 1)); + vhandle[1] = mesh.add_vertex(MyMesh::Point( 1, -1, 1)); + vhandle[2] = mesh.add_vertex(MyMesh::Point( 1, 1, 1)); + vhandle[3] = mesh.add_vertex(MyMesh::Point(-1, 1, 1)); + vhandle[4] = mesh.add_vertex(MyMesh::Point(-1, -1, -1)); + vhandle[5] = mesh.add_vertex(MyMesh::Point( 1, -1, -1)); + vhandle[6] = mesh.add_vertex(MyMesh::Point( 1, 1, -1)); + vhandle[7] = mesh.add_vertex(MyMesh::Point(-1, 1, -1)); + + // generate (quadrilateral) faces + std::vector 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); + + bool ok = OpenMesh::IO::write_mesh(mesh, "output.off"); + + EXPECT_TRUE(ok) << "Cannot write mesh to file 'output.off'"; +} + +TEST_F(OpenMeshTutorials, using_iterators_and_circulators) { + MyMesh mesh; + + bool ok = OpenMesh::IO::read_mesh(mesh, "output.off"); + + EXPECT_TRUE(ok) << "Cannot read mesh from file 'output.off'"; + + // this vector stores the computed centers of gravity + std::vector cogs; + std::vector::iterator cog_it; + cogs.reserve(mesh.n_vertices()); + + // smoothing mesh N times + MyMesh::VertexIter v_it, v_end(mesh.vertices_end()); + MyMesh::VertexVertexIter vv_it; + MyMesh::Point cog; + MyMesh::Scalar valence; + unsigned int i, N(100); + for (i=0; i < N; ++i) + { + cogs.clear(); + for (v_it = mesh.vertices_begin(); v_it != v_end; ++v_it) + { + cog[0] = cog[1] = cog[2] = valence = 0.0; + + for (vv_it = mesh.vv_iter( *v_it ); vv_it.is_valid(); ++vv_it) + { + cog += mesh.point( *vv_it ); + ++valence; + } + cogs.push_back(cog / valence); + } + + for (v_it = mesh.vertices_begin(), cog_it = cogs.begin(); + v_it != v_end; ++v_it, ++cog_it) + if ( !mesh.is_boundary( *v_it ) ) + mesh.set_point( *v_it, *cog_it ); + } + + // write mesh + ok = OpenMesh::IO::write_mesh(mesh, "smoothed_output.off"); + + EXPECT_TRUE(ok) << "Cannot write mesh to file 'smoothed_output.off'"; +} + +TEST_F(OpenMeshTutorials, using_custom_properties) { + MyMesh mesh; + + bool ok = OpenMesh::IO::read_mesh(mesh, "output.off"); + EXPECT_TRUE(ok) << "Cannot read mesh from file 'output.off'"; + + // this vertex property stores the computed centers of gravity + OpenMesh::VPropHandleT cogs; + mesh.add_property(cogs); + + // smoothing mesh N times + MyMesh::VertexIter v_it, v_end(mesh.vertices_end()); + MyMesh::VertexVertexIter vv_it; + MyMesh::Point cog; + MyMesh::Scalar valence; + unsigned int i, N(100); + + for (i=0; i < N; ++i) + { + for (v_it = mesh.vertices_begin(); v_it != v_end; ++v_it) + { + mesh.property(cogs,*v_it).vectorize(0.0f); + valence = 0.0; + + for (vv_it = mesh.vv_iter( *v_it ); vv_it.is_valid(); ++vv_it) + { + mesh.property(cogs,*v_it) += mesh.point( *vv_it ); + ++valence; + } + mesh.property(cogs,*v_it) /= valence; + } + + for (v_it = mesh.vertices_begin(); v_it != v_end; ++v_it) + if ( !mesh.is_boundary( *v_it ) ) + mesh.set_point( *v_it, mesh.property(cogs,*v_it) ); + } + + // write mesh + ok = OpenMesh::IO::write_mesh(mesh, "smoothed_custom_properties_output.off"); + + EXPECT_TRUE(ok) << "Cannot write mesh to file 'smoothed_custom_properties_output.off'"; +} + +TEST_F(OpenMeshTutorials, using_STL_algorithms) { + MyMeshWithTraits mesh; + + bool ok = OpenMesh::IO::read_mesh(mesh, "output.off"); + EXPECT_TRUE(ok) << "Cannot read mesh from file 'output.off'"; + + SmootherT smoother(mesh); + smoother.smooth(100); + + // write mesh + ok = OpenMesh::IO::write_mesh(mesh, "smoothed_STL_output.off"); + + EXPECT_TRUE(ok) << "Cannot write mesh to file 'smoothed_STL_output.off'"; +} + +TEST_F(OpenMeshTutorials, using_standard_properties) { + MyTriMesh mesh; + + mesh.request_vertex_normals(); + EXPECT_TRUE(mesh.has_vertex_normals()) << "Standard vertex property 'Normals' not available"; + + OpenMesh::IO::Options opt; + bool ok = OpenMesh::IO::read_mesh(mesh, "output.off", opt); + EXPECT_TRUE(ok) << "Cannot read mesh from file 'output.off'"; + + // If the file did not provide vertex normals, then calculate them + if ( !opt.check( OpenMesh::IO::Options::VertexNormal ) ) + { + // we need face normals to update the vertex normals + mesh.request_face_normals(); + // let the mesh update the normals + mesh.update_normals(); + // dispose the face normals, as we don't need them anymore + mesh.release_face_normals(); + } + + // move all vertices one unit length along it's normal direction + for (MyMesh::VertexIter v_it = mesh.vertices_begin(); + v_it != mesh.vertices_end(); ++v_it) + { + mesh.set_point( *v_it, mesh.point(*v_it)+mesh.normal(*v_it) ); + } + + // don't need the normals anymore? Remove them! + mesh.release_vertex_normals(); + // just check if it really works + EXPECT_FALSE(mesh.has_vertex_normals()) << "Shouldn't have any vertex normals anymore"; +} + +TEST_F(OpenMeshTutorials, using_mesh_attributes_and_traits) { + MyFancyTriMesh mesh; + + // Just make sure that point element type is double + EXPECT_TRUE(typeid( OpenMesh::vector_traits::value_type ) == + typeid(double)) << "Data type is wrong"; + + // Make sure that normal element type is double + EXPECT_TRUE(typeid( OpenMesh::vector_traits::value_type ) == + typeid(double)) << "Data type is wrong"; + + // Add vertex normals as default property (ref. previous tutorial) + mesh.request_vertex_normals(); + // Add face normals as default property + mesh.request_face_normals(); + + // load a mesh + OpenMesh::IO::Options opt; + bool ok = OpenMesh::IO::read_mesh(mesh, "output.off", opt); + EXPECT_TRUE(ok) << "Cannot read mesh from file 'output.off'"; + + // If the file did not provide vertex normals, then calculate them + if ( !opt.check( OpenMesh::IO::Options::VertexNormal ) && + mesh.has_face_normals() && mesh.has_vertex_normals() ) + { + // let the mesh update the normals + mesh.update_normals(); + } + + // move all vertices one unit length along it's normal direction + for (MyMesh::VertexIter v_it = mesh.vertices_begin(); + v_it != mesh.vertices_end(); ++v_it) + { + mesh.set_point( *v_it, mesh.point(*v_it)+mesh.normal(*v_it) ); + } +} + +TEST_F(OpenMeshTutorials, extending_the_mesh_using_traits) { + MyTriMeshWithCOG mesh; + + bool ok = OpenMesh::IO::read_mesh(mesh, "output.off"); + EXPECT_TRUE(ok) << "Cannot read mesh from file 'output.off'"; + + // smoothing mesh N times + MyTriMeshWithCOG::VertexIter v_it, v_end(mesh.vertices_end()); + MyTriMeshWithCOG::VertexVertexIter vv_it; + MyTriMeshWithCOG::Point cog; + MyTriMeshWithCOG::Scalar valence; + unsigned int i, N(100); + + for (i=0; i < N; ++i) + { + for (v_it = mesh.vertices_begin(); v_it != v_end; ++v_it) + { + cog[0] = cog[1] = cog[2] = valence = 0.0; + + for (vv_it = mesh.vv_iter(*v_it); vv_it.is_valid(); ++vv_it) + { + cog += mesh.point( *vv_it ); + ++valence; + } + mesh.data(*v_it).set_cog(cog / valence); + } + + for (v_it = mesh.vertices_begin(); v_it != v_end; ++v_it) + if (!mesh.is_boundary(*v_it)) + mesh.set_point( *v_it, mesh.data(*v_it).cog()); + } + + // write mesh + ok = OpenMesh::IO::write_mesh(mesh, "smoothed_extended_output.off"); + + EXPECT_TRUE(ok) << "Cannot write mesh to file 'smoothed_extended_output.off'"; +} + +TEST_F(OpenMeshTutorials, deleting_geometry_elements) { + MyMeshWithStatus mesh; + + // generate vertices + MyMeshWithStatus::VertexHandle vhandle[8]; + MyMeshWithStatus::FaceHandle fhandle[6]; + + vhandle[0] = mesh.add_vertex(MyMesh::Point(-1, -1, 1)); + vhandle[1] = mesh.add_vertex(MyMesh::Point( 1, -1, 1)); + vhandle[2] = mesh.add_vertex(MyMesh::Point( 1, 1, 1)); + vhandle[3] = mesh.add_vertex(MyMesh::Point(-1, 1, 1)); + vhandle[4] = mesh.add_vertex(MyMesh::Point(-1, -1, -1)); + vhandle[5] = mesh.add_vertex(MyMesh::Point( 1, -1, -1)); + vhandle[6] = mesh.add_vertex(MyMesh::Point( 1, 1, -1)); + vhandle[7] = mesh.add_vertex(MyMesh::Point(-1, 1, -1)); + + // generate (quadrilateral) faces + std::vector tmp_face_vhandles; + tmp_face_vhandles.clear(); + tmp_face_vhandles.push_back(vhandle[0]); + tmp_face_vhandles.push_back(vhandle[1]); + tmp_face_vhandles.push_back(vhandle[2]); + tmp_face_vhandles.push_back(vhandle[3]); + fhandle[0] = mesh.add_face(tmp_face_vhandles); + + tmp_face_vhandles.clear(); + tmp_face_vhandles.push_back(vhandle[7]); + tmp_face_vhandles.push_back(vhandle[6]); + tmp_face_vhandles.push_back(vhandle[5]); + tmp_face_vhandles.push_back(vhandle[4]); + fhandle[1] = mesh.add_face(tmp_face_vhandles); + + tmp_face_vhandles.clear(); + tmp_face_vhandles.push_back(vhandle[1]); + tmp_face_vhandles.push_back(vhandle[0]); + tmp_face_vhandles.push_back(vhandle[4]); + tmp_face_vhandles.push_back(vhandle[5]); + fhandle[2] = mesh.add_face(tmp_face_vhandles); + + tmp_face_vhandles.clear(); + tmp_face_vhandles.push_back(vhandle[2]); + tmp_face_vhandles.push_back(vhandle[1]); + tmp_face_vhandles.push_back(vhandle[5]); + tmp_face_vhandles.push_back(vhandle[6]); + fhandle[3] = mesh.add_face(tmp_face_vhandles); + tmp_face_vhandles.clear(); + tmp_face_vhandles.push_back(vhandle[3]); + tmp_face_vhandles.push_back(vhandle[2]); + tmp_face_vhandles.push_back(vhandle[6]); + tmp_face_vhandles.push_back(vhandle[7]); + fhandle[4] = mesh.add_face(tmp_face_vhandles); + + tmp_face_vhandles.clear(); + tmp_face_vhandles.push_back(vhandle[0]); + tmp_face_vhandles.push_back(vhandle[3]); + tmp_face_vhandles.push_back(vhandle[7]); + tmp_face_vhandles.push_back(vhandle[4]); + fhandle[5] = mesh.add_face(tmp_face_vhandles); + + // And now delete all faces and vertices + // except face (vh[7], vh[6], vh[5], vh[4]) + // whose handle resides in fhandle[1] + + EXPECT_FALSE(mesh.status(fhandle[0]).deleted()) << "face shouldn't be deleted"; + EXPECT_FALSE(mesh.status(fhandle[1]).deleted()) << "face shouldn't be deleted"; + EXPECT_FALSE(mesh.status(fhandle[2]).deleted()) << "face shouldn't be deleted"; + EXPECT_FALSE(mesh.status(fhandle[3]).deleted()) << "face shouldn't be deleted"; + EXPECT_FALSE(mesh.status(fhandle[4]).deleted()) << "face shouldn't be deleted"; + EXPECT_FALSE(mesh.status(fhandle[5]).deleted()) << "face shouldn't be deleted"; + + // Delete face 0 + mesh.delete_face(fhandle[0], false); + // ... face 2 + mesh.delete_face(fhandle[2], false); + // ... face 3 + mesh.delete_face(fhandle[3], false); + // ... face 4 + mesh.delete_face(fhandle[4], false); + // ... face 5 + mesh.delete_face(fhandle[5], false); + + EXPECT_TRUE(mesh.status(fhandle[0]).deleted()) << "face should be deleted"; + EXPECT_FALSE(mesh.status(fhandle[1]).deleted()) << "face shouldn't be deleted"; + EXPECT_TRUE(mesh.status(fhandle[2]).deleted()) << "face should be deleted"; + EXPECT_TRUE(mesh.status(fhandle[3]).deleted()) << "face should be deleted"; + EXPECT_TRUE(mesh.status(fhandle[4]).deleted()) << "face should be deleted"; + EXPECT_TRUE(mesh.status(fhandle[5]).deleted()) << "face should be deleted"; + + // If isolated vertices result in a face deletion + // they have to be deleted manually. If you want this + // to happen automatically, change the second parameter + // to true. + // Now delete the isolated vertices 0, 1, 2 and 3 + + EXPECT_FALSE(mesh.status(vhandle[0]).deleted()) << "vertex shouldn't be deleted"; + EXPECT_FALSE(mesh.status(vhandle[1]).deleted()) << "vertex shouldn't be deleted"; + EXPECT_FALSE(mesh.status(vhandle[2]).deleted()) << "vertex shouldn't be deleted"; + EXPECT_FALSE(mesh.status(vhandle[3]).deleted()) << "vertex shouldn't be deleted"; + + mesh.delete_vertex(vhandle[0], false); + mesh.delete_vertex(vhandle[1], false); + mesh.delete_vertex(vhandle[2], false); + mesh.delete_vertex(vhandle[3], false); + + EXPECT_TRUE(mesh.status(vhandle[0]).deleted()) << "vertex should be deleted"; + EXPECT_TRUE(mesh.status(vhandle[1]).deleted()) << "vertex should be deleted"; + EXPECT_TRUE(mesh.status(vhandle[2]).deleted()) << "vertex should be deleted"; + EXPECT_TRUE(mesh.status(vhandle[3]).deleted()) << "vertex should be deleted"; + + // Delete all elements that are marked as deleted + // from memory. + mesh.garbage_collection(); + + // write mesh + bool ok = OpenMesh::IO::write_mesh(mesh, "deleted_output.off"); + + EXPECT_TRUE(ok) << "Cannot write mesh to file 'deleted_output.off'"; +} + +TEST_F(OpenMeshTutorials, storing_custom_properties) { + MyMesh mesh; + + // generate a geometry + generate_cube(mesh); + + // define some custom properties + OpenMesh::VPropHandleT vprop_float; + OpenMesh::EPropHandleT eprop_bool; + OpenMesh::FPropHandleT fprop_string; + OpenMesh::HPropHandleT hprop_mydata; + OpenMesh::MPropHandleT mprop_map; + + // registrate them at the mesh object + 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"); + + //fill the props + 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); + + EXPECT_TRUE(fill_props(mesh, vprop_float, true)) << "property not filled correctly"; + EXPECT_TRUE(fill_props(mesh, eprop_bool, true)) << "property not filled correctly"; + EXPECT_TRUE(fill_props(mesh, fprop_string, true)) << "property not filled correctly"; + EXPECT_TRUE(fill_props(mesh, hprop_mydata, true)) << "property not filled correctly"; + EXPECT_TRUE(fill_props(mesh, mprop_map, true)) << "property not filled correctly"; + + //Set persistent flag + mesh.property(vprop_float).set_persistent(true); + EXPECT_TRUE(mesh.property(vprop_float).persistent()) << "property should be persistent"; + mesh.property(eprop_bool).set_persistent(true); + EXPECT_TRUE(mesh.property(eprop_bool).persistent()) << "property should be persistent"; + mesh.property(fprop_string).set_persistent(true); + EXPECT_TRUE(mesh.property(fprop_string).persistent()) << "property should be persistent"; + mesh.property(hprop_mydata).set_persistent(true); + EXPECT_TRUE(mesh.property(hprop_mydata).persistent()) << "property should be persistent"; + mesh.mproperty(mprop_map).set_persistent(true); + EXPECT_TRUE(mesh.mproperty(mprop_map).persistent()) << "property should be persistent"; + + // write mesh + bool ok = OpenMesh::IO::write_mesh( mesh, "persistence-check.om" ); + EXPECT_TRUE(ok) << "Cannot write mesh to file 'persistent-check.om'"; + + // clear mesh + mesh.clear(); + + //Read back mesh + ok = OpenMesh::IO::read_mesh( mesh, "persistence-check.om" ); + EXPECT_TRUE(ok) << "Cannot read mesh from file 'persistent-check.om'"; + + // check props + EXPECT_TRUE(fill_props(mesh, vprop_float, true)) << "property not filled correctly"; + EXPECT_TRUE(fill_props(mesh, eprop_bool, true)) << "property not filled correctly"; + EXPECT_TRUE(fill_props(mesh, fprop_string, true)) << "property not filled correctly"; + EXPECT_TRUE(fill_props(mesh, hprop_mydata, true)) << "property not filled correctly"; + EXPECT_TRUE(fill_props(mesh, mprop_map, true)) << "property not filled correctly"; +} + +}