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:
Jan Möbius
2021-03-17 09:39:52 +00:00
25 changed files with 1213 additions and 276 deletions

View File

@@ -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

View File

@@ -278,7 +278,6 @@ namespace OMFormat {
}; // Chunk
// ------------------------------------------------------------ Helper
// -------------------- get size information
/// Return size of header in bytes.

View File

@@ -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; }
};

View File

@@ -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>
// ----------------------------------------------------------------------------

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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) );
}
};

View File

@@ -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); }
//@}

View File

@@ -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;

View File

@@ -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));
}

View File

@@ -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:
;
}
}
//-----------------------------------------------------------------------------
//=============================================================================

View File

@@ -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;
};

View File

@@ -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;
}

View File

@@ -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;
};

View File

@@ -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;

View File

@@ -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
//=============================================================================

View 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);

View 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 */

View File

@@ -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)

View File

@@ -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