Radium Engine  1.5.0
TopologicalMesh.hpp
1 #pragma once
2 
3 #include <Core/Containers/VectorArray.hpp>
4 #include <Core/Geometry/OpenMesh.hpp>
5 #include <Core/Geometry/StandardAttribNames.hpp>
6 #include <Core/Geometry/TriangleMesh.hpp>
7 #include <Core/RaCore.hpp>
8 #include <Core/Types.hpp>
9 #include <Core/Utils/Index.hpp>
10 #include <Core/Utils/Log.hpp>
11 #include <Core/Utils/StdOptional.hpp>
12 
13 #include <OpenMesh/Core/Mesh/PolyMesh_ArrayKernelT.hh>
14 #include <OpenMesh/Core/Mesh/Traits.hh>
15 #include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
16 #include <OpenMesh/Core/Utils/Property.hh>
17 #include <OpenMesh/Core/Utils/PropertyManager.hh>
18 
19 #include <Eigen/Core>
20 #include <Eigen/Geometry>
21 
22 #include <set>
23 #include <typeinfo>
24 #include <unordered_map>
25 
26 namespace Ra {
27 namespace Core {
28 namespace Geometry {
29 using namespace Utils; // log, AttribXXX
30 
34 struct TopologicalMeshTraits : OpenMesh::DefaultTraits {
35  using Point = Ra::Core::Vector3;
36  using Normal = Ra::Core::Vector3;
37 
38  VertexAttributes( OpenMesh::Attributes::Status | OpenMesh::Attributes::Normal );
39  FaceAttributes( OpenMesh::Attributes::Status | OpenMesh::Attributes::Normal );
40  EdgeAttributes( OpenMesh::Attributes::Status );
41  // Add OpenMesh::Attributes::PrevHalfedge for efficiency ?
42  HalfedgeAttributes( OpenMesh::Attributes::Status | OpenMesh::Attributes::Normal );
43 };
44 
55 class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT<TopologicalMeshTraits>
56 {
57  private:
58  using base = OpenMesh::PolyMesh_ArrayKernelT<TopologicalMeshTraits>;
59  using base::PolyMesh_ArrayKernelT;
60  using Vector3 = Ra::Core::Vector3;
61  using Index = Ra::Core::Utils::Index;
62  class Wedge;
63  class WedgeCollection;
64 
65  public:
66  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
67  class WedgeData;
68  using WedgeIndex = Ra::Core::Utils::Index;
69  using WedgeAttribIndex = Ra::Core::Utils::Index;
70 
74  explicit TopologicalMesh();
75 
80  template <typename MeshIndex>
81  explicit TopologicalMesh( [[deprecated(
82  "Use MultiIndexedGeometry instead" )]] const Ra::Core::Geometry::IndexedGeometry<MeshIndex>&
83  mesh );
84 
90  explicit TopologicalMesh(
92  const Ra::Core::Geometry::MultiIndexedGeometry::LayerKeyType& layerKey );
93 
106  template <typename MeshIndex, typename NonManifoldFaceCommand>
107  explicit TopologicalMesh( [[deprecated( "Use MultiIndexedGeometry instead" )]] const Ra::Core::
109  NonManifoldFaceCommand command );
110 
124  template <typename NonManifoldFaceCommand>
125  explicit TopologicalMesh(
127  const Ra::Core::Geometry::MultiIndexedGeometry::LayerKeyType& layerKey,
128  NonManifoldFaceCommand command );
129 
130  inline void
131  initWithWedge( const Ra::Core::Geometry::MultiIndexedGeometry& mesh,
132  const Ra::Core::Geometry::MultiIndexedGeometry::LayerKeyType& layerKey );
133 
134  template <typename NonManifoldFaceCommand>
135  void initWithWedge( const Ra::Core::Geometry::MultiIndexedGeometry& mesh,
136  const Ra::Core::Geometry::MultiIndexedGeometry::LayerKeyType& layerKey,
137  NonManifoldFaceCommand command );
142  TriangleMesh toTriangleMesh();
143 
149  PolyMesh toPolyMesh();
150 
151  LineMesh toLineMesh();
152 
157  void updateTriangleMesh( Ra::Core::Geometry::MultiIndexedGeometry& mesh );
158  void updateTriangleMeshNormals( Ra::Core::Geometry::MultiIndexedGeometry& mesh );
159  void updateTriangleMeshNormals( AttribArrayGeometry::NormalAttribHandle::Container& normals );
160 
161  void update( const Ra::Core::Geometry::MultiIndexedGeometry& mesh );
162  void updateNormals( const Ra::Core::Geometry::MultiIndexedGeometry& mesh );
163  void updatePositions( const Ra::Core::Geometry::MultiIndexedGeometry& mesh );
164  void updatePositions( const AttribArrayGeometry::PointAttribHandle::Container& vertices );
165  // import other version of halfedge_handle method
166  using base::halfedge_handle;
167 
172  inline HalfedgeHandle halfedge_handle( VertexHandle vh, FaceHandle fh ) const;
173 
176  using base::normal;
177  using base::set_normal;
179 
185  inline void propagate_normal_to_wedges( VertexHandle vh );
186 
191  inline const OpenMesh::HPropHandleT<Index>& getInputTriangleMeshIndexPropHandle() const;
192 
198  inline const OpenMesh::HPropHandleT<Index>& getOutputTriangleMeshIndexPropHandle() const;
199 
205 
206  void updateWedgeNormals();
208 
211  void copyPointsPositionToWedges();
216 
228  bool splitEdge( TopologicalMesh::EdgeHandle eh, Scalar f );
229 
238  void collapse( HalfedgeHandle, bool = false );
239  [[deprecated( "use collapse() instead." )]] void
240  collapseWedge( TopologicalMesh::HalfedgeHandle he, bool keepFromVertex = false );
242 
247  inline std::set<WedgeIndex> getVertexWedges( OpenMesh::VertexHandle vh ) const;
248 
252  inline WedgeIndex getWedgeIndex( OpenMesh::HalfedgeHandle heh ) const;
253 
258  inline const WedgeData& getWedgeData( const WedgeIndex& idx ) const;
259  template <typename T>
260  [[deprecated( "use getWedgeAttrib() instead." )]] const T&
261  getWedgeData( const WedgeIndex& idx, const std::string& name ) const;
262  template <typename T>
263  const T& getWedgeAttrib( const WedgeIndex& idx, const std::string& name ) const;
264 
268  inline unsigned int getWedgeRefCount( const WedgeIndex& idx ) const;
269 
275  inline void setWedgeData( WedgeIndex widx, const WedgeData& wd );
276 
283  template <typename T>
284  [[deprecated( "use setWedgeAttrib() instead." )]] inline bool
285  setWedgeData( const WedgeIndex& idx, const std::string& name, const T& value );
286 
287  template <typename T>
288  inline bool setWedgeAttrib( const WedgeIndex& idx, const std::string& name, const T& value );
289 
291  inline WedgeData newWedgeData() const { return m_wedges.newWedgeData(); }
294  inline WedgeData newWedgeData( HalfedgeHandle he ) const {
295  return m_wedges.newWedgeData( to_vertex_handle( he ), point( to_vertex_handle( he ) ) );
296  }
297 
303  inline WedgeIndex replaceWedge( OpenMesh::HalfedgeHandle he, const WedgeData& wd );
304 
305  template <typename T>
306  inline WedgeAttribIndex addWedgeAttrib( const std::string& name, T value = {} ) {
307  return m_wedges.addAttrib<T>( name, value );
308  }
309 
314  inline void replaceWedgeIndex( OpenMesh::HalfedgeHandle he, const WedgeIndex& widx );
315 
320  inline void mergeEqualWedges();
321 
326  inline void mergeEqualWedges( OpenMesh::VertexHandle vh );
327 
329  void garbage_collection();
330  inline void clean() {
331  base::clean();
332  m_wedges.clean();
333  }
334 
335  inline const std::vector<std::string>& getVec4AttribNames() const;
336  inline const std::vector<std::string>& getVec3AttribNames() const;
337  inline const std::vector<std::string>& getVec2AttribNames() const;
338  inline const std::vector<std::string>& getFloatAttribNames() const;
339 
341  inline bool isFeatureVertex( const VertexHandle& vh ) const;
342 
346  inline bool isFeatureEdge( const EdgeHandle& eh ) const;
347 
348  inline const OpenMesh::HPropHandleT<WedgeIndex>& getWedgeIndexPph() const;
349 
350  void delete_face( FaceHandle _fh, bool _delete_isolated_vertices = true );
351 
356  bool isManifold( VertexHandle vh ) const;
357 
360  bool checkIntegrity() const;
361 
362  void triangulate();
363 
371  class WedgeData
372  {
373  public:
374  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
375 
376  explicit WedgeData() = default;
377  inline bool operator==( const WedgeData& lhs ) const;
378  inline bool operator!=( const WedgeData& lhs ) const;
379  inline bool operator<( const WedgeData& lhs ) const;
380 
381  template <typename T>
382  inline VectorArray<T>& getAttribArray();
383  template <typename T>
384  inline const VectorArray<T>& getAttribArray() const;
385  friend Wedge;
386 
387  // Index m_inputTriangleMeshIndex;
388  // Index m_outputTriangleMeshIndex;
389  VertexHandle m_vertexHandle;
390  Vector3 m_position {};
391  VectorArray<Scalar> m_floatAttrib;
392  VectorArray<Vector2> m_vector2Attrib;
393  VectorArray<Vector3> m_vector3Attrib;
394  VectorArray<Vector4> m_vector4Attrib;
395 
396  private:
397  // return 1 : equals, 2: strict less, 3: strict greater
398  template <typename T>
399  static int compareVector( const T& a, const T& b );
400  };
401 
402  private:
403  // base on openmesh version
404  void collapse_edge( HalfedgeHandle, bool );
405  void collapse_loop( HalfedgeHandle );
406 
412  class RA_CORE_API Wedge
413  {
414  public:
415  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
416 
417  explicit Wedge() {}
418  explicit Wedge( const WedgeData& wd ) : m_wedgeData { wd }, m_refCount { 1 } {};
419  const WedgeData& getWedgeData() const { return m_wedgeData; }
420  void setWedgeData( const WedgeData& wedgeData ) { m_wedgeData = wedgeData; }
421  void setWedgeData( WedgeData&& wedgeData ) { m_wedgeData = std::move( wedgeData ); }
422  void incrementRefCount() { ++m_refCount; }
423  void decrementRefCount() {
424  if ( m_refCount ) --m_refCount;
425  }
427  bool operator==( const Wedge& lhs ) const { return m_wedgeData == lhs.m_wedgeData; }
428 
429  bool isDeleted() const { return m_refCount == 0; }
430  unsigned int getRefCount() const { return m_refCount; }
431 
432  friend WedgeCollection;
433  friend TopologicalMesh;
434 
435  private:
436  WedgeData& getWedgeData() { return m_wedgeData; }
437 
438  WedgeData m_wedgeData {};
439  unsigned int m_refCount { 0 };
440  };
441 
449  class RA_CORE_API WedgeCollection
450  {
451  public:
452  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
453 
461  WedgeIndex add( const WedgeData& wd );
462 
469  inline void del( const WedgeIndex& idx );
470  WedgeIndex newReference( const WedgeIndex& idx );
471 
478  inline const Wedge& getWedge( const WedgeIndex& idx ) const;
479 
480  inline const WedgeData& getWedgeData( const WedgeIndex& idx ) const;
481  template <typename T>
482  inline const T& getWedgeData( const WedgeIndex& idx, const std::string& name ) const;
483  template <typename T>
484  inline T& getWedgeData( const WedgeIndex& idx, int attribIndex );
485  template <typename T>
486  inline const T& getWedgeAttrib( const WedgeIndex& idx, const std::string& name ) const;
487  template <typename T>
488  inline T& getWedgeAttrib( const WedgeIndex& idx, int attribIndex );
489 
490  unsigned int getWedgeRefCount( const WedgeIndex& idx ) const;
491 
493  inline void setWedgeData( const WedgeIndex& idx, const WedgeData& wd );
494 
499  template <typename T>
500  inline bool
501  setWedgeAttrib( TopologicalMesh::WedgeData& wd, const std::string& name, const T& value );
502  template <typename T>
503  inline bool
504  setWedgeAttrib( const WedgeIndex& idx, const std::string& name, const T& value );
505  template <typename T>
506  inline void setWedgeAttrib( const TopologicalMesh::WedgeIndex& idx,
507  const int& attribIndex,
508  const T& value );
509 
510  template <typename T>
511  inline WedgeAttribIndex getWedgeAttribIndex( const std::string& name );
512 
513  inline bool setWedgePosition( const WedgeIndex& idx, const Vector3& value );
514 
516 
517  template <typename T>
518  inline const std::vector<std::string>& getNameArray() const;
519 
520  // name is supposed to be unique within all attribs
521  // not checks are performed
522  // return the index of the the newly added attrib.
523  template <typename T>
524  WedgeAttribIndex addAttribName( const std::string& name );
525 
526  // add attrib to all wedges with default value value
527  template <typename T>
528  WedgeAttribIndex addAttrib( const std::string& name, const T& value = {} );
529 
532  std::vector<int> computeCleanupOffset() const;
537 
538  inline size_t size() const { return m_data.size(); }
539 
541  inline void garbageCollection();
542 
543  inline void clean();
544 
545  // return a new wedgeData with uninit values.
546  inline WedgeData newWedgeData() const;
547  inline WedgeData newWedgeData( TopologicalMesh::VertexHandle vh,
548  TopologicalMesh::Point p ) const;
549 
552  std::vector<std::string> m_floatAttribNames;
553  std::vector<std::string> m_vector2AttribNames;
554  std::vector<std::string> m_vector3AttribNames;
555  std::vector<std::string> m_vector4AttribNames;
556 
559  std::vector<AttribHandle<Scalar>> m_wedgeFloatAttribHandles;
560  std::vector<AttribHandle<Vector2>> m_wedgeVector2AttribHandles;
561  std::vector<AttribHandle<Vector3>> m_wedgeVector3AttribHandles;
562  std::vector<AttribHandle<Vector4>> m_wedgeVector4AttribHandles;
563 
564  template <typename T>
565  inline std::vector<std::string>& getNameArray();
566  AlignedStdVector<Wedge> m_data;
567  };
568 
569  // internal function to build Core Mesh attribs correspondance to wedge attribs.
570  class InitWedgeAttribsFromMultiIndexedGeometry
571  {
572  public:
573  InitWedgeAttribsFromMultiIndexedGeometry(
574  TopologicalMesh* topo,
576  m_topo( topo ), m_triMesh( triMesh ) {}
577  void operator()( AttribBase* attr ) const;
578 
579  private:
580  TopologicalMesh* m_topo;
582  };
583 
586  struct DefaultNonManifoldFaceCommand {
588  DefaultNonManifoldFaceCommand( const std::string& details = {} ) : m_details { details } {}
590  inline void initialize( const Ra::Core::Geometry::MultiIndexedGeometry& ) {}
592  inline void process( const std::vector<TopologicalMesh::VertexHandle>& /*face_vhandles*/ ) {
593  LOG( logWARNING ) << "Invalid face handle returned : face not added " + m_details;
594  }
596  inline void postProcess( TopologicalMesh& ) {}
597 
598  private:
599  std::string m_details;
600  };
602 
603  WedgeData interpolateWedgeAttributes( const WedgeData&, const WedgeData&, Scalar alpha );
604 
606  template <typename T>
607  inline void copyAttribToWedgeData( const Ra::Core::Geometry::MultiIndexedGeometry& mesh,
608  unsigned int vindex,
609  const std::vector<AttribHandle<T>>& attrHandleVec,
610  VectorArray<T>* to );
611 
613  inline void copyMeshToWedgeData( const Ra::Core::Geometry::MultiIndexedGeometry& mesh,
614  unsigned int vindex,
615  const std::vector<AttribHandle<Scalar>>& wprop_float,
616  const std::vector<AttribHandle<Vector2>>& wprop_vec2,
617  const std::vector<AttribHandle<Vector3>>& wprop_vec3,
618  const std::vector<AttribHandle<Vector4>>& wprop_vec4,
619  TopologicalMesh::WedgeData* wd );
620 
621  template <typename T>
622  using HandleAndValueVector =
623  std::vector<std::pair<AttribHandle<T>, T>,
624  Eigen::aligned_allocator<std::pair<AttribHandle<T>, T>>>;
625 
626  void split_copy( EdgeHandle _eh, VertexHandle _vh );
627  void split( EdgeHandle _eh, VertexHandle _vh );
628 
629  OpenMesh::HPropHandleT<WedgeIndex> m_wedgeIndexPph;
630  WedgeCollection m_wedges;
633  OpenMesh::HPropHandleT<Index> m_inputTriangleMeshIndexPph;
634  OpenMesh::HPropHandleT<Index> m_outputTriangleMeshIndexPph;
635 
636  int m_normalsIndex { -1 };
637  // vertex handle idx -> face handle idx -> wedge idx with the same normal
638  std::vector<std::map<int, std::vector<int>>> m_vertexFaceWedgesWithSameNormals;
639 
640  friend class TMOperations;
641 };
642 
643 // heplers
644 void printWedgesInfo( const TopologicalMesh& );
645 
649 
650 inline bool TopologicalMesh::WedgeData::operator==( const TopologicalMesh::WedgeData& lhs ) const {
651  return
652  // do not have this yet, not sure we need to test them
653  // m_inputTriangleMeshIndex == lhs.m_inputTriangleMeshIndex &&
654  // m_outputTriangleMeshIndex == lhs.m_outputTriangleMeshIndex &&
655  m_position == lhs.m_position && m_floatAttrib == lhs.m_floatAttrib &&
656  m_vector2Attrib == lhs.m_vector2Attrib && m_vector3Attrib == lhs.m_vector3Attrib &&
657  m_vector4Attrib == lhs.m_vector4Attrib;
658 }
659 
660 bool TopologicalMesh::WedgeData::operator!=( const TopologicalMesh::WedgeData& lhs ) const {
661  return !( *this == lhs );
662 }
663 
664 inline bool TopologicalMesh::WedgeData::operator<( const TopologicalMesh::WedgeData& lhs ) const {
665 
666  CORE_ASSERT( ( m_floatAttrib.size() == lhs.m_floatAttrib.size() ) &&
667  ( m_vector2Attrib.size() == lhs.m_vector2Attrib.size() ) &&
668  ( m_vector3Attrib.size() == lhs.m_vector3Attrib.size() ) &&
669  ( m_vector4Attrib.size() == lhs.m_vector4Attrib.size() ),
670  "Could only compare wedge with same number of attributes" );
671 
672  {
673  int comp = compareVector( m_position, lhs.m_position );
674  if ( comp == 2 ) return true;
675  if ( comp == 3 ) return false;
676  }
677  for ( size_t i = 0; i < m_floatAttrib.size(); i++ ) {
678  if ( m_floatAttrib[i] < lhs.m_floatAttrib[i] )
679  return true;
680  else if ( m_floatAttrib[i] > lhs.m_floatAttrib[i] )
681  return false;
682  }
683 
684  for ( size_t i = 0; i < m_vector2Attrib.size(); i++ ) {
685  int comp = compareVector( m_vector2Attrib[i], lhs.m_vector2Attrib[i] );
686  if ( comp == 2 ) return true;
687  if ( comp == 3 ) return false;
688  }
689  for ( size_t i = 0; i < m_vector3Attrib.size(); i++ ) {
690  int comp = compareVector( m_vector3Attrib[i], lhs.m_vector3Attrib[i] );
691  if ( comp == 2 ) return true;
692  if ( comp == 3 ) return false;
693  }
694  for ( size_t i = 0; i < m_vector4Attrib.size(); i++ ) {
695  int comp = compareVector( m_vector4Attrib[i], lhs.m_vector4Attrib[i] );
696  if ( comp == 2 ) return true;
697  if ( comp == 3 ) return false;
698  }
699  return false;
700 }
701 
702 #define GET_ATTRIB_ARRAY_HELPER( TYPE, NAME ) \
703  template <> \
704  inline VectorArray<TYPE>& TopologicalMesh::WedgeData::getAttribArray<TYPE>() { \
705  return m_##NAME##Attrib; \
706  } \
707  template <> \
708  inline const VectorArray<TYPE>& TopologicalMesh::WedgeData::getAttribArray<TYPE>() const { \
709  return m_##NAME##Attrib; \
710  }
711 
712 GET_ATTRIB_ARRAY_HELPER( Scalar, float )
713 GET_ATTRIB_ARRAY_HELPER( Vector2, vector2 )
714 GET_ATTRIB_ARRAY_HELPER( Vector3, vector3 )
715 GET_ATTRIB_ARRAY_HELPER( Vector4, vector4 )
716 #undef GET_ATTRIB_ARRAY_HELPER
717 
718 template <typename T>
719 inline VectorArray<T>& TopologicalMesh::WedgeData::getAttribArray() {
720  static_assert( sizeof( T ) == -1, "this type is not supported" );
721 }
722 
723 // return 1 : equals, 2: strict less, 3: strict greater
724 template <typename T>
725 int TopologicalMesh::WedgeData::compareVector( const T& a, const T& b ) {
726  for ( int i = 0; i < T::RowsAtCompileTime; i++ ) {
727  if ( a[i] < b[i] ) return 2;
728  if ( a[i] > b[i] ) return 3;
729  }
730  // (a == b)
731  return 1;
732 }
733 
737 
738 // all in class for the moment
739 
743 
744 inline void TopologicalMesh::WedgeCollection::del( const TopologicalMesh::WedgeIndex& idx ) {
745  if ( idx.isValid() ) m_data[idx].decrementRefCount();
746 }
747 
748 inline TopologicalMesh::WedgeIndex
749 TopologicalMesh::WedgeCollection::newReference( const TopologicalMesh::WedgeIndex& idx ) {
750  if ( idx.isValid() ) m_data[idx].incrementRefCount();
751  return idx;
752 }
753 
754 inline const TopologicalMesh::Wedge&
755 TopologicalMesh::WedgeCollection::getWedge( const TopologicalMesh::WedgeIndex& idx ) const {
756  return m_data[idx];
757 }
758 
759 inline const TopologicalMesh::WedgeData&
760 TopologicalMesh::WedgeCollection::getWedgeData( const WedgeIndex& idx ) const {
761  CORE_ASSERT( idx.isValid() && !m_data[idx].isDeleted(),
762  "access to invalid or deleted wedge is prohibited" );
763 
764  return m_data[idx].getWedgeData();
765 }
766 
767 template <typename T>
768 inline const T&
769 TopologicalMesh::WedgeCollection::getWedgeData( const TopologicalMesh::WedgeIndex& idx,
770  const std::string& name ) const {
771  return getWedgeAttrib<T>( idx, name );
772 }
773 
774 template <typename T>
775 inline const T&
776 TopologicalMesh::WedgeCollection::getWedgeAttrib( const TopologicalMesh::WedgeIndex& idx,
777  const std::string& name ) const {
778  if ( idx.isValid() ) {
779  auto nameArray = getNameArray<T>();
780  auto itr = std::find( nameArray.begin(), nameArray.end(), name );
781  if ( itr != nameArray.end() ) {
782  auto attrIndex = std::distance( nameArray.begin(), itr );
783  return m_data[idx].getWedgeData().getAttribArray<T>()[attrIndex];
784  }
785  else {
786  LOG( logERROR ) << "Warning, set wedge: no wedge attrib named " << name << " of type "
787  << typeid( T ).name();
788  }
789  }
790  static T dummy;
791  return dummy;
792 }
793 
794 template <typename T>
795 inline T& TopologicalMesh::WedgeCollection::getWedgeData( const TopologicalMesh::WedgeIndex& idx,
796  int attribIndex ) {
797  return getWedgeAttrib<T>( idx, attribIndex );
798 }
799 
800 template <typename T>
801 inline T& TopologicalMesh::WedgeCollection::getWedgeAttrib( const TopologicalMesh::WedgeIndex& idx,
802  int attribIndex ) {
803  return m_data[idx].getWedgeData().getAttribArray<T>()[attribIndex];
804 }
805 
806 inline unsigned int
807 TopologicalMesh::WedgeCollection::getWedgeRefCount( const WedgeIndex& idx ) const {
808  CORE_ASSERT( idx.isValid(), "access to invalid or deleted wedge is prohibited" );
809  return m_data[idx].getRefCount();
810 }
811 
812 inline void TopologicalMesh::WedgeCollection::setWedgeData( const TopologicalMesh::WedgeIndex& idx,
813  const TopologicalMesh::WedgeData& wd ) {
814  if ( !( wd.m_floatAttrib.size() == m_floatAttribNames.size() &&
815  wd.m_vector2Attrib.size() == m_vector2AttribNames.size() &&
816  wd.m_vector3Attrib.size() == m_vector3AttribNames.size() &&
817  wd.m_vector4Attrib.size() == m_vector4AttribNames.size() ) ) {
818  LOG( logWARNING ) << "Warning, topological mesh set wedge: number of attribs inconsistency";
819  }
820  if ( idx.isValid() ) m_data[idx].setWedgeData( wd );
821 }
822 
823 template <typename T>
824 inline bool TopologicalMesh::WedgeCollection::setWedgeAttrib( TopologicalMesh::WedgeData& wd,
825  const std::string& name,
826  const T& value ) {
827  auto nameArray = getNameArray<T>();
828  auto itr = std::find( nameArray.begin(), nameArray.end(), name );
829  if ( itr != nameArray.end() ) {
830  auto attrIndex = std::distance( nameArray.begin(), itr );
831  wd.getAttribArray<T>()[attrIndex] = value;
832  return true;
833  }
834  else {
835  LOG( logERROR ) << "Warning, set wedge: no wedge attrib named " << name << " of type "
836  << typeid( T ).name();
837  }
838  return false;
839 }
840 
841 template <typename T>
842 inline bool
843 TopologicalMesh::WedgeCollection::setWedgeAttrib( const TopologicalMesh::WedgeIndex& idx,
844  const std::string& name,
845  const T& value ) {
846  if ( idx.isValid() ) {
847  auto nameArray = getNameArray<T>();
848  auto itr = std::find( nameArray.begin(), nameArray.end(), name );
849  if ( itr != nameArray.end() ) {
850  auto attrIndex = std::distance( nameArray.begin(), itr );
851  m_data[idx].getWedgeData().getAttribArray<T>()[attrIndex] = value;
852  return true;
853  }
854  else {
855  LOG( logERROR ) << "Warning, set wedge: no wedge attrib named " << name << " of type "
856  << typeid( T ).name();
857  }
858  }
859  return false;
860 }
861 
862 template <typename T>
863 inline void
864 TopologicalMesh::WedgeCollection::setWedgeAttrib( const TopologicalMesh::WedgeIndex& idx,
865  const int& attrIndex,
866  const T& value ) {
867  m_data[idx].getWedgeData().getAttribArray<T>()[attrIndex] = value;
868 }
869 
870 template <typename T>
871 inline TopologicalMesh::WedgeAttribIndex
872 TopologicalMesh::WedgeCollection::getWedgeAttribIndex( const std::string& name ) {
873  auto nameArray = getNameArray<T>();
874  auto itr = std::find( nameArray.begin(), nameArray.end(), name );
875  if ( itr != nameArray.end() ) { return std::distance( nameArray.begin(), itr ); }
876  return 0;
877 }
878 
879 inline bool
880 TopologicalMesh::WedgeCollection::setWedgePosition( const TopologicalMesh::WedgeIndex& idx,
881  const Vector3& value ) {
882  if ( idx.isValid() ) {
883  m_data[idx].getWedgeData().m_position = value;
884  return true;
885  }
886  return false;
887 }
888 
889 #define GET_NAME_ARRAY_HELPER( TYPE, NAME ) \
890  template <> \
891  inline const std::vector<std::string>& TopologicalMesh::WedgeCollection::getNameArray<TYPE>() \
892  const { \
893  return m_##NAME##AttribNames; \
894  } \
895  template <> \
896  inline std::vector<std::string>& TopologicalMesh::WedgeCollection::getNameArray<TYPE>() { \
897  return m_##NAME##AttribNames; \
898  }
899 
900 GET_NAME_ARRAY_HELPER( Scalar, float )
901 GET_NAME_ARRAY_HELPER( Vector2, vector2 )
902 GET_NAME_ARRAY_HELPER( Vector3, vector3 )
903 GET_NAME_ARRAY_HELPER( Vector4, vector4 )
904 
905 #undef GET_NAME_ARRAY_HELPER
906 // These template functions are defined above for supported types.
907 // For unsupported types they simply generate a compile error.
908 template <typename T>
909 inline const std::vector<std::string>& TopologicalMesh::WedgeCollection::getNameArray() const {
910 
911  LOG( logWARNING ) << "Warning, mesh attribute " << typeid( T ).name()
912  << " is not supported (only float, vec2, vec3 nor vec4 are supported)";
913  static_assert( sizeof( T ) == -1, "this type is not supported" );
914  return m_floatAttribNames;
915 }
916 
917 template <typename T>
918 inline std::vector<std::string>& TopologicalMesh::WedgeCollection::getNameArray() {
919 
920  LOG( logWARNING ) << "Warning, mesh attribute " << typeid( T ).name()
921  << " is not supported (only float, vec2, vec3 nor vec4 are supported)";
922  static_assert( sizeof( T ) == -1, "this type is not supported" );
923  return m_floatAttribNames;
924 }
925 template <typename T>
926 TopologicalMesh::WedgeAttribIndex
927 TopologicalMesh::WedgeCollection::addAttribName( const std::string& name ) {
928  if ( name != getAttribName( MeshAttrib::VERTEX_POSITION ) ) {
929  getNameArray<T>().push_back( name );
930  }
931  return getNameArray<T>().size() - 1;
932 }
933 
934 template <typename T>
935 TopologicalMesh::WedgeAttribIndex
936 TopologicalMesh::WedgeCollection::addAttrib( const std::string& name, const T& value ) {
937 
938  auto index = addAttribName<T>( name );
939  for ( auto& w : m_data ) {
940  CORE_ASSERT( index = w.getWedgeData().getAttribArray<T>().size(),
941  "inconsistent wedge attrib" );
942  w.getWedgeData().getAttribArray<T>().push_back( value );
943  }
944  return index;
945 }
946 
947 inline void TopologicalMesh::WedgeCollection::garbageCollection() {
948  m_data.erase( std::remove_if( m_data.begin(),
949  m_data.end(),
950  []( const Wedge& w ) { return w.isDeleted(); } ),
951  m_data.end() );
952 }
953 
954 inline void TopologicalMesh::WedgeCollection::clean() {
955  m_data.clear();
956  m_floatAttribNames.clear();
957  m_vector2AttribNames.clear();
958  m_vector3AttribNames.clear();
959  m_vector4AttribNames.clear();
960  m_wedgeFloatAttribHandles.clear();
961  m_wedgeVector2AttribHandles.clear();
962  m_wedgeVector3AttribHandles.clear();
963  m_wedgeVector4AttribHandles.clear();
964 }
965 
966 template <typename T>
967 void init( VectorArray<T>& vec, const std::vector<std::string> names ) {
968  for ( size_t i = 0; i < names.size(); ++i ) {
969  vec.emplace_back();
970  }
971 }
972 // return a new wedgeData with uninit values.
973 inline TopologicalMesh::WedgeData TopologicalMesh::WedgeCollection::newWedgeData() const {
974  WedgeData ret;
975  init<Scalar>( ret.getAttribArray<Scalar>(), m_floatAttribNames );
976  init<Vector2>( ret.getAttribArray<Vector2>(), m_vector2AttribNames );
977  init<Vector3>( ret.getAttribArray<Vector3>(), m_vector3AttribNames );
978  init<Vector4>( ret.getAttribArray<Vector4>(), m_vector4AttribNames );
979  return ret;
980 }
981 
982 inline TopologicalMesh::WedgeData
983 TopologicalMesh::WedgeCollection::newWedgeData( TopologicalMesh::VertexHandle vh,
984  TopologicalMesh::Point p ) const {
985  WedgeData ret = newWedgeData();
986  ret.m_vertexHandle = vh;
987  ret.m_position = p;
988  return ret;
989 }
990 
994 inline void
995 TopologicalMesh::InitWedgeAttribsFromMultiIndexedGeometry::operator()( AttribBase* attr ) const {
996  if ( attr->getSize() != m_triMesh.vertices().size() ) {
997  LOG( logWARNING ) << "[TopologicalMesh] Skip badly sized attribute " << attr->getName();
998  }
999  else if ( attr->getName() != getAttribName( MeshAttrib::VERTEX_POSITION ) ) {
1000  if ( attr->isFloat() ) {
1001  m_topo->m_wedges.m_wedgeFloatAttribHandles.push_back(
1002  m_triMesh.template getAttribHandle<Scalar>( attr->getName() ) );
1003  m_topo->m_wedges.addAttribName<Scalar>( attr->getName() );
1004  }
1005  else if ( attr->isVector2() ) {
1006  m_topo->m_wedges.m_wedgeVector2AttribHandles.push_back(
1007  m_triMesh.template getAttribHandle<Vector2>( attr->getName() ) );
1008  m_topo->m_wedges.addAttribName<Vector2>( attr->getName() );
1009  }
1010  else if ( attr->isVector3() ) {
1011  m_topo->m_wedges.m_wedgeVector3AttribHandles.push_back(
1012  m_triMesh.template getAttribHandle<Vector3>( attr->getName() ) );
1013  m_topo->m_wedges.addAttribName<Vector3>( attr->getName() );
1014  }
1015  else if ( attr->isVector4() ) {
1016  m_topo->m_wedges.m_wedgeVector4AttribHandles.push_back(
1017  m_triMesh.template getAttribHandle<Vector4>( attr->getName() ) );
1018  m_topo->m_wedges.addAttribName<Vector4>( attr->getName() );
1019  }
1020  else
1021  LOG( logWARNING )
1022  << "Warning, mesh attribute " << attr->getName()
1023  << " type is not supported (only float, vec2, vec3 nor vec4 are supported)";
1024  }
1025 }
1026 
1030 
1031 struct hash_vec {
1032  std::size_t operator()( const Vector3& lvalue ) const {
1033  size_t hx = std::hash<Scalar>()( lvalue[0] );
1034  size_t hy = std::hash<Scalar>()( lvalue[1] );
1035  size_t hz = std::hash<Scalar>()( lvalue[2] );
1036  return ( hx ^ ( hy << 1 ) ) ^ hz;
1037  }
1038 };
1039 
1040 template <typename MeshIndex>
1042  TopologicalMesh( mesh, DefaultNonManifoldFaceCommand( "[default ctor]" ) ) {}
1043 
1044 template <typename MeshIndex, typename NonManifoldFaceCommand>
1045 TopologicalMesh::TopologicalMesh( const IndexedGeometry<MeshIndex>& mesh,
1046  NonManifoldFaceCommand command ) :
1047  TopologicalMesh() {
1048  initWithWedge( mesh, mesh.getLayerKey(), command );
1049 }
1050 
1053  const Ra::Core::Geometry::MultiIndexedGeometry::LayerKeyType& layerKey ) :
1054  TopologicalMesh( mesh, layerKey, DefaultNonManifoldFaceCommand( "[default ctor]" ) ) {}
1055 
1056 template <typename NonManifoldFaceCommand>
1059  const Ra::Core::Geometry::MultiIndexedGeometry::LayerKeyType& layerKey,
1060  NonManifoldFaceCommand command ) :
1061  TopologicalMesh() {
1062  initWithWedge( mesh, layerKey, command );
1063 }
1064 
1065 inline void TopologicalMesh::initWithWedge(
1067  const Ra::Core::Geometry::MultiIndexedGeometry::LayerKeyType& layerKey ) {
1068  initWithWedge( mesh,
1069  layerKey,
1070  DefaultNonManifoldFaceCommand( "[initWithWedges (MultiIndexedGeometry)]" ) );
1071 }
1072 
1073 template <typename NonManifoldFaceCommand>
1074 void TopologicalMesh::initWithWedge(
1076  const Ra::Core::Geometry::MultiIndexedGeometry::LayerKeyType& layerKey,
1077  NonManifoldFaceCommand command ) {
1078 
1079  const auto& abstractLayer = mesh.getLayer( layerKey );
1080 
1081  if ( !abstractLayer.hasSemantic( TriangleIndexLayer::staticSemanticName ) &&
1082  !abstractLayer.hasSemantic( QuadIndexLayer::staticSemanticName ) &&
1083  !abstractLayer.hasSemantic( PolyIndexLayer::staticSemanticName ) ) {
1084  LOG( logWARNING ) << "TopologicalMesh: mesh does not contains faces. Aborting conversion";
1085  return;
1086  }
1087 
1088  clean();
1089 
1090  LOG( logDEBUG ) << "TopologicalMesh: load mesh with " << abstractLayer.getSize()
1091  << " faces and " << mesh.vertices().size() << " vertices.";
1092  // use a hashmap for fast search of existing vertex position
1093  using VertexMap = std::unordered_map<Vector3, TopologicalMesh::VertexHandle, hash_vec>;
1094  VertexMap vertexHandles;
1095 
1096  // loop over all attribs and build correspondance pair
1097  mesh.vertexAttribs().for_each_attrib( InitWedgeAttribsFromMultiIndexedGeometry { this, mesh } );
1098 
1099  for ( size_t i = 0; i < mesh.vertices().size(); ++i ) {
1100  // create an empty wedge, with 0 ref
1101  Wedge w;
1102 
1103  WedgeData wd;
1104  wd.m_position = mesh.vertices()[i];
1105  copyMeshToWedgeData( mesh,
1106  i,
1107  m_wedges.m_wedgeFloatAttribHandles,
1108  m_wedges.m_wedgeVector2AttribHandles,
1109  m_wedges.m_wedgeVector3AttribHandles,
1110  m_wedges.m_wedgeVector4AttribHandles,
1111  &wd );
1112  // here ref is not incremented
1113  w.setWedgeData( std::move( wd ) );
1114  // the newly added wedge is not referenced yet, will be done with `newReference` when
1115  // creating faces just below
1116  m_wedges.m_data.push_back( w );
1117  }
1118 
1119  LOG( logDEBUG ) << "TopologicalMesh: have " << m_wedges.size() << " wedges ";
1120 
1121  const bool hasNormals = !mesh.normals().empty();
1122  if ( !hasNormals ) {
1123  release_face_normals();
1124  release_vertex_normals();
1125  release_halfedge_normals();
1126  }
1127 
1128  command.initialize( mesh );
1129 
1130  auto processFaces = [&mesh, &vertexHandles, this, hasNormals, &command]( const auto& faces ) {
1131  size_t num_triangles = faces.size();
1132  for ( unsigned int i = 0; i < num_triangles; i++ ) {
1133  const auto& face = faces[i];
1134  const size_t num_vert = face.size();
1135  std::vector<TopologicalMesh::VertexHandle> face_vhandles( num_vert );
1136  std::vector<TopologicalMesh::Normal> face_normals( num_vert );
1137  std::vector<WedgeIndex> face_wedges( num_vert );
1138 
1139  for ( size_t j = 0; j < num_vert; ++j ) {
1140  unsigned int inMeshVertexIndex = face[j];
1141  const Vector3& p = mesh.vertices()[inMeshVertexIndex];
1142 
1143  typename VertexMap::iterator vtr = vertexHandles.find( p );
1144  TopologicalMesh::VertexHandle vh;
1145  if ( vtr == vertexHandles.end() ) {
1146  vh = add_vertex( p );
1147  vertexHandles.insert( vtr, typename VertexMap::value_type( p, vh ) );
1148  }
1149  else { vh = vtr->second; }
1150 
1151  face_vhandles[j] = vh;
1152  if ( hasNormals ) face_normals[j] = mesh.normals()[inMeshVertexIndex];
1153  face_wedges[j] = WedgeIndex { inMeshVertexIndex };
1154  m_wedges.m_data[inMeshVertexIndex].getWedgeData().m_vertexHandle = vh;
1155  }
1156 
1157  // remove consecutive equal vertex
1158  // first take care of "loop" if begin == *end-1
1159  // apply the same modifications on wedges and normals
1160  // e.g. 1 2 1 becomes 1 2
1161  {
1162  auto begin = face_vhandles.begin();
1163  if ( face_vhandles.size() > 2 ) {
1164  auto end = face_vhandles.end() - 1;
1165  auto wedgeEnd = face_wedges.end() - 1;
1166  auto normalEnd = face_normals.end() - 1;
1167 
1168  while ( begin != end && *begin == *end ) {
1169  end--;
1170  wedgeEnd--;
1171  normalEnd--;
1172  }
1173  face_vhandles.erase( end + 1, face_vhandles.end() );
1174  face_wedges.erase( wedgeEnd + 1, face_wedges.end() );
1175  face_normals.erase( normalEnd + 1, face_normals.end() );
1176  }
1177  }
1178  // then remove duplicates
1179  // e.g. 1 2 2 becomes 1 2
1180  // equiv of
1181  // face_vhandles.erase( std::unique( face_vhandles.begin(), face_vhandles.end() ),
1182  // face_vhandles.end() );
1183  // but handles wedges and normals
1184  // see (https://en.cppreference.com/w/cpp/algorithm/unique)
1185  {
1186  auto first = face_vhandles.begin();
1187  auto wedgeFirst = face_wedges.begin();
1188  auto normalFirst = face_normals.begin();
1189  auto last = face_vhandles.end();
1190 
1191  if ( first != last ) {
1192  auto result = first;
1193  auto wedgeResult = wedgeFirst;
1194  auto normalResult = normalFirst;
1195  while ( ++first != last ) {
1196  if ( !( *result == *first ) ) {
1197  ++result;
1198  ++wedgeResult;
1199  ++normalResult;
1200  if ( result != first ) {
1201  *result = std::move( *first );
1202  *wedgeResult = std::move( *wedgeFirst );
1203  *normalResult = std::move( *normalFirst );
1204  }
1205  }
1206  }
1207  face_vhandles.erase( result + 1, face_vhandles.end() );
1208  face_wedges.erase( wedgeResult + 1, face_wedges.end() );
1209  face_normals.erase( normalResult + 1, face_normals.end() );
1210  }
1211  }
1212 
1214  // unique sort size == vhandles size, if not split ...
1215 
1216  TopologicalMesh::FaceHandle fh;
1217  // skip 2 vertex face
1218  if ( face_vhandles.size() > 2 ) fh = add_face( face_vhandles );
1219 
1220  // In case of topological inconsistancy, face will be invalid (or uninitialized <>
1221  // invalid)
1222  if ( fh.is_valid() ) {
1223  for ( size_t vindex = 0; vindex < face_vhandles.size(); vindex++ ) {
1224  TopologicalMesh::HalfedgeHandle heh =
1225  halfedge_handle( face_vhandles[vindex], fh );
1226  if ( hasNormals ) set_normal( heh, face_normals[vindex] );
1227  property( m_wedgeIndexPph, heh ) = m_wedges.newReference( face_wedges[vindex] );
1228  }
1229  }
1230  else { command.process( face_vhandles ); }
1231  face_vhandles.clear();
1232  face_normals.clear();
1233  }
1234  };
1235 
1236  if ( abstractLayer.hasSemantic( TriangleIndexLayer::staticSemanticName ) ) {
1237  const auto& faces = static_cast<const TriangleIndexLayer&>( abstractLayer ).collection();
1238  LOG( logDEBUG ) << "TopologicalMesh: process " << faces.size() << " triangular faces ";
1239  processFaces( faces );
1240  }
1241  else if ( abstractLayer.hasSemantic( PolyIndexLayer::staticSemanticName ) ) {
1242  const auto& faces = static_cast<const PolyIndexLayer&>( abstractLayer ).collection();
1243  LOG( logDEBUG ) << "TopologicalMesh: process " << faces.size() << " polygonal faces ";
1244  processFaces( faces );
1245  }
1246 
1247  command.postProcess( *this );
1248  if ( hasNormals ) {
1249  m_normalsIndex =
1250  m_wedges.getWedgeAttribIndex<Normal>( getAttribName( MeshAttrib::VERTEX_NORMAL ) );
1251 
1252  m_vertexFaceWedgesWithSameNormals.clear();
1253  m_vertexFaceWedgesWithSameNormals.resize( n_vertices() );
1254 
1255  for ( auto itr = vertices_begin(), stop = vertices_end(); itr != stop; ++itr ) {
1256  std::unordered_map<TopologicalMesh::Normal,
1257  std::pair<std::set<FaceHandle>, std::set<WedgeIndex>>,
1258  hash_vec>
1259  normalSharedByWedges;
1260 
1261  auto vh = *itr;
1262 
1263  for ( ConstVertexIHalfedgeIter vh_it = cvih_iter( vh ); vh_it.is_valid(); ++vh_it ) {
1264  const auto& widx = property( m_wedgeIndexPph, *vh_it );
1265  if ( widx.isValid() && !m_wedges.getWedge( widx ).isDeleted() ) {
1266  auto oldNormal = m_wedges.getWedgeData<Normal>( widx, m_normalsIndex );
1267  normalSharedByWedges[oldNormal].first.insert( face_handle( *vh_it ) );
1268  normalSharedByWedges[oldNormal].second.insert( widx );
1269  }
1270  }
1271 
1272  for ( const auto& pair : normalSharedByWedges ) {
1273  for ( const auto& fh : pair.second.first ) {
1274  auto& v = m_vertexFaceWedgesWithSameNormals[vh.idx()][fh.idx()];
1275  v.insert( v.end(), pair.second.second.begin(), pair.second.second.end() );
1276  }
1277  }
1278  }
1279  }
1280  LOG( logDEBUG ) << "TopologicalMesh: load end with " << m_wedges.size() << " wedges ";
1281 }
1282 
1283 template <typename T>
1284 void TopologicalMesh::copyAttribToWedgeData( const MultiIndexedGeometry& mesh,
1285  unsigned int vindex,
1286  const std::vector<AttribHandle<T>>& attrHandleVec,
1287  VectorArray<T>* to ) {
1288  for ( auto handle : attrHandleVec ) {
1289  auto& attr = mesh.template getAttrib<T>( handle );
1290  to->push_back( attr.data()[vindex] );
1291  }
1292 }
1293 
1294 void TopologicalMesh::copyMeshToWedgeData( const MultiIndexedGeometry& mesh,
1295  unsigned int vindex,
1296  const std::vector<AttribHandle<Scalar>>& wprop_float,
1297  const std::vector<AttribHandle<Vector2>>& wprop_vec2,
1298  const std::vector<AttribHandle<Vector3>>& wprop_vec3,
1299  const std::vector<AttribHandle<Vector4>>& wprop_vec4,
1301  copyAttribToWedgeData( mesh, vindex, wprop_float, &wd->m_floatAttrib );
1302  copyAttribToWedgeData( mesh, vindex, wprop_vec2, &wd->m_vector2Attrib );
1303  copyAttribToWedgeData( mesh, vindex, wprop_vec3, &wd->m_vector3Attrib );
1304  copyAttribToWedgeData( mesh, vindex, wprop_vec4, &wd->m_vector4Attrib );
1305 }
1306 
1307 inline void TopologicalMesh::propagate_normal_to_wedges( VertexHandle vh ) {
1308  if ( !has_halfedge_normals() ) {
1309  LOG( logERROR ) << "TopologicalMesh has no normals, nothing set";
1310  return;
1311  }
1312  for ( VertexIHalfedgeIter vih_it = vih_iter( vh ); vih_it.is_valid(); ++vih_it ) {
1313  auto wd = getWedgeData( property( getWedgeIndexPph(), *vih_it ) );
1314 
1315  m_wedges.setWedgeAttrib( wd, getAttribName( MeshAttrib::VERTEX_NORMAL ), normal( vh ) );
1316 
1317  replaceWedge( *vih_it, wd );
1318  }
1319 }
1320 
1321 inline TopologicalMesh::HalfedgeHandle TopologicalMesh::halfedge_handle( VertexHandle vh,
1322  FaceHandle fh ) const {
1323  for ( ConstVertexIHalfedgeIter vih_it = cvih_iter( vh ); vih_it.is_valid(); ++vih_it ) {
1324  if ( face_handle( *vih_it ) == fh ) { return *vih_it; }
1325  }
1326  CORE_ASSERT( false, "vh is not a vertex of face fh" );
1327  return HalfedgeHandle();
1328 }
1329 
1330 inline const OpenMesh::HPropHandleT<TopologicalMesh::Index>&
1332  return m_inputTriangleMeshIndexPph;
1333 }
1334 
1335 inline const OpenMesh::HPropHandleT<TopologicalMesh::Index>&
1337  return m_outputTriangleMeshIndexPph;
1338 }
1339 
1340 inline std::set<TopologicalMesh::WedgeIndex>
1341 TopologicalMesh::getVertexWedges( OpenMesh::VertexHandle vh ) const {
1342  std::set<TopologicalMesh::WedgeIndex> ret;
1343 
1344  for ( ConstVertexIHalfedgeIter vh_it = cvih_iter( vh ); vh_it.is_valid(); ++vh_it ) {
1345  auto widx = property( m_wedgeIndexPph, *vh_it );
1346  if ( widx.isValid() && !m_wedges.getWedge( widx ).isDeleted() ) ret.insert( widx );
1347  }
1348  return ret;
1349 }
1350 
1351 inline TopologicalMesh::WedgeIndex
1352 TopologicalMesh::getWedgeIndex( OpenMesh::HalfedgeHandle heh ) const {
1353  return property( getWedgeIndexPph(), heh );
1354 }
1355 
1356 inline unsigned int TopologicalMesh::getWedgeRefCount( const WedgeIndex& idx ) const {
1357  return m_wedges.getWedgeRefCount( idx );
1358 }
1359 
1360 template <typename T>
1361 inline bool TopologicalMesh::setWedgeData( const TopologicalMesh::WedgeIndex& idx,
1362  const std::string& name,
1363  const T& value ) {
1364  return setWedgeAttrib( idx, name, value );
1365 }
1366 
1367 template <typename T>
1368 inline bool TopologicalMesh::setWedgeAttrib( const TopologicalMesh::WedgeIndex& idx,
1369  const std::string& name,
1370  const T& value ) {
1371  return m_wedges.setWedgeAttrib( idx, name, value );
1372 }
1373 
1374 inline void TopologicalMesh::setWedgeData( TopologicalMesh::WedgeIndex widx,
1375  const TopologicalMesh::WedgeData& wedge ) {
1376  m_wedges.setWedgeData( widx, wedge );
1377 }
1378 
1379 inline const TopologicalMesh::WedgeData&
1380 TopologicalMesh::getWedgeData( const WedgeIndex& idx ) const {
1381  return m_wedges.getWedgeData( idx );
1382 }
1383 
1384 template <typename T>
1385 inline const T& TopologicalMesh::getWedgeData( const TopologicalMesh::WedgeIndex& idx,
1386  const std::string& name ) const {
1387  return getWedgeAttrib<T>( idx, name );
1388 }
1389 
1390 template <typename T>
1391 inline const T& TopologicalMesh::getWedgeAttrib( const TopologicalMesh::WedgeIndex& idx,
1392  const std::string& name ) const {
1393  return m_wedges.getWedgeData<T>( idx, name );
1394 }
1395 
1396 inline TopologicalMesh::WedgeIndex TopologicalMesh::replaceWedge( OpenMesh::HalfedgeHandle he,
1397  const WedgeData& wd ) {
1398  m_wedges.del( property( getWedgeIndexPph(), he ) );
1399  auto index = m_wedges.add( wd );
1400  property( getWedgeIndexPph(), he ) = index;
1401  return index;
1402 }
1403 
1404 inline void TopologicalMesh::replaceWedgeIndex( OpenMesh::HalfedgeHandle he,
1405  const WedgeIndex& widx ) {
1406  m_wedges.del( property( getWedgeIndexPph(), he ) );
1407  property( getWedgeIndexPph(), he ) = m_wedges.newReference( widx );
1408 }
1409 
1411  for ( auto itr = vertices_begin(), stop = vertices_end(); itr != stop; ++itr ) {
1412  mergeEqualWedges( *itr );
1413  }
1414 }
1415 
1416 inline void TopologicalMesh::mergeEqualWedges( OpenMesh::VertexHandle vh ) {
1417  for ( auto itr = vih_iter( vh ); itr.is_valid(); ++itr ) {
1418  // replace will search if wedge already present and use it, so merge occurs.
1419  if ( !is_boundary( *itr ) )
1420  replaceWedge( *itr, getWedgeData( property( getWedgeIndexPph(), *itr ) ) );
1421  }
1422 }
1423 
1424 inline const std::vector<std::string>& TopologicalMesh::getVec4AttribNames() const {
1425  return m_wedges.m_vector4AttribNames;
1426 }
1427 inline const std::vector<std::string>& TopologicalMesh::getVec3AttribNames() const {
1428  return m_wedges.m_vector3AttribNames;
1429 }
1430 inline const std::vector<std::string>& TopologicalMesh::getVec2AttribNames() const {
1431  return m_wedges.m_vector2AttribNames;
1432 }
1433 inline const std::vector<std::string>& TopologicalMesh::getFloatAttribNames() const {
1434  return m_wedges.m_floatAttribNames;
1435 }
1436 
1437 inline bool TopologicalMesh::isFeatureVertex( const VertexHandle& vh ) const {
1438  return getVertexWedges( vh ).size() != 1;
1439 }
1440 
1441 inline bool TopologicalMesh::isFeatureEdge( const EdgeHandle& eh ) const {
1442  auto heh0 = halfedge_handle( eh, 0 );
1443  auto heh1 = halfedge_handle( eh, 1 );
1444 
1445  return property( m_wedgeIndexPph, heh0 ) !=
1446  property( m_wedgeIndexPph,
1447  prev_halfedge_handle( opposite_halfedge_handle( heh0 ) ) ) ||
1448  property( m_wedgeIndexPph, heh1 ) !=
1449  property( m_wedgeIndexPph,
1450  prev_halfedge_handle( opposite_halfedge_handle( heh1 ) ) );
1451 }
1452 
1453 inline const OpenMesh::HPropHandleT<TopologicalMesh::WedgeIndex>&
1454 TopologicalMesh::getWedgeIndexPph() const {
1455  return m_wedgeIndexPph;
1456 }
1457 
1458 } // namespace Geometry
1459 } // namespace Core
1460 } // namespace Ra
const NormalAttribHandle::Container & normals() const
Access the vertices normals.
const PointAttribHandle::Container & vertices() const
Access the vertices positions.
Utils::AttribManager & vertexAttribs()
A single layer MultiIndexedGeometry.
AbstractGeometry with per-vertex attributes and layers of indices. Each layer represents a different ...
const GeometryIndexLayerBase & getLayer(const LayerKeyType &layerKey) const
Read-only access to a layer.
WedgeIndex getWedgeIndex(OpenMesh::HalfedgeHandle heh) const
void replaceWedgeIndex(OpenMesh::HalfedgeHandle he, const WedgeIndex &widx)
TopologicalMesh([[deprecated("Use MultiIndexedGeometry instead")]] const Ra::Core::Geometry::IndexedGeometry< MeshIndex > &mesh, NonManifoldFaceCommand command)
WedgeIndex replaceWedge(OpenMesh::HalfedgeHandle he, const WedgeData &wd)
bool isFeatureEdge(const EdgeHandle &eh) const
void propagate_normal_to_wedges(VertexHandle vh)
bool isFeatureVertex(const VertexHandle &vh) const
true if more than one wedge arount vertex vh, false if only one wedge
void setWedgeData(WedgeIndex widx, const WedgeData &wd)
std::set< WedgeIndex > getVertexWedges(OpenMesh::VertexHandle vh) const
const OpenMesh::HPropHandleT< Index > & getInputTriangleMeshIndexPropHandle() const
unsigned int getWedgeRefCount(const WedgeIndex &idx) const
const OpenMesh::HPropHandleT< Index > & getOutputTriangleMeshIndexPropHandle() const
TopologicalMesh([[deprecated("Use MultiIndexedGeometry instead")]] const Ra::Core::Geometry::IndexedGeometry< MeshIndex > &mesh)
Convenience constructor.
const WedgeData & getWedgeData(const WedgeIndex &idx) const
WedgeData newWedgeData(HalfedgeHandle he) const
HalfedgeHandle halfedge_handle(VertexHandle vh, FaceHandle fh) const
An attrib handle basically store an Index and a name.
Definition: Attribs.hpp:146
void for_each_attrib(const F &func) const
Definition: Attribs.hpp:755
Quaternion add(const Quaternion &q1, const Quaternion &q2)
Returns the sum of two quaternions.
Definition: Cage.cpp:3
Index layer for polygonal mesh.
Index layer for triangle mesh.