Merge branch 'CustomProperties' into 'master'
Automatic loading of properties stored in files without having to manually create the property before reading. See merge request OpenMesh/OpenMesh!302
This commit is contained in:
@@ -13,6 +13,7 @@
|
||||
<ul>
|
||||
<li>Dropped 32-bit Windows continuous integration and artifact builds (This does not mean that OpenMesh will not build and work on 32-bit, but we don't explicitly test and guarantee it anymore).</li>
|
||||
<li>Changed CCW begin/end/range to start on last element of CW counterpart. May break your code if you depend on CCW begin to start at a specific element.</li>
|
||||
<li>The binary struct that needs to be implemented in order to store properties of user defined types now requires a method type_identifier() which returns an std::string that uniquely identifies the type.
|
||||
</ul>
|
||||
|
||||
<b>Core</b>
|
||||
@@ -30,6 +31,8 @@
|
||||
<ul>
|
||||
<li>STL Reader: Change stl reader behaviour on extension .stl , Don't check for the solid keyword explicitly</li>
|
||||
<li>OM Writer: Removed debug output</li>
|
||||
<li>OM Writer/Reader: Added support for (re)storing properties of type vector<T></li>
|
||||
<li>OM Reader: Properties can now be restored from files without the need to create the properties beforehand. Custom types need to be registered for this to work using the OM_REGISTER_PROPERTY_TYPE macro.</li>
|
||||
</ul>
|
||||
|
||||
<b>Tools</b>
|
||||
|
||||
@@ -44,7 +44,10 @@ else ()
|
||||
vci_add_library (OpenMeshCore SHAREDANDSTATIC ${sources} ${headers})
|
||||
set_target_properties (OpenMeshCore PROPERTIES VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
|
||||
SOVERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} )
|
||||
endif ()
|
||||
|
||||
if (MSVC)
|
||||
target_compile_options(OpenMeshCore PUBLIC /bigobj)
|
||||
endif ()
|
||||
|
||||
# Add core as dependency before fixbundle
|
||||
|
||||
@@ -278,7 +278,6 @@ namespace OMFormat {
|
||||
}; // Chunk
|
||||
|
||||
// ------------------------------------------------------------ Helper
|
||||
|
||||
// -------------------- get size information
|
||||
|
||||
/// Return size of header in bytes.
|
||||
|
||||
@@ -91,31 +91,42 @@ namespace IO {
|
||||
/// It's used by the OM reader/writer modules.
|
||||
///
|
||||
/// The following specialization are provided:
|
||||
/// - Fundamental types except \c long \c double
|
||||
/// - Fundamental types except \c long
|
||||
/// - %OpenMesh vector types
|
||||
/// - %OpenMesh::StatusInfo
|
||||
/// - std::string (max. length 65535)
|
||||
/// - std::vector<T> (requires a specialization for T)
|
||||
///
|
||||
/// \todo Complete documentation of members
|
||||
template < typename T > struct binary
|
||||
template < typename T, typename = void > struct binary
|
||||
{
|
||||
typedef T value_type;
|
||||
|
||||
/// Can we store T? Set this to true in your specialization.
|
||||
static const bool is_streamable = false;
|
||||
|
||||
/// What's the size of T? If it depends on the actual value (e.g. for vectors) return UnknownSize
|
||||
static size_t size_of(void) { return UnknownSize; }
|
||||
/// What't the size of a specific value of type T.
|
||||
static size_t size_of(const value_type&) { return UnknownSize; }
|
||||
|
||||
/// A string that identifies the type of T.
|
||||
static std::string type_identifier (void) { return "UnknownType"; }
|
||||
|
||||
/// Store a value of T and return the number of bytes written
|
||||
static
|
||||
size_t store( std::ostream& /* _os */,
|
||||
const value_type& /* _v */,
|
||||
bool /* _swap=false */)
|
||||
const value_type& /* _v */,
|
||||
bool /* _swap */ = false ,
|
||||
bool /* store_size */ = true ) // for vectors
|
||||
{ X; return 0; }
|
||||
|
||||
/// Restore a value of T and return the number of bytes read
|
||||
static
|
||||
size_t restore( std::istream& /* _is */,
|
||||
value_type& /* _v */,
|
||||
bool /* _swap=false */)
|
||||
value_type& /* _v */,
|
||||
bool /* _swap */ = false ,
|
||||
bool /* store_size */ = true ) // for vectors
|
||||
{ X; return 0; }
|
||||
};
|
||||
|
||||
|
||||
@@ -72,6 +72,11 @@
|
||||
#include <OpenMesh/Core/IO/SR_rbo.hh>
|
||||
#include <OpenMesh/Core/IO/SR_binary.hh>
|
||||
|
||||
|
||||
#include <OpenMesh/Core/Utils/typename.hh>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
//== NAMESPACES ===============================================================
|
||||
|
||||
namespace OpenMesh {
|
||||
@@ -91,6 +96,7 @@ namespace IO {
|
||||
static const bool is_streamable = true; \
|
||||
static size_t size_of(const value_type&) { return sizeof(value_type); } \
|
||||
static size_t size_of(void) { return sizeof(value_type); } \
|
||||
static std::string type_identifier(void) { return #T; } \
|
||||
static size_t store( std::ostream& _os, const value_type& _val, \
|
||||
bool _swap=false) { \
|
||||
value_type tmp = _val; \
|
||||
@@ -120,12 +126,19 @@ SIMPLE_BINARY(char);
|
||||
SIMPLE_BINARY(int8_t);
|
||||
SIMPLE_BINARY(int16_t);
|
||||
SIMPLE_BINARY(int32_t);
|
||||
SIMPLE_BINARY(int64_t);
|
||||
//SIMPLE_BINARY(int64_t); // TODO: This does not work. Find out why.
|
||||
SIMPLE_BINARY(uint8_t);
|
||||
SIMPLE_BINARY(uint16_t);
|
||||
SIMPLE_BINARY(uint32_t);
|
||||
SIMPLE_BINARY(uint64_t);
|
||||
|
||||
//handles
|
||||
SIMPLE_BINARY(FaceHandle);
|
||||
SIMPLE_BINARY(EdgeHandle);
|
||||
SIMPLE_BINARY(HalfedgeHandle);
|
||||
SIMPLE_BINARY(VertexHandle);
|
||||
SIMPLE_BINARY(MeshHandle);
|
||||
|
||||
#undef SIMPLE_BINARY
|
||||
|
||||
// For unsigned long which is of size 64 bit on 64 bit
|
||||
@@ -142,6 +155,7 @@ SIMPLE_BINARY(uint64_t);
|
||||
static const bool is_streamable = true; \
|
||||
static size_t size_of(const value_type&) { return sizeof(value_type); } \
|
||||
static size_t size_of(void) { return sizeof(value_type); } \
|
||||
static std::string type_identifier(void) { return #T; } \
|
||||
static size_t store( std::ostream& _os, const value_type& _val, \
|
||||
bool _swap=false) { \
|
||||
value_type tmp = _val; \
|
||||
@@ -172,12 +186,14 @@ SIMPLE_BINARY(unsigned long);
|
||||
static const bool is_streamable = true; \
|
||||
static size_t size_of(void) { return sizeof(value_type); } \
|
||||
static size_t size_of(const value_type&) { return size_of(); } \
|
||||
static std::string type_identifier(void) { return #T; } \
|
||||
static size_t store( std::ostream& _os, const value_type& _val, \
|
||||
bool _swap=false) { \
|
||||
bool _swap=false) { \
|
||||
value_type tmp = _val; \
|
||||
size_t i, b = size_of(_val), N = value_type::size_; \
|
||||
if (_swap) for (i=0; i<N; ++i) \
|
||||
reverse_byte_order( tmp[i] ); \
|
||||
if (_swap) \
|
||||
for (i=0; i<N; ++i) \
|
||||
reverse_byte_order( tmp[i] ); \
|
||||
_os.write( (const char*)&tmp[0], b ); \
|
||||
return _os.good() ? b : 0; \
|
||||
} \
|
||||
@@ -207,6 +223,7 @@ VECTORTS_BINARY( 1 )
|
||||
VECTORTS_BINARY( 2 )
|
||||
VECTORTS_BINARY( 3 )
|
||||
VECTORTS_BINARY( 4 )
|
||||
VECTORTS_BINARY( 5 )
|
||||
VECTORTS_BINARY( 6 )
|
||||
|
||||
#undef VECTORTS_BINARY
|
||||
@@ -221,7 +238,7 @@ template <> struct binary< std::string > {
|
||||
static size_t size_of() { return UnknownSize; }
|
||||
static size_t size_of(const value_type &_v)
|
||||
{ return sizeof(length_t) + _v.size(); }
|
||||
|
||||
static std::string type_identifier(void) { return "std::string"; }
|
||||
static
|
||||
size_t store(std::ostream& _os, const value_type& _v, bool _swap=false)
|
||||
{
|
||||
@@ -252,7 +269,6 @@ template <> struct binary< std::string > {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <> struct binary<OpenMesh::Attributes::StatusInfo>
|
||||
{
|
||||
typedef OpenMesh::Attributes::StatusInfo value_type;
|
||||
@@ -263,6 +279,7 @@ template <> struct binary<OpenMesh::Attributes::StatusInfo>
|
||||
static size_t size_of() { return sizeof(status_t); }
|
||||
static size_t size_of(const value_type&) { return size_of(); }
|
||||
|
||||
static std::string type_identifier(void) { return "StatusInfo";}
|
||||
static size_t n_bytes(size_t _n_elem)
|
||||
{ return _n_elem*sizeof(status_t); }
|
||||
|
||||
@@ -307,8 +324,106 @@ struct FunctorRestore {
|
||||
bool swap_;
|
||||
};
|
||||
|
||||
#include <OpenMesh/Core/IO/SR_binary_vector_of_fundamentals.inl>
|
||||
#include <OpenMesh/Core/IO/SR_binary_vector_of_string.inl>
|
||||
template <typename T>
|
||||
struct binary< std::vector< T >, typename std::enable_if<std::is_default_constructible<T>::value>::type > {
|
||||
typedef std::vector< T > value_type;
|
||||
typedef typename value_type::value_type elem_type;
|
||||
|
||||
static const bool is_streamable = binary<T>::is_streamable;
|
||||
static size_t size_of(bool _store_size = true)
|
||||
{ return IO::UnknownSize; }
|
||||
|
||||
static size_t size_of(const value_type& _v, bool _store_size = true)
|
||||
{
|
||||
if(binary<T>::size_of() != IO::UnknownSize)
|
||||
{
|
||||
unsigned int N = _v.size();
|
||||
auto res = binary<T>::size_of()*_v.size() + (_store_size? sizeof(decltype(N)) : 0);
|
||||
return res;
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t size = 0;
|
||||
for(auto v : _v)
|
||||
size += binary<T>::size_of(v);
|
||||
if(_store_size)
|
||||
size += binary<unsigned int>::size_of();
|
||||
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
static std::string type_identifier(void) { return "std::vector<" + binary<T>::type_identifier() + ">"; }
|
||||
static
|
||||
size_t store(std::ostream& _os, const value_type& _v, bool _swap=false, bool _store_size = true) {
|
||||
size_t bytes=0;
|
||||
if(_store_size)
|
||||
{
|
||||
unsigned int N = _v.size();
|
||||
bytes += binary<unsigned int>::store( _os, N, _swap );
|
||||
}
|
||||
if (_swap)
|
||||
bytes += std::accumulate( _v.begin(), _v.end(), static_cast<size_t>(0),
|
||||
FunctorStore<elem_type>(_os,_swap) );
|
||||
else
|
||||
{
|
||||
auto elem_size = binary<elem_type>::size_of();
|
||||
if (elem_size != IO::UnknownSize && elem_size == sizeof(elem_type))
|
||||
{
|
||||
// size of all elements is known, equal, and densely packed in vector.
|
||||
// Just store vector data
|
||||
auto bytes_of_vec = size_of(_v, false);
|
||||
bytes += bytes_of_vec;
|
||||
if (_v.size() > 0)
|
||||
_os.write( reinterpret_cast<const char*>(&_v[0]), bytes_of_vec);
|
||||
}
|
||||
else
|
||||
{
|
||||
// store individual elements
|
||||
for (const auto& v : _v)
|
||||
bytes += binary<elem_type>::store(_os, v, _swap);
|
||||
}
|
||||
}
|
||||
return _os.good() ? bytes : 0;
|
||||
}
|
||||
|
||||
static size_t restore(std::istream& _is, value_type& _v, bool _swap=false, bool _restore_size = true) {
|
||||
|
||||
size_t bytes=0;
|
||||
|
||||
if(_restore_size)
|
||||
{
|
||||
unsigned int size_of_vec;
|
||||
bytes += binary<unsigned int>::restore(_is, size_of_vec, _swap);
|
||||
_v.resize(size_of_vec);
|
||||
}
|
||||
|
||||
if ( _swap)
|
||||
bytes += std::accumulate( _v.begin(), _v.end(), size_t(0),
|
||||
FunctorRestore<elem_type>(_is, _swap) );
|
||||
else
|
||||
{
|
||||
auto elem_size = binary<elem_type>::size_of();
|
||||
if (elem_size != IO::UnknownSize && elem_size == sizeof(elem_type))
|
||||
{
|
||||
// size of all elements is known, equal, and densely packed in vector.
|
||||
// Just restore vector data
|
||||
auto bytes_of_vec = size_of(_v, false);
|
||||
bytes += bytes_of_vec;
|
||||
if (_v.size() > 0)
|
||||
_is.read( reinterpret_cast<char*>(&_v[0]), bytes_of_vec );
|
||||
}
|
||||
else
|
||||
{
|
||||
// restore individual elements
|
||||
for (auto& v : _v)
|
||||
bytes += binary<elem_type>::restore(_is, v, _swap);
|
||||
}
|
||||
}
|
||||
return _is.good() ? bytes : 0;
|
||||
}
|
||||
};
|
||||
|
||||
#include <OpenMesh/Core/IO/SR_binary_vector_of_bool.inl>
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
@@ -1,95 +1,103 @@
|
||||
|
||||
template <> struct binary< std::vector<bool> >
|
||||
{
|
||||
|
||||
typedef std::vector< bool > value_type;
|
||||
typedef value_type::value_type elem_type;
|
||||
|
||||
static const bool is_streamable = true;
|
||||
|
||||
static size_t size_of(void) { return UnknownSize; }
|
||||
static size_t size_of(const value_type& _v)
|
||||
static size_t size_of(bool _store_size = true) { return UnknownSize; }
|
||||
static size_t size_of(const value_type& _v, bool _store_size = true)
|
||||
{
|
||||
return _v.size() / 8 + ((_v.size() % 8)!=0);
|
||||
size_t size = _v.size() / 8 + ((_v.size() % 8)!=0);
|
||||
if(_store_size)
|
||||
size += binary<unsigned int>::size_of();
|
||||
return size;
|
||||
}
|
||||
|
||||
static std::string type_identifier(void) { return "std::vector<bool>"; }
|
||||
static
|
||||
size_t store( std::ostream& _ostr, const value_type& _v, bool )
|
||||
size_t store( std::ostream& _ostr, const value_type& _v, bool _swap, bool _store_size = true)
|
||||
{
|
||||
size_t bytes = 0;
|
||||
|
||||
size_t N = _v.size() / 8;
|
||||
size_t R = _v.size() % 8;
|
||||
|
||||
size_t idx; // element index
|
||||
if(_store_size)
|
||||
{
|
||||
unsigned int size_N = _v.size();
|
||||
bytes += binary<unsigned int>::store( _ostr, size_N, _swap );
|
||||
}
|
||||
|
||||
size_t idx; // element index
|
||||
size_t bidx;
|
||||
unsigned char bits; // bitset
|
||||
|
||||
for (idx=0; idx < N; ++idx)
|
||||
for (bidx=idx=0; idx < N; ++idx, bidx+=8)
|
||||
{
|
||||
bits = static_cast<unsigned char>(_v[idx])
|
||||
| (static_cast<unsigned char>(_v[idx+1]) << 1)
|
||||
| (static_cast<unsigned char>(_v[idx+2]) << 2)
|
||||
| (static_cast<unsigned char>(_v[idx+3]) << 3)
|
||||
| (static_cast<unsigned char>(_v[idx+4]) << 4)
|
||||
| (static_cast<unsigned char>(_v[idx+5]) << 5)
|
||||
| (static_cast<unsigned char>(_v[idx+6]) << 6)
|
||||
| (static_cast<unsigned char>(_v[idx+7]) << 7);
|
||||
bits = static_cast<unsigned char>(_v[bidx])
|
||||
| (static_cast<unsigned char>(_v[bidx+1]) << 1)
|
||||
| (static_cast<unsigned char>(_v[bidx+2]) << 2)
|
||||
| (static_cast<unsigned char>(_v[bidx+3]) << 3)
|
||||
| (static_cast<unsigned char>(_v[bidx+4]) << 4)
|
||||
| (static_cast<unsigned char>(_v[bidx+5]) << 5)
|
||||
| (static_cast<unsigned char>(_v[bidx+6]) << 6)
|
||||
| (static_cast<unsigned char>(_v[bidx+7]) << 7);
|
||||
_ostr << bits;
|
||||
}
|
||||
bytes = N;
|
||||
bytes += N;
|
||||
|
||||
if (R)
|
||||
{
|
||||
bits = 0;
|
||||
switch(R)
|
||||
{
|
||||
case 7: bits |= (static_cast<unsigned char>(_v[idx+6]) << 6);
|
||||
case 6: bits |= (static_cast<unsigned char>(_v[idx+5]) << 5);
|
||||
case 5: bits |= (static_cast<unsigned char>(_v[idx+4]) << 4);
|
||||
case 4: bits |= (static_cast<unsigned char>(_v[idx+3]) << 3);
|
||||
case 3: bits |= (static_cast<unsigned char>(_v[idx+2]) << 2);
|
||||
case 2: bits |= (static_cast<unsigned char>(_v[idx+1]) << 1);
|
||||
case 1: bits |= static_cast<unsigned char>(_v[idx+0]);
|
||||
}
|
||||
for (idx=0; idx < R; ++idx)
|
||||
bits |= static_cast<unsigned char>(_v[bidx+idx]) << idx;
|
||||
_ostr << bits;
|
||||
++bytes;
|
||||
}
|
||||
|
||||
assert( bytes == size_of(_v) );
|
||||
assert( bytes == size_of(_v, _store_size) );
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
static
|
||||
size_t restore( std::istream& _istr, value_type& _v, bool )
|
||||
size_t restore( std::istream& _istr, value_type& _v, bool _swap, bool _restore_size = true)
|
||||
{
|
||||
size_t bytes = 0;
|
||||
|
||||
if(_restore_size)
|
||||
{
|
||||
unsigned int size_of_vec;
|
||||
bytes += binary<unsigned int>::restore(_istr, size_of_vec, _swap);
|
||||
_v.resize(size_of_vec);
|
||||
}
|
||||
|
||||
size_t N = _v.size() / 8;
|
||||
size_t R = _v.size() % 8;
|
||||
|
||||
size_t idx; // element index
|
||||
size_t bidx; //
|
||||
unsigned char bits; // bitset
|
||||
|
||||
for (idx=0; idx < N; ++idx)
|
||||
for (bidx=idx=0; idx < N; ++idx, bidx+=8)
|
||||
{
|
||||
_istr >> bits;
|
||||
_v[idx+0] = ((bits & 0x01)!=0);
|
||||
_v[idx+1] = ((bits & 0x02)!=0);
|
||||
_v[idx+2] = ((bits & 0x04)!=0);
|
||||
_v[idx+3] = ((bits & 0x08)!=0);
|
||||
_v[idx+4] = ((bits & 0x10)!=0);
|
||||
_v[idx+5] = ((bits & 0x20)!=0);
|
||||
_v[idx+6] = ((bits & 0x40)!=0);
|
||||
_v[idx+7] = ((bits & 0x80)!=0);
|
||||
_v[bidx+0] = (bits & 0x01) != 0;
|
||||
_v[bidx+1] = (bits & 0x02) != 0;
|
||||
_v[bidx+2] = (bits & 0x04) != 0;
|
||||
_v[bidx+3] = (bits & 0x08) != 0;
|
||||
_v[bidx+4] = (bits & 0x10) != 0;
|
||||
_v[bidx+5] = (bits & 0x20) != 0;
|
||||
_v[bidx+6] = (bits & 0x40) != 0;
|
||||
_v[bidx+7] = (bits & 0x80) != 0;
|
||||
}
|
||||
bytes = N;
|
||||
bytes += N;
|
||||
|
||||
if (R)
|
||||
{
|
||||
_istr >> bits;
|
||||
for(; idx < _v.size(); ++idx)
|
||||
_v[idx] = (bits & (1 << (idx%8)))!=0;
|
||||
for (idx=0; idx < R; ++idx)
|
||||
_v[bidx+idx] = (bits & (1<<idx)) != 0;
|
||||
++bytes;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
|
||||
#define BINARY_VECTOR( T ) \
|
||||
template <> struct binary< std::vector< T > > { \
|
||||
typedef std::vector< T > value_type; \
|
||||
typedef value_type::value_type elem_type; \
|
||||
\
|
||||
static const bool is_streamable = true; \
|
||||
\
|
||||
static size_t size_of(void) \
|
||||
{ return IO::UnknownSize; } \
|
||||
\
|
||||
static size_t size_of(const value_type& _v) \
|
||||
{ return sizeof(elem_type)*_v.size(); } \
|
||||
\
|
||||
static \
|
||||
size_t store(std::ostream& _os, const value_type& _v, bool _swap=false) { \
|
||||
size_t bytes=0; \
|
||||
\
|
||||
if (_swap) \
|
||||
bytes = std::accumulate( _v.begin(), _v.end(), bytes, \
|
||||
FunctorStore<elem_type>(_os,_swap) ); \
|
||||
else { \
|
||||
bytes = size_of(_v); \
|
||||
_os.write( reinterpret_cast<const char*>(&_v[0]), bytes ); \
|
||||
} \
|
||||
return _os.good() ? bytes : 0; \
|
||||
} \
|
||||
\
|
||||
static size_t restore(std::istream& _is, value_type& _v, bool _swap=false) { \
|
||||
size_t bytes=0; \
|
||||
\
|
||||
if ( _swap) \
|
||||
bytes = std::accumulate( _v.begin(), _v.end(), size_t(0), \
|
||||
FunctorRestore<elem_type>(_is, _swap) ); \
|
||||
else \
|
||||
{ \
|
||||
bytes = size_of(_v); \
|
||||
_is.read( reinterpret_cast<char*>(&_v[0]), bytes ); \
|
||||
} \
|
||||
return _is.good() ? bytes : 0; \
|
||||
} \
|
||||
}
|
||||
|
||||
BINARY_VECTOR( short );
|
||||
BINARY_VECTOR( unsigned short );
|
||||
BINARY_VECTOR( int );
|
||||
BINARY_VECTOR( unsigned int );
|
||||
BINARY_VECTOR( long );
|
||||
BINARY_VECTOR( unsigned long );
|
||||
BINARY_VECTOR( float );
|
||||
BINARY_VECTOR( double );
|
||||
|
||||
#undef BINARY_VECTOR
|
||||
@@ -1,39 +0,0 @@
|
||||
|
||||
template <> struct binary< std::vector< std::string > >
|
||||
{
|
||||
// struct binary interface
|
||||
|
||||
typedef std::vector< std::string > value_type;
|
||||
typedef value_type::value_type elem_type;
|
||||
|
||||
static const bool is_streamable = true;
|
||||
|
||||
// Helper
|
||||
|
||||
struct Sum
|
||||
{
|
||||
size_t operator() ( size_t _v1, const elem_type& _s2 )
|
||||
{ return _v1 + binary<elem_type>::size_of(_s2); }
|
||||
};
|
||||
|
||||
// struct binary interface
|
||||
|
||||
static size_t size_of(void) { return UnknownSize; }
|
||||
|
||||
static size_t size_of(const value_type& _v)
|
||||
{ return std::accumulate( _v.begin(), _v.end(), size_t(0), Sum() ); }
|
||||
|
||||
static
|
||||
size_t store(std::ostream& _os, const value_type& _v, bool _swap=false)
|
||||
{
|
||||
return std::accumulate( _v.begin(), _v.end(), size_t(0),
|
||||
FunctorStore<elem_type>(_os, _swap) );
|
||||
}
|
||||
|
||||
static
|
||||
size_t restore(std::istream& _is, value_type& _v, bool _swap=false)
|
||||
{
|
||||
return std::accumulate( _v.begin(), _v.end(), size_t(0),
|
||||
FunctorRestore<elem_type>(_is, _swap) );
|
||||
}
|
||||
};
|
||||
@@ -89,18 +89,34 @@ template <typename T> inline
|
||||
size_t size_of( const T& _v )
|
||||
{ return binary< T >::size_of(_v); }
|
||||
|
||||
template <typename T> inline
|
||||
size_t size_of( const std::vector<T> & _v, bool _store_size = true)
|
||||
{ return binary< std::vector<T> >::size_of(_v, _store_size); }
|
||||
|
||||
template <typename T> inline
|
||||
size_t size_of(void)
|
||||
{ return binary< T >::size_of(); }
|
||||
|
||||
template <typename T> inline
|
||||
size_t store( std::ostream& _os, const T& _v, bool _swap=false)
|
||||
size_t size_of(bool _store_size)
|
||||
{ return binary< std::vector<T> >::size_of(_store_size); }
|
||||
|
||||
template <typename T> inline
|
||||
size_t store( std::ostream& _os, const T& _v, bool _swap =false)
|
||||
{ return binary< T >::store( _os, _v, _swap ); }
|
||||
|
||||
template <typename T> inline
|
||||
size_t restore( std::istream& _is, T& _v, bool _swap=false)
|
||||
size_t store( std::ostream& _os, const std::vector<T>& _v, bool _swap=false, bool _store_size = true)
|
||||
{ return binary< std::vector<T> >::store( _os, _v, _swap, _store_size); }
|
||||
|
||||
template <typename T> inline
|
||||
size_t restore( std::istream& _is, T& _v, bool _swap = false)
|
||||
{ return binary< T >::restore( _is, _v, _swap ); }
|
||||
|
||||
template <typename T> inline
|
||||
size_t restore( std::istream& _is, std::vector<T>& _v, bool _swap=false, bool _restore_size = true)
|
||||
{ return binary< std::vector<T> >::restore( _is, _v, _swap, _restore_size); }
|
||||
|
||||
//@}
|
||||
|
||||
|
||||
|
||||
@@ -152,6 +152,9 @@ public:
|
||||
// set incident face handle for given halfedge
|
||||
virtual void set_face(HalfedgeHandle _heh, FaceHandle _fh) = 0;
|
||||
|
||||
// request texture coordinate property
|
||||
virtual void request_face_texcoords2D() = 0;
|
||||
|
||||
// set vertex texture coordinate
|
||||
virtual void set_texcoord(HalfedgeHandle _heh, const Vec2f& _texcoord) = 0;
|
||||
|
||||
|
||||
@@ -285,9 +285,14 @@ public:
|
||||
mesh_.set_face_handle(_heh, _fh);
|
||||
}
|
||||
|
||||
virtual void request_face_texcoords2D() override
|
||||
{
|
||||
if(!mesh_.has_halfedge_texcoords2D())
|
||||
mesh_.request_halfedge_texcoords2D();
|
||||
}
|
||||
|
||||
virtual void set_texcoord(HalfedgeHandle _heh, const Vec2f& _texcoord) override
|
||||
{
|
||||
{
|
||||
if (mesh_.has_halfedge_texcoords2D())
|
||||
mesh_.set_texcoord2D(_heh, vector_cast<TexCoord2D>(_texcoord));
|
||||
}
|
||||
|
||||
@@ -57,7 +57,9 @@
|
||||
#include <OpenMesh/Core/IO/OMFormat.hh>
|
||||
#include <OpenMesh/Core/IO/reader/OMReader.hh>
|
||||
#include <OpenMesh/Core/IO/writer/OMWriter.hh>
|
||||
#include <OpenMesh/Core/Utils/typename.hh>
|
||||
|
||||
#include <OpenMesh/Core/Utils/PropertyCreator.hh>
|
||||
|
||||
//=== NAMESPACES ==============================================================
|
||||
|
||||
@@ -180,7 +182,6 @@ bool _OMReader_::read_binary(std::istream& _is, BaseImporter& _bi, Options& _opt
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
while (!_is.eof()) {
|
||||
bytes_ += restore(_is, chunk_header_, swap);
|
||||
|
||||
@@ -400,10 +401,17 @@ bool _OMReader_::read_binary_vertex_chunk(std::istream &_is, BaseImporter &_bi,
|
||||
}
|
||||
|
||||
case Chunk::Type_Custom:
|
||||
{
|
||||
if(header_.version_ > OMFormat::mk_version(2,1))
|
||||
{
|
||||
Chunk::PropertyName property_type;
|
||||
bytes_ += restore(_is, property_type, _swap);
|
||||
add_generic_property(property_type, _bi);
|
||||
}
|
||||
|
||||
bytes_ += restore_binary_custom_data(_is, _bi.kernel()->_get_vprop(property_name_), header_.n_vertices_, _swap);
|
||||
|
||||
vidx = header_.n_vertices_;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
@@ -550,12 +558,20 @@ bool _OMReader_::read_binary_face_chunk(std::istream &_is, BaseImporter &_bi, Op
|
||||
}
|
||||
|
||||
case Chunk::Type_Custom:
|
||||
{
|
||||
if(header_.version_ > OMFormat::mk_version(2,1))
|
||||
{
|
||||
Chunk::PropertyName property_type;
|
||||
bytes_ += restore(_is, property_type, _swap);
|
||||
add_generic_property(property_type, _bi);
|
||||
}
|
||||
|
||||
bytes_ += restore_binary_custom_data(_is, _bi.kernel()->_get_fprop(property_name_), header_.n_faces_, _swap);
|
||||
|
||||
fidx = header_.n_faces_;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default: // skip unknown chunks
|
||||
{
|
||||
@@ -583,11 +599,18 @@ bool _OMReader_::read_binary_edge_chunk(std::istream &_is, BaseImporter &_bi, Op
|
||||
|
||||
switch (chunk_header_.type_) {
|
||||
case Chunk::Type_Custom:
|
||||
{
|
||||
if(header_.version_ > OMFormat::mk_version(2,1))
|
||||
{
|
||||
Chunk::PropertyName property_type;
|
||||
bytes_ += restore(_is, property_type, _swap);
|
||||
add_generic_property(property_type, _bi);
|
||||
}
|
||||
|
||||
bytes_ += restore_binary_custom_data(_is, _bi.kernel()->_get_eprop(property_name_), header_.n_edges_, _swap);
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
case Chunk::Type_Status:
|
||||
{
|
||||
assert( OMFormat::dimensions(chunk_header_) == 1);
|
||||
@@ -626,10 +649,39 @@ bool _OMReader_::read_binary_halfedge_chunk(std::istream &_is, BaseImporter &_bi
|
||||
|
||||
switch (chunk_header_.type_) {
|
||||
case Chunk::Type_Custom:
|
||||
{
|
||||
if(header_.version_ > OMFormat::mk_version(2,1))
|
||||
{
|
||||
Chunk::PropertyName property_type;
|
||||
bytes_ += restore(_is, property_type, _swap);
|
||||
add_generic_property(property_type, _bi);
|
||||
}
|
||||
|
||||
bytes_ += restore_binary_custom_data(_is, _bi.kernel()->_get_hprop(property_name_), 2 * header_.n_edges_, _swap);
|
||||
break;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
case Chunk::Type_Texcoord:
|
||||
{
|
||||
assert( OMFormat::dimensions(chunk_header_) == size_t(OpenMesh::Vec2f::dim()));
|
||||
|
||||
//fileOptions_ += OpenMesh::IO::Options::FaceTexCoord;
|
||||
|
||||
if (_opt.face_has_texcoord())
|
||||
{
|
||||
_bi.request_face_texcoords2D();
|
||||
}
|
||||
OpenMesh::Vec2f v2f;
|
||||
for (size_t e_idx = 0; e_idx < header_.n_edges_*2; ++e_idx)
|
||||
{
|
||||
bytes_ += vector_restore(_is, v2f, _swap);
|
||||
if (_opt.face_has_texcoord())
|
||||
_bi.set_texcoord(HalfedgeHandle(int(e_idx)), v2f);
|
||||
}
|
||||
break;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------
|
||||
case Chunk::Type_Topology:
|
||||
{
|
||||
std::vector<HalfedgeHandle> next_halfedges;
|
||||
@@ -703,11 +755,18 @@ bool _OMReader_::read_binary_mesh_chunk(std::istream &_is, BaseImporter &_bi, Op
|
||||
|
||||
switch (chunk_header_.type_) {
|
||||
case Chunk::Type_Custom:
|
||||
{
|
||||
if(header_.version_ > OMFormat::mk_version(2,1))
|
||||
{
|
||||
Chunk::PropertyName property_type;
|
||||
bytes_ += restore(_is, property_type, _swap);
|
||||
add_generic_property(property_type, _bi);
|
||||
}
|
||||
|
||||
bytes_ += restore_binary_custom_data(_is, _bi.kernel()->_get_mprop(property_name_), 1, _swap);
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
default:
|
||||
// skip unknown chunk
|
||||
size_t chunk_size = OMFormat::chunk_data_size(header_, chunk_header_);
|
||||
@@ -747,14 +806,14 @@ size_t _OMReader_::restore_binary_custom_data(std::istream& _is, BaseProperty* _
|
||||
#endif
|
||||
|
||||
#if defined(OM_DEBUG)
|
||||
assert( block_size == b );
|
||||
assert( block_size == b);
|
||||
#endif
|
||||
|
||||
assert( block_size == _bp->size_of());
|
||||
|
||||
block_size = 0;
|
||||
} else {
|
||||
omerr() << "Warning! Property " << _bp->name() << " not loaded: " << "Mismatching data sizes!n";
|
||||
omerr() << "Warning! Property " << _bp->name() << " not loaded: " << "Mismatching data sizes!" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -767,6 +826,57 @@ size_t _OMReader_::restore_binary_custom_data(std::istream& _is, BaseProperty* _
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------helper
|
||||
void _OMReader_:: add_generic_property(OMFormat::Chunk::PropertyName& _property_type, BaseImporter& _bi) const
|
||||
{
|
||||
// We want to support the old way of restoring properties, ie.
|
||||
// the user has manually created the corresponding property.
|
||||
// In that case the property does not need be registered.
|
||||
// However, the _bi.kerne()->_get_prop(property_name_) checks below
|
||||
// May return a property with the correct name but the wrong type.
|
||||
// For now we will have to live with that.
|
||||
|
||||
|
||||
PropertyCreationManager& manager = PropertyCreationManager::instance();
|
||||
switch (chunk_header_.entity_)
|
||||
{
|
||||
case OMFormat::Chunk::Entity_Vertex:
|
||||
{
|
||||
if (_bi.kernel()->_get_vprop(property_name_) == nullptr)
|
||||
manager.create_property<OpenMesh::VertexHandle>(*_bi.kernel(), _property_type, property_name_);
|
||||
break;
|
||||
}
|
||||
case OMFormat::Chunk::Entity_Face:
|
||||
{
|
||||
if (_bi.kernel()->_get_fprop(property_name_) == nullptr)
|
||||
manager.create_property<OpenMesh::FaceHandle>(*_bi.kernel(), _property_type, property_name_);
|
||||
break;
|
||||
}
|
||||
case OMFormat::Chunk::Entity_Edge:
|
||||
{
|
||||
if (_bi.kernel()->_get_eprop(property_name_) == nullptr)
|
||||
manager.create_property<OpenMesh::EdgeHandle>(*_bi.kernel(), _property_type, property_name_);
|
||||
break;
|
||||
}
|
||||
case OMFormat::Chunk::Entity_Halfedge:
|
||||
{
|
||||
if (_bi.kernel()->_get_hprop(property_name_) == nullptr)
|
||||
manager.create_property<OpenMesh::HalfedgeHandle>(*_bi.kernel(), _property_type, property_name_);
|
||||
break;
|
||||
}
|
||||
case OMFormat::Chunk::Entity_Mesh:
|
||||
{
|
||||
if (_bi.kernel()->_get_mprop(property_name_) == nullptr)
|
||||
manager.create_property<OpenMesh::MeshHandle>(*_bi.kernel(), _property_type, property_name_);
|
||||
break;
|
||||
}
|
||||
case OMFormat::Chunk::Entity_Sentinel:
|
||||
;
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//=============================================================================
|
||||
|
||||
@@ -149,11 +149,14 @@ private:
|
||||
Options &_opt,
|
||||
bool _swap) const;
|
||||
|
||||
size_t restore_binary_custom_data( std::istream& _is,
|
||||
BaseProperty* _bp,
|
||||
size_t _n_elem,
|
||||
bool _swap) const;
|
||||
size_t restore_binary_custom_data(std::istream& _is,
|
||||
BaseProperty* _bp,
|
||||
size_t _n_elem,
|
||||
bool _swap) const;
|
||||
|
||||
//------------------helper
|
||||
private:
|
||||
void add_generic_property(OMFormat::Chunk::PropertyName& _property_type, BaseImporter& _bi) const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ _OMWriter_& OMWriter() { return __OMWriterInstance; }
|
||||
|
||||
|
||||
const OMFormat::uchar _OMWriter_::magic_[3] = "OM";
|
||||
const OMFormat::uint8 _OMWriter_::version_ = OMFormat::mk_version(2,1);
|
||||
const OMFormat::uint8 _OMWriter_::version_ = OMFormat::mk_version(2,2);
|
||||
|
||||
|
||||
_OMWriter_::
|
||||
@@ -303,7 +303,6 @@ bool _OMWriter_::write_binary(std::ostream& _os, BaseExporter& _be,
|
||||
chunk_header.dim_ = OMFormat::dim(t);
|
||||
chunk_header.bits_ = OMFormat::bits(t[0]);
|
||||
|
||||
// std::clog << chunk_header << std::endl;
|
||||
bytes += store(_os, chunk_header, swap);
|
||||
|
||||
for (i = 0, nV = header.n_vertices_; i < nV; ++i)
|
||||
@@ -337,6 +336,30 @@ bool _OMWriter_::write_binary(std::ostream& _os, BaseExporter& _be,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ---------- write face texture coords
|
||||
if (_OMWriter_::version_ > OMFormat::mk_version(2,1) && _be.n_edges() && _opt.check(Options::FaceTexCoord))
|
||||
{
|
||||
|
||||
t = _be.texcoord(HalfedgeHandle(0));
|
||||
|
||||
chunk_header.name_ = false;
|
||||
chunk_header.entity_ = OMFormat::Chunk::Entity_Halfedge;
|
||||
chunk_header.type_ = OMFormat::Chunk::Type_Texcoord;
|
||||
chunk_header.signed_ = OMFormat::is_signed(t[0]);
|
||||
chunk_header.float_ = OMFormat::is_float(t[0]);
|
||||
chunk_header.dim_ = OMFormat::dim(t);
|
||||
chunk_header.bits_ = OMFormat::bits(t[0]);
|
||||
|
||||
bytes += store(_os, chunk_header, swap);
|
||||
|
||||
unsigned int nHE;
|
||||
for (i = 0, nHE = header.n_edges_*2; i < nHE; ++i)
|
||||
bytes += vector_store(_os, _be.texcoord(HalfedgeHandle(i)), swap);
|
||||
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
|
||||
// ---------- write vertex topology (outgoing halfedge)
|
||||
if (_be.n_vertices())
|
||||
{
|
||||
@@ -573,7 +596,7 @@ bool _OMWriter_::write_binary(std::ostream& _os, BaseExporter& _be,
|
||||
chunk_header.entity_ = OMFormat::Chunk::Entity_Sentinel;
|
||||
bytes += store(_os, chunk_header, swap);
|
||||
|
||||
// std::clog << "#bytes written: " << bytes << std::endl;
|
||||
omlog() << "#bytes written: " << bytes << std::endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -581,7 +604,7 @@ bool _OMWriter_::write_binary(std::ostream& _os, BaseExporter& _be,
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
size_t _OMWriter_::store_binary_custom_chunk(std::ostream& _os,
|
||||
const BaseProperty& _bp,
|
||||
BaseProperty& _bp,
|
||||
OMFormat::Chunk::Entity _entity,
|
||||
bool _swap) const
|
||||
{
|
||||
@@ -620,16 +643,22 @@ size_t _OMWriter_::store_binary_custom_chunk(std::ostream& _os,
|
||||
// 2. property name
|
||||
bytes += store( _os, OMFormat::Chunk::PropertyName(_bp.name()), _swap );
|
||||
|
||||
// 3. block size
|
||||
bytes += store( _os, _bp.size_of(), OMFormat::Chunk::Integer_32, _swap );
|
||||
//omlog() << " n_bytes = " << _bp.size_of() << std::endl;
|
||||
// 3. data type needed to add property automatically, supported by version 2.1 or later
|
||||
if(_OMWriter_::version_ > OMFormat::mk_version(2,1))
|
||||
{
|
||||
OMFormat::Chunk::PropertyName type = OMFormat::Chunk::PropertyName(_bp.get_storage_name());
|
||||
bytes += store(_os, type, _swap);
|
||||
}
|
||||
|
||||
// 4. data
|
||||
// 4. block size
|
||||
bytes += store( _os, _bp.size_of(), OMFormat::Chunk::Integer_32, _swap );
|
||||
//omlog() << " block size = " << _bp.size_of() << std::endl;
|
||||
|
||||
// 5. data
|
||||
{
|
||||
size_t b;
|
||||
bytes += ( b=_bp.store( _os, _swap ) );
|
||||
//omlog() << " b = " << b << std::endl;
|
||||
assert( b == _bp.size_of() );
|
||||
assert(b == _bp.size_of());
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@@ -121,8 +121,8 @@ protected:
|
||||
bool write_binary(std::ostream&, BaseExporter&, Options) const;
|
||||
|
||||
|
||||
size_t store_binary_custom_chunk( std::ostream&, const BaseProperty&,
|
||||
OMFormat::Chunk::Entity, bool) const;
|
||||
size_t store_binary_custom_chunk(std::ostream&, BaseProperty&,
|
||||
OMFormat::Chunk::Entity, bool) const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -133,6 +133,9 @@ public: // I/O support
|
||||
/// persistency.
|
||||
virtual void set_persistent( bool _yn ) = 0;
|
||||
|
||||
///returns a unique string for the type of the elements
|
||||
virtual std::string get_storage_name() const = 0;
|
||||
|
||||
/// Number of elements in property
|
||||
virtual size_t n_elements() const = 0;
|
||||
|
||||
|
||||
@@ -41,9 +41,9 @@
|
||||
|
||||
|
||||
|
||||
#ifndef OPENMESH_PROPERTY_HH
|
||||
#define OPENMESH_PROPERTY_HH
|
||||
|
||||
//#ifndef OPENMESH_PROPERTY_HH
|
||||
//#define OPENMESH_PROPERTY_HH
|
||||
#pragma once
|
||||
|
||||
//== INCLUDES =================================================================
|
||||
|
||||
@@ -55,6 +55,9 @@
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
#include <OpenMesh/Core/IO/SR_store.hh>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
//== NAMESPACES ===============================================================
|
||||
|
||||
@@ -147,21 +150,23 @@ public:
|
||||
|
||||
virtual size_t store( std::ostream& _ostr, bool _swap ) const override
|
||||
{
|
||||
if ( IO::is_streamable<vector_type>() )
|
||||
return IO::store(_ostr, data_, _swap );
|
||||
if (IO::is_streamable<vector_type>() && element_size() != IO::UnknownSize)
|
||||
return IO::store(_ostr, data_, _swap, false); //does not need to store its length
|
||||
|
||||
size_t bytes = 0;
|
||||
for (size_t i=0; i<n_elements(); ++i)
|
||||
bytes += IO::store( _ostr, data_[i], _swap );
|
||||
bytes += IO::store( _ostr, data_[i], _swap);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
virtual size_t restore( std::istream& _istr, bool _swap ) override
|
||||
{
|
||||
if ( IO::is_streamable<vector_type>() )
|
||||
return IO::restore(_istr, data_, _swap );
|
||||
if ( IO::is_streamable<vector_type>() && element_size() != IO::UnknownSize)
|
||||
return IO::restore(_istr, data_, _swap, false); //does not need to restore its length
|
||||
|
||||
size_t bytes = 0;
|
||||
for (size_t i=0; i<n_elements(); ++i)
|
||||
bytes += IO::restore( _istr, data_[i], _swap );
|
||||
bytes += IO::restore( _istr, data_[i], _swap);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@@ -207,6 +212,10 @@ public: // data access interface
|
||||
return p;
|
||||
}
|
||||
|
||||
std::string get_storage_name() const override
|
||||
{
|
||||
return OpenMesh::IO::binary<T>::type_identifier();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -371,6 +380,11 @@ public:
|
||||
return p;
|
||||
}
|
||||
|
||||
std::string get_storage_name() const override
|
||||
{
|
||||
return OpenMesh::IO::binary<bool>::type_identifier();
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
@@ -381,88 +395,6 @@ private:
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
/** Property specialization for std::string type.
|
||||
*/
|
||||
template <>
|
||||
class PropertyT<std::string> : public BaseProperty
|
||||
{
|
||||
public:
|
||||
|
||||
typedef std::string Value;
|
||||
typedef std::vector<std::string> vector_type;
|
||||
typedef std::string value_type;
|
||||
typedef vector_type::reference reference;
|
||||
typedef vector_type::const_reference const_reference;
|
||||
|
||||
public:
|
||||
|
||||
explicit PropertyT(const std::string& _name = "<unknown>", const std::string& _internal_type_name="" )
|
||||
: BaseProperty(_name, _internal_type_name)
|
||||
{ }
|
||||
|
||||
public: // inherited from BaseProperty
|
||||
|
||||
virtual void reserve(size_t _n) override { data_.reserve(_n); }
|
||||
virtual void resize(size_t _n) override { data_.resize(_n); }
|
||||
virtual void clear() override { data_.clear(); vector_type().swap(data_); }
|
||||
virtual void push_back() override { data_.push_back(std::string()); }
|
||||
virtual void swap(size_t _i0, size_t _i1) override {
|
||||
std::swap(data_[_i0], data_[_i1]);
|
||||
}
|
||||
virtual void copy(size_t _i0, size_t _i1) override
|
||||
{ data_[_i1] = data_[_i0]; }
|
||||
|
||||
public:
|
||||
|
||||
virtual void set_persistent( bool _yn ) override
|
||||
{ check_and_set_persistent<std::string>( _yn ); }
|
||||
|
||||
virtual size_t n_elements() const override { return data_.size(); }
|
||||
virtual size_t element_size() const override { return UnknownSize; }
|
||||
virtual size_t size_of() const override
|
||||
{ return IO::size_of( data_ ); }
|
||||
|
||||
virtual size_t size_of(size_t /* _n_elem */) const override
|
||||
{ return UnknownSize; }
|
||||
|
||||
/// Store self as one binary block. Max. length of a string is 65535 bytes.
|
||||
size_t store( std::ostream& _ostr, bool _swap ) const override
|
||||
{ return IO::store( _ostr, data_, _swap ); }
|
||||
|
||||
size_t restore( std::istream& _istr, bool _swap ) override
|
||||
{ return IO::restore( _istr, data_, _swap ); }
|
||||
|
||||
public:
|
||||
|
||||
const value_type* data() const {
|
||||
if( data_.empty() )
|
||||
return nullptr;
|
||||
|
||||
return (value_type*) &data_[0];
|
||||
}
|
||||
|
||||
/// Access the i'th element. No range check is performed!
|
||||
reference operator[](int _idx) {
|
||||
assert( size_t(_idx) < data_.size());
|
||||
return ((value_type*) &data_[0])[_idx];
|
||||
}
|
||||
|
||||
/// Const access the i'th element. No range check is performed!
|
||||
const_reference operator[](int _idx) const {
|
||||
assert( size_t(_idx) < data_.size());
|
||||
return ((value_type*) &data_[0])[_idx];
|
||||
}
|
||||
|
||||
PropertyT<value_type>* clone() const override {
|
||||
PropertyT<value_type>* p = new PropertyT<value_type>( *this );
|
||||
return p;
|
||||
}
|
||||
private:
|
||||
|
||||
vector_type data_;
|
||||
|
||||
};
|
||||
|
||||
/// Base property handle.
|
||||
template <class T>
|
||||
struct BasePropHandleT : public BaseHandle
|
||||
@@ -578,7 +510,13 @@ struct PropHandle<FaceHandle> {
|
||||
using type = FPropHandleT<T>;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct PropHandle<MeshHandle> {
|
||||
template <typename T>
|
||||
using type = MPropHandleT<T>;
|
||||
};
|
||||
|
||||
} // namespace OpenMesh
|
||||
//=============================================================================
|
||||
#endif // OPENMESH_PROPERTY_HH defined
|
||||
//#endif // OPENMESH_PROPERTY_HH defined
|
||||
//=============================================================================
|
||||
|
||||
153
src/OpenMesh/Core/Utils/PropertyCreator.cc
Normal file
153
src/OpenMesh/Core/Utils/PropertyCreator.cc
Normal file
@@ -0,0 +1,153 @@
|
||||
/* ========================================================================= *
|
||||
* *
|
||||
* OpenMesh *
|
||||
* Copyright (c) 2001-2020, RWTH-Aachen University *
|
||||
* Department of Computer Graphics and Multimedia *
|
||||
* All rights reserved. *
|
||||
* www.openmesh.org *
|
||||
* *
|
||||
*---------------------------------------------------------------------------*
|
||||
* This file is part of OpenMesh. *
|
||||
*---------------------------------------------------------------------------*
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or without *
|
||||
* modification, are permitted provided that the following conditions *
|
||||
* are met: *
|
||||
* *
|
||||
* 1. Redistributions of source code must retain the above copyright notice, *
|
||||
* this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* 2. Redistributions in binary form must reproduce the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer in the *
|
||||
* documentation and/or other materials provided with the distribution. *
|
||||
* *
|
||||
* 3. Neither the name of the copyright holder nor the names of its *
|
||||
* contributors may be used to endorse or promote products derived from *
|
||||
* this software without specific prior written permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
* *
|
||||
* ========================================================================= */
|
||||
|
||||
#include "PropertyCreator.hh"
|
||||
|
||||
#include <OpenMesh/Core/IO/importer/BaseImporter.hh>
|
||||
#include <OpenMesh/Core/Mesh/Handles.hh>
|
||||
#include <OpenMesh/Core/Geometry/VectorT.hh>
|
||||
#include <OpenMesh/Core/IO/SR_types.hh>
|
||||
|
||||
|
||||
namespace OpenMesh {
|
||||
|
||||
PropertyCreationManager& PropertyCreationManager::instance()
|
||||
{
|
||||
static PropertyCreationManager manager;
|
||||
return manager;
|
||||
}
|
||||
|
||||
bool PropertyCreator::can_you_create(const std::string& _type_name)
|
||||
{
|
||||
return _type_name == type_string();
|
||||
}
|
||||
|
||||
|
||||
} /* namespace OpenMesh */
|
||||
|
||||
OM_REGISTER_PROPERTY_TYPE(FaceHandle)
|
||||
OM_REGISTER_PROPERTY_TYPE(EdgeHandle)
|
||||
OM_REGISTER_PROPERTY_TYPE(HalfedgeHandle)
|
||||
OM_REGISTER_PROPERTY_TYPE(VertexHandle)
|
||||
OM_REGISTER_PROPERTY_TYPE(MeshHandle)
|
||||
|
||||
OM_REGISTER_PROPERTY_TYPE(bool)
|
||||
OM_REGISTER_PROPERTY_TYPE(float)
|
||||
OM_REGISTER_PROPERTY_TYPE(double)
|
||||
OM_REGISTER_PROPERTY_TYPE(long double)
|
||||
OM_REGISTER_PROPERTY_TYPE(char)
|
||||
OM_REGISTER_PROPERTY_TYPE(OpenMesh::IO::int8_t )
|
||||
OM_REGISTER_PROPERTY_TYPE(OpenMesh::IO::int16_t )
|
||||
OM_REGISTER_PROPERTY_TYPE(OpenMesh::IO::int32_t )
|
||||
//OM_REGISTER_PROPERTY_TYPE(OpenMesh::IO::int64_t )
|
||||
OM_REGISTER_PROPERTY_TYPE(OpenMesh::IO::uint8_t )
|
||||
OM_REGISTER_PROPERTY_TYPE(OpenMesh::IO::uint16_t)
|
||||
OM_REGISTER_PROPERTY_TYPE(OpenMesh::IO::uint32_t)
|
||||
OM_REGISTER_PROPERTY_TYPE(OpenMesh::IO::uint64_t)
|
||||
OM_REGISTER_PROPERTY_TYPE(std::string)
|
||||
|
||||
OM_REGISTER_PROPERTY_TYPE(std::vector<bool>)
|
||||
OM_REGISTER_PROPERTY_TYPE(std::vector<float>)
|
||||
OM_REGISTER_PROPERTY_TYPE(std::vector<double>)
|
||||
OM_REGISTER_PROPERTY_TYPE(std::vector<long double>)
|
||||
OM_REGISTER_PROPERTY_TYPE(std::vector<char>)
|
||||
OM_REGISTER_PROPERTY_TYPE(std::vector<OpenMesh::IO::int8_t >)
|
||||
OM_REGISTER_PROPERTY_TYPE(std::vector<OpenMesh::IO::int16_t >)
|
||||
OM_REGISTER_PROPERTY_TYPE(std::vector<OpenMesh::IO::int32_t >)
|
||||
OM_REGISTER_PROPERTY_TYPE(std::vector<OpenMesh::IO::uint8_t >)
|
||||
OM_REGISTER_PROPERTY_TYPE(std::vector<OpenMesh::IO::uint16_t>)
|
||||
OM_REGISTER_PROPERTY_TYPE(std::vector<OpenMesh::IO::uint32_t>)
|
||||
OM_REGISTER_PROPERTY_TYPE(std::vector<OpenMesh::IO::uint64_t>)
|
||||
OM_REGISTER_PROPERTY_TYPE(std::vector<std::string>)
|
||||
|
||||
OM_REGISTER_PROPERTY_TYPE(Vec1c);
|
||||
OM_REGISTER_PROPERTY_TYPE(Vec1uc);
|
||||
OM_REGISTER_PROPERTY_TYPE(Vec1s);
|
||||
OM_REGISTER_PROPERTY_TYPE(Vec1us);
|
||||
OM_REGISTER_PROPERTY_TYPE(Vec1i);
|
||||
OM_REGISTER_PROPERTY_TYPE(Vec1ui);
|
||||
OM_REGISTER_PROPERTY_TYPE(Vec1f);
|
||||
OM_REGISTER_PROPERTY_TYPE(Vec1d);
|
||||
|
||||
OM_REGISTER_PROPERTY_TYPE(Vec2c);
|
||||
OM_REGISTER_PROPERTY_TYPE(Vec2uc);
|
||||
OM_REGISTER_PROPERTY_TYPE(Vec2s);
|
||||
OM_REGISTER_PROPERTY_TYPE(Vec2us);
|
||||
OM_REGISTER_PROPERTY_TYPE(Vec2i);
|
||||
OM_REGISTER_PROPERTY_TYPE(Vec2ui);
|
||||
OM_REGISTER_PROPERTY_TYPE(Vec2f);
|
||||
OM_REGISTER_PROPERTY_TYPE(Vec2d);
|
||||
|
||||
OM_REGISTER_PROPERTY_TYPE(Vec3c);
|
||||
OM_REGISTER_PROPERTY_TYPE(Vec3uc);
|
||||
OM_REGISTER_PROPERTY_TYPE(Vec3s);
|
||||
OM_REGISTER_PROPERTY_TYPE(Vec3us);
|
||||
OM_REGISTER_PROPERTY_TYPE(Vec3i);
|
||||
OM_REGISTER_PROPERTY_TYPE(Vec3ui);
|
||||
OM_REGISTER_PROPERTY_TYPE(Vec3f);
|
||||
OM_REGISTER_PROPERTY_TYPE(Vec3d);
|
||||
|
||||
OM_REGISTER_PROPERTY_TYPE(Vec4c);
|
||||
OM_REGISTER_PROPERTY_TYPE(Vec4uc);
|
||||
OM_REGISTER_PROPERTY_TYPE(Vec4s);
|
||||
OM_REGISTER_PROPERTY_TYPE(Vec4us);
|
||||
OM_REGISTER_PROPERTY_TYPE(Vec4i);
|
||||
OM_REGISTER_PROPERTY_TYPE(Vec4ui);
|
||||
OM_REGISTER_PROPERTY_TYPE(Vec4f);
|
||||
OM_REGISTER_PROPERTY_TYPE(Vec4d);
|
||||
|
||||
OM_REGISTER_PROPERTY_TYPE(Vec5c);
|
||||
OM_REGISTER_PROPERTY_TYPE(Vec5uc);
|
||||
OM_REGISTER_PROPERTY_TYPE(Vec5s);
|
||||
OM_REGISTER_PROPERTY_TYPE(Vec5us);
|
||||
OM_REGISTER_PROPERTY_TYPE(Vec5i);
|
||||
OM_REGISTER_PROPERTY_TYPE(Vec5ui);
|
||||
OM_REGISTER_PROPERTY_TYPE(Vec5f);
|
||||
OM_REGISTER_PROPERTY_TYPE(Vec5d);
|
||||
|
||||
OM_REGISTER_PROPERTY_TYPE(Vec6c);
|
||||
OM_REGISTER_PROPERTY_TYPE(Vec6uc);
|
||||
OM_REGISTER_PROPERTY_TYPE(Vec6s);
|
||||
OM_REGISTER_PROPERTY_TYPE(Vec6us);
|
||||
OM_REGISTER_PROPERTY_TYPE(Vec6i);
|
||||
OM_REGISTER_PROPERTY_TYPE(Vec6ui);
|
||||
OM_REGISTER_PROPERTY_TYPE(Vec6f);
|
||||
OM_REGISTER_PROPERTY_TYPE(Vec6d);
|
||||
242
src/OpenMesh/Core/Utils/PropertyCreator.hh
Normal file
242
src/OpenMesh/Core/Utils/PropertyCreator.hh
Normal file
@@ -0,0 +1,242 @@
|
||||
/* ========================================================================= *
|
||||
* *
|
||||
* OpenMesh *
|
||||
* Copyright (c) 2001-2020, RWTH-Aachen University *
|
||||
* Department of Computer Graphics and Multimedia *
|
||||
* All rights reserved. *
|
||||
* www.openmesh.org *
|
||||
* *
|
||||
*---------------------------------------------------------------------------*
|
||||
* This file is part of OpenMesh. *
|
||||
*---------------------------------------------------------------------------*
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or without *
|
||||
* modification, are permitted provided that the following conditions *
|
||||
* are met: *
|
||||
* *
|
||||
* 1. Redistributions of source code must retain the above copyright notice, *
|
||||
* this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* 2. Redistributions in binary form must reproduce the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer in the *
|
||||
* documentation and/or other materials provided with the distribution. *
|
||||
* *
|
||||
* 3. Neither the name of the copyright holder nor the names of its *
|
||||
* contributors may be used to endorse or promote products derived from *
|
||||
* this software without specific prior written permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
* *
|
||||
* ========================================================================= */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <OpenMesh/Core/System/config.h>
|
||||
#include <OpenMesh/Core/Utils/HandleToPropHandle.hh>
|
||||
#include <OpenMesh/Core/Utils/PropertyManager.hh>
|
||||
#include <OpenMesh/Core/Mesh/PolyConnectivity.hh>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
#include <OpenMesh/Core/IO/SR_store.hh>
|
||||
|
||||
|
||||
namespace OpenMesh {
|
||||
|
||||
#define OM_CONCAT_IMPL(a, b) a##b
|
||||
#define OM_CONCAT(a, b) OM_CONCAT_IMPL(a, b)
|
||||
|
||||
/** \brief Base class for property creators
|
||||
*
|
||||
* A PropertyCreator can add a named property to a mesh.
|
||||
* The type of the property is specified in the classes derived from this class.
|
||||
*
|
||||
* */
|
||||
class OPENMESHDLLEXPORT PropertyCreator
|
||||
{
|
||||
public:
|
||||
|
||||
/// The string that corresponds to the type this property creator can create
|
||||
virtual std::string type_string() = 0;
|
||||
|
||||
virtual std::string type_id_string() = 0;
|
||||
|
||||
/// Returns true iff the given _type_name corresponds to the string the derived class can create a property for
|
||||
bool can_you_create(const std::string &_type_name);
|
||||
|
||||
/// Create a vertex property on _mesh with name _property_name
|
||||
virtual void create_vertex_property (BaseKernel& _mesh, const std::string& _property_name) = 0;
|
||||
|
||||
/// Create a halfedge property on _mesh with name _property_name
|
||||
virtual void create_halfedge_property(BaseKernel& _mesh, const std::string& _property_name) = 0;
|
||||
|
||||
/// Create an edge property on _mesh with name _property_name
|
||||
virtual void create_edge_property (BaseKernel& _mesh, const std::string& _property_name) = 0;
|
||||
|
||||
/// Create a face property on _mesh with name _property_name
|
||||
virtual void create_face_property (BaseKernel& _mesh, const std::string& _property_name) = 0;
|
||||
|
||||
/// Create a mesh property on _mesh with name _property_name
|
||||
virtual void create_mesh_property (BaseKernel& _mesh, const std::string& _property_name) = 0;
|
||||
|
||||
|
||||
/// Create a property for the element of type HandleT on _mesh with name _property_name
|
||||
template <typename HandleT>
|
||||
void create_property(BaseKernel& _mesh, const std::string& _property_name);
|
||||
|
||||
virtual ~PropertyCreator() {}
|
||||
|
||||
protected:
|
||||
PropertyCreator() {}
|
||||
|
||||
};
|
||||
|
||||
template <> inline void PropertyCreator::create_property<VertexHandle> (BaseKernel& _mesh, const std::string& _property_name) { create_vertex_property (_mesh, _property_name); }
|
||||
template <> inline void PropertyCreator::create_property<HalfedgeHandle>(BaseKernel& _mesh, const std::string& _property_name) { create_halfedge_property(_mesh, _property_name); }
|
||||
template <> inline void PropertyCreator::create_property<EdgeHandle> (BaseKernel& _mesh, const std::string& _property_name) { create_edge_property (_mesh, _property_name); }
|
||||
template <> inline void PropertyCreator::create_property<FaceHandle> (BaseKernel& _mesh, const std::string& _property_name) { create_face_property (_mesh, _property_name); }
|
||||
template <> inline void PropertyCreator::create_property<MeshHandle> (BaseKernel& _mesh, const std::string& _property_name) { create_mesh_property (_mesh, _property_name); }
|
||||
|
||||
/// Helper class that contains the implementation of the create_<HandleT>_property methods.
|
||||
/// Implementation is injected into PropertyCreatorT.
|
||||
template <typename PropertyCreatorT>
|
||||
class PropertyCreatorImpl : public PropertyCreator
|
||||
{
|
||||
public:
|
||||
std::string type_id_string() override { return get_type_name<typename PropertyCreatorT::type>(); }
|
||||
|
||||
template <typename HandleT, typename PropT>
|
||||
void create_prop(BaseKernel& _mesh, const std::string& _property_name)
|
||||
{
|
||||
using PHandle = typename PropHandle<HandleT>::template type<PropT>;
|
||||
PHandle prop;
|
||||
if (!_mesh.get_property_handle(prop, _property_name))
|
||||
_mesh.add_property(prop, _property_name);
|
||||
}
|
||||
|
||||
void create_vertex_property (BaseKernel& _mesh, const std::string& _property_name) override { create_prop<VertexHandle , typename PropertyCreatorT::type>(_mesh, _property_name); }
|
||||
void create_halfedge_property(BaseKernel& _mesh, const std::string& _property_name) override { create_prop<HalfedgeHandle, typename PropertyCreatorT::type>(_mesh, _property_name);}
|
||||
void create_edge_property (BaseKernel& _mesh, const std::string& _property_name) override { create_prop<EdgeHandle , typename PropertyCreatorT::type>(_mesh, _property_name);}
|
||||
void create_face_property (BaseKernel& _mesh, const std::string& _property_name) override { create_prop<FaceHandle , typename PropertyCreatorT::type>(_mesh, _property_name);}
|
||||
void create_mesh_property (BaseKernel& _mesh, const std::string& _property_name) override { create_prop<MeshHandle , typename PropertyCreatorT::type>(_mesh, _property_name);}
|
||||
|
||||
~PropertyCreatorImpl() override {}
|
||||
protected:
|
||||
PropertyCreatorImpl() {}
|
||||
};
|
||||
|
||||
/// Actual PropertyCreators specialize this class in order to add properties of type T
|
||||
namespace {
|
||||
template <typename T>
|
||||
class PropertyCreatorT : public PropertyCreatorImpl<PropertyCreatorT<T>>
|
||||
{
|
||||
};
|
||||
}
|
||||
|
||||
///used to register custom type, where typename.hh does provide a string for type recognition
|
||||
|
||||
#define OM_REGISTER_PROPERTY_TYPE(ClassName) \
|
||||
namespace OpenMesh { \
|
||||
namespace { /* ensure internal linkage of class */ \
|
||||
template <> \
|
||||
class PropertyCreatorT<ClassName> : public PropertyCreatorImpl<PropertyCreatorT<ClassName>> \
|
||||
{ \
|
||||
public: \
|
||||
using type = ClassName; \
|
||||
std::string type_string() override { return OpenMesh::IO::binary<type>::type_identifier(); } \
|
||||
\
|
||||
PropertyCreatorT() \
|
||||
{ \
|
||||
PropertyCreationManager::instance().register_property_creator(this); \
|
||||
} \
|
||||
~PropertyCreatorT() override {} \
|
||||
}; \
|
||||
} \
|
||||
/* static to ensure internal linkage of object */ \
|
||||
static PropertyCreatorT<ClassName> OM_CONCAT(property_creator_registration_object_, __LINE__); \
|
||||
}
|
||||
|
||||
/** \brief Class for adding properties based on strings
|
||||
*
|
||||
* The PropertyCreationManager holds all PropertyCreators and dispatches the property creation
|
||||
* to them if they are able to create a property for a given string.
|
||||
*
|
||||
* If you want to be able to store your custom properties into a file and automatically load
|
||||
* them without manually adding the property yourself you can register your type by calling the
|
||||
* OM_REGISTER_PROPERTY_TYPE(ClassName, TypeString)
|
||||
* */
|
||||
class OPENMESHDLLEXPORT PropertyCreationManager
|
||||
{
|
||||
public:
|
||||
|
||||
static PropertyCreationManager& instance();
|
||||
|
||||
template <typename HandleT>
|
||||
void create_property(BaseKernel& _mesh, const std::string& _type_name, const std::string& _property_name)
|
||||
{
|
||||
|
||||
auto can_create = [_type_name](OpenMesh::PropertyCreator* pc){
|
||||
return pc->can_you_create(_type_name);
|
||||
};
|
||||
|
||||
std::vector<OpenMesh::PropertyCreator*>::iterator pc_iter = std::find_if(property_creators_.begin(),
|
||||
property_creators_.end(), can_create);
|
||||
if (pc_iter != property_creators_.end())
|
||||
{
|
||||
const auto& pc = *pc_iter;
|
||||
pc->create_property<HandleT>(_mesh, _property_name);
|
||||
return;
|
||||
}
|
||||
|
||||
omerr() << "No property creator registered that can create a property of type " << _type_name << std::endl;
|
||||
omerr() << "You need to register your custom type using OM_REGISTER_PROPERTY_TYPE(ClassName) and declare the struct binary<ClassName>.\
|
||||
See documentation for more details." << std::endl;
|
||||
omerr() << "Adding property failed." << std::endl;
|
||||
}
|
||||
|
||||
void register_property_creator(PropertyCreator* _property_creator)
|
||||
{
|
||||
for (auto pc : property_creators_)
|
||||
if (pc->type_string() == _property_creator->type_string())
|
||||
{
|
||||
if (pc->type_id_string() != _property_creator->type_id_string())
|
||||
{
|
||||
omerr() << "And it looks like you are trying to add a different type with an already existing string identification." << std::endl;
|
||||
omerr() << "Type id of existing type is " << pc->type_id_string() << " trying to add for " << _property_creator->type_id_string() << std::endl;
|
||||
}
|
||||
return;
|
||||
}
|
||||
property_creators_.push_back(_property_creator);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
PropertyCreationManager() {}
|
||||
~PropertyCreationManager() {}
|
||||
|
||||
std::vector<PropertyCreator*> property_creators_;
|
||||
};
|
||||
|
||||
/** \brief Create a property with type corresponding to _type_name on _mesh with name _property_name
|
||||
*
|
||||
* For user defined types you need to register the type using OM_REGISTER_PROPERTY_TYPE(ClassName, TypeString)
|
||||
* */
|
||||
template <typename HandleT>
|
||||
void create_property_from_string(BaseKernel& _mesh, const std::string& _type_name, const std::string& _property_name)
|
||||
{
|
||||
PropertyCreationManager::instance().create_property<HandleT>(_mesh, _type_name, _property_name);
|
||||
}
|
||||
|
||||
} /* namespace OpenMesh */
|
||||
@@ -207,7 +207,7 @@ class PropertyManager {
|
||||
*
|
||||
* @param mesh The mesh on which to create the property.
|
||||
*/
|
||||
PropertyManager(const PolyConnectivity& mesh) : mesh_(mesh), retain_(false), name_("") {
|
||||
explicit PropertyManager(const PolyConnectivity& mesh) : mesh_(mesh), retain_(false), name_("") {
|
||||
PropertyManager::mesh().add_property(prop_, name_);
|
||||
}
|
||||
|
||||
@@ -630,7 +630,7 @@ public:
|
||||
using value_type = typename PropertyT::value_type;
|
||||
using Handle = typename PropertyT::Handle;
|
||||
|
||||
ConstPropertyViewer(const PolyConnectivity& mesh, PropertyT property_handle)
|
||||
ConstPropertyViewer(const PolyConnectivity& mesh, const PropertyT& property_handle)
|
||||
:
|
||||
mesh_(mesh),
|
||||
prop_(property_handle)
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
|
||||
#include <string>
|
||||
#include <typeinfo>
|
||||
#include <vector>
|
||||
#include <OpenMesh/Core/Mesh/Handles.hh>
|
||||
#include <OpenMesh/Core/Geometry/VectorT.hh>
|
||||
|
||||
namespace OpenMesh {
|
||||
|
||||
@@ -23,4 +26,4 @@ std::string get_type_name()
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
}//namespace OpenMesh
|
||||
|
||||
BIN
src/Unittests/TestFiles/cube_tri_with_properties_2_1.om
Normal file
BIN
src/Unittests/TestFiles/cube_tri_with_properties_2_1.om
Normal file
Binary file not shown.
@@ -878,4 +878,24 @@ TEST_F(OpenMeshPropertyManager, mesh_property_initialization) {
|
||||
|
||||
|
||||
|
||||
|
||||
TEST_F(OpenMeshPropertyManager, property_without_default_constructor ) {
|
||||
|
||||
// just check if this compiles
|
||||
|
||||
struct NoDefaultConstructor
|
||||
{
|
||||
int val;
|
||||
NoDefaultConstructor() = delete;
|
||||
NoDefaultConstructor(int i) : val(i) {}
|
||||
};
|
||||
|
||||
OpenMesh::VProp<std::vector<NoDefaultConstructor>> vprop(mesh_);
|
||||
OpenMesh::HProp<std::vector<NoDefaultConstructor>> hprop(mesh_);
|
||||
OpenMesh::EProp<std::vector<NoDefaultConstructor>> eprop(mesh_);
|
||||
OpenMesh::FProp<std::vector<NoDefaultConstructor>> fprop(mesh_);
|
||||
OpenMesh::MProp<std::vector<NoDefaultConstructor>> mprop(mesh_);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,68 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <Unittests/unittests_common.hh>
|
||||
|
||||
#include <OpenMesh/Core/Utils/PropertyManager.hh>
|
||||
#include <OpenMesh/Core/Utils/PropertyCreator.hh>
|
||||
|
||||
struct RegisteredDataType{
|
||||
int ival;
|
||||
double dval;
|
||||
bool bval;
|
||||
OpenMesh::Vec4f vec4fval;
|
||||
RegisteredDataType() : ival(0), dval(0.0) , bval(false), vec4fval(OpenMesh::Vec4f(0,0,0,0)) {}
|
||||
RegisteredDataType(int i) : ival(i), dval(i*1.234567), bval(i%2) , vec4fval(OpenMesh::Vec4f(dval,2*dval,3*dval,4*dval)) {}
|
||||
|
||||
bool operator==(const RegisteredDataType& _other) const
|
||||
{
|
||||
return ival == _other.ival &&
|
||||
dval == _other.dval &&
|
||||
bval == _other.bval &&
|
||||
vec4fval == _other.vec4fval;
|
||||
}
|
||||
};
|
||||
|
||||
namespace OpenMesh
|
||||
{
|
||||
namespace IO
|
||||
{
|
||||
template <> struct binary<RegisteredDataType>
|
||||
{
|
||||
typedef RegisteredDataType 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 std::string type_identifier(void)
|
||||
{
|
||||
return "RegisteredDataType";
|
||||
}
|
||||
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;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -1458,6 +1520,257 @@ TEST_F(OpenMeshReadWriteOM, LoadPolyMeshVersion_2_0) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::string get_type_string(OpenMesh::FaceHandle) { return "Face"; }
|
||||
std::string get_type_string(OpenMesh::EdgeHandle) { return "Edge"; }
|
||||
std::string get_type_string(OpenMesh::HalfedgeHandle) { return "Halfedge"; }
|
||||
std::string get_type_string(OpenMesh::VertexHandle) { return "Vertex"; }
|
||||
|
||||
std::string get_type_string(char) { return "char"; }
|
||||
std::string get_type_string(signed char) { return "signed char"; }
|
||||
std::string get_type_string(double) { return "double"; }
|
||||
std::string get_type_string(float) { return "float"; }
|
||||
std::string get_type_string(int) { return "int"; }
|
||||
std::string get_type_string(short) { return "short"; }
|
||||
std::string get_type_string(unsigned char) { return "unsigned char"; }
|
||||
std::string get_type_string(unsigned int) { return "unsigned int"; }
|
||||
std::string get_type_string(unsigned short) { return "unsigned short"; }
|
||||
std::string get_type_string(bool) { return "bool"; }
|
||||
std::string get_type_string(std::string) { return "string"; }
|
||||
std::string get_type_string(RegisteredDataType) { return "RegisteredDataType"; }
|
||||
|
||||
template <typename T>
|
||||
std::string get_type_string(std::vector<T>) { return "std::vector of " + get_type_string(T()); }
|
||||
|
||||
template <typename T, int Dim>
|
||||
std::string get_type_string(OpenMesh::VectorT<T, Dim>) { return "OM vector of dimension " + std::to_string(Dim) + " of type " + get_type_string(T()); }
|
||||
|
||||
template <typename T>
|
||||
T get_value(int seed, T, int seed2 = 0)
|
||||
{
|
||||
return (seed * 3 + seed2) % 20;
|
||||
}
|
||||
|
||||
std::string get_value(int seed, std::string, int seed2 = 0)
|
||||
{
|
||||
return std::to_string((seed * 3 + seed2) % 20);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::vector<T> get_value(int seed, const std::vector<T>&, int _offset = 0)
|
||||
{
|
||||
int size = get_value(seed, 3);
|
||||
std::vector<T> res(size);
|
||||
for (int i = 0; i < size; ++i)
|
||||
res[i] = get_value(seed, T(), i + _offset);
|
||||
return res;
|
||||
}
|
||||
|
||||
template <typename T, int Dim>
|
||||
OpenMesh::VectorT<T, Dim> get_value(int seed, const OpenMesh::VectorT<T, Dim>&)
|
||||
{
|
||||
OpenMesh::VectorT<T, Dim> res;
|
||||
for (int i = 0; i < Dim; ++i)
|
||||
res[i] = get_value(seed, T(), i);
|
||||
return res;
|
||||
}
|
||||
|
||||
template <typename MeshT, typename HandleT, typename T>
|
||||
OpenMesh::Prop<HandleT, T> add_property(MeshT& _mesh)
|
||||
{
|
||||
std::string name = get_type_string(HandleT()) + ": " + get_type_string(T());
|
||||
OpenMesh::Prop<HandleT, T> prop(_mesh, name.c_str());
|
||||
_mesh.property(prop.getRawProperty()).set_persistent(true);
|
||||
for (auto e : _mesh.template elements<HandleT>())
|
||||
prop[e] = get_value(e.idx(), T());
|
||||
|
||||
return prop;
|
||||
}
|
||||
|
||||
template <typename MeshT, typename HandleT, typename T>
|
||||
void check_property(MeshT& _mesh)
|
||||
{
|
||||
std::string name = get_type_string(HandleT()) + ": " + get_type_string(T());
|
||||
bool has_prop = OpenMesh::hasProperty<HandleT, T>(_mesh, name.c_str());
|
||||
EXPECT_TRUE(has_prop) << "Property " << name << " is not available";
|
||||
if (!has_prop)
|
||||
return;
|
||||
OpenMesh::Prop<HandleT, T> prop(_mesh, name.c_str());
|
||||
for (auto e : _mesh.template elements<HandleT>())
|
||||
EXPECT_EQ(prop[e], get_value(e.idx(), T())) << "For property " << name;
|
||||
}
|
||||
|
||||
template <typename MeshT, typename HandleT, typename T>
|
||||
void request_property(MeshT& _mesh)
|
||||
{
|
||||
std::string name = get_type_string(HandleT()) + ": " + get_type_string(T());
|
||||
OpenMesh::Prop<HandleT, T> prop(_mesh, name.c_str());
|
||||
}
|
||||
|
||||
|
||||
enum class PropertyAction
|
||||
{
|
||||
Add, Check, Request
|
||||
};
|
||||
|
||||
// For a given Handle and Type add, check or request a property
|
||||
template <typename MeshT, typename HandleT, typename T>
|
||||
void do_property(MeshT& _mesh, PropertyAction action)
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case PropertyAction::Add:
|
||||
add_property<MeshT, HandleT, T>(_mesh);
|
||||
break;
|
||||
case PropertyAction::Check:
|
||||
check_property<MeshT, HandleT, T>(_mesh);
|
||||
break;
|
||||
case PropertyAction::Request:
|
||||
request_property<MeshT, HandleT, T>(_mesh);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// for a given handle do action for OpenMesh Vector of dimension Dim with many differnt types
|
||||
template <typename MeshT, typename HandleT, int Dim>
|
||||
void do_all_property_types_vec(MeshT& _mesh, PropertyAction action)
|
||||
{
|
||||
do_property<MeshT, HandleT, OpenMesh::VectorT<signed char , Dim>>(_mesh, action);
|
||||
do_property<MeshT, HandleT, OpenMesh::VectorT<double , Dim>>(_mesh, action);
|
||||
do_property<MeshT, HandleT, OpenMesh::VectorT<float , Dim>>(_mesh, action);
|
||||
do_property<MeshT, HandleT, OpenMesh::VectorT<int , Dim>>(_mesh, action);
|
||||
do_property<MeshT, HandleT, OpenMesh::VectorT<short , Dim>>(_mesh, action);
|
||||
do_property<MeshT, HandleT, OpenMesh::VectorT<unsigned char , Dim>>(_mesh, action);
|
||||
do_property<MeshT, HandleT, OpenMesh::VectorT<unsigned int , Dim>>(_mesh, action);
|
||||
do_property<MeshT, HandleT, OpenMesh::VectorT<unsigned short, Dim>>(_mesh, action);
|
||||
}
|
||||
|
||||
// for a given handle do action for OpenMesh Vectors of dimensions 1 to 4
|
||||
template <typename MeshT, typename HandleT>
|
||||
void do_all_property_types_vec_all_dim(MeshT& _mesh, PropertyAction action)
|
||||
{
|
||||
do_all_property_types_vec<MeshT, HandleT, 1>(_mesh, action);
|
||||
do_all_property_types_vec<MeshT, HandleT, 2>(_mesh, action);
|
||||
do_all_property_types_vec<MeshT, HandleT, 3>(_mesh, action);
|
||||
do_all_property_types_vec<MeshT, HandleT, 4>(_mesh, action);
|
||||
}
|
||||
|
||||
// for a given handle type do action for many different types
|
||||
template <typename MeshT, typename HandleT>
|
||||
void do_all_property_types(MeshT& _mesh, PropertyAction action, int version)
|
||||
{
|
||||
do_property<MeshT, HandleT, int> (_mesh, action);
|
||||
do_property<MeshT, HandleT, double> (_mesh, action);
|
||||
do_property<MeshT, HandleT, float> (_mesh, action);
|
||||
do_property<MeshT, HandleT, char> (_mesh, action);
|
||||
do_property<MeshT, HandleT, bool> (_mesh, action);
|
||||
do_property<MeshT, HandleT, std::string> (_mesh, action);
|
||||
do_property<MeshT, HandleT, RegisteredDataType> (_mesh, action);
|
||||
|
||||
if(version >= 22)
|
||||
{
|
||||
do_property<MeshT, HandleT, std::vector<int>> (_mesh, action);
|
||||
do_property<MeshT, HandleT, std::vector<double>> (_mesh, action);
|
||||
do_property<MeshT, HandleT, std::vector<float>> (_mesh, action);
|
||||
do_property<MeshT, HandleT, std::vector<char>> (_mesh, action);
|
||||
do_property<MeshT, HandleT, std::vector<bool>> (_mesh, action);
|
||||
do_property<MeshT, HandleT, std::vector<std::string>> (_mesh, action);
|
||||
do_property<MeshT, HandleT, std::vector<RegisteredDataType>> (_mesh, action);
|
||||
|
||||
do_property<MeshT, HandleT, std::vector<std::vector<int>>> (_mesh, action);
|
||||
do_property<MeshT, HandleT, std::vector<std::vector<double>>> (_mesh, action);
|
||||
do_property<MeshT, HandleT, std::vector<std::vector<float>>> (_mesh, action);
|
||||
do_property<MeshT, HandleT, std::vector<std::vector<char>>> (_mesh, action);
|
||||
do_property<MeshT, HandleT, std::vector<std::vector<bool>>> (_mesh, action);
|
||||
do_property<MeshT, HandleT, std::vector<std::vector<std::string>>> (_mesh, action);
|
||||
do_property<MeshT, HandleT, std::vector<std::vector<RegisteredDataType>>> (_mesh, action);
|
||||
|
||||
do_property<MeshT, HandleT, std::vector<std::vector<std::vector<int>>>> (_mesh, action);
|
||||
do_property<MeshT, HandleT, std::vector<std::vector<std::vector<double>>>> (_mesh, action);
|
||||
do_property<MeshT, HandleT, std::vector<std::vector<std::vector<float>>>> (_mesh, action);
|
||||
do_property<MeshT, HandleT, std::vector<std::vector<std::vector<char>>>> (_mesh, action);
|
||||
do_property<MeshT, HandleT, std::vector<std::vector<std::vector<bool>>>> (_mesh, action);
|
||||
do_property<MeshT, HandleT, std::vector<std::vector<std::vector<std::string>>>> (_mesh, action);
|
||||
do_property<MeshT, HandleT, std::vector<std::vector<std::vector<RegisteredDataType>>>> (_mesh, action);
|
||||
}
|
||||
|
||||
do_all_property_types_vec_all_dim<MeshT, HandleT>(_mesh, action);
|
||||
}
|
||||
|
||||
// Do action for all property types for faces, edges, halfedges and vertices
|
||||
template <typename MeshT>
|
||||
void do_all_properties(MeshT& _mesh, PropertyAction action, int version)
|
||||
{
|
||||
do_all_property_types<MeshT,OpenMesh::FaceHandle> (_mesh, action, version);
|
||||
do_all_property_types<MeshT,OpenMesh::EdgeHandle> (_mesh, action, version);
|
||||
do_all_property_types<MeshT,OpenMesh::HalfedgeHandle>(_mesh, action, version);
|
||||
do_all_property_types<MeshT,OpenMesh::VertexHandle> (_mesh, action, version);
|
||||
}
|
||||
|
||||
template <typename MeshT> void add_all_properties(MeshT& _mesh, int version) { do_all_properties(_mesh, PropertyAction::Add , version); }
|
||||
template <typename MeshT> void check_all_properties(MeshT& _mesh, int version) { do_all_properties(_mesh, PropertyAction::Check , version); }
|
||||
template <typename MeshT> void request_all_properties(MeshT& _mesh, int version) { do_all_properties(_mesh, PropertyAction::Request, version); }
|
||||
|
||||
/*
|
||||
* Load a triangle mesh from an om file of version 2.1 with properties
|
||||
*/
|
||||
TEST_F(OpenMeshReadWriteOM, LoadTriangleMeshWithPropertiesVersion_2_1) {
|
||||
|
||||
int version = 21;
|
||||
mesh_.clear();
|
||||
|
||||
std::string file_name = "cube_tri_with_properties_2_1.om";
|
||||
|
||||
request_all_properties(mesh_, version);
|
||||
bool ok = OpenMesh::IO::read_mesh(mesh_, file_name);
|
||||
|
||||
ASSERT_TRUE(ok) << file_name;
|
||||
|
||||
ASSERT_EQ(8u , mesh_.n_vertices()) << "The number of loaded vertices is not correct!";
|
||||
ASSERT_EQ(18u , mesh_.n_edges()) << "The number of loaded edges is not correct!";
|
||||
ASSERT_EQ(12u , mesh_.n_faces()) << "The number of loaded faces is not correct!";
|
||||
ASSERT_EQ(36u , mesh_.n_halfedges()) << "The number of loaded halfedges is not correct!";
|
||||
|
||||
check_all_properties(mesh_, version);
|
||||
}
|
||||
|
||||
/*
|
||||
* store and load a triangle mesh from an om file of the current version with properties
|
||||
*/
|
||||
TEST_F(OpenMeshReadWriteOM, LoadTriangleMeshWithPropertiesCurrentVersion) {
|
||||
|
||||
// TODO: create a LoadTriangleMeshWithPropertiesVersion_2_2 unittest from the file resulting from this test
|
||||
// so we will keep testing version 2.2 in the future.
|
||||
|
||||
int version = 22;
|
||||
mesh_.clear();
|
||||
|
||||
std::string file_name = "cube_tri_version_2_0.om";
|
||||
|
||||
bool ok = OpenMesh::IO::read_mesh(mesh_, file_name);
|
||||
|
||||
ASSERT_TRUE(ok) << file_name;
|
||||
ASSERT_EQ(8u , mesh_.n_vertices()) << "The number of loaded vertices is not correct!";
|
||||
ASSERT_EQ(18u , mesh_.n_edges()) << "The number of loaded edges is not correct!";
|
||||
ASSERT_EQ(12u , mesh_.n_faces()) << "The number of loaded faces is not correct!";
|
||||
ASSERT_EQ(36u , mesh_.n_halfedges()) << "The number of loaded halfedges is not correct!";
|
||||
|
||||
add_all_properties(mesh_, version);
|
||||
mesh_.request_halfedge_texcoords2D();
|
||||
|
||||
std::string file_name_2_2 = "cube_tri_with_properties_2_2.om";
|
||||
OpenMesh::IO::Options ops(OpenMesh::IO::Options::Custom);
|
||||
ops += OpenMesh::IO::Options::FaceTexCoord;
|
||||
|
||||
OpenMesh::IO::write_mesh(mesh_, file_name_2_2, ops);
|
||||
|
||||
Mesh new_mesh;
|
||||
OpenMesh::IO::read_mesh(new_mesh, file_name_2_2, ops);
|
||||
|
||||
check_all_properties(new_mesh, version);
|
||||
EXPECT_TRUE(new_mesh.has_halfedge_texcoords2D());
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to load mesh from om file with a version that is not yet supported
|
||||
*/
|
||||
@@ -1509,6 +1822,39 @@ TEST_F(OpenMeshReadWriteOM, WriteAndLoadDoubles) {
|
||||
EXPECT_EQ(mesh.normal(OpenMesh::FaceHandle(0)), mesh2.normal(OpenMesh::FaceHandle(0)));
|
||||
}
|
||||
|
||||
/*
|
||||
* Create Property from String
|
||||
*/
|
||||
TEST_F(OpenMeshReadWriteOM, PropertyFromString)
|
||||
{
|
||||
{
|
||||
std::string int_prop_name = "my int prop";
|
||||
OpenMesh::create_property_from_string<OpenMesh::VertexHandle>(mesh_, "int32_t", int_prop_name);
|
||||
bool has_int_prop = OpenMesh::hasProperty<OpenMesh::VertexHandle, int>(mesh_, int_prop_name.c_str());
|
||||
EXPECT_TRUE(has_int_prop);
|
||||
}
|
||||
|
||||
{
|
||||
std::string double_prop_name = "my double prop";
|
||||
OpenMesh::create_property_from_string<OpenMesh::VertexHandle>(mesh_, "double", double_prop_name);
|
||||
bool has_double_prop = OpenMesh::hasProperty<OpenMesh::VertexHandle, double>(mesh_, double_prop_name.c_str());
|
||||
EXPECT_TRUE(has_double_prop);
|
||||
}
|
||||
|
||||
{
|
||||
std::string vec_float_prop_name = "my vector of floats prop";
|
||||
OpenMesh::create_property_from_string<OpenMesh::VertexHandle>(mesh_, "std::vector<float>", vec_float_prop_name);
|
||||
bool has_vec_float_prop = OpenMesh::hasProperty<OpenMesh::VertexHandle, std::vector<float>>(mesh_, vec_float_prop_name.c_str());
|
||||
EXPECT_TRUE(has_vec_float_prop);
|
||||
}
|
||||
|
||||
{
|
||||
std::string MyData_prop_name = "my MyData prop";
|
||||
OpenMesh::create_property_from_string<OpenMesh::VertexHandle>(mesh_, "RegisteredDataType", MyData_prop_name);
|
||||
bool has_myData_prop = OpenMesh::hasProperty<OpenMesh::VertexHandle, RegisteredDataType>(mesh_, MyData_prop_name.c_str());
|
||||
EXPECT_TRUE(has_myData_prop);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
@@ -1558,13 +1904,30 @@ TEST_F(OpenMeshReadWriteOM, WriteAndLoadBoolCheckSpaces) {
|
||||
// Check if the property is still ok
|
||||
for (unsigned int i = 0; i < 8; ++i)
|
||||
{
|
||||
if ( i == 5)
|
||||
EXPECT_TRUE( mesh.property(prop,mesh2.vertex_handle((i)) ) );
|
||||
else
|
||||
EXPECT_FALSE(mesh.property(prop,mesh2.vertex_handle((i))));
|
||||
if ( i == 5)
|
||||
EXPECT_TRUE( mesh.property(prop,mesh2.vertex_handle((i)) ) );
|
||||
else
|
||||
EXPECT_FALSE(mesh.property(prop,mesh2.vertex_handle((i))));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
OM_REGISTER_PROPERTY_TYPE(RegisteredDataType)
|
||||
OM_REGISTER_PROPERTY_TYPE(std::vector<std::string>)
|
||||
OM_REGISTER_PROPERTY_TYPE(std::vector<float>)
|
||||
OM_REGISTER_PROPERTY_TYPE(std::vector<RegisteredDataType>)
|
||||
OM_REGISTER_PROPERTY_TYPE(std::vector<std::vector<int>>)
|
||||
OM_REGISTER_PROPERTY_TYPE(std::vector<std::vector<double>>)
|
||||
OM_REGISTER_PROPERTY_TYPE(std::vector<std::vector<float>>)
|
||||
OM_REGISTER_PROPERTY_TYPE(std::vector<std::vector<char>>)
|
||||
OM_REGISTER_PROPERTY_TYPE(std::vector<std::vector<bool>>)
|
||||
OM_REGISTER_PROPERTY_TYPE(std::vector<std::vector<std::string>>)
|
||||
OM_REGISTER_PROPERTY_TYPE(std::vector<std::vector<RegisteredDataType>>)
|
||||
OM_REGISTER_PROPERTY_TYPE(std::vector<std::vector<std::vector<int>>>)
|
||||
OM_REGISTER_PROPERTY_TYPE(std::vector<std::vector<std::vector<double>>>)
|
||||
OM_REGISTER_PROPERTY_TYPE(std::vector<std::vector<std::vector<float>>>)
|
||||
OM_REGISTER_PROPERTY_TYPE(std::vector<std::vector<std::vector<char>>>)
|
||||
OM_REGISTER_PROPERTY_TYPE(std::vector<std::vector<std::vector<bool>>>)
|
||||
OM_REGISTER_PROPERTY_TYPE(std::vector<std::vector<std::vector<std::string>>>)
|
||||
OM_REGISTER_PROPERTY_TYPE(std::vector<std::vector<std::vector<RegisteredDataType>>>)
|
||||
|
||||
@@ -79,6 +79,7 @@ namespace OpenMesh {
|
||||
return size_of();
|
||||
}
|
||||
|
||||
static std::string type_identifier(void) { return "MyData"; }
|
||||
static size_t store(std::ostream& _os, const value_type& _v, bool _swap=false)
|
||||
{
|
||||
size_t bytes;
|
||||
@@ -125,6 +126,7 @@ namespace OpenMesh {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
static std::string type_identifier(void) { return "MyMap"; }
|
||||
static
|
||||
size_t store(std::ostream& _os, const value_type& _v, bool _swap=false)
|
||||
{
|
||||
@@ -787,7 +789,7 @@ TEST_F(OpenMeshTutorials, storing_custom_properties) {
|
||||
|
||||
//Read back mesh
|
||||
ok = OpenMesh::IO::read_mesh( mesh, "persistence-check.om" );
|
||||
EXPECT_TRUE(ok) << "Cannot read mesh from file 'persistent-check.om'";
|
||||
EXPECT_TRUE(ok) << "Cannot read mesh from file 'persistence-check.om'";
|
||||
|
||||
// check props
|
||||
EXPECT_TRUE(fill_props(mesh, vprop_float, true)) << "property not filled correctly";
|
||||
|
||||
Reference in New Issue
Block a user