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>
9 #include <Core/Utils/Index.hpp>
10 #include <Core/Utils/Log.hpp>
11 #include <Core/Utils/StdOptional.hpp>
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>
20 #include <Eigen/Geometry>
24 #include <unordered_map>
29 using namespace Utils;
35 using Point = Ra::Core::Vector3;
36 using Normal = Ra::Core::Vector3;
38 VertexAttributes( OpenMesh::Attributes::Status | OpenMesh::Attributes::Normal );
39 FaceAttributes( OpenMesh::Attributes::Status | OpenMesh::Attributes::Normal );
40 EdgeAttributes( OpenMesh::Attributes::Status );
42 HalfedgeAttributes( OpenMesh::Attributes::Status | OpenMesh::Attributes::Normal );
55 class RA_CORE_API
TopologicalMesh :
public OpenMesh::PolyMesh_ArrayKernelT<TopologicalMeshTraits>
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;
63 class WedgeCollection;
66 EIGEN_MAKE_ALIGNED_OPERATOR_NEW
68 using WedgeIndex = Ra::Core::Utils::Index;
69 using WedgeAttribIndex = Ra::Core::Utils::Index;
80 template <
typename MeshIndex>
92 const Ra::Core::Geometry::MultiIndexedGeometry::LayerKeyType& layerKey );
106 template <
typename MeshIndex,
typename NonManifoldFaceCommand>
107 explicit TopologicalMesh( [[deprecated(
"Use MultiIndexedGeometry instead" )]]
const Ra::Core::
109 NonManifoldFaceCommand command );
124 template <
typename NonManifoldFaceCommand>
127 const Ra::Core::Geometry::MultiIndexedGeometry::LayerKeyType& layerKey,
128 NonManifoldFaceCommand command );
132 const Ra::Core::Geometry::MultiIndexedGeometry::LayerKeyType& layerKey );
134 template <
typename NonManifoldFaceCommand>
136 const Ra::Core::Geometry::MultiIndexedGeometry::LayerKeyType& layerKey,
137 NonManifoldFaceCommand command );
142 TriangleMesh toTriangleMesh();
149 PolyMesh toPolyMesh();
151 LineMesh toLineMesh();
159 void updateTriangleMeshNormals( AttribArrayGeometry::NormalAttribHandle::Container& normals );
164 void updatePositions(
const AttribArrayGeometry::PointAttribHandle::Container& vertices );
166 using base::halfedge_handle;
172 inline HalfedgeHandle halfedge_handle( VertexHandle vh, FaceHandle fh )
const;
177 using base::set_normal;
185 inline void propagate_normal_to_wedges( VertexHandle vh );
191 inline const OpenMesh::HPropHandleT<Index>& getInputTriangleMeshIndexPropHandle()
const;
198 inline const OpenMesh::HPropHandleT<Index>& getOutputTriangleMeshIndexPropHandle()
const;
206 void updateWedgeNormals();
211 void copyPointsPositionToWedges();
228 bool splitEdge( TopologicalMesh::EdgeHandle eh, Scalar f );
238 void collapse( HalfedgeHandle,
bool =
false );
239 [[deprecated(
"use collapse() instead." )]]
void
240 collapseWedge( TopologicalMesh::HalfedgeHandle he,
bool keepFromVertex =
false );
247 inline std::set<WedgeIndex> getVertexWedges( OpenMesh::VertexHandle vh )
const;
252 inline WedgeIndex getWedgeIndex( OpenMesh::HalfedgeHandle heh )
const;
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;
268 inline unsigned int getWedgeRefCount(
const WedgeIndex& idx )
const;
275 inline void setWedgeData( WedgeIndex widx,
const WedgeData& wd );
283 template <
typename T>
284 [[deprecated(
"use setWedgeAttrib() instead." )]]
inline bool
285 setWedgeData(
const WedgeIndex& idx,
const std::string& name,
const T& value );
287 template <
typename T>
288 inline bool setWedgeAttrib(
const WedgeIndex& idx,
const std::string& name,
const T& value );
295 return m_wedges.newWedgeData( to_vertex_handle( he ), point( to_vertex_handle( he ) ) );
303 inline WedgeIndex replaceWedge( OpenMesh::HalfedgeHandle he,
const WedgeData& wd );
305 template <
typename T>
306 inline WedgeAttribIndex addWedgeAttrib(
const std::string& name, T value = {} ) {
307 return m_wedges.addAttrib<T>( name, value );
314 inline void replaceWedgeIndex( OpenMesh::HalfedgeHandle he,
const WedgeIndex& widx );
320 inline void mergeEqualWedges();
326 inline void mergeEqualWedges( OpenMesh::VertexHandle vh );
329 void garbage_collection();
330 inline void clean() {
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;
341 inline bool isFeatureVertex(
const VertexHandle& vh )
const;
346 inline bool isFeatureEdge(
const EdgeHandle& eh )
const;
348 inline const OpenMesh::HPropHandleT<WedgeIndex>& getWedgeIndexPph()
const;
350 void delete_face( FaceHandle _fh,
bool _delete_isolated_vertices =
true );
356 bool isManifold( VertexHandle vh )
const;
360 bool checkIntegrity()
const;
374 EIGEN_MAKE_ALIGNED_OPERATOR_NEW
377 inline bool operator==(
const WedgeData& lhs )
const;
378 inline bool operator!=(
const WedgeData& lhs )
const;
379 inline bool operator<(
const WedgeData& lhs )
const;
381 template <
typename T>
383 template <
typename T>
389 VertexHandle m_vertexHandle;
390 Vector3 m_position {};
398 template <
typename T>
399 static int compareVector(
const T& a,
const T& b );
404 void collapse_edge( HalfedgeHandle,
bool );
405 void collapse_loop( HalfedgeHandle );
412 class RA_CORE_API Wedge
415 EIGEN_MAKE_ALIGNED_OPERATOR_NEW
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;
427 bool operator==(
const Wedge& lhs )
const {
return m_wedgeData == lhs.m_wedgeData; }
429 bool isDeleted()
const {
return m_refCount == 0; }
430 unsigned int getRefCount()
const {
return m_refCount; }
432 friend WedgeCollection;
433 friend TopologicalMesh;
436 WedgeData& getWedgeData() {
return m_wedgeData; }
438 WedgeData m_wedgeData {};
439 unsigned int m_refCount { 0 };
449 class RA_CORE_API WedgeCollection
452 EIGEN_MAKE_ALIGNED_OPERATOR_NEW
461 WedgeIndex
add(
const WedgeData& wd );
469 inline void del(
const WedgeIndex& idx );
470 WedgeIndex newReference(
const WedgeIndex& idx );
478 inline const Wedge& getWedge(
const WedgeIndex& idx )
const;
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 );
490 unsigned int getWedgeRefCount(
const WedgeIndex& idx )
const;
493 inline void setWedgeData(
const WedgeIndex& idx,
const WedgeData& wd );
499 template <
typename T>
501 setWedgeAttrib( TopologicalMesh::WedgeData& wd,
const std::string& name,
const T& value );
502 template <
typename T>
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,
510 template <
typename T>
511 inline WedgeAttribIndex getWedgeAttribIndex(
const std::string& name );
513 inline bool setWedgePosition(
const WedgeIndex& idx,
const Vector3& value );
517 template <
typename T>
518 inline const std::vector<std::string>& getNameArray()
const;
523 template <
typename T>
524 WedgeAttribIndex addAttribName(
const std::string& name );
527 template <
typename T>
528 WedgeAttribIndex addAttrib(
const std::string& name,
const T& value = {} );
532 std::vector<int> computeCleanupOffset()
const;
538 inline size_t size()
const {
return m_data.size(); }
541 inline void garbageCollection();
546 inline WedgeData newWedgeData()
const;
547 inline WedgeData newWedgeData( TopologicalMesh::VertexHandle vh,
548 TopologicalMesh::Point p )
const;
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;
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;
564 template <
typename T>
565 inline std::vector<std::string>& getNameArray();
566 AlignedStdVector<Wedge> m_data;
570 class InitWedgeAttribsFromMultiIndexedGeometry
573 InitWedgeAttribsFromMultiIndexedGeometry(
574 TopologicalMesh* topo,
576 m_topo( topo ), m_triMesh( triMesh ) {}
577 void operator()( AttribBase* attr )
const;
580 TopologicalMesh* m_topo;
586 struct DefaultNonManifoldFaceCommand {
588 DefaultNonManifoldFaceCommand(
const std::string& details = {} ) : m_details { details } {}
592 inline void process(
const std::vector<TopologicalMesh::VertexHandle>& ) {
593 LOG( logWARNING ) <<
"Invalid face handle returned : face not added " + m_details;
596 inline void postProcess( TopologicalMesh& ) {}
599 std::string m_details;
603 WedgeData interpolateWedgeAttributes(
const WedgeData&,
const WedgeData&, Scalar alpha );
606 template <
typename T>
609 const std::vector<AttribHandle<T>>& attrHandleVec,
610 VectorArray<T>* to );
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 );
621 template <
typename T>
622 using HandleAndValueVector =
623 std::vector<std::pair<AttribHandle<T>, T>,
624 Eigen::aligned_allocator<std::pair<AttribHandle<T>, T>>>;
626 void split_copy( EdgeHandle _eh, VertexHandle _vh );
627 void split( EdgeHandle _eh, VertexHandle _vh );
629 OpenMesh::HPropHandleT<WedgeIndex> m_wedgeIndexPph;
630 WedgeCollection m_wedges;
633 OpenMesh::HPropHandleT<Index> m_inputTriangleMeshIndexPph;
634 OpenMesh::HPropHandleT<Index> m_outputTriangleMeshIndexPph;
636 int m_normalsIndex { -1 };
638 std::vector<std::map<int, std::vector<int>>> m_vertexFaceWedgesWithSameNormals;
640 friend class TMOperations;
644 void printWedgesInfo(
const TopologicalMesh& );
650 inline bool TopologicalMesh::WedgeData::operator==(
const TopologicalMesh::WedgeData& lhs )
const {
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;
660 bool TopologicalMesh::WedgeData::operator!=(
const TopologicalMesh::WedgeData& lhs )
const {
661 return !( *
this == lhs );
664 inline bool TopologicalMesh::WedgeData::operator<(
const TopologicalMesh::WedgeData& lhs )
const {
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" );
673 int comp = compareVector( m_position, lhs.m_position );
674 if ( comp == 2 )
return true;
675 if ( comp == 3 )
return false;
677 for (
size_t i = 0; i < m_floatAttrib.size(); i++ ) {
678 if ( m_floatAttrib[i] < lhs.m_floatAttrib[i] )
680 else if ( m_floatAttrib[i] > lhs.m_floatAttrib[i] )
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;
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;
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;
702 #define GET_ATTRIB_ARRAY_HELPER( TYPE, NAME ) \
704 inline VectorArray<TYPE>& TopologicalMesh::WedgeData::getAttribArray<TYPE>() { \
705 return m_##NAME##Attrib; \
708 inline const VectorArray<TYPE>& TopologicalMesh::WedgeData::getAttribArray<TYPE>() const { \
709 return m_##NAME##Attrib; \
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
718 template <
typename T>
719 inline VectorArray<T>& TopologicalMesh::WedgeData::getAttribArray() {
720 static_assert(
sizeof( T ) == -1,
"this type is not supported" );
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;
744 inline void TopologicalMesh::WedgeCollection::del(
const TopologicalMesh::WedgeIndex& idx ) {
745 if ( idx.isValid() ) m_data[idx].decrementRefCount();
748 inline TopologicalMesh::WedgeIndex
749 TopologicalMesh::WedgeCollection::newReference(
const TopologicalMesh::WedgeIndex& idx ) {
750 if ( idx.isValid() ) m_data[idx].incrementRefCount();
754 inline const TopologicalMesh::Wedge&
755 TopologicalMesh::WedgeCollection::getWedge(
const TopologicalMesh::WedgeIndex& idx )
const {
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" );
764 return m_data[idx].getWedgeData();
767 template <
typename T>
769 TopologicalMesh::WedgeCollection::getWedgeData(
const TopologicalMesh::WedgeIndex& idx,
770 const std::string& name )
const {
771 return getWedgeAttrib<T>( idx, name );
774 template <
typename 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];
786 LOG( logERROR ) <<
"Warning, set wedge: no wedge attrib named " << name <<
" of type "
787 <<
typeid( T ).name();
794 template <
typename T>
795 inline T& TopologicalMesh::WedgeCollection::getWedgeData(
const TopologicalMesh::WedgeIndex& idx,
797 return getWedgeAttrib<T>( idx, attribIndex );
800 template <
typename T>
801 inline T& TopologicalMesh::WedgeCollection::getWedgeAttrib(
const TopologicalMesh::WedgeIndex& idx,
803 return m_data[idx].getWedgeData().getAttribArray<T>()[attribIndex];
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();
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";
820 if ( idx.isValid() ) m_data[idx].setWedgeData( wd );
823 template <
typename T>
824 inline bool TopologicalMesh::WedgeCollection::setWedgeAttrib( TopologicalMesh::WedgeData& wd,
825 const std::string& name,
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;
835 LOG( logERROR ) <<
"Warning, set wedge: no wedge attrib named " << name <<
" of type "
836 <<
typeid( T ).name();
841 template <
typename T>
843 TopologicalMesh::WedgeCollection::setWedgeAttrib(
const TopologicalMesh::WedgeIndex& idx,
844 const std::string& name,
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;
855 LOG( logERROR ) <<
"Warning, set wedge: no wedge attrib named " << name <<
" of type "
856 <<
typeid( T ).name();
862 template <
typename T>
864 TopologicalMesh::WedgeCollection::setWedgeAttrib(
const TopologicalMesh::WedgeIndex& idx,
865 const int& attrIndex,
867 m_data[idx].getWedgeData().getAttribArray<T>()[attrIndex] = value;
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 ); }
880 TopologicalMesh::WedgeCollection::setWedgePosition(
const TopologicalMesh::WedgeIndex& idx,
881 const Vector3& value ) {
882 if ( idx.isValid() ) {
883 m_data[idx].getWedgeData().m_position = value;
889 #define GET_NAME_ARRAY_HELPER( TYPE, NAME ) \
891 inline const std::vector<std::string>& TopologicalMesh::WedgeCollection::getNameArray<TYPE>() \
893 return m_##NAME##AttribNames; \
896 inline std::vector<std::string>& TopologicalMesh::WedgeCollection::getNameArray<TYPE>() { \
897 return m_##NAME##AttribNames; \
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 )
905 #undef GET_NAME_ARRAY_HELPER
908 template <
typename T>
909 inline const std::vector<std::string>& TopologicalMesh::WedgeCollection::getNameArray()
const {
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;
917 template <
typename T>
918 inline std::vector<std::string>& TopologicalMesh::WedgeCollection::getNameArray() {
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;
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 );
931 return getNameArray<T>().size() - 1;
934 template <
typename T>
935 TopologicalMesh::WedgeAttribIndex
936 TopologicalMesh::WedgeCollection::addAttrib(
const std::string& name,
const T& value ) {
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 );
947 inline void TopologicalMesh::WedgeCollection::garbageCollection() {
948 m_data.erase( std::remove_if( m_data.begin(),
950 [](
const Wedge& w ) { return w.isDeleted(); } ),
954 inline void TopologicalMesh::WedgeCollection::clean() {
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();
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 ) {
973 inline TopologicalMesh::WedgeData TopologicalMesh::WedgeCollection::newWedgeData()
const {
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 );
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;
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();
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() );
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() );
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() );
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() );
1022 <<
"Warning, mesh attribute " << attr->getName()
1023 <<
" type is not supported (only float, vec2, vec3 nor vec4 are supported)";
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;
1040 template <
typename MeshIndex>
1042 TopologicalMesh( mesh, DefaultNonManifoldFaceCommand(
"[default ctor]" ) ) {}
1044 template <
typename MeshIndex,
typename NonManifoldFaceCommand>
1046 NonManifoldFaceCommand command ) :
1048 initWithWedge( mesh, mesh.getLayerKey(), command );
1053 const Ra::Core::Geometry::MultiIndexedGeometry::LayerKeyType& layerKey ) :
1054 TopologicalMesh( mesh, layerKey, DefaultNonManifoldFaceCommand(
"[default ctor]" ) ) {}
1056 template <
typename NonManifoldFaceCommand>
1059 const Ra::Core::Geometry::MultiIndexedGeometry::LayerKeyType& layerKey,
1060 NonManifoldFaceCommand command ) :
1062 initWithWedge( mesh, layerKey, command );
1065 inline void TopologicalMesh::initWithWedge(
1067 const Ra::Core::Geometry::MultiIndexedGeometry::LayerKeyType& layerKey ) {
1068 initWithWedge( mesh,
1070 DefaultNonManifoldFaceCommand(
"[initWithWedges (MultiIndexedGeometry)]" ) );
1073 template <
typename NonManifoldFaceCommand>
1074 void TopologicalMesh::initWithWedge(
1076 const Ra::Core::Geometry::MultiIndexedGeometry::LayerKeyType& layerKey,
1077 NonManifoldFaceCommand command ) {
1079 const auto& abstractLayer = mesh.
getLayer( layerKey );
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";
1090 LOG( logDEBUG ) <<
"TopologicalMesh: load mesh with " << abstractLayer.getSize()
1091 <<
" faces and " << mesh.
vertices().size() <<
" vertices.";
1093 using VertexMap = std::unordered_map<Vector3, TopologicalMesh::VertexHandle, hash_vec>;
1094 VertexMap vertexHandles;
1099 for (
size_t i = 0; i < mesh.
vertices().size(); ++i ) {
1104 wd.m_position = mesh.
vertices()[i];
1105 copyMeshToWedgeData( mesh,
1107 m_wedges.m_wedgeFloatAttribHandles,
1108 m_wedges.m_wedgeVector2AttribHandles,
1109 m_wedges.m_wedgeVector3AttribHandles,
1110 m_wedges.m_wedgeVector4AttribHandles,
1113 w.setWedgeData( std::move( wd ) );
1116 m_wedges.m_data.push_back( w );
1119 LOG( logDEBUG ) <<
"TopologicalMesh: have " << m_wedges.size() <<
" wedges ";
1121 const bool hasNormals = !mesh.
normals().empty();
1122 if ( !hasNormals ) {
1123 release_face_normals();
1124 release_vertex_normals();
1125 release_halfedge_normals();
1128 command.initialize( mesh );
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 );
1139 for (
size_t j = 0; j < num_vert; ++j ) {
1140 unsigned int inMeshVertexIndex = face[j];
1141 const Vector3& p = mesh.
vertices()[inMeshVertexIndex];
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 ) );
1149 else { vh = vtr->second; }
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;
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;
1168 while ( begin != end && *begin == *end ) {
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() );
1186 auto first = face_vhandles.begin();
1187 auto wedgeFirst = face_wedges.begin();
1188 auto normalFirst = face_normals.begin();
1189 auto last = face_vhandles.end();
1191 if ( first != last ) {
1192 auto result = first;
1193 auto wedgeResult = wedgeFirst;
1194 auto normalResult = normalFirst;
1195 while ( ++first != last ) {
1196 if ( !( *result == *first ) ) {
1200 if ( result != first ) {
1201 *result = std::move( *first );
1202 *wedgeResult = std::move( *wedgeFirst );
1203 *normalResult = std::move( *normalFirst );
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() );
1216 TopologicalMesh::FaceHandle fh;
1218 if ( face_vhandles.size() > 2 ) fh = add_face( face_vhandles );
1222 if ( fh.is_valid() ) {
1223 for (
size_t vindex = 0; vindex < face_vhandles.size(); vindex++ ) {
1224 TopologicalMesh::HalfedgeHandle heh =
1226 if ( hasNormals ) set_normal( heh, face_normals[vindex] );
1227 property( m_wedgeIndexPph, heh ) = m_wedges.newReference( face_wedges[vindex] );
1230 else { command.process( face_vhandles ); }
1231 face_vhandles.clear();
1232 face_normals.clear();
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 );
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 );
1247 command.postProcess( *
this );
1250 m_wedges.getWedgeAttribIndex<Normal>( getAttribName( MeshAttrib::VERTEX_NORMAL ) );
1252 m_vertexFaceWedgesWithSameNormals.clear();
1253 m_vertexFaceWedgesWithSameNormals.resize( n_vertices() );
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>>,
1259 normalSharedByWedges;
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 );
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() );
1280 LOG( logDEBUG ) <<
"TopologicalMesh: load end with " << m_wedges.size() <<
" wedges ";
1283 template <
typename T>
1285 unsigned int vindex,
1288 for (
auto handle : attrHandleVec ) {
1289 auto& attr = mesh.template getAttrib<T>( handle );
1290 to->push_back( attr.data()[vindex] );
1295 unsigned int vindex,
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 );
1308 if ( !has_halfedge_normals() ) {
1309 LOG( logERROR ) <<
"TopologicalMesh has no normals, nothing set";
1312 for ( VertexIHalfedgeIter vih_it = vih_iter( vh ); vih_it.is_valid(); ++vih_it ) {
1313 auto wd =
getWedgeData( property( getWedgeIndexPph(), *vih_it ) );
1315 m_wedges.setWedgeAttrib( wd, getAttribName( MeshAttrib::VERTEX_NORMAL ), normal( 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; }
1326 CORE_ASSERT(
false,
"vh is not a vertex of face fh" );
1327 return HalfedgeHandle();
1330 inline const OpenMesh::HPropHandleT<TopologicalMesh::Index>&
1332 return m_inputTriangleMeshIndexPph;
1335 inline const OpenMesh::HPropHandleT<TopologicalMesh::Index>&
1337 return m_outputTriangleMeshIndexPph;
1340 inline std::set<TopologicalMesh::WedgeIndex>
1342 std::set<TopologicalMesh::WedgeIndex> ret;
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 );
1351 inline TopologicalMesh::WedgeIndex
1353 return property( getWedgeIndexPph(), heh );
1357 return m_wedges.getWedgeRefCount( idx );
1360 template <
typename T>
1362 const std::string& name,
1364 return setWedgeAttrib( idx, name, value );
1367 template <
typename T>
1368 inline bool TopologicalMesh::setWedgeAttrib(
const TopologicalMesh::WedgeIndex& idx,
1369 const std::string& name,
1371 return m_wedges.setWedgeAttrib( idx, name, value );
1376 m_wedges.setWedgeData( widx, wedge );
1381 return m_wedges.getWedgeData( idx );
1384 template <
typename T>
1386 const std::string& name )
const {
1387 return getWedgeAttrib<T>( idx, name );
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 );
1398 m_wedges.del( property( getWedgeIndexPph(), he ) );
1399 auto index = m_wedges.add( wd );
1400 property( getWedgeIndexPph(), he ) = index;
1405 const WedgeIndex& widx ) {
1406 m_wedges.del( property( getWedgeIndexPph(), he ) );
1407 property( getWedgeIndexPph(), he ) = m_wedges.newReference( widx );
1411 for (
auto itr = vertices_begin(), stop = vertices_end(); itr != stop; ++itr ) {
1417 for (
auto itr = vih_iter( vh ); itr.is_valid(); ++itr ) {
1419 if ( !is_boundary( *itr ) )
1424 inline const std::vector<std::string>& TopologicalMesh::getVec4AttribNames()
const {
1425 return m_wedges.m_vector4AttribNames;
1427 inline const std::vector<std::string>& TopologicalMesh::getVec3AttribNames()
const {
1428 return m_wedges.m_vector3AttribNames;
1430 inline const std::vector<std::string>& TopologicalMesh::getVec2AttribNames()
const {
1431 return m_wedges.m_vector2AttribNames;
1433 inline const std::vector<std::string>& TopologicalMesh::getFloatAttribNames()
const {
1434 return m_wedges.m_floatAttribNames;
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 ) ) );
1453 inline const OpenMesh::HPropHandleT<TopologicalMesh::WedgeIndex>&
1454 TopologicalMesh::getWedgeIndexPph()
const {
1455 return m_wedgeIndexPph;
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
WedgeData newWedgeData() 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.
void for_each_attrib(const F &func) const
Quaternion add(const Quaternion &q1, const Quaternion &q2)
Returns the sum of two quaternions.
Index layer for polygonal mesh.
Index layer for triangle mesh.