Radium Engine  1.5.20
Loading...
Searching...
No Matches
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
26namespace Ra {
27namespace Core {
28namespace Geometry {
29using namespace Utils; // log, AttribXXX
30
34struct 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
55class 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 class WedgeData;
67 using WedgeIndex = Ra::Core::Utils::Index;
68 using WedgeAttribIndex = Ra::Core::Utils::Index;
69
73 explicit TopologicalMesh();
74
79 template <typename MeshIndex>
80 explicit TopologicalMesh( [[deprecated(
81 "Use MultiIndexedGeometry instead" )]] const Ra::Core::Geometry::IndexedGeometry<MeshIndex>&
82 mesh );
83
89 explicit TopologicalMesh(
92
105 template <typename MeshIndex, typename NonManifoldFaceCommand>
106 explicit TopologicalMesh( [[deprecated( "Use MultiIndexedGeometry instead" )]] const Ra::Core::
108 NonManifoldFaceCommand command );
109
123 template <typename NonManifoldFaceCommand>
124 explicit TopologicalMesh(
127 NonManifoldFaceCommand command );
128
129 inline void
130 initWithWedge( const Ra::Core::Geometry::MultiIndexedGeometry& mesh,
132
133 template <typename NonManifoldFaceCommand>
134 void initWithWedge( const Ra::Core::Geometry::MultiIndexedGeometry& mesh,
136 NonManifoldFaceCommand command );
141 TriangleMesh toTriangleMesh();
142
148 PolyMesh toPolyMesh();
149
150 LineMesh toLineMesh();
151
156 void updateTriangleMesh( Ra::Core::Geometry::MultiIndexedGeometry& mesh );
157 void updateTriangleMeshNormals( Ra::Core::Geometry::MultiIndexedGeometry& mesh );
158 void updateTriangleMeshNormals( AttribArrayGeometry::NormalAttribHandle::Container& normals );
159
160 void update( const Ra::Core::Geometry::MultiIndexedGeometry& mesh );
161 void updateNormals( const Ra::Core::Geometry::MultiIndexedGeometry& mesh );
162 void updatePositions( const Ra::Core::Geometry::MultiIndexedGeometry& mesh );
163 void updatePositions( const AttribArrayGeometry::PointAttribHandle::Container& vertices );
164 // import other version of halfedge_handle method
165 using base::halfedge_handle;
166
171 inline HalfedgeHandle halfedge_handle( VertexHandle vh, FaceHandle fh ) const;
172
175 using base::normal;
176 using base::set_normal;
178
184 inline void propagate_normal_to_wedges( VertexHandle vh );
185
190 inline const OpenMesh::HPropHandleT<Index>& getInputTriangleMeshIndexPropHandle() const;
191
197 inline const OpenMesh::HPropHandleT<Index>& getOutputTriangleMeshIndexPropHandle() const;
198
204
205 void updateWedgeNormals();
207
210 void copyPointsPositionToWedges();
215
227 bool splitEdge( TopologicalMesh::EdgeHandle eh, Scalar f );
228
238 void collapse( HalfedgeHandle he, bool keepFromVertex = 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
372 {
373 public:
374 explicit WedgeData() = default;
375 inline bool operator==( const WedgeData& lhs ) const;
376 inline bool operator!=( const WedgeData& lhs ) const;
377 inline bool operator<( const WedgeData& lhs ) const;
378
379 template <typename T>
380 inline VectorArray<T>& getAttribArray();
381 template <typename T>
382 inline const VectorArray<T>& getAttribArray() const;
383 friend Wedge;
384
385 // Index m_inputTriangleMeshIndex;
386 // Index m_outputTriangleMeshIndex;
387 VertexHandle m_vertexHandle;
388 Vector3 m_position {};
389 VectorArray<Scalar> m_floatAttrib;
390 VectorArray<Vector2> m_vector2Attrib;
391 VectorArray<Vector3> m_vector3Attrib;
392 VectorArray<Vector4> m_vector4Attrib;
393
394 private:
395 // return 1 : equals, 2: strict less, 3: strict greater
396 template <typename T>
397 static int compareVector( const T& a, const T& b );
398 };
399
400 private:
401 // base on openmesh version
402 void collapse_edge( HalfedgeHandle, bool );
403 void collapse_loop( HalfedgeHandle );
404
410 class RA_CORE_API Wedge
411 {
412 public:
413 explicit Wedge() {}
414 explicit Wedge( const WedgeData& wd ) : m_wedgeData { wd }, m_refCount { 1 } {};
415 const WedgeData& getWedgeData() const { return m_wedgeData; }
416 void setWedgeData( const WedgeData& wedgeData ) { m_wedgeData = wedgeData; }
417 void setWedgeData( WedgeData&& wedgeData ) { m_wedgeData = std::move( wedgeData ); }
418 void incrementRefCount() { ++m_refCount; }
419 void decrementRefCount() {
420 if ( m_refCount ) --m_refCount;
421 }
423 bool operator==( const Wedge& lhs ) const { return m_wedgeData == lhs.m_wedgeData; }
424
425 bool isDeleted() const { return m_refCount == 0; }
426 unsigned int getRefCount() const { return m_refCount; }
427
428 friend WedgeCollection;
429 friend TopologicalMesh;
430
431 private:
432 WedgeData& getWedgeData() { return m_wedgeData; }
433
434 WedgeData m_wedgeData {};
435 unsigned int m_refCount { 0 };
436 };
437
445 class RA_CORE_API WedgeCollection
446 {
447 public:
455 WedgeIndex add( const WedgeData& wd );
456
463 inline void del( const WedgeIndex& idx );
464 WedgeIndex newReference( const WedgeIndex& idx );
465
472 inline const Wedge& getWedge( const WedgeIndex& idx ) const;
473
474 inline const WedgeData& getWedgeData( const WedgeIndex& idx ) const;
475 template <typename T>
476 inline const T& getWedgeData( const WedgeIndex& idx, const std::string& name ) const;
477 template <typename T>
478 inline T& getWedgeData( const WedgeIndex& idx, int attribIndex );
479 template <typename T>
480 inline const T& getWedgeAttrib( const WedgeIndex& idx, const std::string& name ) const;
481 template <typename T>
482 inline T& getWedgeAttrib( const WedgeIndex& idx, int attribIndex );
483
484 unsigned int getWedgeRefCount( const WedgeIndex& idx ) const;
485
487 inline void setWedgeData( const WedgeIndex& idx, const WedgeData& wd );
488
493 template <typename T>
494 inline bool
495 setWedgeAttrib( TopologicalMesh::WedgeData& wd, const std::string& name, const T& value );
496 template <typename T>
497 inline bool
498 setWedgeAttrib( const WedgeIndex& idx, const std::string& name, const T& value );
499 template <typename T>
500 inline void setWedgeAttrib( const TopologicalMesh::WedgeIndex& idx,
501 const int& attribIndex,
502 const T& value );
503
504 template <typename T>
505 inline WedgeAttribIndex getWedgeAttribIndex( const std::string& name );
506
507 inline bool setWedgePosition( const WedgeIndex& idx, const Vector3& value );
508
510
511 template <typename T>
512 inline const std::vector<std::string>& getNameArray() const;
513
514 // name is supposed to be unique within all attribs
515 // not checks are performed
516 // return the index of the the newly added attrib.
517 template <typename T>
518 WedgeAttribIndex addAttribName( const std::string& name );
519
520 // add attrib to all wedges with default value value
521 template <typename T>
522 WedgeAttribIndex addAttrib( const std::string& name, const T& value = {} );
523
526 std::vector<int> computeCleanupOffset() const;
531
532 inline size_t size() const { return m_data.size(); }
533
535 inline void garbageCollection();
536
537 inline void clean();
538
539 // return a new wedgeData with uninit values.
540 inline WedgeData newWedgeData() const;
541 inline WedgeData newWedgeData( TopologicalMesh::VertexHandle vh,
542 TopologicalMesh::Point p ) const;
543
546 std::vector<std::string> m_floatAttribNames;
547 std::vector<std::string> m_vector2AttribNames;
548 std::vector<std::string> m_vector3AttribNames;
549 std::vector<std::string> m_vector4AttribNames;
550
553 std::vector<AttribHandle<Scalar>> m_wedgeFloatAttribHandles;
554 std::vector<AttribHandle<Vector2>> m_wedgeVector2AttribHandles;
555 std::vector<AttribHandle<Vector3>> m_wedgeVector3AttribHandles;
556 std::vector<AttribHandle<Vector4>> m_wedgeVector4AttribHandles;
557
558 template <typename T>
559 inline std::vector<std::string>& getNameArray();
560 AlignedStdVector<Wedge> m_data;
561 };
562
563 // internal function to build Core Mesh attribs correspondance to wedge attribs.
564 class InitWedgeAttribsFromMultiIndexedGeometry
565 {
566 public:
567 InitWedgeAttribsFromMultiIndexedGeometry(
568 TopologicalMesh* topo,
570 m_topo( topo ), m_triMesh( triMesh ) {}
571 void operator()( AttribBase* attr ) const;
572
573 private:
574 TopologicalMesh* m_topo;
576 };
577
580 struct DefaultNonManifoldFaceCommand {
582 DefaultNonManifoldFaceCommand( const std::string& details = {} ) : m_details { details } {}
584 inline void initialize( const Ra::Core::Geometry::MultiIndexedGeometry& ) {}
586 inline void process( const std::vector<TopologicalMesh::VertexHandle>& /*face_vhandles*/ ) {
587 LOG( logWARNING ) << "Invalid face handle returned : face not added " + m_details;
588 }
590 inline void postProcess( TopologicalMesh& ) {}
591
592 private:
593 std::string m_details;
594 };
596
597 WedgeData interpolateWedgeAttributes( const WedgeData&, const WedgeData&, Scalar alpha );
598
600 template <typename T>
601 inline void copyAttribToWedgeData( const Ra::Core::Geometry::MultiIndexedGeometry& mesh,
602 unsigned int vindex,
603 const std::vector<AttribHandle<T>>& attrHandleVec,
604 VectorArray<T>* to );
605
607 inline void copyMeshToWedgeData( const Ra::Core::Geometry::MultiIndexedGeometry& mesh,
608 unsigned int vindex,
609 const std::vector<AttribHandle<Scalar>>& wprop_float,
610 const std::vector<AttribHandle<Vector2>>& wprop_vec2,
611 const std::vector<AttribHandle<Vector3>>& wprop_vec3,
612 const std::vector<AttribHandle<Vector4>>& wprop_vec4,
613 TopologicalMesh::WedgeData* wd );
614
615 template <typename T>
616 using HandleAndValueVector =
618 Eigen::aligned_allocator<std::pair<AttribHandle<T>, T>>>;
619
620 void split_copy( EdgeHandle _eh, VertexHandle _vh );
621 void split( EdgeHandle _eh, VertexHandle _vh );
622
623 OpenMesh::HPropHandleT<WedgeIndex> m_wedgeIndexPph;
624 WedgeCollection m_wedges;
627 OpenMesh::HPropHandleT<Index> m_inputTriangleMeshIndexPph;
628 OpenMesh::HPropHandleT<Index> m_outputTriangleMeshIndexPph;
629
630 int m_normalsIndex { -1 };
631 // vertex handle idx -> face handle idx -> wedge idx with the same normal
632 std::vector<std::map<int, std::vector<int>>> m_vertexFaceWedgesWithSameNormals;
633
634 friend class TMOperations;
635};
636
637// heplers
638void printWedgesInfo( const TopologicalMesh& );
639
643
644inline bool TopologicalMesh::WedgeData::operator==( const TopologicalMesh::WedgeData& lhs ) const {
645 return
646 // do not have this yet, not sure we need to test them
647 // m_inputTriangleMeshIndex == lhs.m_inputTriangleMeshIndex &&
648 // m_outputTriangleMeshIndex == lhs.m_outputTriangleMeshIndex &&
649 m_position == lhs.m_position && m_floatAttrib == lhs.m_floatAttrib &&
650 m_vector2Attrib == lhs.m_vector2Attrib && m_vector3Attrib == lhs.m_vector3Attrib &&
651 m_vector4Attrib == lhs.m_vector4Attrib;
652}
653
654bool TopologicalMesh::WedgeData::operator!=( const TopologicalMesh::WedgeData& lhs ) const {
655 return !( *this == lhs );
656}
657
658inline bool TopologicalMesh::WedgeData::operator<( const TopologicalMesh::WedgeData& lhs ) const {
659
660 CORE_ASSERT( ( m_floatAttrib.size() == lhs.m_floatAttrib.size() ) &&
661 ( m_vector2Attrib.size() == lhs.m_vector2Attrib.size() ) &&
662 ( m_vector3Attrib.size() == lhs.m_vector3Attrib.size() ) &&
663 ( m_vector4Attrib.size() == lhs.m_vector4Attrib.size() ),
664 "Could only compare wedge with same number of attributes" );
665
666 {
667 int comp = compareVector( m_position, lhs.m_position );
668 if ( comp == 2 ) return true;
669 if ( comp == 3 ) return false;
670 }
671 for ( size_t i = 0; i < m_floatAttrib.size(); i++ ) {
672 if ( m_floatAttrib[i] < lhs.m_floatAttrib[i] )
673 return true;
674 else if ( m_floatAttrib[i] > lhs.m_floatAttrib[i] )
675 return false;
676 }
677
678 for ( size_t i = 0; i < m_vector2Attrib.size(); i++ ) {
679 int comp = compareVector( m_vector2Attrib[i], lhs.m_vector2Attrib[i] );
680 if ( comp == 2 ) return true;
681 if ( comp == 3 ) return false;
682 }
683 for ( size_t i = 0; i < m_vector3Attrib.size(); i++ ) {
684 int comp = compareVector( m_vector3Attrib[i], lhs.m_vector3Attrib[i] );
685 if ( comp == 2 ) return true;
686 if ( comp == 3 ) return false;
687 }
688 for ( size_t i = 0; i < m_vector4Attrib.size(); i++ ) {
689 int comp = compareVector( m_vector4Attrib[i], lhs.m_vector4Attrib[i] );
690 if ( comp == 2 ) return true;
691 if ( comp == 3 ) return false;
692 }
693 return false;
694}
695
696#define GET_ATTRIB_ARRAY_HELPER( TYPE, NAME ) \
697 template <> \
698 inline VectorArray<TYPE>& TopologicalMesh::WedgeData::getAttribArray<TYPE>() { \
699 return m_##NAME##Attrib; \
700 } \
701 template <> \
702 inline const VectorArray<TYPE>& TopologicalMesh::WedgeData::getAttribArray<TYPE>() const { \
703 return m_##NAME##Attrib; \
704 }
705
706GET_ATTRIB_ARRAY_HELPER( Scalar, float )
707GET_ATTRIB_ARRAY_HELPER( Vector2, vector2 )
708GET_ATTRIB_ARRAY_HELPER( Vector3, vector3 )
709GET_ATTRIB_ARRAY_HELPER( Vector4, vector4 )
710#undef GET_ATTRIB_ARRAY_HELPER
711
712template <typename T>
713inline VectorArray<T>& TopologicalMesh::WedgeData::getAttribArray() {
714 static_assert( sizeof( T ) == -1, "this type is not supported" );
715}
716
717// return 1 : equals, 2: strict less, 3: strict greater
718template <typename T>
719int TopologicalMesh::WedgeData::compareVector( const T& a, const T& b ) {
720 for ( int i = 0; i < T::RowsAtCompileTime; i++ ) {
721 if ( a[i] < b[i] ) return 2;
722 if ( a[i] > b[i] ) return 3;
723 }
724 // (a == b)
725 return 1;
726}
727
731
732// all in class for the moment
733
737
738inline void TopologicalMesh::WedgeCollection::del( const TopologicalMesh::WedgeIndex& idx ) {
739 if ( idx.isValid() ) m_data[idx].decrementRefCount();
740}
741
742inline TopologicalMesh::WedgeIndex
743TopologicalMesh::WedgeCollection::newReference( const TopologicalMesh::WedgeIndex& idx ) {
744 if ( idx.isValid() ) m_data[idx].incrementRefCount();
745 return idx;
746}
747
748inline const TopologicalMesh::Wedge&
749TopologicalMesh::WedgeCollection::getWedge( const TopologicalMesh::WedgeIndex& idx ) const {
750 return m_data[idx];
751}
752
753inline const TopologicalMesh::WedgeData&
754TopologicalMesh::WedgeCollection::getWedgeData( const WedgeIndex& idx ) const {
755 CORE_ASSERT( idx.isValid() && !m_data[idx].isDeleted(),
756 "access to invalid or deleted wedge is prohibited" );
757
758 return m_data[idx].getWedgeData();
759}
760
761template <typename T>
762inline const T&
763TopologicalMesh::WedgeCollection::getWedgeData( const TopologicalMesh::WedgeIndex& idx,
764 const std::string& name ) const {
765 return getWedgeAttrib<T>( idx, name );
766}
767
768template <typename T>
769inline const T&
770TopologicalMesh::WedgeCollection::getWedgeAttrib( const TopologicalMesh::WedgeIndex& idx,
771 const std::string& name ) const {
772 if ( idx.isValid() ) {
773 auto nameArray = getNameArray<T>();
774 auto itr = std::find( nameArray.begin(), nameArray.end(), name );
775 if ( itr != nameArray.end() ) {
776 auto attrIndex = std::distance( nameArray.begin(), itr );
777 return m_data[idx].getWedgeData().getAttribArray<T>()[attrIndex];
778 }
779 else {
780 LOG( logERROR ) << "Warning, set wedge: no wedge attrib named " << name << " of type "
781 << typeid( T ).name();
782 }
783 }
784 static T dummy;
785 return dummy;
786}
787
788template <typename T>
789inline T& TopologicalMesh::WedgeCollection::getWedgeData( const TopologicalMesh::WedgeIndex& idx,
790 int attribIndex ) {
791 return getWedgeAttrib<T>( idx, attribIndex );
792}
793
794template <typename T>
795inline T& TopologicalMesh::WedgeCollection::getWedgeAttrib( const TopologicalMesh::WedgeIndex& idx,
796 int attribIndex ) {
797 return m_data[idx].getWedgeData().getAttribArray<T>()[attribIndex];
798}
799
800inline unsigned int
801TopologicalMesh::WedgeCollection::getWedgeRefCount( const WedgeIndex& idx ) const {
802 CORE_ASSERT( idx.isValid(), "access to invalid or deleted wedge is prohibited" );
803 return m_data[idx].getRefCount();
804}
805
806inline void TopologicalMesh::WedgeCollection::setWedgeData( const TopologicalMesh::WedgeIndex& idx,
807 const TopologicalMesh::WedgeData& wd ) {
808 if ( !( wd.m_floatAttrib.size() == m_floatAttribNames.size() &&
809 wd.m_vector2Attrib.size() == m_vector2AttribNames.size() &&
810 wd.m_vector3Attrib.size() == m_vector3AttribNames.size() &&
811 wd.m_vector4Attrib.size() == m_vector4AttribNames.size() ) ) {
812 LOG( logWARNING ) << "Warning, topological mesh set wedge: number of attribs inconsistency";
813 }
814 if ( idx.isValid() ) m_data[idx].setWedgeData( wd );
815}
816
817template <typename T>
818inline bool TopologicalMesh::WedgeCollection::setWedgeAttrib( TopologicalMesh::WedgeData& wd,
819 const std::string& name,
820 const T& value ) {
821 auto nameArray = getNameArray<T>();
822 auto itr = std::find( nameArray.begin(), nameArray.end(), name );
823 if ( itr != nameArray.end() ) {
824 auto attrIndex = std::distance( nameArray.begin(), itr );
825 wd.getAttribArray<T>()[attrIndex] = value;
826 return true;
827 }
828 else {
829 LOG( logERROR ) << "Warning, set wedge: no wedge attrib named " << name << " of type "
830 << typeid( T ).name();
831 }
832 return false;
833}
834
835template <typename T>
836inline bool
837TopologicalMesh::WedgeCollection::setWedgeAttrib( const TopologicalMesh::WedgeIndex& idx,
838 const std::string& name,
839 const T& value ) {
840 if ( idx.isValid() ) {
841 auto nameArray = getNameArray<T>();
842 auto itr = std::find( nameArray.begin(), nameArray.end(), name );
843 if ( itr != nameArray.end() ) {
844 auto attrIndex = std::distance( nameArray.begin(), itr );
845 m_data[idx].getWedgeData().getAttribArray<T>()[attrIndex] = value;
846 return true;
847 }
848 else {
849 LOG( logERROR ) << "Warning, set wedge: no wedge attrib named " << name << " of type "
850 << typeid( T ).name();
851 }
852 }
853 return false;
854}
855
856template <typename T>
857inline void
858TopologicalMesh::WedgeCollection::setWedgeAttrib( const TopologicalMesh::WedgeIndex& idx,
859 const int& attrIndex,
860 const T& value ) {
861 m_data[idx].getWedgeData().getAttribArray<T>()[attrIndex] = value;
862}
863
864template <typename T>
865inline TopologicalMesh::WedgeAttribIndex
866TopologicalMesh::WedgeCollection::getWedgeAttribIndex( const std::string& name ) {
867 auto nameArray = getNameArray<T>();
868 auto itr = std::find( nameArray.begin(), nameArray.end(), name );
869 if ( itr != nameArray.end() ) { return std::distance( nameArray.begin(), itr ); }
870 return 0;
871}
872
873inline bool
874TopologicalMesh::WedgeCollection::setWedgePosition( const TopologicalMesh::WedgeIndex& idx,
875 const Vector3& value ) {
876 if ( idx.isValid() ) {
877 m_data[idx].getWedgeData().m_position = value;
878 return true;
879 }
880 return false;
881}
882
883#define GET_NAME_ARRAY_HELPER( TYPE, NAME ) \
884 template <> \
885 inline const std::vector<std::string>& TopologicalMesh::WedgeCollection::getNameArray<TYPE>() \
886 const { \
887 return m_##NAME##AttribNames; \
888 } \
889 template <> \
890 inline std::vector<std::string>& TopologicalMesh::WedgeCollection::getNameArray<TYPE>() { \
891 return m_##NAME##AttribNames; \
892 }
893
894GET_NAME_ARRAY_HELPER( Scalar, float )
895GET_NAME_ARRAY_HELPER( Vector2, vector2 )
896GET_NAME_ARRAY_HELPER( Vector3, vector3 )
897GET_NAME_ARRAY_HELPER( Vector4, vector4 )
898
899#undef GET_NAME_ARRAY_HELPER
900// These template functions are defined above for supported types.
901// For unsupported types they simply generate a compile error.
902template <typename T>
903inline const std::vector<std::string>& TopologicalMesh::WedgeCollection::getNameArray() const {
904
905 LOG( logWARNING ) << "Warning, mesh attribute " << typeid( T ).name()
906 << " is not supported (only float, vec2, vec3 nor vec4 are supported)";
907 static_assert( sizeof( T ) == -1, "this type is not supported" );
908 return m_floatAttribNames;
909}
910
911template <typename T>
912inline std::vector<std::string>& TopologicalMesh::WedgeCollection::getNameArray() {
913
914 LOG( logWARNING ) << "Warning, mesh attribute " << typeid( T ).name()
915 << " is not supported (only float, vec2, vec3 nor vec4 are supported)";
916 static_assert( sizeof( T ) == -1, "this type is not supported" );
917 return m_floatAttribNames;
918}
919template <typename T>
920TopologicalMesh::WedgeAttribIndex
921TopologicalMesh::WedgeCollection::addAttribName( const std::string& name ) {
922 if ( name != getAttribName( MeshAttrib::VERTEX_POSITION ) ) {
923 getNameArray<T>().push_back( name );
924 }
925 return getNameArray<T>().size() - 1;
926}
927
928template <typename T>
929TopologicalMesh::WedgeAttribIndex
930TopologicalMesh::WedgeCollection::addAttrib( const std::string& name, const T& value ) {
931
932 auto index = addAttribName<T>( name );
933 for ( auto& w : m_data ) {
934 CORE_ASSERT( index = w.getWedgeData().getAttribArray<T>().size(),
935 "inconsistent wedge attrib" );
936 w.getWedgeData().getAttribArray<T>().push_back( value );
937 }
938 return index;
939}
940
941inline void TopologicalMesh::WedgeCollection::garbageCollection() {
942 m_data.erase( std::remove_if( m_data.begin(),
943 m_data.end(),
944 []( const Wedge& w ) { return w.isDeleted(); } ),
945 m_data.end() );
946}
947
948inline void TopologicalMesh::WedgeCollection::clean() {
949 m_data.clear();
950 m_floatAttribNames.clear();
951 m_vector2AttribNames.clear();
952 m_vector3AttribNames.clear();
953 m_vector4AttribNames.clear();
954 m_wedgeFloatAttribHandles.clear();
955 m_wedgeVector2AttribHandles.clear();
956 m_wedgeVector3AttribHandles.clear();
957 m_wedgeVector4AttribHandles.clear();
958}
959
960template <typename T>
961void init( VectorArray<T>& vec, const std::vector<std::string> names ) {
962 for ( size_t i = 0; i < names.size(); ++i ) {
963 vec.emplace_back();
964 }
965}
966// return a new wedgeData with uninit values.
967inline TopologicalMesh::WedgeData TopologicalMesh::WedgeCollection::newWedgeData() const {
968 WedgeData ret;
969 init<Scalar>( ret.getAttribArray<Scalar>(), m_floatAttribNames );
970 init<Vector2>( ret.getAttribArray<Vector2>(), m_vector2AttribNames );
971 init<Vector3>( ret.getAttribArray<Vector3>(), m_vector3AttribNames );
972 init<Vector4>( ret.getAttribArray<Vector4>(), m_vector4AttribNames );
973 return ret;
974}
975
976inline TopologicalMesh::WedgeData
977TopologicalMesh::WedgeCollection::newWedgeData( TopologicalMesh::VertexHandle vh,
978 TopologicalMesh::Point p ) const {
979 WedgeData ret = newWedgeData();
980 ret.m_vertexHandle = vh;
981 ret.m_position = p;
982 return ret;
983}
984
988inline void
989TopologicalMesh::InitWedgeAttribsFromMultiIndexedGeometry::operator()( AttribBase* attr ) const {
990 if ( attr->getSize() != m_triMesh.vertices().size() ) {
991 LOG( logWARNING ) << "[TopologicalMesh] Skip badly sized attribute " << attr->getName();
992 }
993 else if ( attr->getName() != getAttribName( MeshAttrib::VERTEX_POSITION ) ) {
994 if ( attr->isFloat() ) {
995 m_topo->m_wedges.m_wedgeFloatAttribHandles.push_back(
996 m_triMesh.template getAttribHandle<Scalar>( attr->getName() ) );
997 m_topo->m_wedges.addAttribName<Scalar>( attr->getName() );
998 }
999 else if ( attr->isVector2() ) {
1000 m_topo->m_wedges.m_wedgeVector2AttribHandles.push_back(
1001 m_triMesh.template getAttribHandle<Vector2>( attr->getName() ) );
1002 m_topo->m_wedges.addAttribName<Vector2>( attr->getName() );
1003 }
1004 else if ( attr->isVector3() ) {
1005 m_topo->m_wedges.m_wedgeVector3AttribHandles.push_back(
1006 m_triMesh.template getAttribHandle<Vector3>( attr->getName() ) );
1007 m_topo->m_wedges.addAttribName<Vector3>( attr->getName() );
1008 }
1009 else if ( attr->isVector4() ) {
1010 m_topo->m_wedges.m_wedgeVector4AttribHandles.push_back(
1011 m_triMesh.template getAttribHandle<Vector4>( attr->getName() ) );
1012 m_topo->m_wedges.addAttribName<Vector4>( attr->getName() );
1013 }
1014 else
1015 LOG( logWARNING )
1016 << "Warning, mesh attribute " << attr->getName()
1017 << " type is not supported (only float, vec2, vec3 nor vec4 are supported)";
1018 }
1019}
1020
1024
1025struct hash_vec {
1026 std::size_t operator()( const Vector3& lvalue ) const {
1027 size_t hx = std::hash<Scalar>()( lvalue[0] );
1028 size_t hy = std::hash<Scalar>()( lvalue[1] );
1029 size_t hz = std::hash<Scalar>()( lvalue[2] );
1030 return ( hx ^ ( hy << 1 ) ) ^ hz;
1031 }
1032};
1033
1034template <typename MeshIndex>
1036 TopologicalMesh( mesh, DefaultNonManifoldFaceCommand( "[default ctor]" ) ) {}
1037
1038template <typename MeshIndex, typename NonManifoldFaceCommand>
1040 NonManifoldFaceCommand command ) :
1041 TopologicalMesh() {
1042 initWithWedge( mesh, mesh.getLayerKey(), command );
1043}
1044
1048 TopologicalMesh( mesh, layerKey, DefaultNonManifoldFaceCommand( "[default ctor]" ) ) {}
1049
1050template <typename NonManifoldFaceCommand>
1054 NonManifoldFaceCommand command ) :
1055 TopologicalMesh() {
1056 initWithWedge( mesh, layerKey, command );
1057}
1058
1059inline void TopologicalMesh::initWithWedge(
1062 initWithWedge( mesh,
1063 layerKey,
1064 DefaultNonManifoldFaceCommand( "[initWithWedges (MultiIndexedGeometry)]" ) );
1065}
1066
1067template <typename NonManifoldFaceCommand>
1068void TopologicalMesh::initWithWedge(
1071 NonManifoldFaceCommand command ) {
1072
1073 const auto& abstractLayer = mesh.getLayer( layerKey );
1074
1075 if ( !abstractLayer.hasSemantic( TriangleIndexLayer::staticSemanticName ) &&
1076 !abstractLayer.hasSemantic( QuadIndexLayer::staticSemanticName ) &&
1077 !abstractLayer.hasSemantic( PolyIndexLayer::staticSemanticName ) ) {
1078 LOG( logWARNING ) << "TopologicalMesh: mesh does not contains faces. Aborting conversion";
1079 return;
1080 }
1081
1082 clean();
1083
1084 LOG( logDEBUG ) << "TopologicalMesh: load mesh with " << abstractLayer.getSize()
1085 << " faces and " << mesh.vertices().size() << " vertices.";
1086 // use a hashmap for fast search of existing vertex position
1088 VertexMap vertexHandles;
1089
1090 // loop over all attribs and build correspondance pair
1091 mesh.vertexAttribs().for_each_attrib( InitWedgeAttribsFromMultiIndexedGeometry { this, mesh } );
1092
1093 for ( size_t i = 0; i < mesh.vertices().size(); ++i ) {
1094 // create an empty wedge, with 0 ref
1095 Wedge w;
1096
1097 WedgeData wd;
1098 wd.m_position = mesh.vertices()[i];
1099 copyMeshToWedgeData( mesh,
1100 i,
1101 m_wedges.m_wedgeFloatAttribHandles,
1102 m_wedges.m_wedgeVector2AttribHandles,
1103 m_wedges.m_wedgeVector3AttribHandles,
1104 m_wedges.m_wedgeVector4AttribHandles,
1105 &wd );
1106 // here ref is not incremented
1107 w.setWedgeData( std::move( wd ) );
1108 // the newly added wedge is not referenced yet, will be done with `newReference` when
1109 // creating faces just below
1110 m_wedges.m_data.push_back( w );
1111 }
1112
1113 LOG( logDEBUG ) << "TopologicalMesh: have " << m_wedges.size() << " wedges ";
1114
1115 const bool hasNormals = !mesh.normals().empty();
1116 if ( !hasNormals ) {
1117 release_face_normals();
1118 release_vertex_normals();
1119 release_halfedge_normals();
1120 }
1121
1122 command.initialize( mesh );
1123
1124 auto processFaces = [&mesh, &vertexHandles, this, hasNormals, &command]( const auto& faces ) {
1125 size_t num_triangles = faces.size();
1126 for ( unsigned int i = 0; i < num_triangles; i++ ) {
1127 const auto& face = faces[i];
1128 const size_t num_vert = face.size();
1129 std::vector<TopologicalMesh::VertexHandle> face_vhandles( num_vert );
1130 std::vector<TopologicalMesh::Normal> face_normals( num_vert );
1131 std::vector<WedgeIndex> face_wedges( num_vert );
1132
1133 for ( size_t j = 0; j < num_vert; ++j ) {
1134 unsigned int inMeshVertexIndex = face[j];
1135 const Vector3& p = mesh.vertices()[inMeshVertexIndex];
1136
1137 typename VertexMap::iterator vtr = vertexHandles.find( p );
1138 TopologicalMesh::VertexHandle vh;
1139 if ( vtr == vertexHandles.end() ) {
1140 vh = add_vertex( p );
1141 vertexHandles.insert( vtr, typename VertexMap::value_type( p, vh ) );
1142 }
1143 else { vh = vtr->second; }
1144
1145 face_vhandles[j] = vh;
1146 if ( hasNormals ) face_normals[j] = mesh.normals()[inMeshVertexIndex];
1147 face_wedges[j] = WedgeIndex { inMeshVertexIndex };
1148 m_wedges.m_data[inMeshVertexIndex].getWedgeData().m_vertexHandle = vh;
1149 }
1150
1151 // remove consecutive equal vertex
1152 // first take care of "loop" if begin == *end-1
1153 // apply the same modifications on wedges and normals
1154 // e.g. 1 2 1 becomes 1 2
1155 {
1156 auto begin = face_vhandles.begin();
1157 if ( face_vhandles.size() > 2 ) {
1158 auto end = face_vhandles.end() - 1;
1159 auto wedgeEnd = face_wedges.end() - 1;
1160 auto normalEnd = face_normals.end() - 1;
1161
1162 while ( begin != end && *begin == *end ) {
1163 end--;
1164 wedgeEnd--;
1165 normalEnd--;
1166 }
1167 face_vhandles.erase( end + 1, face_vhandles.end() );
1168 face_wedges.erase( wedgeEnd + 1, face_wedges.end() );
1169 face_normals.erase( normalEnd + 1, face_normals.end() );
1170 }
1171 }
1172 // then remove duplicates
1173 // e.g. 1 2 2 becomes 1 2
1174 // equiv of
1175 // face_vhandles.erase( std::unique( face_vhandles.begin(), face_vhandles.end() ),
1176 // face_vhandles.end() );
1177 // but handles wedges and normals
1178 // see (https://en.cppreference.com/w/cpp/algorithm/unique)
1179 {
1180 auto first = face_vhandles.begin();
1181 auto wedgeFirst = face_wedges.begin();
1182 auto normalFirst = face_normals.begin();
1183 auto last = face_vhandles.end();
1184
1185 if ( first != last ) {
1186 auto result = first;
1187 auto wedgeResult = wedgeFirst;
1188 auto normalResult = normalFirst;
1189 while ( ++first != last ) {
1190 if ( !( *result == *first ) ) {
1191 ++result;
1192 ++wedgeResult;
1193 ++normalResult;
1194 if ( result != first ) {
1195 *result = std::move( *first );
1196 *wedgeResult = std::move( *wedgeFirst );
1197 *normalResult = std::move( *normalFirst );
1198 }
1199 }
1200 }
1201 face_vhandles.erase( result + 1, face_vhandles.end() );
1202 face_wedges.erase( wedgeResult + 1, face_wedges.end() );
1203 face_normals.erase( normalResult + 1, face_normals.end() );
1204 }
1205 }
1206
1208 // unique sort size == vhandles size, if not split ...
1209
1210 TopologicalMesh::FaceHandle fh;
1211 // skip 2 vertex face
1212 if ( face_vhandles.size() > 2 ) fh = add_face( face_vhandles );
1213
1214 // In case of topological inconsistancy, face will be invalid (or uninitialized <>
1215 // invalid)
1216 if ( fh.is_valid() ) {
1217 for ( size_t vindex = 0; vindex < face_vhandles.size(); vindex++ ) {
1218 TopologicalMesh::HalfedgeHandle heh =
1219 halfedge_handle( face_vhandles[vindex], fh );
1220 if ( hasNormals ) set_normal( heh, face_normals[vindex] );
1221 property( m_wedgeIndexPph, heh ) = m_wedges.newReference( face_wedges[vindex] );
1222 }
1223 }
1224 else { command.process( face_vhandles ); }
1225 face_vhandles.clear();
1226 face_normals.clear();
1227 }
1228 };
1229
1230 if ( abstractLayer.hasSemantic( TriangleIndexLayer::staticSemanticName ) ) {
1231 const auto& faces = static_cast<const TriangleIndexLayer&>( abstractLayer ).collection();
1232 LOG( logDEBUG ) << "TopologicalMesh: process " << faces.size() << " triangular faces ";
1233 processFaces( faces );
1234 }
1235 else if ( abstractLayer.hasSemantic( PolyIndexLayer::staticSemanticName ) ) {
1236 const auto& faces = static_cast<const PolyIndexLayer&>( abstractLayer ).collection();
1237 LOG( logDEBUG ) << "TopologicalMesh: process " << faces.size() << " polygonal faces ";
1238 processFaces( faces );
1239 }
1240
1241 command.postProcess( *this );
1242 if ( hasNormals ) {
1243 m_normalsIndex =
1244 m_wedges.getWedgeAttribIndex<Normal>( getAttribName( MeshAttrib::VERTEX_NORMAL ) );
1245
1246 m_vertexFaceWedgesWithSameNormals.clear();
1247 m_vertexFaceWedgesWithSameNormals.resize( n_vertices() );
1248
1249 for ( auto itr = vertices_begin(), stop = vertices_end(); itr != stop; ++itr ) {
1250 std::unordered_map<TopologicalMesh::Normal,
1252 hash_vec>
1253 normalSharedByWedges;
1254
1255 auto vh = *itr;
1256
1257 for ( ConstVertexIHalfedgeIter vh_it = cvih_iter( vh ); vh_it.is_valid(); ++vh_it ) {
1258 const auto& widx = property( m_wedgeIndexPph, *vh_it );
1259 if ( widx.isValid() && !m_wedges.getWedge( widx ).isDeleted() ) {
1260 auto oldNormal = m_wedges.getWedgeData<Normal>( widx, m_normalsIndex );
1261 normalSharedByWedges[oldNormal].first.insert( face_handle( *vh_it ) );
1262 normalSharedByWedges[oldNormal].second.insert( widx );
1263 }
1264 }
1265
1266 for ( const auto& pair : normalSharedByWedges ) {
1267 for ( const auto& fh : pair.second.first ) {
1268 auto& v = m_vertexFaceWedgesWithSameNormals[vh.idx()][fh.idx()];
1269 v.insert( v.end(), pair.second.second.begin(), pair.second.second.end() );
1270 }
1271 }
1272 }
1273 }
1274 LOG( logDEBUG ) << "TopologicalMesh: load end with " << m_wedges.size() << " wedges ";
1275}
1276
1277template <typename T>
1278void TopologicalMesh::copyAttribToWedgeData( const MultiIndexedGeometry& mesh,
1279 unsigned int vindex,
1280 const std::vector<AttribHandle<T>>& attrHandleVec,
1281 VectorArray<T>* to ) {
1282 for ( auto handle : attrHandleVec ) {
1283 auto& attr = mesh.template getAttrib<T>( handle );
1284 to->push_back( attr.data()[vindex] );
1285 }
1286}
1287
1288void TopologicalMesh::copyMeshToWedgeData( const MultiIndexedGeometry& mesh,
1289 unsigned int vindex,
1290 const std::vector<AttribHandle<Scalar>>& wprop_float,
1291 const std::vector<AttribHandle<Vector2>>& wprop_vec2,
1292 const std::vector<AttribHandle<Vector3>>& wprop_vec3,
1293 const std::vector<AttribHandle<Vector4>>& wprop_vec4,
1295 copyAttribToWedgeData( mesh, vindex, wprop_float, &wd->m_floatAttrib );
1296 copyAttribToWedgeData( mesh, vindex, wprop_vec2, &wd->m_vector2Attrib );
1297 copyAttribToWedgeData( mesh, vindex, wprop_vec3, &wd->m_vector3Attrib );
1298 copyAttribToWedgeData( mesh, vindex, wprop_vec4, &wd->m_vector4Attrib );
1299}
1300
1301inline void TopologicalMesh::propagate_normal_to_wedges( VertexHandle vh ) {
1302 if ( !has_halfedge_normals() ) {
1303 LOG( logERROR ) << "TopologicalMesh has no normals, nothing set";
1304 return;
1305 }
1306 for ( VertexIHalfedgeIter vih_it = vih_iter( vh ); vih_it.is_valid(); ++vih_it ) {
1307 auto wd = getWedgeData( property( getWedgeIndexPph(), *vih_it ) );
1308
1309 m_wedges.setWedgeAttrib( wd, getAttribName( MeshAttrib::VERTEX_NORMAL ), normal( vh ) );
1310
1311 replaceWedge( *vih_it, wd );
1312 }
1313}
1314
1315inline TopologicalMesh::HalfedgeHandle TopologicalMesh::halfedge_handle( VertexHandle vh,
1316 FaceHandle fh ) const {
1317 for ( ConstVertexIHalfedgeIter vih_it = cvih_iter( vh ); vih_it.is_valid(); ++vih_it ) {
1318 if ( face_handle( *vih_it ) == fh ) { return *vih_it; }
1319 }
1320 CORE_ASSERT( false, "vh is not a vertex of face fh" );
1321 return HalfedgeHandle();
1322}
1323
1324inline const OpenMesh::HPropHandleT<TopologicalMesh::Index>&
1326 return m_inputTriangleMeshIndexPph;
1327}
1328
1329inline const OpenMesh::HPropHandleT<TopologicalMesh::Index>&
1331 return m_outputTriangleMeshIndexPph;
1332}
1333
1335TopologicalMesh::getVertexWedges( OpenMesh::VertexHandle vh ) const {
1337
1338 for ( ConstVertexIHalfedgeIter vh_it = cvih_iter( vh ); vh_it.is_valid(); ++vh_it ) {
1339 auto widx = property( m_wedgeIndexPph, *vh_it );
1340 if ( widx.isValid() && !m_wedges.getWedge( widx ).isDeleted() ) ret.insert( widx );
1341 }
1342 return ret;
1343}
1344
1345inline TopologicalMesh::WedgeIndex
1346TopologicalMesh::getWedgeIndex( OpenMesh::HalfedgeHandle heh ) const {
1347 return property( getWedgeIndexPph(), heh );
1348}
1349
1350inline unsigned int TopologicalMesh::getWedgeRefCount( const WedgeIndex& idx ) const {
1351 return m_wedges.getWedgeRefCount( idx );
1352}
1353
1354template <typename T>
1355inline bool TopologicalMesh::setWedgeData( const TopologicalMesh::WedgeIndex& idx,
1356 const std::string& name,
1357 const T& value ) {
1358 return setWedgeAttrib( idx, name, value );
1359}
1360
1361template <typename T>
1362inline bool TopologicalMesh::setWedgeAttrib( const TopologicalMesh::WedgeIndex& idx,
1363 const std::string& name,
1364 const T& value ) {
1365 return m_wedges.setWedgeAttrib( idx, name, value );
1366}
1367
1368inline void TopologicalMesh::setWedgeData( TopologicalMesh::WedgeIndex widx,
1369 const TopologicalMesh::WedgeData& wedge ) {
1370 m_wedges.setWedgeData( widx, wedge );
1371}
1372
1373inline const TopologicalMesh::WedgeData&
1374TopologicalMesh::getWedgeData( const WedgeIndex& idx ) const {
1375 return m_wedges.getWedgeData( idx );
1376}
1377
1378template <typename T>
1379inline const T& TopologicalMesh::getWedgeData( const TopologicalMesh::WedgeIndex& idx,
1380 const std::string& name ) const {
1381 return getWedgeAttrib<T>( idx, name );
1382}
1383
1384template <typename T>
1385inline const T& TopologicalMesh::getWedgeAttrib( const TopologicalMesh::WedgeIndex& idx,
1386 const std::string& name ) const {
1387 return m_wedges.getWedgeData<T>( idx, name );
1388}
1389
1390inline TopologicalMesh::WedgeIndex TopologicalMesh::replaceWedge( OpenMesh::HalfedgeHandle he,
1391 const WedgeData& wd ) {
1392 m_wedges.del( property( getWedgeIndexPph(), he ) );
1393 auto index = m_wedges.add( wd );
1394 property( getWedgeIndexPph(), he ) = index;
1395 return index;
1396}
1397
1398inline void TopologicalMesh::replaceWedgeIndex( OpenMesh::HalfedgeHandle he,
1399 const WedgeIndex& widx ) {
1400 m_wedges.del( property( getWedgeIndexPph(), he ) );
1401 property( getWedgeIndexPph(), he ) = m_wedges.newReference( widx );
1402}
1403
1405 for ( auto itr = vertices_begin(), stop = vertices_end(); itr != stop; ++itr ) {
1406 mergeEqualWedges( *itr );
1407 }
1408}
1409
1410inline void TopologicalMesh::mergeEqualWedges( OpenMesh::VertexHandle vh ) {
1411 for ( auto itr = vih_iter( vh ); itr.is_valid(); ++itr ) {
1412 // replace will search if wedge already present and use it, so merge occurs.
1413 if ( !is_boundary( *itr ) )
1414 replaceWedge( *itr, getWedgeData( property( getWedgeIndexPph(), *itr ) ) );
1415 }
1416}
1417
1418inline const std::vector<std::string>& TopologicalMesh::getVec4AttribNames() const {
1419 return m_wedges.m_vector4AttribNames;
1420}
1421inline const std::vector<std::string>& TopologicalMesh::getVec3AttribNames() const {
1422 return m_wedges.m_vector3AttribNames;
1423}
1424inline const std::vector<std::string>& TopologicalMesh::getVec2AttribNames() const {
1425 return m_wedges.m_vector2AttribNames;
1426}
1427inline const std::vector<std::string>& TopologicalMesh::getFloatAttribNames() const {
1428 return m_wedges.m_floatAttribNames;
1429}
1430
1431inline bool TopologicalMesh::isFeatureVertex( const VertexHandle& vh ) const {
1432 return getVertexWedges( vh ).size() != 1;
1433}
1434
1435inline bool TopologicalMesh::isFeatureEdge( const EdgeHandle& eh ) const {
1436 auto heh0 = halfedge_handle( eh, 0 );
1437 auto heh1 = halfedge_handle( eh, 1 );
1438
1439 return property( m_wedgeIndexPph, heh0 ) !=
1440 property( m_wedgeIndexPph,
1441 prev_halfedge_handle( opposite_halfedge_handle( heh0 ) ) ) ||
1442 property( m_wedgeIndexPph, heh1 ) !=
1443 property( m_wedgeIndexPph,
1444 prev_halfedge_handle( opposite_halfedge_handle( heh1 ) ) );
1445}
1446
1447inline const OpenMesh::HPropHandleT<TopologicalMesh::WedgeIndex>&
1448TopologicalMesh::getWedgeIndexPph() const {
1449 return m_wedgeIndexPph;
1450}
1451
1452} // namespace Geometry
1453} // namespace Core
1454} // namespace Ra
T begin(T... args)
const NormalAttribHandle::Container & normals() const
Access the vertices normals.
const PointAttribHandle::Container & vertices() const
Access the vertices positions.
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)
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
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:754
This class implements ContainerIntrospectionInterface for AlignedStdVector.
T clear(T... args)
T distance(T... args)
T end(T... args)
T erase(T... args)
T find(T... args)
T insert(T... args)
T move(T... args)
Quaternion add(const Quaternion &q1, const Quaternion &q2)
Returns the sum of two quaternions.
This namespace contains everything "low level", related to data, datastuctures, and computation.
Definition Cage.cpp:4
@ Geometry
"Geometry" render objects are those loaded using Radium::IO and generated by GeometrySystem
hepler function to manage enum as underlying types in VariableSet
Definition Cage.cpp:3
T push_back(T... args)
T remove_if(T... args)
T resize(T... args)
T size(T... args)
Index layer for polygonal mesh.
Index layer for triangle mesh.