From aada215d2ba292bc1dd7967d4ac1cd0485c01d21 Mon Sep 17 00:00:00 2001 From: dlyr Date: Wed, 17 Mar 2021 15:17:19 +0100 Subject: [PATCH 01/37] [core] save topological mesh current status as deprecated. --- cmake/filelistCore.cmake | 3 + .../Geometry/deprecated/TopologicalMesh.cpp | 1009 ++++++++++++++++ .../Geometry/deprecated/TopologicalMesh.hpp | 717 +++++++++++ .../Geometry/deprecated/TopologicalMesh.inl | 1052 +++++++++++++++++ 4 files changed, 2781 insertions(+) create mode 100644 src/Core/Geometry/deprecated/TopologicalMesh.cpp create mode 100644 src/Core/Geometry/deprecated/TopologicalMesh.hpp create mode 100644 src/Core/Geometry/deprecated/TopologicalMesh.inl diff --git a/cmake/filelistCore.cmake b/cmake/filelistCore.cmake index d2a3227c21e..c2398990585 100644 --- a/cmake/filelistCore.cmake +++ b/cmake/filelistCore.cmake @@ -23,6 +23,7 @@ set( core_sources Geometry/Adjacency.cpp Geometry/Area.cpp Geometry/CatmullClarkSubdivider.cpp + Geometry/deprecated/TopologicalMesh.cpp Geometry/HeatDiffusion.cpp Geometry/Laplacian.cpp Geometry/LoopSubdivider.cpp @@ -91,6 +92,7 @@ set( core_headers Geometry/Area.hpp Geometry/CatmullClarkSubdivider.hpp Geometry/Curve2D.hpp + Geometry/deprecated/TopologicalMesh.hpp Geometry/DistanceQueries.hpp Geometry/Frustum.hpp Geometry/HeatDiffusion.hpp @@ -154,6 +156,7 @@ set( core_inlines Containers/Grid.inl Containers/Tex.inl Geometry/Curve2D.inl + Geometry/deprecated/TopologicalMesh.inl Geometry/DistanceQueries.inl Geometry/MeshPrimitives.inl Geometry/PolyLine.inl diff --git a/src/Core/Geometry/deprecated/TopologicalMesh.cpp b/src/Core/Geometry/deprecated/TopologicalMesh.cpp new file mode 100644 index 00000000000..fa4001490d5 --- /dev/null +++ b/src/Core/Geometry/deprecated/TopologicalMesh.cpp @@ -0,0 +1,1009 @@ +#include + +#include +#include + +#include + +#include +#include +#include + +namespace Ra { +namespace Core { +namespace Geometry { +namespace deprecated { +using namespace Utils; // log, AttribXXX + +///////////////// HELPERS /////////////// + +std::string wedgeInfo( const Ra::Core::Geometry::TopologicalMesh& topo, + const Ra::Core::Geometry::TopologicalMesh::WedgeIndex& idx ) { + + std::stringstream buffer; + if ( !idx.isValid() ) + { + buffer << "wedge (invalid) "; + return buffer.str(); + } + + const Ra::Core::Geometry::TopologicalMesh::WedgeData& wd = topo.getWedgeData( idx ); + + buffer << "wedge (" << idx << "," << topo.getWedgeRefCount( idx ) << "), "; + auto& floatAttrNames = topo.getFloatAttribNames(); + for ( size_t i = 0; i < floatAttrNames.size(); ++i ) + { + buffer << floatAttrNames[i]; + buffer << "["; + buffer << wd.m_floatAttrib[i]; + buffer << "], "; + } + auto vec2AttrNames = topo.getVec2AttribNames(); + for ( size_t i = 0; i < vec2AttrNames.size(); ++i ) + { + buffer << vec2AttrNames[i]; + buffer << "["; + buffer << wd.m_vector2Attrib[i].transpose(); + buffer << "], "; + } + auto vec3AttrNames = topo.getVec3AttribNames(); + for ( size_t i = 0; i < vec3AttrNames.size(); ++i ) + { + buffer << vec3AttrNames[i]; + buffer << "["; + buffer << wd.m_vector3Attrib[i].transpose(); + buffer << "], "; + } + + auto vec4AttrNames = topo.getVec4AttribNames(); + for ( size_t i = 0; i < vec4AttrNames.size(); ++i ) + { + buffer << vec4AttrNames[i]; + buffer << "["; + buffer << wd.m_vector4Attrib[i].transpose(); + buffer << "], "; + } + + return buffer.str(); +} + +bool TopologicalMesh::isManifold( VertexHandle vh ) const { + return is_manifold( vh ); +} + +bool TopologicalMesh::checkIntegrity() const { + std::vector count( m_wedges.size(), 0 ); + bool ret = true; + for ( auto he_itr {halfedges_begin()}; he_itr != halfedges_end(); ++he_itr ) + { + auto widx = property( m_wedgeIndexPph, *he_itr ); + if ( widx.isValid() ) + { + count[widx]++; + + if ( m_wedges.getWedgeData( widx ).m_position != point( to_vertex_handle( *he_itr ) ) ) + { + LOG( logWARNING ) << "topological mesh wedge inconsistency, wedge and to position " + "differ for widx " + << widx << ", have " + << m_wedges.getWedgeData( widx ).m_position.transpose() + << "instead of " + << point( to_vertex_handle( *he_itr ) ).transpose(); + } + } + } + + for ( int widx = 0; widx < int( m_wedges.size() ); ++widx ) + { + if ( m_wedges.getWedge( WedgeIndex {widx} ).getRefCount() != count[widx] ) + { + LOG( logWARNING ) << "topological mesh wedge count inconsistency, have " << count[widx] + << " instead of " + << m_wedges.getWedge( WedgeIndex {widx} ).getRefCount() + << " for wedge id " << widx; + ret = false; + } + } + return ret; +} + +void printWedgesInfo( const Ra::Core::Geometry::TopologicalMesh& topo ) { + using namespace Ra::Core; + + for ( auto itr = topo.vertices_sbegin(); itr != topo.vertices_end(); ++itr ) + { + LOG( Utils::logINFO ) << "vertex " << *itr; + auto wedges = topo.getVertexWedges( *itr ); + for ( auto wedgeIndex : wedges ) + { + LOG( Utils::logINFO ) << wedgeInfo( topo, wedgeIndex ); + } + } + + for ( auto itr = topo.halfedges_sbegin(); itr != topo.halfedges_end(); ++itr ) + { + LOG( Utils::logINFO ) << "he " << *itr + << ( topo.is_boundary( *itr ) ? " boundary " : " inner " ); + LOG( Utils::logINFO ) << wedgeInfo( topo, topo.property( topo.getWedgeIndexPph(), *itr ) ); + } +} + +template +void addAttribPairToCore( TriangleMesh& triMesh, + const TopologicalMesh* topoMesh, + OpenMesh::HPropHandleT oh, + std::vector

& vprop ) { + AttribHandle h = triMesh.addAttrib( topoMesh->property( oh ).name() ); + vprop.push_back( std::make_pair( h, oh ) ); +} + +template +using HandleAndValueVector = std::vector, T>, + Eigen::aligned_allocator, T>>>; + +template +void copyAttribToCoreVertex( HandleAndValueVector& data, + const TopologicalMesh* topoMesh, + const std::vector

& vprop, + TopologicalMesh::HalfedgeHandle heh ) { + for ( auto pp : vprop ) + { + data.push_back( std::make_pair( pp.first, topoMesh->property( pp.second, heh ) ) ); + } +} + +template +void copyAttribToCore( TriangleMesh& triMesh, const HandleAndValueVector& data ) { + + for ( auto pp : data ) + { + auto& attr = triMesh.getAttrib( pp.first ); + auto& attrData = attr.getDataWithLock(); + attrData.push_back( pp.second ); + attr.unlock(); + } +} + +//! [Default command implementation] +struct DefaultNonManifoldFaceCommand { + /// \brief details string is printed along with the message + DefaultNonManifoldFaceCommand( std::string details = {} ) : m_details {details} {} + /// \brief Initalize with input Ra::Core::Geometry::TriangleMesh + inline void initialize( const TriangleMesh& /*triMesh*/ ) {} + /// \brief Process non-manifold face + inline void process( const std::vector& /*face_vhandles*/ ) { + LOG( logWARNING ) << "Invalid face handle returned : face not added " + m_details; + /// TODO memorize invalid faces for post processing ... + /// see + /// https://www.graphics.rwth-aachen.de/media/openflipper_static/Daily-Builds/Doc/Free/Developer/OBJImporter_8cc_source.html + /// for an exemple of loading + } + /// \brief If needed, apply post-processing on the Ra::Core::Geometry::TopologicalMesh + inline void postProcess( TopologicalMesh& /*tm*/ ) {} + //! [Default command implementation] + private: + std::string m_details; +}; + +void TopologicalMesh::initWithWedge( const TriangleMesh& triMesh ) { + initWithWedge( triMesh, DefaultNonManifoldFaceCommand( "[initWithWedges]" ) ); +} + +TopologicalMesh::TopologicalMesh( const TriangleMesh& triMesh ) : + TopologicalMesh( triMesh, DefaultNonManifoldFaceCommand( "[default ctor (props)]" ) ) {} + +TopologicalMesh::TopologicalMesh() { + add_property( m_inputTriangleMeshIndexPph ); + add_property( m_wedgeIndexPph ); +} + +TriangleMesh TopologicalMesh::toTriangleMesh() { + struct VertexDataInternal { + Vector3 _vertex; + Vector3 _normal; + + HandleAndValueVector _float; + HandleAndValueVector _vec2; + HandleAndValueVector _vec3; + HandleAndValueVector _vec4; + + EIGEN_MAKE_ALIGNED_OPERATOR_NEW + + bool operator==( const VertexDataInternal& lhs ) const { + return _vertex == lhs._vertex && _normal == lhs._normal && _float == lhs._float && + _vec2 == lhs._vec2 && _vec3 == lhs._vec3 && _vec4 == lhs._vec4; + } + }; + + struct hash_vec { + size_t operator()( const VertexDataInternal& lvalue ) const { + size_t hx = std::hash()( lvalue._vertex[0] ); + size_t hy = std::hash()( lvalue._vertex[1] ); + size_t hz = std::hash()( lvalue._vertex[2] ); + return ( hx ^ ( hy << 1 ) ) ^ hz; + } + }; + + TriangleMesh out; + + using VertexMap = std::unordered_map; + + VertexMap vertexHandles; + + if ( !get_property_handle( m_outputTriangleMeshIndexPph, "OutputTriangleMeshIndices" ) ) + { add_property( m_outputTriangleMeshIndexPph, "OutputTriangleMeshIndices" ); } + std::vector> vprop_float; + std::vector> vprop_vec2; + std::vector> vprop_vec3; + std::vector> vprop_vec4; + + // loop over all attribs and build correspondance pair + vprop_float.reserve( m_floatPph.size() ); + for ( auto oh : m_floatPph ) + addAttribPairToCore( out, this, oh, vprop_float ); + vprop_vec2.reserve( m_vec2Pph.size() ); + for ( auto oh : m_vec2Pph ) + addAttribPairToCore( out, this, oh, vprop_vec2 ); + vprop_vec3.reserve( m_vec3Pph.size() ); + for ( auto oh : m_vec3Pph ) + addAttribPairToCore( out, this, oh, vprop_vec3 ); + vprop_vec4.reserve( m_vec4Pph.size() ); + for ( auto oh : m_vec4Pph ) + addAttribPairToCore( out, this, oh, vprop_vec4 ); + + // iterator over all faces + unsigned int vertexIndex = 0; + + // out will have at least n_vertices vertices and normals. + TriangleMesh::PointAttribHandle::Container vertices; + TriangleMesh::NormalAttribHandle::Container normals; + TriangleMesh::IndexContainerType indices; + + vertices.reserve( n_vertices() ); + normals.reserve( n_vertices() ); + indices.reserve( n_faces() ); + + for ( TopologicalMesh::FaceIter f_it = faces_sbegin(); f_it != faces_end(); ++f_it ) + { + int tindices[3]; + int i = 0; + + // iterator over vertex (through halfedge to get access to halfedge normals) + for ( TopologicalMesh::ConstFaceHalfedgeIter fh_it = cfh_iter( *f_it ); fh_it.is_valid(); + ++fh_it ) + { + VertexDataInternal v; + CORE_ASSERT( i < 3, "Non-triangular face found." ); + v._vertex = point( to_vertex_handle( *fh_it ) ); + + if ( has_halfedge_normals() ) + { v._normal = normal( to_vertex_handle( *fh_it ), *f_it ); } + copyAttribToCoreVertex( v._float, this, vprop_float, *fh_it ); + copyAttribToCoreVertex( v._vec2, this, vprop_vec2, *fh_it ); + copyAttribToCoreVertex( v._vec3, this, vprop_vec3, *fh_it ); + copyAttribToCoreVertex( v._vec4, this, vprop_vec4, *fh_it ); + + int vi; + VertexMap::iterator vtr = vertexHandles.find( v ); + if ( vtr == vertexHandles.end() ) + { + vi = int( vertexIndex++ ); + vertexHandles.insert( vtr, VertexMap::value_type( v, vi ) ); + vertices.push_back( v._vertex ); + if ( has_halfedge_normals() ) { normals.push_back( v._normal ); } + copyAttribToCore( out, v._float ); + copyAttribToCore( out, v._vec2 ); + copyAttribToCore( out, v._vec3 ); + copyAttribToCore( out, v._vec4 ); + } + else + { vi = vtr->second; } + tindices[i] = vi; + property( m_outputTriangleMeshIndexPph, *fh_it ) = vi; + i++; + } + indices.emplace_back( tindices[0], tindices[1], tindices[2] ); + } + out.setVertices( std::move( vertices ) ); + if ( has_halfedge_normals() ) { out.setNormals( std::move( normals ) ); } + out.setIndices( std::move( indices ) ); + CORE_ASSERT( vertexIndex == vertices.size(), + "Inconsistent number of faces in generated TriangleMesh." ); + + return out; +} + +template +void copyWedgeDataToAttribContainer( AlignedStdVector::Container>& c, + const VectorArray& wd ) { + for ( size_t i = 0; i < wd.size(); ++i ) + { + c[i].push_back( wd[i] ); + } +} + +template +void moveContainerToMesh( TriangleMesh& out, + const std::vector& names, + AlignedStdVector::Container>& wedgeAttribData ) { + for ( size_t i = 0; i < wedgeAttribData.size(); ++i ) + { + auto attrHandle = out.addAttrib( names[i] ); + out.getAttrib( attrHandle ).setData( std::move( wedgeAttribData[i] ) ); + } +} + +TriangleMesh TopologicalMesh::toTriangleMeshFromWedges() { + // first cleanup deleted element + garbage_collection(); + + TriangleMesh out; + TriangleMesh::IndexContainerType indices; + + /// add attribs to out + std::vector> wedgeFloatAttribHandles; + std::vector> wedgeVector2AttribHandles; + std::vector> wedgeVector3AttribHandles; + std::vector> wedgeVector4AttribHandles; + + TriangleMesh::PointAttribHandle::Container wedgePosition; + AlignedStdVector::Container> wedgeFloatAttribData( + m_wedges.m_floatAttribNames.size() ); + AlignedStdVector::Container> wedgeVector2AttribData( + m_wedges.m_vector2AttribNames.size() ); + AlignedStdVector::Container> wedgeVector3AttribData( + m_wedges.m_vector3AttribNames.size() ); + AlignedStdVector::Container> wedgeVector4AttribData( + m_wedges.m_vector4AttribNames.size() ); + + /// Wedges are output vertices ! + for ( WedgeIndex widx {0}; widx < WedgeIndex {m_wedges.size()}; ++widx ) + { + const auto& wd = m_wedges.getWedgeData( widx ); + wedgePosition.push_back( wd.m_position ); + copyWedgeDataToAttribContainer( wedgeFloatAttribData, wd.m_floatAttrib ); + copyWedgeDataToAttribContainer( wedgeVector2AttribData, wd.m_vector2Attrib ); + copyWedgeDataToAttribContainer( wedgeVector3AttribData, wd.m_vector3Attrib ); + copyWedgeDataToAttribContainer( wedgeVector4AttribData, wd.m_vector4Attrib ); + } + + out.setVertices( std::move( wedgePosition ) ); + moveContainerToMesh( out, m_wedges.m_floatAttribNames, wedgeFloatAttribData ); + moveContainerToMesh( out, m_wedges.m_vector2AttribNames, wedgeVector2AttribData ); + moveContainerToMesh( out, m_wedges.m_vector3AttribNames, wedgeVector3AttribData ); + moveContainerToMesh( out, m_wedges.m_vector4AttribNames, wedgeVector4AttribData ); + + for ( TopologicalMesh::FaceIter f_it = faces_sbegin(); f_it != faces_end(); ++f_it ) + { + int tindices[3]; + int i = 0; + + for ( TopologicalMesh::ConstFaceHalfedgeIter fh_it = cfh_iter( *f_it ); fh_it.is_valid(); + ++fh_it ) + { + CORE_ASSERT( i < 3, "Non-triangular face found." ); + tindices[i] = property( m_wedgeIndexPph, *fh_it ); + i++; + } + indices.emplace_back( tindices[0], tindices[1], tindices[2] ); + } + + out.setIndices( std::move( indices ) ); + + return out; +} + +void TopologicalMesh::updateTriangleMesh( Ra::Core::Geometry::TriangleMesh& /*mesh*/ ) { + CORE_ASSERT( false, "not implemented yet" ); + ///\todo ;) +} + +bool TopologicalMesh::splitEdge( TopologicalMesh::EdgeHandle eh, Scalar f ) { + // Global schema of operation + /* + TRIANGLES ONLY + before after + A A + / F0 \ / F2 | F0 \ + / \ / | \ + /h1 h0\ /h1 e2|e0 h0\ + / he0 \ / he2 | he0 \ + V1 -------- V0 V1 ------ V ------ V0 + \ he1 / \ he3 | he1 / + \o1 o0/ \o1 e3|e1 o0/ + \ / \ | / + \ F1 / \ F3 | F1 / + B B + + */ + + // incorrect factor + if ( f < 0 || f > 1 ) { return false; } + + // get existing topology data + HalfedgeHandle he0 = halfedge_handle( eh, 0 ); + HalfedgeHandle he1 = halfedge_handle( eh, 1 ); + VertexHandle v0 = to_vertex_handle( he0 ); + VertexHandle v1 = to_vertex_handle( he1 ); + FaceHandle F0 = face_handle( he0 ); + FaceHandle F1 = face_handle( he1 ); + + // not triangles or holes + if ( ( !is_boundary( he0 ) && valence( F0 ) != 3 ) || + ( !is_boundary( he1 ) && valence( F1 ) != 3 ) ) + { return false; } + + // add the new vertex + const Point p = Point( f * point( v0 ) + ( Scalar( 1. ) - f ) * point( v1 ) ); + VertexHandle v = add_vertex( p ); + + // create the new faces and reconnect the topology + HalfedgeHandle he3 = new_edge( v, v1 ); + HalfedgeHandle he2 = opposite_halfedge_handle( he3 ); + set_halfedge_handle( v, he0 ); + set_vertex_handle( he1, v ); + + // does F0 exist + if ( !is_boundary( he0 ) ) + { + HalfedgeHandle h0 = next_halfedge_handle( he0 ); + HalfedgeHandle h1 = next_halfedge_handle( h0 ); + // create new edge + VertexHandle A = to_vertex_handle( h0 ); + HalfedgeHandle e2 = new_edge( v, A ); + HalfedgeHandle e0 = opposite_halfedge_handle( e2 ); + // split F0 + FaceHandle F2 = new_face(); + set_halfedge_handle( F0, he0 ); + set_halfedge_handle( F2, h1 ); + // update F0 + set_face_handle( h0, F0 ); + set_face_handle( e0, F0 ); + set_face_handle( he0, F0 ); + set_next_halfedge_handle( he0, h0 ); + set_next_halfedge_handle( h0, e0 ); + set_next_halfedge_handle( e0, he0 ); + // update F2 + set_face_handle( h1, F2 ); + set_face_handle( he2, F2 ); + set_face_handle( e2, F2 ); + set_next_halfedge_handle( e2, h1 ); + set_next_halfedge_handle( h1, he2 ); + set_next_halfedge_handle( he2, e2 ); + // deal with custom properties + // interpolate at he2 + interpolateAllProps( h1, he0, he2, 0.5 ); + // copy at e0, and e2 + copyAllProps( he2, e0 ); + } + else + { + HalfedgeHandle h1 = prev_halfedge_handle( he0 ); + set_next_halfedge_handle( h1, he2 ); + set_next_halfedge_handle( he2, he0 ); + // next halfedge handle of he0 already is h0 + // halfedge handle of V already is he0 + } + + // does F1 exist + if ( !is_boundary( he1 ) ) + { + HalfedgeHandle o1 = next_halfedge_handle( he1 ); + HalfedgeHandle o0 = next_halfedge_handle( o1 ); + // create new edge + VertexHandle B = to_vertex_handle( o1 ); + HalfedgeHandle e1 = new_edge( v, B ); + HalfedgeHandle e3 = opposite_halfedge_handle( e1 ); + // split F1 + FaceHandle F3 = new_face(); + set_halfedge_handle( F3, o1 ); + set_halfedge_handle( F1, he1 ); + // update F1 + set_face_handle( o1, F3 ); + set_face_handle( e3, F3 ); + set_face_handle( he3, F3 ); + set_next_halfedge_handle( he3, o1 ); + set_next_halfedge_handle( o1, e3 ); + set_next_halfedge_handle( e3, he3 ); + // update F3 + set_face_handle( o0, F1 ); + set_face_handle( he1, F1 ); + set_face_handle( e1, F1 ); + set_next_halfedge_handle( he1, e1 ); + set_next_halfedge_handle( e1, o0 ); + set_next_halfedge_handle( o0, he1 ); + // deal with custom properties + // first copy at he3 + copyAllProps( he1, he3 ); + // interpolate at he1 + interpolateAllProps( o0, he3, he1, 0.5 ); + // copy at e1, and e3 + copyAllProps( he1, e3 ); + copyAllProps( o1, e1 ); + } + else + { + HalfedgeHandle o1 = next_halfedge_handle( he1 ); + // next halfedge handle of o0 already is he1 + set_next_halfedge_handle( he1, he3 ); + set_next_halfedge_handle( he3, o1 ); + // halfedge handle of V already is he0 + } + + // ensure consistency at v1 + if ( halfedge_handle( v1 ) == he0 ) { set_halfedge_handle( v1, he2 ); } + + return true; +} + +template +void interpolate( const VectorArray& in1, + const VectorArray& in2, + VectorArray& out, + const Scalar alpha ) { + for ( size_t i = 0; i < in1.size(); ++i ) + { + out.push_back( ( 1_ra - alpha ) * in1[i] + alpha * in2[i] ); + } +} + +TopologicalMesh::WedgeData +TopologicalMesh::interpolateWedgeAttributes( const TopologicalMesh::WedgeData& w1, + const TopologicalMesh::WedgeData& w2, + Scalar alpha ) { + WedgeData ret; + interpolate( w1.m_floatAttrib, w2.m_floatAttrib, ret.m_floatAttrib, alpha ); + interpolate( w1.m_vector2Attrib, w2.m_vector2Attrib, ret.m_vector2Attrib, alpha ); + interpolate( w1.m_vector3Attrib, w2.m_vector3Attrib, ret.m_vector3Attrib, alpha ); + interpolate( w1.m_vector4Attrib, w2.m_vector4Attrib, ret.m_vector4Attrib, alpha ); + return ret; +} + +//----------------------------------------------------------------------------- +// from /OpenMesh/Core/Mesh/TriConnectivity.cc +void TopologicalMesh::split( EdgeHandle _eh, VertexHandle _vh ) { + HalfedgeHandle h0 = halfedge_handle( _eh, 0 ); + HalfedgeHandle o0 = halfedge_handle( _eh, 1 ); + + VertexHandle v2 = to_vertex_handle( o0 ); + + HalfedgeHandle e1 = new_edge( _vh, v2 ); + HalfedgeHandle t1 = opposite_halfedge_handle( e1 ); + + FaceHandle f0 = face_handle( h0 ); + FaceHandle f3 = face_handle( o0 ); + + set_halfedge_handle( _vh, h0 ); + set_vertex_handle( o0, _vh ); + + if ( !is_boundary( h0 ) ) + { + HalfedgeHandle h1 = next_halfedge_handle( h0 ); + HalfedgeHandle h2 = next_halfedge_handle( h1 ); + + VertexHandle v1 = to_vertex_handle( h1 ); + + HalfedgeHandle e0 = new_edge( _vh, v1 ); + HalfedgeHandle t0 = opposite_halfedge_handle( e0 ); + + FaceHandle f1 = new_face(); + set_halfedge_handle( f0, h0 ); + set_halfedge_handle( f1, h2 ); + + set_face_handle( h1, f0 ); + set_face_handle( t0, f0 ); + set_face_handle( h0, f0 ); + + set_face_handle( h2, f1 ); + set_face_handle( t1, f1 ); + set_face_handle( e0, f1 ); + + set_next_halfedge_handle( h0, h1 ); + set_next_halfedge_handle( h1, t0 ); + set_next_halfedge_handle( t0, h0 ); + + set_next_halfedge_handle( e0, h2 ); + set_next_halfedge_handle( h2, t1 ); + set_next_halfedge_handle( t1, e0 ); + } + else + { + set_next_halfedge_handle( prev_halfedge_handle( h0 ), t1 ); + set_next_halfedge_handle( t1, h0 ); + // halfedge handle of _vh already is h0 + } + + if ( !is_boundary( o0 ) ) + { + HalfedgeHandle o1 = next_halfedge_handle( o0 ); + HalfedgeHandle o2 = next_halfedge_handle( o1 ); + + VertexHandle v3 = to_vertex_handle( o1 ); + + HalfedgeHandle e2 = new_edge( _vh, v3 ); + HalfedgeHandle t2 = opposite_halfedge_handle( e2 ); + + FaceHandle f2 = new_face(); + set_halfedge_handle( f2, o1 ); + set_halfedge_handle( f3, o0 ); + + set_face_handle( o1, f2 ); + set_face_handle( t2, f2 ); + set_face_handle( e1, f2 ); + + set_face_handle( o2, f3 ); + set_face_handle( o0, f3 ); + set_face_handle( e2, f3 ); + + set_next_halfedge_handle( e1, o1 ); + set_next_halfedge_handle( o1, t2 ); + set_next_halfedge_handle( t2, e1 ); + + set_next_halfedge_handle( o0, e2 ); + set_next_halfedge_handle( e2, o2 ); + set_next_halfedge_handle( o2, o0 ); + } + else + { + set_next_halfedge_handle( e1, next_halfedge_handle( o0 ) ); + set_next_halfedge_handle( o0, e1 ); + set_halfedge_handle( _vh, e1 ); + } + + if ( halfedge_handle( v2 ) == h0 ) set_halfedge_handle( v2, t1 ); +} + +//----------------------------------------------------------------------------- + +void TopologicalMesh::split_copy( EdgeHandle _eh, VertexHandle _vh ) { + const VertexHandle v0 = to_vertex_handle( halfedge_handle( _eh, 0 ) ); + const VertexHandle v1 = to_vertex_handle( halfedge_handle( _eh, 1 ) ); + + const int nf = n_faces(); + + // Split the halfedge ( handle will be preserved) + split( _eh, _vh ); + + // Copy the properties of the original edge to all neighbor edges that + // have been created + for ( VEIter ve_it = ve_iter( _vh ); ve_it.is_valid(); ++ve_it ) + copy_all_properties( _eh, *ve_it, true ); + + for ( auto vh : {v0, v1} ) + { + // get the halfedge pointing from new vertex to old vertex + const HalfedgeHandle h = find_halfedge( _vh, vh ); + // for boundaries there are no faces whose properties need to be copied + if ( !is_boundary( h ) ) + { + FaceHandle fh0 = face_handle( h ); + FaceHandle fh1 = face_handle( opposite_halfedge_handle( prev_halfedge_handle( h ) ) ); + // is fh0 the new face? + if ( fh0.idx() >= nf ) std::swap( fh0, fh1 ); + + // copy properties from old face to new face + copy_all_properties( fh0, fh1, true ); + } + } +} + +bool TopologicalMesh::splitEdgeWedge( TopologicalMesh::EdgeHandle eh, Scalar f ) { + // Global schema of operation + /* + TRIANGLES ONLY + before after + + / \ / | \ + / \ / | \ + /h2 h1\ /r2 r1|s2 s1\ + / h0 -->\ / r0 | s0=h0 \ + V0 -------- V1 V0-(1-f)-V---f---V1 + \<-- o0 / \ u0 | t0=o0 / + \o1 o2/ \u1 u2|t1 t2/ + \ / \ | / + \ / \ | / + + + */ + + // incorrect factor + if ( f < 0 || f > 1 ) { return false; } + + if ( is_boundary( eh ) ) + { + CORE_ASSERT( false, "ouch" ); + return false; + } + + const auto h0 = halfedge_handle( eh, 0 ); + const auto o0 = halfedge_handle( eh, 1 ); + + const auto v0 = to_vertex_handle( o0 ); + const auto v1 = to_vertex_handle( h0 ); + + // add the new point + const Point p = Point( f * point( v1 ) + ( 1_ra - f ) * point( v0 ) ); + VertexHandle vh = add_vertex( p ); + + const auto h1 = next_halfedge_handle( h0 ); + const auto h2 = next_halfedge_handle( h1 ); + + const auto o1 = next_halfedge_handle( o0 ); + const auto o2 = next_halfedge_handle( o1 ); + + // compute interpolated wedge, or the two wedges if not the same wedges + // around the two vertices of the edge (we always compute for two wedges, + // even if add will return the same wedge. + const auto hw0idx = property( m_wedgeIndexPph, h2 ); + const auto hw1idx = property( m_wedgeIndexPph, h0 ); + const auto ow0idx = property( m_wedgeIndexPph, o2 ); + const auto ow1idx = property( m_wedgeIndexPph, o0 ); + const auto hw0 = m_wedges.getWedgeData( hw0idx ); + const auto hw1 = m_wedges.getWedgeData( hw1idx ); + const auto ow0 = m_wedges.getWedgeData( ow0idx ); + const auto ow1 = m_wedges.getWedgeData( ow1idx ); + auto hvw = interpolateWedgeAttributes( hw0, hw1, f ); + auto ovw = interpolateWedgeAttributes( ow1, ow0, f ); + hvw.m_position = p; + ovw.m_position = p; + auto hvwidx = m_wedges.add( hvw ); + auto ovwidx = m_wedges.add( ovw ); + + split_copy( eh, vh ); + + auto r0 = find_halfedge( v0, vh ); + auto s0 = find_halfedge( vh, v1 ); + auto t0 = find_halfedge( v1, vh ); + auto u0 = find_halfedge( vh, v0 ); + + auto r1 = next_halfedge_handle( r0 ); + auto r2 = next_halfedge_handle( r1 ); + + auto s1 = next_halfedge_handle( s0 ); + auto s2 = next_halfedge_handle( s1 ); + + auto t1 = next_halfedge_handle( t0 ); + auto t2 = next_halfedge_handle( t1 ); + + auto u1 = next_halfedge_handle( u0 ); + auto u2 = next_halfedge_handle( u1 ); + + CORE_ASSERT( s0 == h0, "TopologicalMesh: splitEdgeWedge inconsistency" ); + CORE_ASSERT( t0 == o0, "TopologicalMesh: splitEdgeWedge inconsistency" ); + + auto updateWedgeIndex1 = [this]( WedgeIndex widx_, + HalfedgeHandle r0_, + HalfedgeHandle r1_, + HalfedgeHandle r2_, + HalfedgeHandle h1_, + HalfedgeHandle h2_ ) { + CORE_UNUSED( r2_ ); + CORE_UNUSED( h2_ ); + + if ( !is_boundary( r0_ ) ) + { + CORE_ASSERT( r2_ == h2_, "TopologicalMesh: splitEdgeWedge inconsistency" ); + + // Increment here, the first reference is for the other he + property( this->m_wedgeIndexPph, r0_ ) = this->m_wedges.newReference( widx_ ); + property( this->m_wedgeIndexPph, r1_ ) = + this->m_wedges.newReference( property( this->m_wedgeIndexPph, h1_ ) ); + } + else + { property( this->m_wedgeIndexPph, r0_ ) = WedgeIndex {}; } + }; + + auto updateWedgeIndex2 = [this]( WedgeIndex widx_, + HalfedgeHandle s0_, + HalfedgeHandle s1_, + HalfedgeHandle s2_, + HalfedgeHandle h0_, + HalfedgeHandle h1_ ) { + CORE_UNUSED( s1_ ); + CORE_UNUSED( h1_ ); + + if ( !is_boundary( s0_ ) ) + { + CORE_ASSERT( s1_ == h1_, "TopologicalMesh: splitEdgeWedge inconsistency" ); + // do not increment here, since add has set ref to 1 + property( this->m_wedgeIndexPph, s2_ ) = widx_; + // "steal" ref from previous he (actually s0 is h0, u0 is the steal + // from o0. + property( this->m_wedgeIndexPph, s0_ ) = property( this->m_wedgeIndexPph, h0_ ); + } + else + { property( this->m_wedgeIndexPph, s0_ ) = WedgeIndex {}; } + }; + + // this update read from o0, must be done before t which reads from o0 + updateWedgeIndex2( ovwidx, u0, u1, u2, o0, o1 ); + // those update might be in any order + updateWedgeIndex2( hvwidx, s0, s1, s2, h0, h1 ); + updateWedgeIndex1( hvwidx, r0, r1, r2, h1, h2 ); + updateWedgeIndex1( ovwidx, t0, t1, t2, o1, o2 ); + + return true; +} + +void TopologicalMesh::collapseWedge( TopologicalMesh::HalfedgeHandle heh ) { + HalfedgeHandle h = heh; + HalfedgeHandle hn = next_halfedge_handle( h ); + HalfedgeHandle hp = prev_halfedge_handle( h ); + + HalfedgeHandle o = opposite_halfedge_handle( h ); + HalfedgeHandle on = next_halfedge_handle( o ); + HalfedgeHandle op = prev_halfedge_handle( o ); + + // FaceHandle fh = face_handle( h ); + // FaceHandle fo = face_handle( o ); + + VertexHandle vh = to_vertex_handle( h ); + VertexHandle vo = to_vertex_handle( o ); + + auto position = m_wedges.getWedgeData( property( m_wedgeIndexPph, heh ) ).m_position; + auto widx = property( m_wedgeIndexPph, heh ); + + CORE_ASSERT( widx.isValid(), "try to collapse onto an invalid wedge" ); + CORE_ASSERT( !isFeatureVertex( vo ), "try to collapse a feature vertex" ); + + for ( VertexIHalfedgeIter vih_it( vih_iter( vo ) ); vih_it.is_valid(); ++vih_it ) + { + // delete and set to new widx + m_wedges.del( property( m_wedgeIndexPph, *vih_it ) ); + property( m_wedgeIndexPph, *vih_it ) = m_wedges.newReference( widx ); + } + // but remove one ref for the deleted opposite he + m_wedges.del( property( m_wedgeIndexPph, o ) ); + + // and delete wedge of the remove he + // first if h is not boundary, copy the wedgeIndex of hn to hp to it + if ( !is_boundary( h ) ) + { + property( m_wedgeIndexPph, hp ) = + m_wedges.newReference( property( m_wedgeIndexPph, opposite_halfedge_handle( hn ) ) ); + } + m_wedges.del( property( m_wedgeIndexPph, hn ) ); + m_wedges.del( property( m_wedgeIndexPph, opposite_halfedge_handle( hn ) ) ); + + if ( !is_boundary( o ) ) + { + property( m_wedgeIndexPph, on ) = + m_wedges.newReference( property( m_wedgeIndexPph, opposite_halfedge_handle( op ) ) ); + } + m_wedges.del( property( m_wedgeIndexPph, op ) ); + m_wedges.del( property( m_wedgeIndexPph, opposite_halfedge_handle( op ) ) ); + + base::collapse( h ); + + for ( VertexIHalfedgeIter vih_it( vih_iter( vh ) ); vih_it.is_valid(); ++vih_it ) + { + // delete and set to new widx + m_wedges.setWedgePosition( property( m_wedgeIndexPph, *vih_it ), position ); + } +} + +void TopologicalMesh::garbage_collection() { + for ( HalfedgeIter he_it = halfedges_begin(); he_it != halfedges_end(); ++he_it ) + { + // already done in collapseWedge + // if ( status( *he_it ).deleted() ) { m_wedges.del(property( + // m_wedgeIndexPph, *he_it )); } + } + + auto offset = m_wedges.computeCleanupOffset(); + for ( HalfedgeIter he_it = halfedges_begin(); he_it != halfedges_end(); ++he_it ) + { + if ( !status( *he_it ).deleted() ) + { + auto index = property( m_wedgeIndexPph, *he_it ); + if ( index.isValid() ) { property( m_wedgeIndexPph, *he_it ) = index - offset[index]; } + } + } + m_wedges.garbageCollection(); + base::garbage_collection(); + + for ( HalfedgeIter he_it = halfedges_begin(); he_it != halfedges_end(); ++he_it ) + { + ON_ASSERT( auto idx = property( m_wedgeIndexPph, *he_it ); ); + CORE_ASSERT( !idx.isValid() || !m_wedges.getWedge( idx ).isDeleted(), + "references deleted wedge remains after garbage collection" ); + } + for ( size_t i = 0; i < m_wedges.size(); ++i ) + { + CORE_ASSERT( !m_wedges.getWedge( WedgeIndex {i} ).isDeleted(), + "deleted wedge remains after garbage collection" ); + } +} + +void TopologicalMesh::delete_face( FaceHandle _fh, bool _delete_isolated_vertices ) { + for ( auto itr = fh_begin( _fh ); itr.is_valid(); ++itr ) + { + auto idx = property( m_wedgeIndexPph, *itr ); + if ( idx.isInvalid() ) + { + LOG( logWARNING ) + << "[TopologicalMesh::delete_face] halfedge has an invalid wedge index"; + } + else + { m_wedges.del( idx ); } + // set an invalid index for the boundary halfedges + property( m_wedgeIndexPph, *itr ) = WedgeIndex {}; + } + base::delete_face( _fh, _delete_isolated_vertices ); +} + +void TopologicalMesh::InitWedgeProps::operator()( AttribBase* attr ) const { + if ( attr->getSize() != m_triMesh.vertices().size() ) + { LOG( logWARNING ) << "[TopologicalMesh] Skip badly sized attribute " << attr->getName(); } + else if ( attr->getName() != std::string( "in_position" ) ) + { + if ( attr->isFloat() ) + { + m_topo->m_wedges.m_wedgeFloatAttribHandles.push_back( + m_triMesh.getAttribHandle( attr->getName() ) ); + m_topo->m_wedges.addProp( attr->getName() ); + } + else if ( attr->isVector2() ) + { + m_topo->m_wedges.m_wedgeVector2AttribHandles.push_back( + m_triMesh.getAttribHandle( attr->getName() ) ); + m_topo->m_wedges.addProp( attr->getName() ); + } + else if ( attr->isVector3() ) + { + m_topo->m_wedges.m_wedgeVector3AttribHandles.push_back( + m_triMesh.getAttribHandle( attr->getName() ) ); + m_topo->m_wedges.addProp( attr->getName() ); + } + else if ( attr->isVector4() ) + { + m_topo->m_wedges.m_wedgeVector4AttribHandles.push_back( + m_triMesh.getAttribHandle( attr->getName() ) ); + m_topo->m_wedges.addProp( attr->getName() ); + } + else + LOG( logWARNING ) + << "Warning, mesh attribute " << attr->getName() + << " type is not supported (only float, vec2, vec3 nor vec4 are supported)"; + } +} + +/////////////// WEDGES RELATED STUFF ///////////////// + +TopologicalMesh::WedgeIndex +TopologicalMesh::WedgeCollection::add( const TopologicalMesh::WedgeData& wd ) { + WedgeIndex idx; + auto itr = std::find( m_data.begin(), m_data.end(), Wedge {wd} ); + + if ( itr == m_data.end() ) + { + idx = m_data.size(); + m_data.emplace_back( wd ); + } + else + { + itr->incrementRefCount(); + idx = std::distance( m_data.begin(), itr ); + } + return idx; +} + +std::vector TopologicalMesh::WedgeCollection::computeCleanupOffset() const { + std::vector ret( m_data.size(), 0 ); + int currentOffset = 0; + for ( size_t i = 0; i < m_data.size(); ++i ) + { + if ( m_data[i].isDeleted() ) + { + ++currentOffset; + ret[i] = -1; + } + else + { ret[i] = currentOffset; } + } + return ret; +} +} // namespace deprecated +} // namespace Geometry +} // namespace Core +} // namespace Ra diff --git a/src/Core/Geometry/deprecated/TopologicalMesh.hpp b/src/Core/Geometry/deprecated/TopologicalMesh.hpp new file mode 100644 index 00000000000..5afe2403bfe --- /dev/null +++ b/src/Core/Geometry/deprecated/TopologicalMesh.hpp @@ -0,0 +1,717 @@ +#pragma once + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include + +namespace Ra { +namespace Core { +namespace Geometry { +namespace deprecated { +using namespace Utils; // log, AttribXXX + +/** + * Define the Traits to be used by OpenMesh for TopologicalMesh. + */ +struct TopologicalMeshTraits : OpenMesh::DefaultTraits { + using Point = Ra::Core::Vector3; + using Normal = Ra::Core::Vector3; + + VertexAttributes( OpenMesh::Attributes::Status | OpenMesh::Attributes::Normal ); + FaceAttributes( OpenMesh::Attributes::Status | OpenMesh::Attributes::Normal ); + EdgeAttributes( OpenMesh::Attributes::Status ); + // Add OpenMesh::Attributes::PrevHalfedge for efficiency ? + HalfedgeAttributes( OpenMesh::Attributes::Status | OpenMesh::Attributes::Normal ); +}; + +/** + * This class represents a mesh with topological information on the + * vertex graph, using a half-edge representation. + * + * This integration is inspired by: + * https://gist.github.com/Unril/03fa353d0461ed6bd41d + * + * \todo rename methods to respect Radium guideline (get/set/is, camelCase) + * \todo private inheritance from OpenMesh, and import relevant methods. + */ +class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT +{ + private: + using base = OpenMesh::PolyMesh_ArrayKernelT; + using base::PolyMesh_ArrayKernelT; + using Index = Ra::Core::Utils::Index; + using Vector3 = Ra::Core::Vector3; + class Wedge; + + public: + EIGEN_MAKE_ALIGNED_OPERATOR_NEW + + using WedgeIndex = Index; + + /** + * Construct a topological mesh from a triangle mesh. + * This operation merges vertex with same position, but keeps vertex + * attributes on halfedges, so that TriangleMesh vertices with the same 3D + * position are represented only once in the topological mesh. + * \note This is a costly operation. + * + * \tparam NonManifoldFaceCommand Command executed when non-manifold faces are + * found. API and default implementation: + * \snippet Core/Geometry/TopologicalMesh.cpp Default command implementation + * + */ + template + explicit TopologicalMesh( const Ra::Core::Geometry::TriangleMesh& triMesh, + NonManifoldFaceCommand command ); + + /** + * \brief Convenience constructor + * \see TopologicalMesh( const Ra::Core::Geometry::TriangleMesh&, NonManifoldFaceCommand) + */ + explicit TopologicalMesh( const Ra::Core::Geometry::TriangleMesh& triMesh ); + void initWithWedge( const Ra::Core::Geometry::TriangleMesh& triMesh ); + template + void initWithWedge( const Ra::Core::Geometry::TriangleMesh& triMesh, + NonManifoldFaceCommand command ); + + /** + * Construct an empty topological mesh, only init mandatory properties. + */ + explicit TopologicalMesh(); + + /** + * Return a triangleMesh from the topological mesh. + * \note This is a costly operation. + * \warning It uses the attributes defined on halfedges. Do not work well if attribs are defined + * on wedges (initWithWedge), in this case use toTriangleMeshFromWedges() + */ + TriangleMesh toTriangleMesh(); + + /** + * Return a triangleMesh from the topological mesh. + * \note This is a costly operation. + * \warning It uses the attributes defined on wedges + */ + TriangleMesh toTriangleMeshFromWedges(); + + /** + * Update triangle mesh data, assuming the mesh and this topo mesh has the + * same topology. + * \warning note implemented yet. + */ + void updateTriangleMesh( Ra::Core::Geometry::TriangleMesh& mesh ); + + // import other version of halfedge_handle method + using base::halfedge_handle; + + /** + * Return the half-edge associated with a given vertex and face. + * \note Asserts if vh is not a member of fh. + */ + inline HalfedgeHandle halfedge_handle( VertexHandle vh, FaceHandle fh ) const; + + /** + * Get normal of the vertex vh, when member of fh. + * \note Asserts if vh is not a member of fh. + */ + [[deprecated]] inline const Normal& normal( VertexHandle vh, FaceHandle fh ) const; + + /** + * Set normal of the vertex vh, when member of fh. + * \note Asserts if vh is not a member of fh. + */ + [[deprecated]] void set_normal( VertexHandle vh, FaceHandle fh, const Normal& n ); + + /// Import Base definition of normal and set normal. + ///@{ + using base::normal; + using base::set_normal; + ///@} + + /** + * Set the normal n to all the halfedges that points to vh (i.e. incomming + * halfedges) . + * If you work with vertex normals, please call this function on all vertex + * handles before convertion with toTriangleMesh. + */ + [[deprecated]] void propagate_normal_to_halfedges( VertexHandle vh ); + + /** + * Return a handle to the halfedge property storing vertices indices within + * the TriangleMesh *this has been built on. + */ + inline const OpenMesh::HPropHandleT& getInputTriangleMeshIndexPropHandle() const; + + /** + * Return a handle to the halfedge property storing vertices indices within + * the TriangleMesh returned by toTriangleMesh(). + * \note This property is valid only after toTriangleMesh() has been called. + */ + inline const OpenMesh::HPropHandleT& getOutputTriangleMeshIndexPropHandle() const; + + /** + * \name Const access to handles of the HalfEdge properties coming from + * the TriangleMesh attributes. + */ + ///@{ + [[deprecated]] inline const std::vector>& + getFloatPropsHandles() const; + [[deprecated]] inline const std::vector>& + getVector2PropsHandles() const; + [[deprecated]] inline const std::vector>& + getVector3PropsHandles() const; + [[deprecated]] inline const std::vector>& + getVector4PropsHandles() const; + ///@} + + /** + * \name Dealing with normals + * Utils to deal with normals when modifying the mesh topology. + */ + ///@{ + + /** + * Create a new property for normals on faces of \a mesh. + * \note This new property will have to be propagated onto the newly created + * halfedges with copyNormal(). + */ + inline void createNormalPropOnFaces( OpenMesh::FPropHandleT& fProp ); + + /** + * Remove face property \a prop from \a mesh. + * \note Invalidates the property handle. + */ + inline void clearProp( OpenMesh::FPropHandleT& fProp ); + + /** + * Copy the normal property from \a input_heh to \a copy_heh. + */ + inline void copyNormal( HalfedgeHandle input_heh, HalfedgeHandle copy_heh ); + + /** Copy the face normal property \a fProp from \a fh to \a heh. + * \note \a fProp must have been previously created through createNormalPropOnFaces(). + */ + inline void + copyNormalFromFace( FaceHandle fh, HalfedgeHandle heh, OpenMesh::FPropHandleT fProp ); + + /** + * Interpolate normal property on edge center (after edge split). + */ + inline void + interpolateNormal( HalfedgeHandle in_a, HalfedgeHandle in_b, HalfedgeHandle out, Scalar f ); + + /** Interpolate normal property on face center. + * \note \a fProp must have been previously created through createNormalPropOnFaces(). + */ + inline void interpolateNormalOnFaces( FaceHandle fh, OpenMesh::FPropHandleT fProp ); + ///@} + + /** + * \name Dealing with custom properties + * Utils to deal with custom properties of any type when modifying the mesh topology. + */ + ///@{ + + /** + * Create a new property for each \a input properties of \a mesh on faces. + * \note This new property will have to be propagated onto the newly created + * halfedges with copyProps(). + */ + template + void createPropsOnFaces( const std::vector>& input, + std::vector>& output ); + + /** + * Remove \a props from \a mesh. + * \note Clears \a props. + */ + template + void clearProps( std::vector>& props ); + + /** + * Copy \a props properties from \a input_heh to \a copy_heh. + */ + template + void copyProps( HalfedgeHandle input_heh, + HalfedgeHandle copy_heh, + const std::vector>& props ); + + /** + * Copy face properties \a props from \a fh to \a heh. + * \note \a fProps must have been previously created through createPropsOnFaces(). + */ + template + void copyPropsFromFace( FaceHandle fh, + HalfedgeHandle heh, + const std::vector>& fProps, + const std::vector>& hProps ); + + /** + * Interpolate \a props on edge center (after edge split). + */ + template + void interpolateProps( HalfedgeHandle in_a, + HalfedgeHandle in_b, + HalfedgeHandle out, + Scalar f, + const std::vector>& props ); + + /** + * Interpolate \a hprops on face center. + * \note \a fProps must have been previously created through createPropsOnFaces(). + */ + template + void interpolatePropsOnFaces( FaceHandle fh, + const std::vector>& hProps, + const std::vector>& fProps ); + ///@} + /** + * \name Deal with all attributes* Utils to deal with the normal and + custom properties when modifying the mesh topology.*/ + + ///@{ + + /** + * Create a new property for each property of \a mesh on faces. + * Outputs the new face properties handles in the corresponding output parameters. + * \note These new properties will have to be propagated onto the newly created + * halfedges with copyAllProps(). + */ + inline void createAllPropsOnFaces( OpenMesh::FPropHandleT& normalProp, + std::vector>& floatProps, + std::vector>& vec2Props, + std::vector>& vec3Props, + std::vector>& vec4Props ); + + /** + * Remove all the given properties from \a mesh. + * \note Invalidates \a normalProp and clears the given property containers. + */ + inline void clearAllProps( OpenMesh::FPropHandleT& normalProp, + std::vector>& floatProps, + std::vector>& vec2Props, + std::vector>& vec3Props, + std::vector>& vec4Props ); + + /** + * Copy all properties from \a input_heh to \a copy_heh. + */ + inline void copyAllProps( HalfedgeHandle input_heh, HalfedgeHandle copy_heh ); + + /** + * Copy all given face properties from \a fh to \a heh. + * \note Each property must have been previously created either all at once + * through createAllPropsOnFaces(), or individually through + * createNormalPropOnFaces() and createPropsOnFaces(). + */ + inline void copyAllPropsFromFace( FaceHandle fh, + HalfedgeHandle heh, + OpenMesh::FPropHandleT normalProp, + std::vector>& floatProps, + std::vector>& vec2Props, + std::vector>& vec3Props, + std::vector>& vec4Props ); + + /** + * Interpolate all properties on edge center (after edge split). + */ + inline void + interpolateAllProps( HalfedgeHandle in_a, HalfedgeHandle in_b, HalfedgeHandle out, Scalar f ); + + /** + * Interpolate \a hprops on face center. + * \note Each property must have been previously created either all at once + * through createAllPropsOnFaces(), or individually through + * createNormalPropOnFaces() and createPropsOnFaces(). + */ + inline void + interpolateAllPropsOnFaces( FaceHandle fh, + OpenMesh::FPropHandleT normalProp, + std::vector>& floatProps, + std::vector>& vec2Props, + std::vector>& vec3Props, + std::vector>& vec4Props ); + ///@} + + /** + * Inner class WedgeData represents the actual data per wedge, including position. + * + * At any time m_position as to be equal to the wedge's vertex point. + * All wedges have the same set of attributes. + * Access and management is delegated to TopologicalMesh and WedgeCollection + */ + class WedgeData + { + public: + EIGEN_MAKE_ALIGNED_OPERATOR_NEW + + // Index m_inputTriangleMeshIndex; + // Index m_outputTriangleMeshIndex; + Vector3 m_position {}; + VectorArray m_floatAttrib; + VectorArray m_vector2Attrib; + VectorArray m_vector3Attrib; + VectorArray m_vector4Attrib; + + template + inline VectorArray& getAttribArray(); + + explicit WedgeData() = default; + inline bool operator==( const WedgeData& lhs ) const; + inline bool operator!=( const WedgeData& lhs ) const; + inline bool operator<( const WedgeData& lhs ) const; + friend Wedge; + + private: + // return 1 : equals, 2: strict less, 3: strict greater + template + static int compareVector( const T& a, const T& b ); + }; + + /** + * \name Topological operations + */ + ///@{ + /** + * Apply a 2-4 edge split. + * \param eh The handle to the edge to split. + * \param f The interpolation factor to place the new point on the edge. + * Must be in [0,1]. + * \return True if the edge has been split, false otherwise. + * \note Only applies on edges between 2 triangles, and if \a f is in [0,1]. + * \note Mesh attributes are linearly interpolated on the newly created + * halfedge. + * \note f=0 correspond to halfedge_handle( eh, 0 ) (i.e. first vertex of + * the edge) + */ + bool splitEdge( TopologicalMesh::EdgeHandle eh, Scalar f ); + bool splitEdgeWedge( TopologicalMesh::EdgeHandle eh, Scalar f ); + + /** + * Halfedge collapes \a he. + * vo=from_vertex_handle(he) is deleted. + * After collapse vo incoming halfedges points to vh = to_vertex_handle(he). + * Wedge indices are updated to reflect the change in topology. + * For detailed topological modifications see \ref develmeshes. + * \param he halfedge's hangle to collapse. + */ + void collapseWedge( TopologicalMesh::HalfedgeHandle he ); + ///@} + + /** + * Return the set of WedgeIndex incident to a given Vertex \a vh. + * only valid non deleted wedges are present in the set. + */ + inline std::set getVertexWedges( OpenMesh::VertexHandle vh ) const; + + /** + * get the wedge index associated with an halfedge + */ + inline WedgeIndex getWedgeIndex( OpenMesh::HalfedgeHandle heh ) const; + + /** + * Access to wedge data. + * \param idx must be valid and correspond to a non delete wedge index. + */ + inline const WedgeData& getWedgeData( const WedgeIndex& idx ) const; + + /** + * Return the wedge refcount, for debug purpose. + */ + inline unsigned int getWedgeRefCount( const WedgeIndex& idx ) const; + + /** set WedgeData \a wd to the wedge with index \a widx. + * All halfedge that point to widx will get the new values. + * \param widx index of the wedge + * \param wd data to set to wedge that correspond to widx + */ + inline void setWedgeData( WedgeIndex widx, const WedgeData& wd ); + + /** + * Change the WedgeData associated for \a idx, for attrib \a name to \a value. + * The data is changed for all halfedges referencing this wedge. + * \return true if the wedge is set, false if nothing set, i.e. if name is not an attrib of + * type T. + */ + template + inline bool setWedgeData( const WedgeIndex& idx, const std::string& name, const T& value ); + + /** + * Replace the wedge data associated with an halfedge. + * The old wedge is "deleted". If wedge data correspond to an already + * present wedge, it's index is used. + */ + inline void replaceWedge( OpenMesh::HalfedgeHandle he, const WedgeData& wd ); + + /** + * Replace the wedge index associated with an halfedge. + * The old wedge is "deleted". The new wedge reference count is incremented. + */ + inline void replaceWedgeIndex( OpenMesh::HalfedgeHandle he, const WedgeIndex& widx ); + + /** + * call mergeEquelWedges( vh ) for every vertices of the mesh. + * \see void mergeEqualWedges( OpenMesh::VertexHandle vh ); + */ + inline void mergeEqualWedges(); + + /** + * Merge (make same index) wegdes with the same data around \a vh + * \param vh vertex handle to process + */ + inline void mergeEqualWedges( OpenMesh::VertexHandle vh ); + + /// Remove deleted element from the mesh, including wedges. + void garbage_collection(); + + inline const std::vector& getVec4AttribNames() const; + inline const std::vector& getVec3AttribNames() const; + inline const std::vector& getVec2AttribNames() const; + inline const std::vector& getFloatAttribNames() const; + + /// true if more than one wedge arount vertex \a vh, false if only one wedge + inline bool isFeatureVertex( const VertexHandle& vh ) const; + + /// true if at least one of edge's vertex as two different wedge arount the + /// edge. + /// false if the two vertices have the same wedge for both face aside the edge. + inline bool isFeatureEdge( const EdgeHandle& eh ) const; + + inline const OpenMesh::HPropHandleT& getWedgeIndexPph() const; + + void delete_face( FaceHandle _fh, bool _delete_isolated_vertices = true ); + + /** + * is the vertex a "bow tie" vertex ? + * \note Alias for OpenMesh::is_manifold + */ + bool isManifold( VertexHandle vh ) const; + + /// Check if evrything looks right in the data structure + /// \return true if ok, false if ko. + bool checkIntegrity() const; + + private: + // internal function to build TriangleMesh attribs correspondance to wedge attribs. + class RA_CORE_API InitWedgeProps + { + public: + InitWedgeProps( TopologicalMesh* topo, const TriangleMesh& triMesh ) : + m_topo( topo ), m_triMesh( triMesh ) {} + void operator()( AttribBase* attr ) const; + + private: + TopologicalMesh* m_topo; + const TriangleMesh& m_triMesh; + }; + + class WedgeCollection; + // + /** + * This private class manage wedge data and refcount, to maintain deleted status + * + * \internal We need to export this class to make it accessible in .inl + */ + class RA_CORE_API Wedge + { + WedgeData m_wedgeData {}; + unsigned int m_refCount {0}; + + private: + WedgeData& getWedgeData() { return m_wedgeData; } + + public: + EIGEN_MAKE_ALIGNED_OPERATOR_NEW + + explicit Wedge() {} + explicit Wedge( const WedgeData& wd ) : m_wedgeData {wd}, m_refCount {1} {}; + const WedgeData& getWedgeData() const { return m_wedgeData; } + void setWedgeData( const WedgeData& wedgeData ) { m_wedgeData = wedgeData; } + void setWedgeData( WedgeData&& wedgeData ) { m_wedgeData = std::move( wedgeData ); } + void incrementRefCount() { ++m_refCount; } + void decrementRefCount() { + if ( m_refCount ) --m_refCount; + } + /// comparison ignore refCount + bool operator==( const Wedge& lhs ) const { return m_wedgeData == lhs.m_wedgeData; } + + bool isDeleted() const { return m_refCount == 0; } + unsigned int getRefCount() const { return m_refCount; } + + friend WedgeCollection; + }; + + /** + * This private class manage the wedge collection. + * Most of the data members are public so that the enclosing class can + * easily manage the data. + * + * \internal We need to export this class to make it accessible in .inl + */ + class RA_CORE_API WedgeCollection + { + public: + EIGEN_MAKE_ALIGNED_OPERATOR_NEW + + template + inline const std::vector& getNameArray() const; + + template + inline std::vector& getNameArray(); + + /** + * Add wd to the wedge collection, and return the index. + * If a wedge with same data is already present, it's index is returned, + * otherwise a new wedge is added to the wedges collection. + * \param wd Data to insert. + * \return the index of the inserted (or found) wedge. + */ + WedgeIndex add( const WedgeData& wd ); + + /** + * Delete the wedge \a idx from the collection. + * These deletion actually just remove one reference from an halfedge + * to the wedge data. If the wedge is still referenced by other + * halfedges, it will not be removed during garbageCollection. + */ + void del( const WedgeIndex& idx ); + WedgeIndex newReference( const WedgeIndex& idx ); + + /** + * Return the wedge data associated with \a idx + */ + const WedgeData& getWedgeData( const WedgeIndex& idx ) const { + CORE_ASSERT( idx.isValid() && !m_data[idx].isDeleted(), + "access to invalid or deleted wedge is prohibited" ); + + return m_data[idx].getWedgeData(); + } + + unsigned int getWedgeRefCount( const WedgeIndex& idx ) const { + CORE_ASSERT( idx.isValid(), "access to invalid or deleted wedge is prohibited" ); + return m_data[idx].getRefCount(); + } + + /// Return the wedge (not the data) for in class manipulation. + /// client code should use getWedgeData only. + inline const Wedge& getWedge( const WedgeIndex& idx ) const; + + /// \see TopologicalMesh::setWedgeData + inline void setWedgeData( const WedgeIndex& idx, const WedgeData& wd ); + + /// \see TopologicalMesh::setWedgeData + template + inline bool setWedgeData( const WedgeIndex& idx, const std::string& name, const T& value ); + inline bool setWedgePosition( const WedgeIndex& idx, const Vector3& value ); + + // name is supposed to be unique within all attribs + // not checks are performed + template + void addProp( const std::string& name ); + + /// return the offset ot apply to each wedgeindex so that + /// after garbageCollection all indices are valid and coherent. + std::vector computeCleanupOffset() const; + + /// remove unreferenced wedge, halfedges need to be reindexed. + inline void garbageCollection(); + + /// \todo removeDuplicateWedge + /// merge wedges with same data + /// return old->new index correspondance to update wedgeIndexPph + /// inline void removeDuplicateWedge + inline size_t size() const { return m_data.size(); } + + /// attrib names associated to vertex/wedges, getted from CoreMesh, if any, + std::vector m_floatAttribNames; + std::vector m_vector2AttribNames; + std::vector m_vector3AttribNames; + std::vector m_vector4AttribNames; + + /// attrib handle from the CoreMesh given at construction, if any. + std::vector> m_wedgeFloatAttribHandles; + std::vector> m_wedgeVector2AttribHandles; + std::vector> m_wedgeVector3AttribHandles; + std::vector> m_wedgeVector4AttribHandles; + + // private: + AlignedStdVector m_data; + }; + + WedgeData interpolateWedgeAttributes( const WedgeData&, const WedgeData&, Scalar alpha ); + + template + inline void copyAttribToWedgeData( const TriangleMesh& mesh, + unsigned int vindex, + const std::vector>& attrHandleVec, + VectorArray* to ); + + inline void copyMeshToWedgeData( const TriangleMesh& mesh, + unsigned int vindex, + const std::vector>& wprop_float, + const std::vector>& wprop_vec2, + const std::vector>& wprop_vec3, + const std::vector>& wprop_vec4, + TopologicalMesh::WedgeData* wd ); + + template + using HandleAndValueVector = + std::vector, T>, + Eigen::aligned_allocator, T>>>; + + template + using PropPair = std::pair, OpenMesh::HPropHandleT>; + + template + [[deprecated]] inline void copyAttribToTopo( const TriangleMesh& triMesh, + const std::vector>& vprop, + TopologicalMesh::HalfedgeHandle heh, + unsigned int vindex ); + + template + [[deprecated]] inline void addAttribPairToTopo( const TriangleMesh& triMesh, + AttribManager::pointer_type attr, + std::vector>& vprop, + std::vector>& pph ); + + void split_copy( EdgeHandle _eh, VertexHandle _vh ); + void split( EdgeHandle _eh, VertexHandle _vh ); + + OpenMesh::HPropHandleT m_wedgeIndexPph; /**< Halfedges' Wedge index */ + WedgeCollection m_wedges; /**< Wedge data management */ + + ///\todo to be deleted/updated + OpenMesh::HPropHandleT m_inputTriangleMeshIndexPph; + OpenMesh::HPropHandleT m_outputTriangleMeshIndexPph; + [[deprecated]] std::vector> m_floatPph; + [[deprecated]] std::vector> m_vec2Pph; + [[deprecated]] std::vector> m_vec3Pph; + [[deprecated]] std::vector> m_vec4Pph; + + friend class TMOperations; +}; + +// heplers +void printWedgesInfo( const TopologicalMesh& ); + +} // namespace deprecated +} // namespace Geometry +} // namespace Core +} // namespace Ra +#include diff --git a/src/Core/Geometry/deprecated/TopologicalMesh.inl b/src/Core/Geometry/deprecated/TopologicalMesh.inl new file mode 100644 index 00000000000..03a826a3794 --- /dev/null +++ b/src/Core/Geometry/deprecated/TopologicalMesh.inl @@ -0,0 +1,1052 @@ +#pragma once + +#include "TopologicalMesh.hpp" + +#include +#include + +namespace Ra { +namespace Core { +namespace Geometry { +namespace deprecated { +template +inline TopologicalMesh::TopologicalMesh( const TriangleMesh& triMesh, + NonManifoldFaceCommand command ) : + TopologicalMesh() { + + LOG( logINFO ) << "TopologicalMesh: load triMesh with " << triMesh.getIndices().size() + << " faces and " << triMesh.vertices().size() << " vertices."; + + struct hash_vec { + size_t operator()( const Vector3& lvalue ) const { + size_t hx = std::hash()( lvalue[0] ); + size_t hy = std::hash()( lvalue[1] ); + size_t hz = std::hash()( lvalue[2] ); + return ( hx ^ ( hy << 1 ) ) ^ hz; + } + }; + // use a hashmap for fast search of existing vertex position + using VertexMap = std::unordered_map; + VertexMap vertexHandles; + + std::vector> vprop_float; + std::vector, OpenMesh::HPropHandleT>> vprop_vec2; + std::vector, OpenMesh::HPropHandleT>> vprop_vec3; + std::vector, OpenMesh::HPropHandleT>> vprop_vec4; + + // loop over all attribs and build correspondance pair + triMesh.vertexAttribs().for_each_attrib( + [&triMesh, this, &vprop_float, &vprop_vec2, &vprop_vec3, &vprop_vec4]( const auto& attr ) { + // skip builtin attribs + if ( attr->getName() != std::string( "in_position" ) && + attr->getName() != std::string( "in_normal" ) ) + { + if ( attr->isFloat() ) + addAttribPairToTopo( triMesh, attr, vprop_float, m_floatPph ); + else if ( attr->isVector2() ) + addAttribPairToTopo( triMesh, attr, vprop_vec2, m_vec2Pph ); + else if ( attr->isVector3() ) + addAttribPairToTopo( triMesh, attr, vprop_vec3, m_vec3Pph ); + else if ( attr->isVector4() ) + addAttribPairToTopo( triMesh, attr, vprop_vec4, m_vec4Pph ); + else + LOG( logWARNING ) + << "Warning, mesh attribute " << attr->getName() + << " type is not supported (only float, vec2, vec3 nor vec4 are supported)"; + } + } ); + + // loop over all attribs and build correspondance pair + triMesh.vertexAttribs().for_each_attrib( InitWedgeProps {this, triMesh} ); + + size_t num_triangles = triMesh.getIndices().size(); + + command.initialize( triMesh ); + + const bool hasNormals = !triMesh.normals().empty(); + if ( !hasNormals ) + { + release_face_normals(); + release_vertex_normals(); + release_halfedge_normals(); + } + for ( unsigned int i = 0; i < num_triangles; i++ ) + { + std::vector face_vhandles( 3 ); + std::vector face_normals( 3 ); + std::vector face_vertexIndex( 3 ); + std::vector face_wedges( 3 ); + const auto& triangle = triMesh.getIndices()[i]; + for ( size_t j = 0; j < 3; ++j ) + { + unsigned int inMeshVertexIndex = triangle[j]; + const Vector3& p = triMesh.vertices()[inMeshVertexIndex]; + + typename VertexMap::iterator vtr = vertexHandles.find( p ); + + TopologicalMesh::VertexHandle vh; + if ( vtr == vertexHandles.end() ) + { + vh = add_vertex( p ); + vertexHandles.insert( vtr, typename VertexMap::value_type( p, vh ) ); + } + else + { vh = vtr->second; } + + face_vhandles[j] = vh; + face_vertexIndex[j] = inMeshVertexIndex; + if ( hasNormals ) face_normals[j] = triMesh.normals()[inMeshVertexIndex]; + + WedgeData wd; + wd.m_position = p; + + copyMeshToWedgeData( triMesh, + inMeshVertexIndex, + m_wedges.m_wedgeFloatAttribHandles, + m_wedges.m_wedgeVector2AttribHandles, + m_wedges.m_wedgeVector3AttribHandles, + m_wedges.m_wedgeVector4AttribHandles, + &wd ); + + face_wedges[j] = m_wedges.add( wd ); + } + + // take care of degen, see below in method initWithWedge for comments + // copied from initFromWedges EXECPT THE TWO LINES WITH COMMENT + // x-----------------------------------------------------------------------------------x + { + auto begin = face_vhandles.begin(); + if ( face_vhandles.size() > 2 ) + { + auto end = face_vhandles.end() - 1; + auto wedgeEnd = face_wedges.end() - 1; + auto normalEnd = face_normals.end() - 1; + + while ( begin != end && *begin == *end ) + { + end--; + // WARNING explicit del wedge (not needed in initWithWedges) + m_wedges.del( *wedgeEnd ); + wedgeEnd--; + normalEnd--; + } + face_vhandles.erase( end + 1, face_vhandles.end() ); + face_wedges.erase( wedgeEnd + 1, face_wedges.end() ); + face_normals.erase( normalEnd + 1, face_normals.end() ); + } + } + + { + auto first = face_vhandles.begin(); + auto wedgeFirst = face_wedges.begin(); + auto normalFirst = face_normals.begin(); + auto last = face_vhandles.end(); + + if ( first != last ) + { + auto result = first; + auto wedgeResult = wedgeFirst; + auto normalResult = normalFirst; + while ( ++first != last ) + { + if ( !( *result == *first ) ) + { + ++result; + ++wedgeResult; + ++normalResult; + if ( result != first ) + { + *result = std::move( *first ); + // WARNING explicit del wedge (not needed in initWithWedges) + m_wedges.del( *wedgeResult ); + *wedgeResult = std::move( *wedgeFirst ); + *normalResult = std::move( *normalFirst ); + } + } + } + face_vhandles.erase( result + 1, face_vhandles.end() ); + face_wedges.erase( wedgeResult + 1, face_wedges.end() ); + face_normals.erase( normalResult + 1, face_normals.end() ); + } + } + TopologicalMesh::FaceHandle fh; + // skip 2 vertex face + if ( face_vhandles.size() > 2 ) fh = add_face( face_vhandles ); + // x-----------------------------------------------------------------------------------x + + if ( fh.is_valid() ) + { + for ( size_t vindex = 0; vindex < face_vhandles.size(); vindex++ ) + { + TopologicalMesh::HalfedgeHandle heh = halfedge_handle( face_vhandles[vindex], fh ); + if ( hasNormals ) set_normal( heh, face_normals[vindex] ); + property( m_inputTriangleMeshIndexPph, heh ) = face_vertexIndex[vindex]; + copyAttribToTopo( triMesh, vprop_float, heh, face_vertexIndex[vindex] ); + copyAttribToTopo( triMesh, vprop_vec2, heh, face_vertexIndex[vindex] ); + copyAttribToTopo( triMesh, vprop_vec3, heh, face_vertexIndex[vindex] ); + copyAttribToTopo( triMesh, vprop_vec4, heh, face_vertexIndex[vindex] ); + property( m_wedgeIndexPph, heh ) = face_wedges[vindex]; + } + } + else + { + for ( auto wedgeIndex : face_wedges ) + m_wedges.del( wedgeIndex ); + command.process( face_vhandles ); + } + face_vhandles.clear(); + face_normals.clear(); + face_vertexIndex.clear(); + } + command.postProcess( *this ); + + // grabage collect since some wedge might already be deleted + garbage_collection(); +} + +template +void TopologicalMesh::initWithWedge( const TriangleMesh& triMesh, NonManifoldFaceCommand command ) { + + LOG( logINFO ) << "TopologicalMesh: load triMesh with " << triMesh.getIndices().size() + << " faces and " << triMesh.vertices().size() << " vertices."; + + ///\todo use a kdtree + struct hash_vec { + size_t operator()( const Vector3& lvalue ) const { + size_t hx = std::hash()( lvalue[0] ); + size_t hy = std::hash()( lvalue[1] ); + size_t hz = std::hash()( lvalue[2] ); + return ( hx ^ ( hy << 1 ) ) ^ hz; + } + }; + // use a hashmap for fast search of existing vertex position + using VertexMap = std::unordered_map; + VertexMap vertexHandles; + + // loop over all attribs and build correspondance pair + triMesh.vertexAttribs().for_each_attrib( InitWedgeProps {this, triMesh} ); + + size_t num_triangles = triMesh.getIndices().size(); + + for ( size_t i = 0; i < triMesh.vertices().size(); ++i ) + { + // create an empty wedge, with 0 ref + Wedge w; + + WedgeData wd; + wd.m_position = triMesh.vertices()[i]; + copyMeshToWedgeData( triMesh, + i, + m_wedges.m_wedgeFloatAttribHandles, + m_wedges.m_wedgeVector2AttribHandles, + m_wedges.m_wedgeVector3AttribHandles, + m_wedges.m_wedgeVector4AttribHandles, + &wd ); + // here ref is not incremented + w.setWedgeData( std::move( wd ) ); + // the newly added wedge is not referenced yet, will be done with `newReference` when + // creating faces just below + m_wedges.m_data.push_back( w ); + } + + LOG( logINFO ) << "TopologicalMesh: have " << m_wedges.size() << " wedges "; + + const bool hasNormals = !triMesh.normals().empty(); + if ( !hasNormals ) + { + release_face_normals(); + release_vertex_normals(); + release_halfedge_normals(); + } + + command.initialize( triMesh ); + for ( unsigned int i = 0; i < num_triangles; i++ ) + { + std::vector face_vhandles( 3 ); + std::vector face_normals( 3 ); + std::vector face_wedges( 3 ); + const auto& triangle = triMesh.getIndices()[i]; + + for ( size_t j = 0; j < 3; ++j ) + { + unsigned int inMeshVertexIndex = triangle[j]; + const Vector3& p = triMesh.vertices()[inMeshVertexIndex]; + + typename VertexMap::iterator vtr = vertexHandles.find( p ); + TopologicalMesh::VertexHandle vh; + if ( vtr == vertexHandles.end() ) + { + vh = add_vertex( p ); + vertexHandles.insert( vtr, typename VertexMap::value_type( p, vh ) ); + } + else + { vh = vtr->second; } + + face_vhandles[j] = vh; + if ( hasNormals ) face_normals[j] = triMesh.normals()[inMeshVertexIndex]; + face_wedges[j] = WedgeIndex {inMeshVertexIndex}; + } + + // remove consecutive equal vertex + // first take care of "loop" if begin == *end-1 + // apply the same modifications on wedges and normals + // e.g. 1 2 1 becomes 1 2 + { + auto begin = face_vhandles.begin(); + if ( face_vhandles.size() > 2 ) + { + auto end = face_vhandles.end() - 1; + auto wedgeEnd = face_wedges.end() - 1; + auto normalEnd = face_normals.end() - 1; + + while ( begin != end && *begin == *end ) + { + end--; + wedgeEnd--; + normalEnd--; + } + face_vhandles.erase( end + 1, face_vhandles.end() ); + face_wedges.erase( wedgeEnd + 1, face_wedges.end() ); + face_normals.erase( normalEnd + 1, face_normals.end() ); + } + } + // then remove duplicates + // e.g. 1 2 2 becomes 1 2 + // equiv of + // face_vhandles.erase( std::unique( face_vhandles.begin(), face_vhandles.end() ), + // face_vhandles.end() ); + // but handles wedges and normals + // see (https://en.cppreference.com/w/cpp/algorithm/unique) + { + auto first = face_vhandles.begin(); + auto wedgeFirst = face_wedges.begin(); + auto normalFirst = face_normals.begin(); + auto last = face_vhandles.end(); + + if ( first != last ) + { + auto result = first; + auto wedgeResult = wedgeFirst; + auto normalResult = normalFirst; + while ( ++first != last ) + { + if ( !( *result == *first ) ) + { + ++result; + ++wedgeResult; + ++normalResult; + if ( result != first ) + { + *result = std::move( *first ); + *wedgeResult = std::move( *wedgeFirst ); + *normalResult = std::move( *normalFirst ); + } + } + } + face_vhandles.erase( result + 1, face_vhandles.end() ); + face_wedges.erase( wedgeResult + 1, face_wedges.end() ); + face_normals.erase( normalResult + 1, face_normals.end() ); + } + } + + ///\todo and "cross face ?" + // unique sort size == vhandles size, if not split ... + + TopologicalMesh::FaceHandle fh; + // skip 2 vertex face + if ( face_vhandles.size() > 2 ) fh = add_face( face_vhandles ); + + // In case of topological inconsistancy, face will be invalid (or uninitialized <> invalid) + if ( fh.is_valid() ) + { + for ( size_t vindex = 0; vindex < face_vhandles.size(); vindex++ ) + { + TopologicalMesh::HalfedgeHandle heh = halfedge_handle( face_vhandles[vindex], fh ); + if ( hasNormals ) set_normal( heh, face_normals[vindex] ); + property( m_wedgeIndexPph, heh ) = m_wedges.newReference( face_wedges[vindex] ); + } + } + else + { command.process( face_vhandles ); } + face_vhandles.clear(); + face_normals.clear(); + } + command.postProcess( *this ); + + LOG( logINFO ) << "TopologicalMesh: load end with " << m_wedges.size() << " wedges "; +} + +template +void TopologicalMesh::copyAttribToWedgeData( const TriangleMesh& mesh, + unsigned int vindex, + const std::vector>& attrHandleVec, + VectorArray* to ) { + for ( auto handle : attrHandleVec ) + { + auto& attr = mesh.getAttrib( handle ); + to->push_back( attr.data()[vindex] ); + } +} + +template +void TopologicalMesh::addAttribPairToTopo( const TriangleMesh& triMesh, + AttribManager::pointer_type attr, + std::vector>& vprop, + std::vector>& pph ) { + AttribHandle h = triMesh.getAttribHandle( attr->getName() ); + if ( attr->getSize() == triMesh.vertices().size() ) + { + OpenMesh::HPropHandleT oh; + this->add_property( oh, attr->getName() ); + vprop.push_back( std::make_pair( h, oh ) ); + pph.push_back( oh ); + } + else + { + LOG( logWARNING ) << "[TopologicalMesh] Skip badly sized attribute " << attr->getName() + << "."; + } +} + +void TopologicalMesh::copyMeshToWedgeData( const TriangleMesh& mesh, + unsigned int vindex, + const std::vector>& wprop_float, + const std::vector>& wprop_vec2, + const std::vector>& wprop_vec3, + const std::vector>& wprop_vec4, + TopologicalMesh::WedgeData* wd ) { + + copyAttribToWedgeData( mesh, vindex, wprop_float, &wd->m_floatAttrib ); + copyAttribToWedgeData( mesh, vindex, wprop_vec2, &wd->m_vector2Attrib ); + copyAttribToWedgeData( mesh, vindex, wprop_vec3, &wd->m_vector3Attrib ); + copyAttribToWedgeData( mesh, vindex, wprop_vec4, &wd->m_vector4Attrib ); +} + +template +void TopologicalMesh::copyAttribToTopo( const TriangleMesh& triMesh, + const std::vector>& vprop, + TopologicalMesh::HalfedgeHandle heh, + unsigned int vindex ) { + for ( auto pp : vprop ) + { + this->property( pp.second, heh ) = triMesh.getAttrib( pp.first ).data()[vindex]; + } +} + +inline const TopologicalMesh::Normal& TopologicalMesh::normal( VertexHandle vh, + FaceHandle fh ) const { + // find halfedge that point to vh and member of fh + if ( !has_halfedge_normals() ) + { + LOG( logERROR ) << "TopologicalMesh has no normals, return dummy ref to (0,0,0)"; + static TopologicalMesh::Normal dummy {0_ra, 0_ra, 0_ra}; + return dummy; + } + return normal( halfedge_handle( vh, fh ) ); +} + +inline void TopologicalMesh::set_normal( VertexHandle vh, FaceHandle fh, const Normal& n ) { + if ( !has_halfedge_normals() ) + { + LOG( logERROR ) << "TopologicalMesh has no normals, nothing set"; + return; + } + + set_normal( halfedge_handle( vh, fh ), n ); +} + +inline void TopologicalMesh::propagate_normal_to_halfedges( VertexHandle vh ) { + if ( !has_halfedge_normals() ) + { + LOG( logERROR ) << "TopologicalMesh has no normals, nothing set"; + return; + } + for ( VertexIHalfedgeIter vih_it = vih_iter( vh ); vih_it.is_valid(); ++vih_it ) + { + set_normal( *vih_it, normal( vh ) ); + } +} + +inline TopologicalMesh::HalfedgeHandle TopologicalMesh::halfedge_handle( VertexHandle vh, + FaceHandle fh ) const { + for ( ConstVertexIHalfedgeIter vih_it = cvih_iter( vh ); vih_it.is_valid(); ++vih_it ) + { + if ( face_handle( *vih_it ) == fh ) { return *vih_it; } + } + CORE_ASSERT( false, "vh is not a vertex of face fh" ); + return HalfedgeHandle(); +} + +inline const OpenMesh::HPropHandleT& +TopologicalMesh::getInputTriangleMeshIndexPropHandle() const { + return m_inputTriangleMeshIndexPph; +} + +inline const OpenMesh::HPropHandleT& +TopologicalMesh::getOutputTriangleMeshIndexPropHandle() const { + return m_outputTriangleMeshIndexPph; +} + +inline const std::vector>& +TopologicalMesh::getFloatPropsHandles() const { + return m_floatPph; +} + +inline const std::vector>& +TopologicalMesh::getVector2PropsHandles() const { + return m_vec2Pph; +} + +inline const std::vector>& +TopologicalMesh::getVector3PropsHandles() const { + return m_vec3Pph; +} + +inline const std::vector>& +TopologicalMesh::getVector4PropsHandles() const { + return m_vec4Pph; +} + +inline void TopologicalMesh::createNormalPropOnFaces( OpenMesh::FPropHandleT& fProp ) { + if ( !has_halfedge_normals() ) + { + LOG( logERROR ) << "TopologicalMesh has no normals, nothing set"; + return; + } + auto nph = halfedge_normals_pph(); + add_property( fProp, property( nph ).name() + "_subdiv_copy_F" ); +} + +inline void TopologicalMesh::clearProp( OpenMesh::FPropHandleT& fProp ) { + remove_property( fProp ); +} + +inline void TopologicalMesh::copyNormal( HalfedgeHandle input_heh, HalfedgeHandle copy_heh ) { + if ( !has_halfedge_normals() ) + { + LOG( logERROR ) << "TopologicalMesh has no normals, nothing set"; + return; + } + auto nph = halfedge_normals_pph(); + property( nph, copy_heh ) = property( nph, input_heh ); +} + +inline void TopologicalMesh::copyNormalFromFace( FaceHandle fh, + HalfedgeHandle heh, + OpenMesh::FPropHandleT fProp ) { + if ( !has_halfedge_normals() ) + { + LOG( logERROR ) << "TopologicalMesh has no normals, nothing set"; + return; + } + auto nph = halfedge_normals_pph(); + property( nph, heh ) = property( fProp, fh ); +} + +inline void TopologicalMesh::interpolateNormal( HalfedgeHandle in_a, + HalfedgeHandle in_b, + HalfedgeHandle out, + Scalar f ) { + auto nph = halfedge_normals_pph(); + property( nph, out ) = + ( ( 1 - f ) * property( nph, in_a ) + f * property( nph, in_b ) ).normalized(); +} + +inline void TopologicalMesh::interpolateNormalOnFaces( FaceHandle fh, + OpenMesh::FPropHandleT fProp ) { + if ( !has_halfedge_normals() ) + { + LOG( logERROR ) << "TopologicalMesh has no normals, nothing set"; + return; + } + auto nph = halfedge_normals_pph(); + + // init sum to first + auto heh = halfedge_handle( fh ); + property( fProp, fh ) = property( nph, heh ); + heh = next_halfedge_handle( heh ); + + // sum others + for ( size_t i = 1; i < valence( fh ); ++i ) + { + property( fProp, fh ) += property( nph, heh ); + heh = next_halfedge_handle( heh ); + } + + // normalize + property( fProp, fh ) = property( fProp, fh ).normalized(); +} + +template +void TopologicalMesh::createPropsOnFaces( const std::vector>& input, + std::vector>& output ) { + output.reserve( input.size() ); + for ( const auto& oh : input ) + { + OpenMesh::FPropHandleT oh_; + add_property( oh_, property( oh ).name() + "_subdiv_copy_F" ); + output.push_back( oh_ ); + } +} + +template +void TopologicalMesh::clearProps( std::vector>& props ) { + for ( auto& oh : props ) + { + remove_property( oh ); + } + props.clear(); +} + +template +void TopologicalMesh::copyProps( HalfedgeHandle input_heh, + HalfedgeHandle copy_heh, + const std::vector>& props ) { + for ( const auto& oh : props ) + { + property( oh, copy_heh ) = property( oh, input_heh ); + } +} + +template +void TopologicalMesh::copyPropsFromFace( FaceHandle fh, + HalfedgeHandle heh, + const std::vector>& fProps, + const std::vector>& hProps ) { + for ( uint i = 0; i < fProps.size(); ++i ) + { + auto hp = hProps[i]; + auto fp = fProps[i]; + property( hp, heh ) = property( fp, fh ); + } +} + +template +void TopologicalMesh::interpolateProps( HalfedgeHandle in_a, + HalfedgeHandle in_b, + HalfedgeHandle out, + Scalar f, + const std::vector>& props ) { + // interpolate properties + for ( const auto& oh : props ) + { + property( oh, out ) = ( 1 - f ) * property( oh, in_a ) + f * property( oh, in_b ); + } +} + +template +void TopologicalMesh::interpolatePropsOnFaces( + FaceHandle fh, + const std::vector>& hProps, + const std::vector>& fProps ) { + auto heh = halfedge_handle( fh ); + const size_t v = valence( fh ); + + // init sum to first + for ( size_t j = 0; j < fProps.size(); ++j ) + { + auto hp = hProps[j]; + auto fp = fProps[j]; + property( fp, fh ) = property( hp, heh ); + } + heh = next_halfedge_handle( heh ); + // sum others + for ( size_t i = 1; i < v; ++i ) + { + for ( size_t j = 0; j < fProps.size(); ++j ) + { + auto hp = hProps[j]; + auto fp = fProps[j]; + property( fp, fh ) += property( hp, heh ); + } + heh = next_halfedge_handle( heh ); + } + // normalize + for ( size_t j = 0; j < fProps.size(); ++j ) + { + auto fp = fProps[j]; + property( fp, fh ) = property( fp, fh ) / v; + } +} + +inline void +TopologicalMesh::createAllPropsOnFaces( OpenMesh::FPropHandleT& normalProp, + std::vector>& floatProps, + std::vector>& vec2Props, + std::vector>& vec3Props, + std::vector>& vec4Props ) { + createNormalPropOnFaces( normalProp ); + createPropsOnFaces( getFloatPropsHandles(), floatProps ); + createPropsOnFaces( getVector2PropsHandles(), vec2Props ); + createPropsOnFaces( getVector3PropsHandles(), vec3Props ); + createPropsOnFaces( getVector4PropsHandles(), vec4Props ); +} + +inline void +TopologicalMesh::clearAllProps( OpenMesh::FPropHandleT& normalProp, + std::vector>& floatProps, + std::vector>& vec2Props, + std::vector>& vec3Props, + std::vector>& vec4Props ) { + clearProp( normalProp ); + clearProps( floatProps ); + clearProps( vec2Props ); + clearProps( vec3Props ); + clearProps( vec4Props ); +} + +inline void TopologicalMesh::copyAllProps( HalfedgeHandle input_heh, HalfedgeHandle copy_heh ) { + copyNormal( input_heh, copy_heh ); + copyProps( input_heh, copy_heh, getFloatPropsHandles() ); + copyProps( input_heh, copy_heh, getVector2PropsHandles() ); + copyProps( input_heh, copy_heh, getVector3PropsHandles() ); + copyProps( input_heh, copy_heh, getVector4PropsHandles() ); +} + +inline void +TopologicalMesh::copyAllPropsFromFace( FaceHandle fh, + HalfedgeHandle heh, + OpenMesh::FPropHandleT normalProp, + std::vector>& floatProps, + std::vector>& vec2Props, + std::vector>& vec3Props, + std::vector>& vec4Props ) { + copyNormalFromFace( fh, heh, normalProp ); + copyPropsFromFace( fh, heh, floatProps, getFloatPropsHandles() ); + copyPropsFromFace( fh, heh, vec2Props, getVector2PropsHandles() ); + copyPropsFromFace( fh, heh, vec3Props, getVector3PropsHandles() ); + copyPropsFromFace( fh, heh, vec4Props, getVector4PropsHandles() ); +} + +inline void TopologicalMesh::interpolateAllProps( HalfedgeHandle in_a, + HalfedgeHandle in_b, + HalfedgeHandle out, + Scalar f ) { + interpolateNormal( in_a, in_b, out, f ); + interpolateProps( in_a, in_b, out, f, getFloatPropsHandles() ); + interpolateProps( in_a, in_b, out, f, getVector2PropsHandles() ); + interpolateProps( in_a, in_b, out, f, getVector3PropsHandles() ); + interpolateProps( in_a, in_b, out, f, getVector4PropsHandles() ); +} + +inline void TopologicalMesh::interpolateAllPropsOnFaces( + FaceHandle fh, + OpenMesh::FPropHandleT normalProp, + std::vector>& floatProps, + std::vector>& vec2Props, + std::vector>& vec3Props, + std::vector>& vec4Props ) { + interpolateNormalOnFaces( fh, normalProp ); + interpolatePropsOnFaces( fh, getFloatPropsHandles(), floatProps ); + interpolatePropsOnFaces( fh, getVector2PropsHandles(), vec2Props ); + interpolatePropsOnFaces( fh, getVector3PropsHandles(), vec3Props ); + interpolatePropsOnFaces( fh, getVector4PropsHandles(), vec4Props ); +} + +inline std::set +TopologicalMesh::getVertexWedges( OpenMesh::VertexHandle vh ) const { + std::set ret; + + for ( ConstVertexIHalfedgeIter vh_it = cvih_iter( vh ); vh_it.is_valid(); ++vh_it ) + { + auto widx = property( m_wedgeIndexPph, *vh_it ); + if ( widx.isValid() && !m_wedges.getWedge( widx ).isDeleted() ) ret.insert( widx ); + } + return ret; +} + +inline TopologicalMesh::WedgeIndex +TopologicalMesh::getWedgeIndex( OpenMesh::HalfedgeHandle heh ) const { + return property( getWedgeIndexPph(), heh ); +} + +inline const TopologicalMesh::WedgeData& +TopologicalMesh::getWedgeData( const WedgeIndex& idx ) const { + return m_wedges.getWedgeData( idx ); +} + +inline unsigned int TopologicalMesh::getWedgeRefCount( const WedgeIndex& idx ) const { + return m_wedges.getWedgeRefCount( idx ); +} + +inline void TopologicalMesh::setWedgeData( TopologicalMesh::WedgeIndex widx, + const TopologicalMesh::WedgeData& wedge ) { + m_wedges.setWedgeData( widx, wedge ); +} + +template +inline bool TopologicalMesh::setWedgeData( const TopologicalMesh::WedgeIndex& idx, + const std::string& name, + const T& value ) { + return m_wedges.setWedgeData( idx, name, value ); +} + +inline void TopologicalMesh::replaceWedge( OpenMesh::HalfedgeHandle he, const WedgeData& wd ) { + m_wedges.del( property( getWedgeIndexPph(), he ) ); + property( getWedgeIndexPph(), he ) = m_wedges.add( wd ); +} + +inline void TopologicalMesh::replaceWedgeIndex( OpenMesh::HalfedgeHandle he, + const WedgeIndex& widx ) { + m_wedges.del( property( getWedgeIndexPph(), he ) ); + property( getWedgeIndexPph(), he ) = m_wedges.newReference( widx ); +} + +inline void TopologicalMesh::mergeEqualWedges() { + for ( auto itr = vertices_begin(), stop = vertices_end(); itr != stop; ++itr ) + { + mergeEqualWedges( *itr ); + } +} + +inline void TopologicalMesh::mergeEqualWedges( OpenMesh::VertexHandle vh ) { + + for ( auto itr = vih_iter( vh ); itr.is_valid(); ++itr ) + { + // replace will search if wedge already present and use it, so merge occurs. + replaceWedge( *itr, getWedgeData( property( getWedgeIndexPph(), *itr ) ) ); + } +} + +inline const std::vector& TopologicalMesh::getVec4AttribNames() const { + return m_wedges.m_vector4AttribNames; +} +inline const std::vector& TopologicalMesh::getVec3AttribNames() const { + return m_wedges.m_vector3AttribNames; +} +inline const std::vector& TopologicalMesh::getVec2AttribNames() const { + return m_wedges.m_vector2AttribNames; +} +inline const std::vector& TopologicalMesh::getFloatAttribNames() const { + return m_wedges.m_floatAttribNames; +} + +inline bool TopologicalMesh::isFeatureVertex( const VertexHandle& vh ) const { + return getVertexWedges( vh ).size() != 1; +} + +inline bool TopologicalMesh::isFeatureEdge( const EdgeHandle& eh ) const { + + auto heh0 = halfedge_handle( eh, 0 ); + auto heh1 = halfedge_handle( eh, 1 ); + + return property( m_wedgeIndexPph, heh0 ) != + property( m_wedgeIndexPph, + prev_halfedge_handle( opposite_halfedge_handle( heh0 ) ) ) || + property( m_wedgeIndexPph, heh1 ) != + property( m_wedgeIndexPph, + prev_halfedge_handle( opposite_halfedge_handle( heh1 ) ) ); +} + +inline const OpenMesh::HPropHandleT& +TopologicalMesh::getWedgeIndexPph() const { + return m_wedgeIndexPph; +} + +//////////////////////////////////////////////////////////////////////////////// +/////////////////// WEDGES RELATED STUFF ////////////////////////////// +/////////////////// WedgeCollection ////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +inline void TopologicalMesh::WedgeCollection::del( const TopologicalMesh::WedgeIndex& idx ) { + if ( idx.isValid() ) m_data[idx].decrementRefCount(); +} + +inline TopologicalMesh::WedgeIndex +TopologicalMesh::WedgeCollection::newReference( const TopologicalMesh::WedgeIndex& idx ) { + if ( idx.isValid() ) m_data[idx].incrementRefCount(); + return idx; +} + +inline const TopologicalMesh::Wedge& +TopologicalMesh::WedgeCollection::getWedge( const TopologicalMesh::WedgeIndex& idx ) const { + return m_data[idx]; +} + +inline void TopologicalMesh::WedgeCollection::setWedgeData( const TopologicalMesh::WedgeIndex& idx, + const TopologicalMesh::WedgeData& wd ) { + if ( !( wd.m_floatAttrib.size() == m_floatAttribNames.size() && + wd.m_vector2Attrib.size() == m_vector2AttribNames.size() && + wd.m_vector3Attrib.size() == m_vector3AttribNames.size() && + wd.m_vector4Attrib.size() == m_vector4AttribNames.size() ) ) + { + LOG( logWARNING ) << "Warning, topological mesh set wedge: number of attribs inconsistency"; + } + if ( idx.isValid() ) m_data[idx].setWedgeData( wd ); +} + +#define GET_NAME_ARRAY_HELPER( TYPE, NAME ) \ + template <> \ + inline const std::vector& TopologicalMesh::WedgeCollection::getNameArray() \ + const { \ + return m_##NAME##AttribNames; \ + } \ + template <> \ + inline std::vector& TopologicalMesh::WedgeCollection::getNameArray() { \ + return m_##NAME##AttribNames; \ + } + +GET_NAME_ARRAY_HELPER( float, float ) +GET_NAME_ARRAY_HELPER( Vector2, vector2 ) +GET_NAME_ARRAY_HELPER( Vector3, vector3 ) +GET_NAME_ARRAY_HELPER( Vector4, vector4 ) + +#undef GET_NAME_ARRAY_HELPER +// These template functions are defined above for supported types. +// For unsupported types they simply generate a compile error. +template +inline const std::vector& TopologicalMesh::WedgeCollection::getNameArray() const { + + LOG( logWARNING ) << "Warning, mesh attribute " << typeid( T ).name() + << " is not supported (only float, vec2, vec3 nor vec4 are supported)"; + static_assert( sizeof( T ) == -1, "this type is not supported" ); + return m_floatAttribNames; +} + +template +inline std::vector& TopologicalMesh::WedgeCollection::getNameArray() { + + LOG( logWARNING ) << "Warning, mesh attribute " << typeid( T ).name() + << " is not supported (only float, vec2, vec3 nor vec4 are supported)"; + static_assert( sizeof( T ) == -1, "this type is not supported" ); + return m_floatAttribNames; +} + +template +inline bool TopologicalMesh::WedgeCollection::setWedgeData( const TopologicalMesh::WedgeIndex& idx, + const std::string& name, + const T& value ) { + if ( idx.isValid() ) + { + auto nameArray = getNameArray(); + auto itr = std::find( nameArray.begin(), nameArray.end(), name ); + if ( itr != nameArray.end() ) + { + auto attrIndex = std::distance( nameArray.begin(), itr ); + m_data[idx].getWedgeData().getAttribArray()[attrIndex] = value; + return true; + } + else + { + LOG( logERROR ) << "Warning, set wedge: no wedge attrib named " << name << " of type " + << typeid( T ).name(); + } + } + return false; +} + +inline bool +TopologicalMesh::WedgeCollection::setWedgePosition( const TopologicalMesh::WedgeIndex& idx, + const Vector3& value ) { + if ( idx.isValid() ) + { + m_data[idx].getWedgeData().m_position = value; + return true; + } + return false; +} + +template +void TopologicalMesh::WedgeCollection::addProp( const std::string& name ) { + if ( name != std::string( "in_position" ) ) { getNameArray().push_back( name ); } +} + +inline void TopologicalMesh::WedgeCollection::garbageCollection() { + m_data.erase( std::remove_if( m_data.begin(), + m_data.end(), + []( const Wedge& w ) { return w.isDeleted(); } ), + m_data.end() ); +} + +//////////////////////////////////////////////////////////////////////////////// +/////////////////// WedgeData ////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +// return 1 : equals, 2: strict less, 3: strict greater +template +int TopologicalMesh::WedgeData::compareVector( const T& a, const T& b ) { + for ( int i = 0; i < T::RowsAtCompileTime; i++ ) + { + if ( a[i] < b[i] ) return 2; + if ( a[i] > b[i] ) return 3; + } + // (a == b) + return 1; +} + +inline bool TopologicalMesh::WedgeData::operator==( const TopologicalMesh::WedgeData& lhs ) const { + return + // do not have this yet, not sure we need to test them + // m_inputTriangleMeshIndex == lhs.m_inputTriangleMeshIndex && + // m_outputTriangleMeshIndex == lhs.m_outputTriangleMeshIndex && + m_position == lhs.m_position && m_floatAttrib == lhs.m_floatAttrib && + m_vector2Attrib == lhs.m_vector2Attrib && m_vector3Attrib == lhs.m_vector3Attrib && + m_vector4Attrib == lhs.m_vector4Attrib; +} + +inline bool TopologicalMesh::WedgeData::operator<( const TopologicalMesh::WedgeData& lhs ) const { + + CORE_ASSERT( ( m_floatAttrib.size() == lhs.m_floatAttrib.size() ) && + ( m_vector2Attrib.size() == lhs.m_vector2Attrib.size() ) && + ( m_vector3Attrib.size() == lhs.m_vector3Attrib.size() ) && + ( m_vector4Attrib.size() == lhs.m_vector4Attrib.size() ), + "Could only compare wedge with same number of attributes" ); + + { + int comp = compareVector( m_position, lhs.m_position ); + if ( comp == 2 ) return true; + if ( comp == 3 ) return false; + } + for ( size_t i = 0; i < m_floatAttrib.size(); i++ ) + { + if ( m_floatAttrib[i] < lhs.m_floatAttrib[i] ) + return true; + else if ( m_floatAttrib[i] > lhs.m_floatAttrib[i] ) + return false; + } + + for ( size_t i = 0; i < m_vector2Attrib.size(); i++ ) + { + int comp = compareVector( m_vector2Attrib[i], lhs.m_vector2Attrib[i] ); + if ( comp == 2 ) return true; + if ( comp == 3 ) return false; + } + for ( size_t i = 0; i < m_vector3Attrib.size(); i++ ) + { + int comp = compareVector( m_vector3Attrib[i], lhs.m_vector3Attrib[i] ); + if ( comp == 2 ) return true; + if ( comp == 3 ) return false; + } + for ( size_t i = 0; i < m_vector4Attrib.size(); i++ ) + { + int comp = compareVector( m_vector4Attrib[i], lhs.m_vector4Attrib[i] ); + if ( comp == 2 ) return true; + if ( comp == 3 ) return false; + } + return false; +} + +bool TopologicalMesh::WedgeData::operator!=( const TopologicalMesh::WedgeData& lhs ) const { + return !( *this == lhs ); +} + +#define GET_ATTRIB_ARRAY_HELPER( TYPE, NAME ) \ + template <> \ + inline VectorArray& TopologicalMesh::WedgeData::getAttribArray() { \ + return m_##NAME##Attrib; \ + } + +GET_ATTRIB_ARRAY_HELPER( float, float ) +GET_ATTRIB_ARRAY_HELPER( Vector2, vector2 ) +GET_ATTRIB_ARRAY_HELPER( Vector3, vector3 ) +GET_ATTRIB_ARRAY_HELPER( Vector4, vector4 ) +#undef GET_ATTRIB_ARRAY_HELPER + +template +inline VectorArray& TopologicalMesh::WedgeData::getAttribArray() { + static_assert( sizeof( T ) == -1, "this type is not supported" ); +} +} // namespace deprecated +} // namespace Geometry +} // namespace Core +} // namespace Ra From 43e8ec8ea488ceba0e54d0634694c009d0f738b1 Mon Sep 17 00:00:00 2001 From: dlyr Date: Wed, 17 Mar 2021 15:35:25 +0100 Subject: [PATCH 02/37] [core] clean deprecated code that refer new version. --- .../Geometry/deprecated/TopologicalMesh.cpp | 545 +--------------- .../Geometry/deprecated/TopologicalMesh.hpp | 339 +--------- .../Geometry/deprecated/TopologicalMesh.inl | 584 +----------------- 3 files changed, 14 insertions(+), 1454 deletions(-) diff --git a/src/Core/Geometry/deprecated/TopologicalMesh.cpp b/src/Core/Geometry/deprecated/TopologicalMesh.cpp index fa4001490d5..cd265796a54 100644 --- a/src/Core/Geometry/deprecated/TopologicalMesh.cpp +++ b/src/Core/Geometry/deprecated/TopologicalMesh.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -13,121 +13,11 @@ namespace Ra { namespace Core { namespace Geometry { namespace deprecated { + using namespace Utils; // log, AttribXXX ///////////////// HELPERS /////////////// -std::string wedgeInfo( const Ra::Core::Geometry::TopologicalMesh& topo, - const Ra::Core::Geometry::TopologicalMesh::WedgeIndex& idx ) { - - std::stringstream buffer; - if ( !idx.isValid() ) - { - buffer << "wedge (invalid) "; - return buffer.str(); - } - - const Ra::Core::Geometry::TopologicalMesh::WedgeData& wd = topo.getWedgeData( idx ); - - buffer << "wedge (" << idx << "," << topo.getWedgeRefCount( idx ) << "), "; - auto& floatAttrNames = topo.getFloatAttribNames(); - for ( size_t i = 0; i < floatAttrNames.size(); ++i ) - { - buffer << floatAttrNames[i]; - buffer << "["; - buffer << wd.m_floatAttrib[i]; - buffer << "], "; - } - auto vec2AttrNames = topo.getVec2AttribNames(); - for ( size_t i = 0; i < vec2AttrNames.size(); ++i ) - { - buffer << vec2AttrNames[i]; - buffer << "["; - buffer << wd.m_vector2Attrib[i].transpose(); - buffer << "], "; - } - auto vec3AttrNames = topo.getVec3AttribNames(); - for ( size_t i = 0; i < vec3AttrNames.size(); ++i ) - { - buffer << vec3AttrNames[i]; - buffer << "["; - buffer << wd.m_vector3Attrib[i].transpose(); - buffer << "], "; - } - - auto vec4AttrNames = topo.getVec4AttribNames(); - for ( size_t i = 0; i < vec4AttrNames.size(); ++i ) - { - buffer << vec4AttrNames[i]; - buffer << "["; - buffer << wd.m_vector4Attrib[i].transpose(); - buffer << "], "; - } - - return buffer.str(); -} - -bool TopologicalMesh::isManifold( VertexHandle vh ) const { - return is_manifold( vh ); -} - -bool TopologicalMesh::checkIntegrity() const { - std::vector count( m_wedges.size(), 0 ); - bool ret = true; - for ( auto he_itr {halfedges_begin()}; he_itr != halfedges_end(); ++he_itr ) - { - auto widx = property( m_wedgeIndexPph, *he_itr ); - if ( widx.isValid() ) - { - count[widx]++; - - if ( m_wedges.getWedgeData( widx ).m_position != point( to_vertex_handle( *he_itr ) ) ) - { - LOG( logWARNING ) << "topological mesh wedge inconsistency, wedge and to position " - "differ for widx " - << widx << ", have " - << m_wedges.getWedgeData( widx ).m_position.transpose() - << "instead of " - << point( to_vertex_handle( *he_itr ) ).transpose(); - } - } - } - - for ( int widx = 0; widx < int( m_wedges.size() ); ++widx ) - { - if ( m_wedges.getWedge( WedgeIndex {widx} ).getRefCount() != count[widx] ) - { - LOG( logWARNING ) << "topological mesh wedge count inconsistency, have " << count[widx] - << " instead of " - << m_wedges.getWedge( WedgeIndex {widx} ).getRefCount() - << " for wedge id " << widx; - ret = false; - } - } - return ret; -} - -void printWedgesInfo( const Ra::Core::Geometry::TopologicalMesh& topo ) { - using namespace Ra::Core; - - for ( auto itr = topo.vertices_sbegin(); itr != topo.vertices_end(); ++itr ) - { - LOG( Utils::logINFO ) << "vertex " << *itr; - auto wedges = topo.getVertexWedges( *itr ); - for ( auto wedgeIndex : wedges ) - { - LOG( Utils::logINFO ) << wedgeInfo( topo, wedgeIndex ); - } - } - - for ( auto itr = topo.halfedges_sbegin(); itr != topo.halfedges_end(); ++itr ) - { - LOG( Utils::logINFO ) << "he " << *itr - << ( topo.is_boundary( *itr ) ? " boundary " : " inner " ); - LOG( Utils::logINFO ) << wedgeInfo( topo, topo.property( topo.getWedgeIndexPph(), *itr ) ); - } -} - template void addAttribPairToCore( TriangleMesh& triMesh, const TopologicalMesh* topoMesh, @@ -178,23 +68,18 @@ struct DefaultNonManifoldFaceCommand { /// https://www.graphics.rwth-aachen.de/media/openflipper_static/Daily-Builds/Doc/Free/Developer/OBJImporter_8cc_source.html /// for an exemple of loading } - /// \brief If needed, apply post-processing on the Ra::Core::Geometry::TopologicalMesh + /// \brief If needed, apply post-processing on the TopologicalMesh inline void postProcess( TopologicalMesh& /*tm*/ ) {} //! [Default command implementation] private: std::string m_details; }; -void TopologicalMesh::initWithWedge( const TriangleMesh& triMesh ) { - initWithWedge( triMesh, DefaultNonManifoldFaceCommand( "[initWithWedges]" ) ); -} - TopologicalMesh::TopologicalMesh( const TriangleMesh& triMesh ) : TopologicalMesh( triMesh, DefaultNonManifoldFaceCommand( "[default ctor (props)]" ) ) {} TopologicalMesh::TopologicalMesh() { add_property( m_inputTriangleMeshIndexPph ); - add_property( m_wedgeIndexPph ); } TriangleMesh TopologicalMesh::toTriangleMesh() { @@ -313,91 +198,6 @@ TriangleMesh TopologicalMesh::toTriangleMesh() { return out; } -template -void copyWedgeDataToAttribContainer( AlignedStdVector::Container>& c, - const VectorArray& wd ) { - for ( size_t i = 0; i < wd.size(); ++i ) - { - c[i].push_back( wd[i] ); - } -} - -template -void moveContainerToMesh( TriangleMesh& out, - const std::vector& names, - AlignedStdVector::Container>& wedgeAttribData ) { - for ( size_t i = 0; i < wedgeAttribData.size(); ++i ) - { - auto attrHandle = out.addAttrib( names[i] ); - out.getAttrib( attrHandle ).setData( std::move( wedgeAttribData[i] ) ); - } -} - -TriangleMesh TopologicalMesh::toTriangleMeshFromWedges() { - // first cleanup deleted element - garbage_collection(); - - TriangleMesh out; - TriangleMesh::IndexContainerType indices; - - /// add attribs to out - std::vector> wedgeFloatAttribHandles; - std::vector> wedgeVector2AttribHandles; - std::vector> wedgeVector3AttribHandles; - std::vector> wedgeVector4AttribHandles; - - TriangleMesh::PointAttribHandle::Container wedgePosition; - AlignedStdVector::Container> wedgeFloatAttribData( - m_wedges.m_floatAttribNames.size() ); - AlignedStdVector::Container> wedgeVector2AttribData( - m_wedges.m_vector2AttribNames.size() ); - AlignedStdVector::Container> wedgeVector3AttribData( - m_wedges.m_vector3AttribNames.size() ); - AlignedStdVector::Container> wedgeVector4AttribData( - m_wedges.m_vector4AttribNames.size() ); - - /// Wedges are output vertices ! - for ( WedgeIndex widx {0}; widx < WedgeIndex {m_wedges.size()}; ++widx ) - { - const auto& wd = m_wedges.getWedgeData( widx ); - wedgePosition.push_back( wd.m_position ); - copyWedgeDataToAttribContainer( wedgeFloatAttribData, wd.m_floatAttrib ); - copyWedgeDataToAttribContainer( wedgeVector2AttribData, wd.m_vector2Attrib ); - copyWedgeDataToAttribContainer( wedgeVector3AttribData, wd.m_vector3Attrib ); - copyWedgeDataToAttribContainer( wedgeVector4AttribData, wd.m_vector4Attrib ); - } - - out.setVertices( std::move( wedgePosition ) ); - moveContainerToMesh( out, m_wedges.m_floatAttribNames, wedgeFloatAttribData ); - moveContainerToMesh( out, m_wedges.m_vector2AttribNames, wedgeVector2AttribData ); - moveContainerToMesh( out, m_wedges.m_vector3AttribNames, wedgeVector3AttribData ); - moveContainerToMesh( out, m_wedges.m_vector4AttribNames, wedgeVector4AttribData ); - - for ( TopologicalMesh::FaceIter f_it = faces_sbegin(); f_it != faces_end(); ++f_it ) - { - int tindices[3]; - int i = 0; - - for ( TopologicalMesh::ConstFaceHalfedgeIter fh_it = cfh_iter( *f_it ); fh_it.is_valid(); - ++fh_it ) - { - CORE_ASSERT( i < 3, "Non-triangular face found." ); - tindices[i] = property( m_wedgeIndexPph, *fh_it ); - i++; - } - indices.emplace_back( tindices[0], tindices[1], tindices[2] ); - } - - out.setIndices( std::move( indices ) ); - - return out; -} - -void TopologicalMesh::updateTriangleMesh( Ra::Core::Geometry::TriangleMesh& /*mesh*/ ) { - CORE_ASSERT( false, "not implemented yet" ); - ///\todo ;) -} - bool TopologicalMesh::splitEdge( TopologicalMesh::EdgeHandle eh, Scalar f ) { // Global schema of operation /* @@ -536,29 +336,6 @@ bool TopologicalMesh::splitEdge( TopologicalMesh::EdgeHandle eh, Scalar f ) { return true; } -template -void interpolate( const VectorArray& in1, - const VectorArray& in2, - VectorArray& out, - const Scalar alpha ) { - for ( size_t i = 0; i < in1.size(); ++i ) - { - out.push_back( ( 1_ra - alpha ) * in1[i] + alpha * in2[i] ); - } -} - -TopologicalMesh::WedgeData -TopologicalMesh::interpolateWedgeAttributes( const TopologicalMesh::WedgeData& w1, - const TopologicalMesh::WedgeData& w2, - Scalar alpha ) { - WedgeData ret; - interpolate( w1.m_floatAttrib, w2.m_floatAttrib, ret.m_floatAttrib, alpha ); - interpolate( w1.m_vector2Attrib, w2.m_vector2Attrib, ret.m_vector2Attrib, alpha ); - interpolate( w1.m_vector3Attrib, w2.m_vector3Attrib, ret.m_vector3Attrib, alpha ); - interpolate( w1.m_vector4Attrib, w2.m_vector4Attrib, ret.m_vector4Attrib, alpha ); - return ret; -} - //----------------------------------------------------------------------------- // from /OpenMesh/Core/Mesh/TriConnectivity.cc void TopologicalMesh::split( EdgeHandle _eh, VertexHandle _vh ) { @@ -687,322 +464,6 @@ void TopologicalMesh::split_copy( EdgeHandle _eh, VertexHandle _vh ) { } } -bool TopologicalMesh::splitEdgeWedge( TopologicalMesh::EdgeHandle eh, Scalar f ) { - // Global schema of operation - /* - TRIANGLES ONLY - before after - - / \ / | \ - / \ / | \ - /h2 h1\ /r2 r1|s2 s1\ - / h0 -->\ / r0 | s0=h0 \ - V0 -------- V1 V0-(1-f)-V---f---V1 - \<-- o0 / \ u0 | t0=o0 / - \o1 o2/ \u1 u2|t1 t2/ - \ / \ | / - \ / \ | / - - - */ - - // incorrect factor - if ( f < 0 || f > 1 ) { return false; } - - if ( is_boundary( eh ) ) - { - CORE_ASSERT( false, "ouch" ); - return false; - } - - const auto h0 = halfedge_handle( eh, 0 ); - const auto o0 = halfedge_handle( eh, 1 ); - - const auto v0 = to_vertex_handle( o0 ); - const auto v1 = to_vertex_handle( h0 ); - - // add the new point - const Point p = Point( f * point( v1 ) + ( 1_ra - f ) * point( v0 ) ); - VertexHandle vh = add_vertex( p ); - - const auto h1 = next_halfedge_handle( h0 ); - const auto h2 = next_halfedge_handle( h1 ); - - const auto o1 = next_halfedge_handle( o0 ); - const auto o2 = next_halfedge_handle( o1 ); - - // compute interpolated wedge, or the two wedges if not the same wedges - // around the two vertices of the edge (we always compute for two wedges, - // even if add will return the same wedge. - const auto hw0idx = property( m_wedgeIndexPph, h2 ); - const auto hw1idx = property( m_wedgeIndexPph, h0 ); - const auto ow0idx = property( m_wedgeIndexPph, o2 ); - const auto ow1idx = property( m_wedgeIndexPph, o0 ); - const auto hw0 = m_wedges.getWedgeData( hw0idx ); - const auto hw1 = m_wedges.getWedgeData( hw1idx ); - const auto ow0 = m_wedges.getWedgeData( ow0idx ); - const auto ow1 = m_wedges.getWedgeData( ow1idx ); - auto hvw = interpolateWedgeAttributes( hw0, hw1, f ); - auto ovw = interpolateWedgeAttributes( ow1, ow0, f ); - hvw.m_position = p; - ovw.m_position = p; - auto hvwidx = m_wedges.add( hvw ); - auto ovwidx = m_wedges.add( ovw ); - - split_copy( eh, vh ); - - auto r0 = find_halfedge( v0, vh ); - auto s0 = find_halfedge( vh, v1 ); - auto t0 = find_halfedge( v1, vh ); - auto u0 = find_halfedge( vh, v0 ); - - auto r1 = next_halfedge_handle( r0 ); - auto r2 = next_halfedge_handle( r1 ); - - auto s1 = next_halfedge_handle( s0 ); - auto s2 = next_halfedge_handle( s1 ); - - auto t1 = next_halfedge_handle( t0 ); - auto t2 = next_halfedge_handle( t1 ); - - auto u1 = next_halfedge_handle( u0 ); - auto u2 = next_halfedge_handle( u1 ); - - CORE_ASSERT( s0 == h0, "TopologicalMesh: splitEdgeWedge inconsistency" ); - CORE_ASSERT( t0 == o0, "TopologicalMesh: splitEdgeWedge inconsistency" ); - - auto updateWedgeIndex1 = [this]( WedgeIndex widx_, - HalfedgeHandle r0_, - HalfedgeHandle r1_, - HalfedgeHandle r2_, - HalfedgeHandle h1_, - HalfedgeHandle h2_ ) { - CORE_UNUSED( r2_ ); - CORE_UNUSED( h2_ ); - - if ( !is_boundary( r0_ ) ) - { - CORE_ASSERT( r2_ == h2_, "TopologicalMesh: splitEdgeWedge inconsistency" ); - - // Increment here, the first reference is for the other he - property( this->m_wedgeIndexPph, r0_ ) = this->m_wedges.newReference( widx_ ); - property( this->m_wedgeIndexPph, r1_ ) = - this->m_wedges.newReference( property( this->m_wedgeIndexPph, h1_ ) ); - } - else - { property( this->m_wedgeIndexPph, r0_ ) = WedgeIndex {}; } - }; - - auto updateWedgeIndex2 = [this]( WedgeIndex widx_, - HalfedgeHandle s0_, - HalfedgeHandle s1_, - HalfedgeHandle s2_, - HalfedgeHandle h0_, - HalfedgeHandle h1_ ) { - CORE_UNUSED( s1_ ); - CORE_UNUSED( h1_ ); - - if ( !is_boundary( s0_ ) ) - { - CORE_ASSERT( s1_ == h1_, "TopologicalMesh: splitEdgeWedge inconsistency" ); - // do not increment here, since add has set ref to 1 - property( this->m_wedgeIndexPph, s2_ ) = widx_; - // "steal" ref from previous he (actually s0 is h0, u0 is the steal - // from o0. - property( this->m_wedgeIndexPph, s0_ ) = property( this->m_wedgeIndexPph, h0_ ); - } - else - { property( this->m_wedgeIndexPph, s0_ ) = WedgeIndex {}; } - }; - - // this update read from o0, must be done before t which reads from o0 - updateWedgeIndex2( ovwidx, u0, u1, u2, o0, o1 ); - // those update might be in any order - updateWedgeIndex2( hvwidx, s0, s1, s2, h0, h1 ); - updateWedgeIndex1( hvwidx, r0, r1, r2, h1, h2 ); - updateWedgeIndex1( ovwidx, t0, t1, t2, o1, o2 ); - - return true; -} - -void TopologicalMesh::collapseWedge( TopologicalMesh::HalfedgeHandle heh ) { - HalfedgeHandle h = heh; - HalfedgeHandle hn = next_halfedge_handle( h ); - HalfedgeHandle hp = prev_halfedge_handle( h ); - - HalfedgeHandle o = opposite_halfedge_handle( h ); - HalfedgeHandle on = next_halfedge_handle( o ); - HalfedgeHandle op = prev_halfedge_handle( o ); - - // FaceHandle fh = face_handle( h ); - // FaceHandle fo = face_handle( o ); - - VertexHandle vh = to_vertex_handle( h ); - VertexHandle vo = to_vertex_handle( o ); - - auto position = m_wedges.getWedgeData( property( m_wedgeIndexPph, heh ) ).m_position; - auto widx = property( m_wedgeIndexPph, heh ); - - CORE_ASSERT( widx.isValid(), "try to collapse onto an invalid wedge" ); - CORE_ASSERT( !isFeatureVertex( vo ), "try to collapse a feature vertex" ); - - for ( VertexIHalfedgeIter vih_it( vih_iter( vo ) ); vih_it.is_valid(); ++vih_it ) - { - // delete and set to new widx - m_wedges.del( property( m_wedgeIndexPph, *vih_it ) ); - property( m_wedgeIndexPph, *vih_it ) = m_wedges.newReference( widx ); - } - // but remove one ref for the deleted opposite he - m_wedges.del( property( m_wedgeIndexPph, o ) ); - - // and delete wedge of the remove he - // first if h is not boundary, copy the wedgeIndex of hn to hp to it - if ( !is_boundary( h ) ) - { - property( m_wedgeIndexPph, hp ) = - m_wedges.newReference( property( m_wedgeIndexPph, opposite_halfedge_handle( hn ) ) ); - } - m_wedges.del( property( m_wedgeIndexPph, hn ) ); - m_wedges.del( property( m_wedgeIndexPph, opposite_halfedge_handle( hn ) ) ); - - if ( !is_boundary( o ) ) - { - property( m_wedgeIndexPph, on ) = - m_wedges.newReference( property( m_wedgeIndexPph, opposite_halfedge_handle( op ) ) ); - } - m_wedges.del( property( m_wedgeIndexPph, op ) ); - m_wedges.del( property( m_wedgeIndexPph, opposite_halfedge_handle( op ) ) ); - - base::collapse( h ); - - for ( VertexIHalfedgeIter vih_it( vih_iter( vh ) ); vih_it.is_valid(); ++vih_it ) - { - // delete and set to new widx - m_wedges.setWedgePosition( property( m_wedgeIndexPph, *vih_it ), position ); - } -} - -void TopologicalMesh::garbage_collection() { - for ( HalfedgeIter he_it = halfedges_begin(); he_it != halfedges_end(); ++he_it ) - { - // already done in collapseWedge - // if ( status( *he_it ).deleted() ) { m_wedges.del(property( - // m_wedgeIndexPph, *he_it )); } - } - - auto offset = m_wedges.computeCleanupOffset(); - for ( HalfedgeIter he_it = halfedges_begin(); he_it != halfedges_end(); ++he_it ) - { - if ( !status( *he_it ).deleted() ) - { - auto index = property( m_wedgeIndexPph, *he_it ); - if ( index.isValid() ) { property( m_wedgeIndexPph, *he_it ) = index - offset[index]; } - } - } - m_wedges.garbageCollection(); - base::garbage_collection(); - - for ( HalfedgeIter he_it = halfedges_begin(); he_it != halfedges_end(); ++he_it ) - { - ON_ASSERT( auto idx = property( m_wedgeIndexPph, *he_it ); ); - CORE_ASSERT( !idx.isValid() || !m_wedges.getWedge( idx ).isDeleted(), - "references deleted wedge remains after garbage collection" ); - } - for ( size_t i = 0; i < m_wedges.size(); ++i ) - { - CORE_ASSERT( !m_wedges.getWedge( WedgeIndex {i} ).isDeleted(), - "deleted wedge remains after garbage collection" ); - } -} - -void TopologicalMesh::delete_face( FaceHandle _fh, bool _delete_isolated_vertices ) { - for ( auto itr = fh_begin( _fh ); itr.is_valid(); ++itr ) - { - auto idx = property( m_wedgeIndexPph, *itr ); - if ( idx.isInvalid() ) - { - LOG( logWARNING ) - << "[TopologicalMesh::delete_face] halfedge has an invalid wedge index"; - } - else - { m_wedges.del( idx ); } - // set an invalid index for the boundary halfedges - property( m_wedgeIndexPph, *itr ) = WedgeIndex {}; - } - base::delete_face( _fh, _delete_isolated_vertices ); -} - -void TopologicalMesh::InitWedgeProps::operator()( AttribBase* attr ) const { - if ( attr->getSize() != m_triMesh.vertices().size() ) - { LOG( logWARNING ) << "[TopologicalMesh] Skip badly sized attribute " << attr->getName(); } - else if ( attr->getName() != std::string( "in_position" ) ) - { - if ( attr->isFloat() ) - { - m_topo->m_wedges.m_wedgeFloatAttribHandles.push_back( - m_triMesh.getAttribHandle( attr->getName() ) ); - m_topo->m_wedges.addProp( attr->getName() ); - } - else if ( attr->isVector2() ) - { - m_topo->m_wedges.m_wedgeVector2AttribHandles.push_back( - m_triMesh.getAttribHandle( attr->getName() ) ); - m_topo->m_wedges.addProp( attr->getName() ); - } - else if ( attr->isVector3() ) - { - m_topo->m_wedges.m_wedgeVector3AttribHandles.push_back( - m_triMesh.getAttribHandle( attr->getName() ) ); - m_topo->m_wedges.addProp( attr->getName() ); - } - else if ( attr->isVector4() ) - { - m_topo->m_wedges.m_wedgeVector4AttribHandles.push_back( - m_triMesh.getAttribHandle( attr->getName() ) ); - m_topo->m_wedges.addProp( attr->getName() ); - } - else - LOG( logWARNING ) - << "Warning, mesh attribute " << attr->getName() - << " type is not supported (only float, vec2, vec3 nor vec4 are supported)"; - } -} - -/////////////// WEDGES RELATED STUFF ///////////////// - -TopologicalMesh::WedgeIndex -TopologicalMesh::WedgeCollection::add( const TopologicalMesh::WedgeData& wd ) { - WedgeIndex idx; - auto itr = std::find( m_data.begin(), m_data.end(), Wedge {wd} ); - - if ( itr == m_data.end() ) - { - idx = m_data.size(); - m_data.emplace_back( wd ); - } - else - { - itr->incrementRefCount(); - idx = std::distance( m_data.begin(), itr ); - } - return idx; -} - -std::vector TopologicalMesh::WedgeCollection::computeCleanupOffset() const { - std::vector ret( m_data.size(), 0 ); - int currentOffset = 0; - for ( size_t i = 0; i < m_data.size(); ++i ) - { - if ( m_data[i].isDeleted() ) - { - ++currentOffset; - ret[i] = -1; - } - else - { ret[i] = currentOffset; } - } - return ret; -} } // namespace deprecated } // namespace Geometry } // namespace Core diff --git a/src/Core/Geometry/deprecated/TopologicalMesh.hpp b/src/Core/Geometry/deprecated/TopologicalMesh.hpp index 5afe2403bfe..fe538b798b8 100644 --- a/src/Core/Geometry/deprecated/TopologicalMesh.hpp +++ b/src/Core/Geometry/deprecated/TopologicalMesh.hpp @@ -57,13 +57,10 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT - void initWithWedge( const Ra::Core::Geometry::TriangleMesh& triMesh, - NonManifoldFaceCommand command ); /** * Construct an empty topological mesh, only init mandatory properties. @@ -98,18 +91,9 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT>& vec4Props ); ///@} - /** - * Inner class WedgeData represents the actual data per wedge, including position. - * - * At any time m_position as to be equal to the wedge's vertex point. - * All wedges have the same set of attributes. - * Access and management is delegated to TopologicalMesh and WedgeCollection - */ - class WedgeData - { - public: - EIGEN_MAKE_ALIGNED_OPERATOR_NEW - - // Index m_inputTriangleMeshIndex; - // Index m_outputTriangleMeshIndex; - Vector3 m_position {}; - VectorArray m_floatAttrib; - VectorArray m_vector2Attrib; - VectorArray m_vector3Attrib; - VectorArray m_vector4Attrib; - - template - inline VectorArray& getAttribArray(); - - explicit WedgeData() = default; - inline bool operator==( const WedgeData& lhs ) const; - inline bool operator!=( const WedgeData& lhs ) const; - inline bool operator<( const WedgeData& lhs ) const; - friend Wedge; - - private: - // return 1 : equals, 2: strict less, 3: strict greater - template - static int compareVector( const T& a, const T& b ); - }; - /** * \name Topological operations */ @@ -403,273 +352,9 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT getVertexWedges( OpenMesh::VertexHandle vh ) const; - - /** - * get the wedge index associated with an halfedge - */ - inline WedgeIndex getWedgeIndex( OpenMesh::HalfedgeHandle heh ) const; - - /** - * Access to wedge data. - * \param idx must be valid and correspond to a non delete wedge index. - */ - inline const WedgeData& getWedgeData( const WedgeIndex& idx ) const; - - /** - * Return the wedge refcount, for debug purpose. - */ - inline unsigned int getWedgeRefCount( const WedgeIndex& idx ) const; - - /** set WedgeData \a wd to the wedge with index \a widx. - * All halfedge that point to widx will get the new values. - * \param widx index of the wedge - * \param wd data to set to wedge that correspond to widx - */ - inline void setWedgeData( WedgeIndex widx, const WedgeData& wd ); - - /** - * Change the WedgeData associated for \a idx, for attrib \a name to \a value. - * The data is changed for all halfedges referencing this wedge. - * \return true if the wedge is set, false if nothing set, i.e. if name is not an attrib of - * type T. - */ - template - inline bool setWedgeData( const WedgeIndex& idx, const std::string& name, const T& value ); - - /** - * Replace the wedge data associated with an halfedge. - * The old wedge is "deleted". If wedge data correspond to an already - * present wedge, it's index is used. - */ - inline void replaceWedge( OpenMesh::HalfedgeHandle he, const WedgeData& wd ); - - /** - * Replace the wedge index associated with an halfedge. - * The old wedge is "deleted". The new wedge reference count is incremented. - */ - inline void replaceWedgeIndex( OpenMesh::HalfedgeHandle he, const WedgeIndex& widx ); - - /** - * call mergeEquelWedges( vh ) for every vertices of the mesh. - * \see void mergeEqualWedges( OpenMesh::VertexHandle vh ); - */ - inline void mergeEqualWedges(); - - /** - * Merge (make same index) wegdes with the same data around \a vh - * \param vh vertex handle to process - */ - inline void mergeEqualWedges( OpenMesh::VertexHandle vh ); - - /// Remove deleted element from the mesh, including wedges. - void garbage_collection(); - - inline const std::vector& getVec4AttribNames() const; - inline const std::vector& getVec3AttribNames() const; - inline const std::vector& getVec2AttribNames() const; - inline const std::vector& getFloatAttribNames() const; - - /// true if more than one wedge arount vertex \a vh, false if only one wedge - inline bool isFeatureVertex( const VertexHandle& vh ) const; - - /// true if at least one of edge's vertex as two different wedge arount the - /// edge. - /// false if the two vertices have the same wedge for both face aside the edge. - inline bool isFeatureEdge( const EdgeHandle& eh ) const; - - inline const OpenMesh::HPropHandleT& getWedgeIndexPph() const; - - void delete_face( FaceHandle _fh, bool _delete_isolated_vertices = true ); - - /** - * is the vertex a "bow tie" vertex ? - * \note Alias for OpenMesh::is_manifold - */ - bool isManifold( VertexHandle vh ) const; - - /// Check if evrything looks right in the data structure - /// \return true if ok, false if ko. - bool checkIntegrity() const; - private: - // internal function to build TriangleMesh attribs correspondance to wedge attribs. - class RA_CORE_API InitWedgeProps - { - public: - InitWedgeProps( TopologicalMesh* topo, const TriangleMesh& triMesh ) : - m_topo( topo ), m_triMesh( triMesh ) {} - void operator()( AttribBase* attr ) const; - - private: - TopologicalMesh* m_topo; - const TriangleMesh& m_triMesh; - }; - - class WedgeCollection; - // - /** - * This private class manage wedge data and refcount, to maintain deleted status - * - * \internal We need to export this class to make it accessible in .inl - */ - class RA_CORE_API Wedge - { - WedgeData m_wedgeData {}; - unsigned int m_refCount {0}; - - private: - WedgeData& getWedgeData() { return m_wedgeData; } - - public: - EIGEN_MAKE_ALIGNED_OPERATOR_NEW - - explicit Wedge() {} - explicit Wedge( const WedgeData& wd ) : m_wedgeData {wd}, m_refCount {1} {}; - const WedgeData& getWedgeData() const { return m_wedgeData; } - void setWedgeData( const WedgeData& wedgeData ) { m_wedgeData = wedgeData; } - void setWedgeData( WedgeData&& wedgeData ) { m_wedgeData = std::move( wedgeData ); } - void incrementRefCount() { ++m_refCount; } - void decrementRefCount() { - if ( m_refCount ) --m_refCount; - } - /// comparison ignore refCount - bool operator==( const Wedge& lhs ) const { return m_wedgeData == lhs.m_wedgeData; } - - bool isDeleted() const { return m_refCount == 0; } - unsigned int getRefCount() const { return m_refCount; } - - friend WedgeCollection; - }; - - /** - * This private class manage the wedge collection. - * Most of the data members are public so that the enclosing class can - * easily manage the data. - * - * \internal We need to export this class to make it accessible in .inl - */ - class RA_CORE_API WedgeCollection - { - public: - EIGEN_MAKE_ALIGNED_OPERATOR_NEW - - template - inline const std::vector& getNameArray() const; - - template - inline std::vector& getNameArray(); - - /** - * Add wd to the wedge collection, and return the index. - * If a wedge with same data is already present, it's index is returned, - * otherwise a new wedge is added to the wedges collection. - * \param wd Data to insert. - * \return the index of the inserted (or found) wedge. - */ - WedgeIndex add( const WedgeData& wd ); - - /** - * Delete the wedge \a idx from the collection. - * These deletion actually just remove one reference from an halfedge - * to the wedge data. If the wedge is still referenced by other - * halfedges, it will not be removed during garbageCollection. - */ - void del( const WedgeIndex& idx ); - WedgeIndex newReference( const WedgeIndex& idx ); - - /** - * Return the wedge data associated with \a idx - */ - const WedgeData& getWedgeData( const WedgeIndex& idx ) const { - CORE_ASSERT( idx.isValid() && !m_data[idx].isDeleted(), - "access to invalid or deleted wedge is prohibited" ); - - return m_data[idx].getWedgeData(); - } - - unsigned int getWedgeRefCount( const WedgeIndex& idx ) const { - CORE_ASSERT( idx.isValid(), "access to invalid or deleted wedge is prohibited" ); - return m_data[idx].getRefCount(); - } - - /// Return the wedge (not the data) for in class manipulation. - /// client code should use getWedgeData only. - inline const Wedge& getWedge( const WedgeIndex& idx ) const; - - /// \see TopologicalMesh::setWedgeData - inline void setWedgeData( const WedgeIndex& idx, const WedgeData& wd ); - - /// \see TopologicalMesh::setWedgeData - template - inline bool setWedgeData( const WedgeIndex& idx, const std::string& name, const T& value ); - inline bool setWedgePosition( const WedgeIndex& idx, const Vector3& value ); - - // name is supposed to be unique within all attribs - // not checks are performed - template - void addProp( const std::string& name ); - - /// return the offset ot apply to each wedgeindex so that - /// after garbageCollection all indices are valid and coherent. - std::vector computeCleanupOffset() const; - - /// remove unreferenced wedge, halfedges need to be reindexed. - inline void garbageCollection(); - - /// \todo removeDuplicateWedge - /// merge wedges with same data - /// return old->new index correspondance to update wedgeIndexPph - /// inline void removeDuplicateWedge - inline size_t size() const { return m_data.size(); } - - /// attrib names associated to vertex/wedges, getted from CoreMesh, if any, - std::vector m_floatAttribNames; - std::vector m_vector2AttribNames; - std::vector m_vector3AttribNames; - std::vector m_vector4AttribNames; - - /// attrib handle from the CoreMesh given at construction, if any. - std::vector> m_wedgeFloatAttribHandles; - std::vector> m_wedgeVector2AttribHandles; - std::vector> m_wedgeVector3AttribHandles; - std::vector> m_wedgeVector4AttribHandles; - - // private: - AlignedStdVector m_data; - }; - - WedgeData interpolateWedgeAttributes( const WedgeData&, const WedgeData&, Scalar alpha ); - - template - inline void copyAttribToWedgeData( const TriangleMesh& mesh, - unsigned int vindex, - const std::vector>& attrHandleVec, - VectorArray* to ); - - inline void copyMeshToWedgeData( const TriangleMesh& mesh, - unsigned int vindex, - const std::vector>& wprop_float, - const std::vector>& wprop_vec2, - const std::vector>& wprop_vec3, - const std::vector>& wprop_vec4, - TopologicalMesh::WedgeData* wd ); - template using HandleAndValueVector = std::vector, T>, @@ -679,23 +364,20 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT, OpenMesh::HPropHandleT>; template - [[deprecated]] inline void copyAttribToTopo( const TriangleMesh& triMesh, - const std::vector>& vprop, - TopologicalMesh::HalfedgeHandle heh, - unsigned int vindex ); + inline void copyAttribToTopo( const TriangleMesh& triMesh, + const std::vector>& vprop, + TopologicalMesh::HalfedgeHandle heh, + unsigned int vindex ); template - [[deprecated]] inline void addAttribPairToTopo( const TriangleMesh& triMesh, - AttribManager::pointer_type attr, - std::vector>& vprop, - std::vector>& pph ); + inline void addAttribPairToTopo( const TriangleMesh& triMesh, + AttribManager::pointer_type attr, + std::vector>& vprop, + std::vector>& pph ); void split_copy( EdgeHandle _eh, VertexHandle _vh ); void split( EdgeHandle _eh, VertexHandle _vh ); - OpenMesh::HPropHandleT m_wedgeIndexPph; /**< Halfedges' Wedge index */ - WedgeCollection m_wedges; /**< Wedge data management */ - ///\todo to be deleted/updated OpenMesh::HPropHandleT m_inputTriangleMeshIndexPph; OpenMesh::HPropHandleT m_outputTriangleMeshIndexPph; @@ -707,11 +389,8 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT +#include diff --git a/src/Core/Geometry/deprecated/TopologicalMesh.inl b/src/Core/Geometry/deprecated/TopologicalMesh.inl index 03a826a3794..ae0edd8dd4a 100644 --- a/src/Core/Geometry/deprecated/TopologicalMesh.inl +++ b/src/Core/Geometry/deprecated/TopologicalMesh.inl @@ -56,9 +56,6 @@ inline TopologicalMesh::TopologicalMesh( const TriangleMesh& triMesh, } } ); - // loop over all attribs and build correspondance pair - triMesh.vertexAttribs().for_each_attrib( InitWedgeProps {this, triMesh} ); - size_t num_triangles = triMesh.getIndices().size(); command.initialize( triMesh ); @@ -75,7 +72,6 @@ inline TopologicalMesh::TopologicalMesh( const TriangleMesh& triMesh, std::vector face_vhandles( 3 ); std::vector face_normals( 3 ); std::vector face_vertexIndex( 3 ); - std::vector face_wedges( 3 ); const auto& triangle = triMesh.getIndices()[i]; for ( size_t j = 0; j < 3; ++j ) { @@ -96,80 +92,10 @@ inline TopologicalMesh::TopologicalMesh( const TriangleMesh& triMesh, face_vhandles[j] = vh; face_vertexIndex[j] = inMeshVertexIndex; if ( hasNormals ) face_normals[j] = triMesh.normals()[inMeshVertexIndex]; - - WedgeData wd; - wd.m_position = p; - - copyMeshToWedgeData( triMesh, - inMeshVertexIndex, - m_wedges.m_wedgeFloatAttribHandles, - m_wedges.m_wedgeVector2AttribHandles, - m_wedges.m_wedgeVector3AttribHandles, - m_wedges.m_wedgeVector4AttribHandles, - &wd ); - - face_wedges[j] = m_wedges.add( wd ); } - // take care of degen, see below in method initWithWedge for comments - // copied from initFromWedges EXECPT THE TWO LINES WITH COMMENT - // x-----------------------------------------------------------------------------------x - { - auto begin = face_vhandles.begin(); - if ( face_vhandles.size() > 2 ) - { - auto end = face_vhandles.end() - 1; - auto wedgeEnd = face_wedges.end() - 1; - auto normalEnd = face_normals.end() - 1; - - while ( begin != end && *begin == *end ) - { - end--; - // WARNING explicit del wedge (not needed in initWithWedges) - m_wedges.del( *wedgeEnd ); - wedgeEnd--; - normalEnd--; - } - face_vhandles.erase( end + 1, face_vhandles.end() ); - face_wedges.erase( wedgeEnd + 1, face_wedges.end() ); - face_normals.erase( normalEnd + 1, face_normals.end() ); - } - } - - { - auto first = face_vhandles.begin(); - auto wedgeFirst = face_wedges.begin(); - auto normalFirst = face_normals.begin(); - auto last = face_vhandles.end(); - - if ( first != last ) - { - auto result = first; - auto wedgeResult = wedgeFirst; - auto normalResult = normalFirst; - while ( ++first != last ) - { - if ( !( *result == *first ) ) - { - ++result; - ++wedgeResult; - ++normalResult; - if ( result != first ) - { - *result = std::move( *first ); - // WARNING explicit del wedge (not needed in initWithWedges) - m_wedges.del( *wedgeResult ); - *wedgeResult = std::move( *wedgeFirst ); - *normalResult = std::move( *normalFirst ); - } - } - } - face_vhandles.erase( result + 1, face_vhandles.end() ); - face_wedges.erase( wedgeResult + 1, face_wedges.end() ); - face_normals.erase( normalResult + 1, face_normals.end() ); - } - } TopologicalMesh::FaceHandle fh; + // skip 2 vertex face if ( face_vhandles.size() > 2 ) fh = add_face( face_vhandles ); // x-----------------------------------------------------------------------------------x @@ -185,15 +111,10 @@ inline TopologicalMesh::TopologicalMesh( const TriangleMesh& triMesh, copyAttribToTopo( triMesh, vprop_vec2, heh, face_vertexIndex[vindex] ); copyAttribToTopo( triMesh, vprop_vec3, heh, face_vertexIndex[vindex] ); copyAttribToTopo( triMesh, vprop_vec4, heh, face_vertexIndex[vindex] ); - property( m_wedgeIndexPph, heh ) = face_wedges[vindex]; } } else - { - for ( auto wedgeIndex : face_wedges ) - m_wedges.del( wedgeIndex ); - command.process( face_vhandles ); - } + { command.process( face_vhandles ); } face_vhandles.clear(); face_normals.clear(); face_vertexIndex.clear(); @@ -204,190 +125,6 @@ inline TopologicalMesh::TopologicalMesh( const TriangleMesh& triMesh, garbage_collection(); } -template -void TopologicalMesh::initWithWedge( const TriangleMesh& triMesh, NonManifoldFaceCommand command ) { - - LOG( logINFO ) << "TopologicalMesh: load triMesh with " << triMesh.getIndices().size() - << " faces and " << triMesh.vertices().size() << " vertices."; - - ///\todo use a kdtree - struct hash_vec { - size_t operator()( const Vector3& lvalue ) const { - size_t hx = std::hash()( lvalue[0] ); - size_t hy = std::hash()( lvalue[1] ); - size_t hz = std::hash()( lvalue[2] ); - return ( hx ^ ( hy << 1 ) ) ^ hz; - } - }; - // use a hashmap for fast search of existing vertex position - using VertexMap = std::unordered_map; - VertexMap vertexHandles; - - // loop over all attribs and build correspondance pair - triMesh.vertexAttribs().for_each_attrib( InitWedgeProps {this, triMesh} ); - - size_t num_triangles = triMesh.getIndices().size(); - - for ( size_t i = 0; i < triMesh.vertices().size(); ++i ) - { - // create an empty wedge, with 0 ref - Wedge w; - - WedgeData wd; - wd.m_position = triMesh.vertices()[i]; - copyMeshToWedgeData( triMesh, - i, - m_wedges.m_wedgeFloatAttribHandles, - m_wedges.m_wedgeVector2AttribHandles, - m_wedges.m_wedgeVector3AttribHandles, - m_wedges.m_wedgeVector4AttribHandles, - &wd ); - // here ref is not incremented - w.setWedgeData( std::move( wd ) ); - // the newly added wedge is not referenced yet, will be done with `newReference` when - // creating faces just below - m_wedges.m_data.push_back( w ); - } - - LOG( logINFO ) << "TopologicalMesh: have " << m_wedges.size() << " wedges "; - - const bool hasNormals = !triMesh.normals().empty(); - if ( !hasNormals ) - { - release_face_normals(); - release_vertex_normals(); - release_halfedge_normals(); - } - - command.initialize( triMesh ); - for ( unsigned int i = 0; i < num_triangles; i++ ) - { - std::vector face_vhandles( 3 ); - std::vector face_normals( 3 ); - std::vector face_wedges( 3 ); - const auto& triangle = triMesh.getIndices()[i]; - - for ( size_t j = 0; j < 3; ++j ) - { - unsigned int inMeshVertexIndex = triangle[j]; - const Vector3& p = triMesh.vertices()[inMeshVertexIndex]; - - typename VertexMap::iterator vtr = vertexHandles.find( p ); - TopologicalMesh::VertexHandle vh; - if ( vtr == vertexHandles.end() ) - { - vh = add_vertex( p ); - vertexHandles.insert( vtr, typename VertexMap::value_type( p, vh ) ); - } - else - { vh = vtr->second; } - - face_vhandles[j] = vh; - if ( hasNormals ) face_normals[j] = triMesh.normals()[inMeshVertexIndex]; - face_wedges[j] = WedgeIndex {inMeshVertexIndex}; - } - - // remove consecutive equal vertex - // first take care of "loop" if begin == *end-1 - // apply the same modifications on wedges and normals - // e.g. 1 2 1 becomes 1 2 - { - auto begin = face_vhandles.begin(); - if ( face_vhandles.size() > 2 ) - { - auto end = face_vhandles.end() - 1; - auto wedgeEnd = face_wedges.end() - 1; - auto normalEnd = face_normals.end() - 1; - - while ( begin != end && *begin == *end ) - { - end--; - wedgeEnd--; - normalEnd--; - } - face_vhandles.erase( end + 1, face_vhandles.end() ); - face_wedges.erase( wedgeEnd + 1, face_wedges.end() ); - face_normals.erase( normalEnd + 1, face_normals.end() ); - } - } - // then remove duplicates - // e.g. 1 2 2 becomes 1 2 - // equiv of - // face_vhandles.erase( std::unique( face_vhandles.begin(), face_vhandles.end() ), - // face_vhandles.end() ); - // but handles wedges and normals - // see (https://en.cppreference.com/w/cpp/algorithm/unique) - { - auto first = face_vhandles.begin(); - auto wedgeFirst = face_wedges.begin(); - auto normalFirst = face_normals.begin(); - auto last = face_vhandles.end(); - - if ( first != last ) - { - auto result = first; - auto wedgeResult = wedgeFirst; - auto normalResult = normalFirst; - while ( ++first != last ) - { - if ( !( *result == *first ) ) - { - ++result; - ++wedgeResult; - ++normalResult; - if ( result != first ) - { - *result = std::move( *first ); - *wedgeResult = std::move( *wedgeFirst ); - *normalResult = std::move( *normalFirst ); - } - } - } - face_vhandles.erase( result + 1, face_vhandles.end() ); - face_wedges.erase( wedgeResult + 1, face_wedges.end() ); - face_normals.erase( normalResult + 1, face_normals.end() ); - } - } - - ///\todo and "cross face ?" - // unique sort size == vhandles size, if not split ... - - TopologicalMesh::FaceHandle fh; - // skip 2 vertex face - if ( face_vhandles.size() > 2 ) fh = add_face( face_vhandles ); - - // In case of topological inconsistancy, face will be invalid (or uninitialized <> invalid) - if ( fh.is_valid() ) - { - for ( size_t vindex = 0; vindex < face_vhandles.size(); vindex++ ) - { - TopologicalMesh::HalfedgeHandle heh = halfedge_handle( face_vhandles[vindex], fh ); - if ( hasNormals ) set_normal( heh, face_normals[vindex] ); - property( m_wedgeIndexPph, heh ) = m_wedges.newReference( face_wedges[vindex] ); - } - } - else - { command.process( face_vhandles ); } - face_vhandles.clear(); - face_normals.clear(); - } - command.postProcess( *this ); - - LOG( logINFO ) << "TopologicalMesh: load end with " << m_wedges.size() << " wedges "; -} - -template -void TopologicalMesh::copyAttribToWedgeData( const TriangleMesh& mesh, - unsigned int vindex, - const std::vector>& attrHandleVec, - VectorArray* to ) { - for ( auto handle : attrHandleVec ) - { - auto& attr = mesh.getAttrib( handle ); - to->push_back( attr.data()[vindex] ); - } -} - template void TopologicalMesh::addAttribPairToTopo( const TriangleMesh& triMesh, AttribManager::pointer_type attr, @@ -408,20 +145,6 @@ void TopologicalMesh::addAttribPairToTopo( const TriangleMesh& triMesh, } } -void TopologicalMesh::copyMeshToWedgeData( const TriangleMesh& mesh, - unsigned int vindex, - const std::vector>& wprop_float, - const std::vector>& wprop_vec2, - const std::vector>& wprop_vec3, - const std::vector>& wprop_vec4, - TopologicalMesh::WedgeData* wd ) { - - copyAttribToWedgeData( mesh, vindex, wprop_float, &wd->m_floatAttrib ); - copyAttribToWedgeData( mesh, vindex, wprop_vec2, &wd->m_vector2Attrib ); - copyAttribToWedgeData( mesh, vindex, wprop_vec3, &wd->m_vector3Attrib ); - copyAttribToWedgeData( mesh, vindex, wprop_vec4, &wd->m_vector4Attrib ); -} - template void TopologicalMesh::copyAttribToTopo( const TriangleMesh& triMesh, const std::vector>& vprop, @@ -743,309 +466,6 @@ inline void TopologicalMesh::interpolateAllPropsOnFaces( interpolatePropsOnFaces( fh, getVector4PropsHandles(), vec4Props ); } -inline std::set -TopologicalMesh::getVertexWedges( OpenMesh::VertexHandle vh ) const { - std::set ret; - - for ( ConstVertexIHalfedgeIter vh_it = cvih_iter( vh ); vh_it.is_valid(); ++vh_it ) - { - auto widx = property( m_wedgeIndexPph, *vh_it ); - if ( widx.isValid() && !m_wedges.getWedge( widx ).isDeleted() ) ret.insert( widx ); - } - return ret; -} - -inline TopologicalMesh::WedgeIndex -TopologicalMesh::getWedgeIndex( OpenMesh::HalfedgeHandle heh ) const { - return property( getWedgeIndexPph(), heh ); -} - -inline const TopologicalMesh::WedgeData& -TopologicalMesh::getWedgeData( const WedgeIndex& idx ) const { - return m_wedges.getWedgeData( idx ); -} - -inline unsigned int TopologicalMesh::getWedgeRefCount( const WedgeIndex& idx ) const { - return m_wedges.getWedgeRefCount( idx ); -} - -inline void TopologicalMesh::setWedgeData( TopologicalMesh::WedgeIndex widx, - const TopologicalMesh::WedgeData& wedge ) { - m_wedges.setWedgeData( widx, wedge ); -} - -template -inline bool TopologicalMesh::setWedgeData( const TopologicalMesh::WedgeIndex& idx, - const std::string& name, - const T& value ) { - return m_wedges.setWedgeData( idx, name, value ); -} - -inline void TopologicalMesh::replaceWedge( OpenMesh::HalfedgeHandle he, const WedgeData& wd ) { - m_wedges.del( property( getWedgeIndexPph(), he ) ); - property( getWedgeIndexPph(), he ) = m_wedges.add( wd ); -} - -inline void TopologicalMesh::replaceWedgeIndex( OpenMesh::HalfedgeHandle he, - const WedgeIndex& widx ) { - m_wedges.del( property( getWedgeIndexPph(), he ) ); - property( getWedgeIndexPph(), he ) = m_wedges.newReference( widx ); -} - -inline void TopologicalMesh::mergeEqualWedges() { - for ( auto itr = vertices_begin(), stop = vertices_end(); itr != stop; ++itr ) - { - mergeEqualWedges( *itr ); - } -} - -inline void TopologicalMesh::mergeEqualWedges( OpenMesh::VertexHandle vh ) { - - for ( auto itr = vih_iter( vh ); itr.is_valid(); ++itr ) - { - // replace will search if wedge already present and use it, so merge occurs. - replaceWedge( *itr, getWedgeData( property( getWedgeIndexPph(), *itr ) ) ); - } -} - -inline const std::vector& TopologicalMesh::getVec4AttribNames() const { - return m_wedges.m_vector4AttribNames; -} -inline const std::vector& TopologicalMesh::getVec3AttribNames() const { - return m_wedges.m_vector3AttribNames; -} -inline const std::vector& TopologicalMesh::getVec2AttribNames() const { - return m_wedges.m_vector2AttribNames; -} -inline const std::vector& TopologicalMesh::getFloatAttribNames() const { - return m_wedges.m_floatAttribNames; -} - -inline bool TopologicalMesh::isFeatureVertex( const VertexHandle& vh ) const { - return getVertexWedges( vh ).size() != 1; -} - -inline bool TopologicalMesh::isFeatureEdge( const EdgeHandle& eh ) const { - - auto heh0 = halfedge_handle( eh, 0 ); - auto heh1 = halfedge_handle( eh, 1 ); - - return property( m_wedgeIndexPph, heh0 ) != - property( m_wedgeIndexPph, - prev_halfedge_handle( opposite_halfedge_handle( heh0 ) ) ) || - property( m_wedgeIndexPph, heh1 ) != - property( m_wedgeIndexPph, - prev_halfedge_handle( opposite_halfedge_handle( heh1 ) ) ); -} - -inline const OpenMesh::HPropHandleT& -TopologicalMesh::getWedgeIndexPph() const { - return m_wedgeIndexPph; -} - -//////////////////////////////////////////////////////////////////////////////// -/////////////////// WEDGES RELATED STUFF ////////////////////////////// -/////////////////// WedgeCollection ////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// - -inline void TopologicalMesh::WedgeCollection::del( const TopologicalMesh::WedgeIndex& idx ) { - if ( idx.isValid() ) m_data[idx].decrementRefCount(); -} - -inline TopologicalMesh::WedgeIndex -TopologicalMesh::WedgeCollection::newReference( const TopologicalMesh::WedgeIndex& idx ) { - if ( idx.isValid() ) m_data[idx].incrementRefCount(); - return idx; -} - -inline const TopologicalMesh::Wedge& -TopologicalMesh::WedgeCollection::getWedge( const TopologicalMesh::WedgeIndex& idx ) const { - return m_data[idx]; -} - -inline void TopologicalMesh::WedgeCollection::setWedgeData( const TopologicalMesh::WedgeIndex& idx, - const TopologicalMesh::WedgeData& wd ) { - if ( !( wd.m_floatAttrib.size() == m_floatAttribNames.size() && - wd.m_vector2Attrib.size() == m_vector2AttribNames.size() && - wd.m_vector3Attrib.size() == m_vector3AttribNames.size() && - wd.m_vector4Attrib.size() == m_vector4AttribNames.size() ) ) - { - LOG( logWARNING ) << "Warning, topological mesh set wedge: number of attribs inconsistency"; - } - if ( idx.isValid() ) m_data[idx].setWedgeData( wd ); -} - -#define GET_NAME_ARRAY_HELPER( TYPE, NAME ) \ - template <> \ - inline const std::vector& TopologicalMesh::WedgeCollection::getNameArray() \ - const { \ - return m_##NAME##AttribNames; \ - } \ - template <> \ - inline std::vector& TopologicalMesh::WedgeCollection::getNameArray() { \ - return m_##NAME##AttribNames; \ - } - -GET_NAME_ARRAY_HELPER( float, float ) -GET_NAME_ARRAY_HELPER( Vector2, vector2 ) -GET_NAME_ARRAY_HELPER( Vector3, vector3 ) -GET_NAME_ARRAY_HELPER( Vector4, vector4 ) - -#undef GET_NAME_ARRAY_HELPER -// These template functions are defined above for supported types. -// For unsupported types they simply generate a compile error. -template -inline const std::vector& TopologicalMesh::WedgeCollection::getNameArray() const { - - LOG( logWARNING ) << "Warning, mesh attribute " << typeid( T ).name() - << " is not supported (only float, vec2, vec3 nor vec4 are supported)"; - static_assert( sizeof( T ) == -1, "this type is not supported" ); - return m_floatAttribNames; -} - -template -inline std::vector& TopologicalMesh::WedgeCollection::getNameArray() { - - LOG( logWARNING ) << "Warning, mesh attribute " << typeid( T ).name() - << " is not supported (only float, vec2, vec3 nor vec4 are supported)"; - static_assert( sizeof( T ) == -1, "this type is not supported" ); - return m_floatAttribNames; -} - -template -inline bool TopologicalMesh::WedgeCollection::setWedgeData( const TopologicalMesh::WedgeIndex& idx, - const std::string& name, - const T& value ) { - if ( idx.isValid() ) - { - auto nameArray = getNameArray(); - auto itr = std::find( nameArray.begin(), nameArray.end(), name ); - if ( itr != nameArray.end() ) - { - auto attrIndex = std::distance( nameArray.begin(), itr ); - m_data[idx].getWedgeData().getAttribArray()[attrIndex] = value; - return true; - } - else - { - LOG( logERROR ) << "Warning, set wedge: no wedge attrib named " << name << " of type " - << typeid( T ).name(); - } - } - return false; -} - -inline bool -TopologicalMesh::WedgeCollection::setWedgePosition( const TopologicalMesh::WedgeIndex& idx, - const Vector3& value ) { - if ( idx.isValid() ) - { - m_data[idx].getWedgeData().m_position = value; - return true; - } - return false; -} - -template -void TopologicalMesh::WedgeCollection::addProp( const std::string& name ) { - if ( name != std::string( "in_position" ) ) { getNameArray().push_back( name ); } -} - -inline void TopologicalMesh::WedgeCollection::garbageCollection() { - m_data.erase( std::remove_if( m_data.begin(), - m_data.end(), - []( const Wedge& w ) { return w.isDeleted(); } ), - m_data.end() ); -} - -//////////////////////////////////////////////////////////////////////////////// -/////////////////// WedgeData ////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// - -// return 1 : equals, 2: strict less, 3: strict greater -template -int TopologicalMesh::WedgeData::compareVector( const T& a, const T& b ) { - for ( int i = 0; i < T::RowsAtCompileTime; i++ ) - { - if ( a[i] < b[i] ) return 2; - if ( a[i] > b[i] ) return 3; - } - // (a == b) - return 1; -} - -inline bool TopologicalMesh::WedgeData::operator==( const TopologicalMesh::WedgeData& lhs ) const { - return - // do not have this yet, not sure we need to test them - // m_inputTriangleMeshIndex == lhs.m_inputTriangleMeshIndex && - // m_outputTriangleMeshIndex == lhs.m_outputTriangleMeshIndex && - m_position == lhs.m_position && m_floatAttrib == lhs.m_floatAttrib && - m_vector2Attrib == lhs.m_vector2Attrib && m_vector3Attrib == lhs.m_vector3Attrib && - m_vector4Attrib == lhs.m_vector4Attrib; -} - -inline bool TopologicalMesh::WedgeData::operator<( const TopologicalMesh::WedgeData& lhs ) const { - - CORE_ASSERT( ( m_floatAttrib.size() == lhs.m_floatAttrib.size() ) && - ( m_vector2Attrib.size() == lhs.m_vector2Attrib.size() ) && - ( m_vector3Attrib.size() == lhs.m_vector3Attrib.size() ) && - ( m_vector4Attrib.size() == lhs.m_vector4Attrib.size() ), - "Could only compare wedge with same number of attributes" ); - - { - int comp = compareVector( m_position, lhs.m_position ); - if ( comp == 2 ) return true; - if ( comp == 3 ) return false; - } - for ( size_t i = 0; i < m_floatAttrib.size(); i++ ) - { - if ( m_floatAttrib[i] < lhs.m_floatAttrib[i] ) - return true; - else if ( m_floatAttrib[i] > lhs.m_floatAttrib[i] ) - return false; - } - - for ( size_t i = 0; i < m_vector2Attrib.size(); i++ ) - { - int comp = compareVector( m_vector2Attrib[i], lhs.m_vector2Attrib[i] ); - if ( comp == 2 ) return true; - if ( comp == 3 ) return false; - } - for ( size_t i = 0; i < m_vector3Attrib.size(); i++ ) - { - int comp = compareVector( m_vector3Attrib[i], lhs.m_vector3Attrib[i] ); - if ( comp == 2 ) return true; - if ( comp == 3 ) return false; - } - for ( size_t i = 0; i < m_vector4Attrib.size(); i++ ) - { - int comp = compareVector( m_vector4Attrib[i], lhs.m_vector4Attrib[i] ); - if ( comp == 2 ) return true; - if ( comp == 3 ) return false; - } - return false; -} - -bool TopologicalMesh::WedgeData::operator!=( const TopologicalMesh::WedgeData& lhs ) const { - return !( *this == lhs ); -} - -#define GET_ATTRIB_ARRAY_HELPER( TYPE, NAME ) \ - template <> \ - inline VectorArray& TopologicalMesh::WedgeData::getAttribArray() { \ - return m_##NAME##Attrib; \ - } - -GET_ATTRIB_ARRAY_HELPER( float, float ) -GET_ATTRIB_ARRAY_HELPER( Vector2, vector2 ) -GET_ATTRIB_ARRAY_HELPER( Vector3, vector3 ) -GET_ATTRIB_ARRAY_HELPER( Vector4, vector4 ) -#undef GET_ATTRIB_ARRAY_HELPER - -template -inline VectorArray& TopologicalMesh::WedgeData::getAttribArray() { - static_assert( sizeof( T ) == -1, "this type is not supported" ); -} } // namespace deprecated } // namespace Geometry } // namespace Core From c06df4dcbc5b2411782b5c74deaa921a530638c0 Mon Sep 17 00:00:00 2001 From: dlyr Date: Tue, 23 Feb 2021 15:52:15 +0100 Subject: [PATCH 03/37] [core] Remove unneeded lines. --- src/Core/Geometry/TopologicalMesh.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/Core/Geometry/TopologicalMesh.cpp b/src/Core/Geometry/TopologicalMesh.cpp index 10c3231541f..c96ad0d7283 100644 --- a/src/Core/Geometry/TopologicalMesh.cpp +++ b/src/Core/Geometry/TopologicalMesh.cpp @@ -341,11 +341,6 @@ TriangleMesh TopologicalMesh::toTriangleMeshFromWedges() { TriangleMesh::IndexContainerType indices; /// add attribs to out - std::vector> wedgeFloatAttribHandles; - std::vector> wedgeVector2AttribHandles; - std::vector> wedgeVector3AttribHandles; - std::vector> wedgeVector4AttribHandles; - TriangleMesh::PointAttribHandle::Container wedgePosition; AlignedStdVector::Container> wedgeFloatAttribData( m_wedges.m_floatAttribNames.size() ); From 9be14253b7c896ba245093d17cac2fb03adf0bd8 Mon Sep 17 00:00:00 2001 From: dlyr Date: Tue, 23 Feb 2021 15:53:21 +0100 Subject: [PATCH 04/37] [core] Add update from/to TriangleMesh and update wedge normals. --- src/Core/Geometry/TopologicalMesh.cpp | 53 +++++++++++++++++++++++++-- src/Core/Geometry/TopologicalMesh.hpp | 3 +- src/Core/Geometry/TopologicalMesh.inl | 33 +++++++++++++++++ 3 files changed, 85 insertions(+), 4 deletions(-) diff --git a/src/Core/Geometry/TopologicalMesh.cpp b/src/Core/Geometry/TopologicalMesh.cpp index c96ad0d7283..29e9defdb89 100644 --- a/src/Core/Geometry/TopologicalMesh.cpp +++ b/src/Core/Geometry/TopologicalMesh.cpp @@ -388,9 +388,56 @@ TriangleMesh TopologicalMesh::toTriangleMeshFromWedges() { return out; } -void TopologicalMesh::updateTriangleMesh( Ra::Core::Geometry::TriangleMesh& /*mesh*/ ) { - CORE_ASSERT( false, "not implemented yet" ); - ///\todo ;) +void TopologicalMesh::updateTriangleMesh( Ra::Core::Geometry::TriangleMesh& out ) { + TriangleMesh::PointAttribHandle::Container wedgePosition; + AlignedStdVector::Container> wedgeFloatAttribData( + m_wedges.m_floatAttribNames.size() ); + AlignedStdVector::Container> wedgeVector2AttribData( + m_wedges.m_vector2AttribNames.size() ); + AlignedStdVector::Container> wedgeVector3AttribData( + m_wedges.m_vector3AttribNames.size() ); + AlignedStdVector::Container> wedgeVector4AttribData( + m_wedges.m_vector4AttribNames.size() ); + + /// Wedges are output vertices ! + for ( WedgeIndex widx {0}; widx < WedgeIndex( m_wedges.size() ); ++widx ) + { + const auto& wd = m_wedges.getWedgeData( widx ); + wedgePosition.push_back( wd.m_position ); + copyWedgeDataToAttribContainer( wedgeFloatAttribData, wd.m_floatAttrib ); + copyWedgeDataToAttribContainer( wedgeVector2AttribData, wd.m_vector2Attrib ); + copyWedgeDataToAttribContainer( wedgeVector3AttribData, wd.m_vector3Attrib ); + copyWedgeDataToAttribContainer( wedgeVector4AttribData, wd.m_vector4Attrib ); + } + + out.setVertices( std::move( wedgePosition ) ); + moveContainerToMesh( out, m_wedges.m_floatAttribNames, wedgeFloatAttribData ); + moveContainerToMesh( out, m_wedges.m_vector2AttribNames, wedgeVector2AttribData ); + moveContainerToMesh( out, m_wedges.m_vector3AttribNames, wedgeVector3AttribData ); + moveContainerToMesh( out, m_wedges.m_vector4AttribNames, wedgeVector4AttribData ); +} + +void TopologicalMesh::update( const Ra::Core::Geometry::TriangleMesh& triMesh ) { + for ( size_t i = 0; i < triMesh.vertices().size(); ++i ) + { + WedgeData wd; + wd.m_position = triMesh.vertices()[i]; + copyMeshToWedgeData( triMesh, + i, + m_wedges.m_wedgeFloatAttribHandles, + m_wedges.m_wedgeVector2AttribHandles, + m_wedges.m_wedgeVector3AttribHandles, + m_wedges.m_wedgeVector4AttribHandles, + &wd ); + // here ref is not incremented + m_wedges.setWedgeData( i, wd ); + } + // update positions + for ( auto itr = halfedges_begin(), stop = halfedges_end(); itr != stop; ++itr ) + { + point( to_vertex_handle( *itr ) ) = + m_wedges.getWedgeData( getWedgeIndex( *itr ) ).m_position; + } } bool TopologicalMesh::splitEdge( TopologicalMesh::EdgeHandle eh, Scalar f ) { diff --git a/src/Core/Geometry/TopologicalMesh.hpp b/src/Core/Geometry/TopologicalMesh.hpp index 92ead49a09c..f3d82c613b0 100644 --- a/src/Core/Geometry/TopologicalMesh.hpp +++ b/src/Core/Geometry/TopologicalMesh.hpp @@ -112,9 +112,9 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT>, + hash_vec> + newNormals; + for ( auto itr = vertices_begin(), stop = vertices_end(); itr != stop; ++itr ) + { + auto vh = *itr; + for ( ConstVertexIHalfedgeIter vh_it = cvih_iter( vh ); vh_it.is_valid(); ++vh_it ) + { + auto widx = property( m_wedgeIndexPph, *vh_it ); + if ( widx.isValid() && !m_wedges.getWedge( widx ).isDeleted() ) + { + auto oldNormal = normal( face_handle( *vh_it ) ); + auto newNormal = normal( face_handle( *vh_it ) ); + newNormals[oldNormal].first += newNormal; + newNormals[oldNormal].second.insert( widx ); + } + } + } + for ( auto pair : newNormals ) + { + pair.second.first /= pair.second.second.size(); + for ( auto widx : pair.second.second ) + { + setWedgeData( widx, "in_normal", pair.first ); + } + } +} + inline void TopologicalMesh::createNormalPropOnFaces( OpenMesh::FPropHandleT& fProp ) { if ( !has_halfedge_normals() ) { From 952d77b68a2a4559563c97a209ad467733980361 Mon Sep 17 00:00:00 2001 From: dlyr Date: Fri, 26 Feb 2021 15:38:27 +0100 Subject: [PATCH 05/37] [core] Fix Topo updates and optimizing, sort of. --- src/Core/Geometry/TopologicalMesh.cpp | 46 +++++++++++++++- src/Core/Geometry/TopologicalMesh.hpp | 28 +++++++++- src/Core/Geometry/TopologicalMesh.inl | 79 ++++++++++++++++++++++----- 3 files changed, 135 insertions(+), 18 deletions(-) diff --git a/src/Core/Geometry/TopologicalMesh.cpp b/src/Core/Geometry/TopologicalMesh.cpp index 29e9defdb89..c99671dbc7e 100644 --- a/src/Core/Geometry/TopologicalMesh.cpp +++ b/src/Core/Geometry/TopologicalMesh.cpp @@ -417,6 +417,22 @@ void TopologicalMesh::updateTriangleMesh( Ra::Core::Geometry::TriangleMesh& out moveContainerToMesh( out, m_wedges.m_vector4AttribNames, wedgeVector4AttribData ); } +void TopologicalMesh::updateTriangleMeshNormals( + AttribArrayGeometry::NormalAttribHandle::Container& normals ) { + auto normalsIndex = m_wedges.getWedgeAttribIndex( "in_normal" ); +#pragma omp parallel for + for ( unsigned int widx = 0; widx < m_wedges.size(); ++widx ) + { + normals[widx] = m_wedges.getWedgeData( widx, normalsIndex ); + } +} + +void TopologicalMesh::updateTriangleMeshNormals( Ra::Core::Geometry::TriangleMesh& out ) { + auto& normals = out.normalsWithLock(); + updateTriangleMeshNormals( normals ); + out.normalsUnlock(); +} + void TopologicalMesh::update( const Ra::Core::Geometry::TriangleMesh& triMesh ) { for ( size_t i = 0; i < triMesh.vertices().size(); ++i ) { @@ -429,7 +445,6 @@ void TopologicalMesh::update( const Ra::Core::Geometry::TriangleMesh& triMesh ) m_wedges.m_wedgeVector3AttribHandles, m_wedges.m_wedgeVector4AttribHandles, &wd ); - // here ref is not incremented m_wedges.setWedgeData( i, wd ); } // update positions @@ -440,6 +455,35 @@ void TopologicalMesh::update( const Ra::Core::Geometry::TriangleMesh& triMesh ) } } +void TopologicalMesh::updatePositions( const Ra::Core::Geometry::TriangleMesh& triMesh ) { + updatePositions( triMesh.vertices() ); +} + +void TopologicalMesh::updatePositions( + const AttribArrayGeometry::PointAttribHandle::Container& vertices ) { +#pragma omp parallel for + for ( size_t i = 0; i < vertices.size(); ++i ) + { + m_wedges.setWedgePosition( i, vertices[i] ); + } + // update positions + for ( auto itr = halfedges_begin(), stop = halfedges_end(); itr != stop; ++itr ) + { + point( to_vertex_handle( *itr ) ) = + m_wedges.getWedgeData( getWedgeIndex( *itr ) ).m_position; + } +} + +void TopologicalMesh::updateNormals( const Ra::Core::Geometry::TriangleMesh& triMesh ) { + auto& normals = triMesh.normals(); + auto normalsIndex = m_wedges.getWedgeAttribIndex( "in_normal" ); +#pragma omp parallel for + for ( size_t i = 0; i < triMesh.vertices().size(); ++i ) + { + m_wedges.setWedgeData( i, normalsIndex, normals[i] ); + } +} + bool TopologicalMesh::splitEdge( TopologicalMesh::EdgeHandle eh, Scalar f ) { // Global schema of operation /* diff --git a/src/Core/Geometry/TopologicalMesh.hpp b/src/Core/Geometry/TopologicalMesh.hpp index f3d82c613b0..a96d71f2573 100644 --- a/src/Core/Geometry/TopologicalMesh.hpp +++ b/src/Core/Geometry/TopologicalMesh.hpp @@ -114,8 +114,13 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT inline VectorArray& getAttribArray(); + template + inline const VectorArray& getAttribArray() const; explicit WedgeData() = default; inline bool operator==( const WedgeData& lhs ) const; @@ -430,7 +437,8 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT + const T& getWedgeData( const WedgeIndex& idx, const std::string& name ) const; /** * Return the wedge refcount, for debug purpose. */ @@ -611,6 +619,10 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT + inline const T& getWedgeData( const WedgeIndex& idx, const std::string& name ) const; + template + inline T& getWedgeData( const WedgeIndex& idx, int attribIndex ); /// \see TopologicalMesh::setWedgeData inline void setWedgeData( const WedgeIndex& idx, const WedgeData& wd ); @@ -619,6 +631,18 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT inline bool setWedgeData( const WedgeIndex& idx, const std::string& name, const T& value ); inline bool setWedgePosition( const WedgeIndex& idx, const Vector3& value ); + template + inline void setWedgeData( const TopologicalMesh::WedgeIndex& idx, + const int& attribIndex, + const T& value ); + + template + inline int getWedgeAttribIndex( const std::string& name ) { + auto nameArray = getNameArray(); + auto itr = std::find( nameArray.begin(), nameArray.end(), name ); + if ( itr != nameArray.end() ) { return std::distance( nameArray.begin(), itr ); } + return 0; + } // name is supposed to be unique within all attribs // not checks are performed diff --git a/src/Core/Geometry/TopologicalMesh.inl b/src/Core/Geometry/TopologicalMesh.inl index 3e30f1fe93f..4ca2af2c42e 100644 --- a/src/Core/Geometry/TopologicalMesh.inl +++ b/src/Core/Geometry/TopologicalMesh.inl @@ -510,32 +510,35 @@ TopologicalMesh::getVector4PropsHandles() const { inline void TopologicalMesh::updateWedgeNormals() { // update_face_normals(); + auto normalsIndex = m_wedges.getWedgeAttribIndex( "in_normal" ); - std::unordered_map>, - hash_vec> - newNormals; for ( auto itr = vertices_begin(), stop = vertices_end(); itr != stop; ++itr ) { + std::unordered_map>, + hash_vec> + newNormals; + auto vh = *itr; + for ( ConstVertexIHalfedgeIter vh_it = cvih_iter( vh ); vh_it.is_valid(); ++vh_it ) { auto widx = property( m_wedgeIndexPph, *vh_it ); if ( widx.isValid() && !m_wedges.getWedge( widx ).isDeleted() ) { - auto oldNormal = normal( face_handle( *vh_it ) ); + auto oldNormal = m_wedges.getWedgeData( widx, normalsIndex ); auto newNormal = normal( face_handle( *vh_it ) ); newNormals[oldNormal].first += newNormal; newNormals[oldNormal].second.insert( widx ); } } - } - for ( auto pair : newNormals ) - { - pair.second.first /= pair.second.second.size(); - for ( auto widx : pair.second.second ) + for ( auto pair : newNormals ) { - setWedgeData( widx, "in_normal", pair.first ); + pair.second.first /= pair.second.second.size(); + for ( auto widx : pair.second.second ) + { + m_wedges.setWedgeData( widx, normalsIndex, pair.first ); + } } } } @@ -798,6 +801,41 @@ TopologicalMesh::getWedgeData( const WedgeIndex& idx ) const { return m_wedges.getWedgeData( idx ); } +template +inline const T& TopologicalMesh::getWedgeData( const TopologicalMesh::WedgeIndex& idx, + const std::string& name ) const { + return m_wedges.getWedgeData( idx, name ); +} + +template +inline const T& +TopologicalMesh::WedgeCollection::getWedgeData( const TopologicalMesh::WedgeIndex& idx, + const std::string& name ) const { + if ( idx.isValid() ) + { + auto nameArray = getNameArray(); + auto itr = std::find( nameArray.begin(), nameArray.end(), name ); + if ( itr != nameArray.end() ) + { + auto attrIndex = std::distance( nameArray.begin(), itr ); + return m_data[idx].getWedgeData().getAttribArray()[attrIndex]; + } + else + { + LOG( logERROR ) << "Warning, set wedge: no wedge attrib named " << name << " of type " + << typeid( T ).name(); + } + } + static T dummy; + return dummy; +} + +template +inline T& TopologicalMesh::WedgeCollection::getWedgeData( const TopologicalMesh::WedgeIndex& idx, + int attribIndex ) { + return m_data[idx].getWedgeData().getAttribArray()[attribIndex]; +} + inline unsigned int TopologicalMesh::getWedgeRefCount( const WedgeIndex& idx ) const { return m_wedges.getWedgeRefCount( idx ); } @@ -968,6 +1006,13 @@ inline bool TopologicalMesh::WedgeCollection::setWedgeData( const TopologicalMes return false; } +template +inline void TopologicalMesh::WedgeCollection::setWedgeData( const TopologicalMesh::WedgeIndex& idx, + const int& attrIndex, + const T& value ) { + m_data[idx].getWedgeData().getAttribArray()[attrIndex] = value; +} + inline bool TopologicalMesh::WedgeCollection::setWedgePosition( const TopologicalMesh::WedgeIndex& idx, const Vector3& value ) { @@ -1063,10 +1108,14 @@ bool TopologicalMesh::WedgeData::operator!=( const TopologicalMesh::WedgeData& l return !( *this == lhs ); } -#define GET_ATTRIB_ARRAY_HELPER( TYPE, NAME ) \ - template <> \ - inline VectorArray& TopologicalMesh::WedgeData::getAttribArray() { \ - return m_##NAME##Attrib; \ +#define GET_ATTRIB_ARRAY_HELPER( TYPE, NAME ) \ + template <> \ + inline VectorArray& TopologicalMesh::WedgeData::getAttribArray() { \ + return m_##NAME##Attrib; \ + } \ + template <> \ + inline const VectorArray& TopologicalMesh::WedgeData::getAttribArray() const { \ + return m_##NAME##Attrib; \ } GET_ATTRIB_ARRAY_HELPER( float, float ) From 2581405f0867ae1f1130da9f2936b9b94f060cc0 Mon Sep 17 00:00:00 2001 From: dlyr Date: Fri, 26 Feb 2021 15:39:56 +0100 Subject: [PATCH 06/37] [core] Topo store normal index, use direct acces to wedge data. --- src/Core/Geometry/TopologicalMesh.cpp | 16 ++--- src/Core/Geometry/TopologicalMesh.hpp | 5 ++ src/Core/Geometry/TopologicalMesh.inl | 90 +++++++++++++++++++++++++-- 3 files changed, 95 insertions(+), 16 deletions(-) diff --git a/src/Core/Geometry/TopologicalMesh.cpp b/src/Core/Geometry/TopologicalMesh.cpp index c99671dbc7e..9bb53e4abb0 100644 --- a/src/Core/Geometry/TopologicalMesh.cpp +++ b/src/Core/Geometry/TopologicalMesh.cpp @@ -419,11 +419,10 @@ void TopologicalMesh::updateTriangleMesh( Ra::Core::Geometry::TriangleMesh& out void TopologicalMesh::updateTriangleMeshNormals( AttribArrayGeometry::NormalAttribHandle::Container& normals ) { - auto normalsIndex = m_wedges.getWedgeAttribIndex( "in_normal" ); #pragma omp parallel for for ( unsigned int widx = 0; widx < m_wedges.size(); ++widx ) { - normals[widx] = m_wedges.getWedgeData( widx, normalsIndex ); + normals[widx] = m_wedges.getWedgeData( widx, m_normalsIndex ); } } @@ -461,26 +460,21 @@ void TopologicalMesh::updatePositions( const Ra::Core::Geometry::TriangleMesh& t void TopologicalMesh::updatePositions( const AttribArrayGeometry::PointAttribHandle::Container& vertices ) { + #pragma omp parallel for for ( size_t i = 0; i < vertices.size(); ++i ) { m_wedges.setWedgePosition( i, vertices[i] ); - } - // update positions - for ( auto itr = halfedges_begin(), stop = halfedges_end(); itr != stop; ++itr ) - { - point( to_vertex_handle( *itr ) ) = - m_wedges.getWedgeData( getWedgeIndex( *itr ) ).m_position; + point( m_wedges.m_data[i].getWedgeData().m_vertexHandle ) = vertices[i]; } } void TopologicalMesh::updateNormals( const Ra::Core::Geometry::TriangleMesh& triMesh ) { - auto& normals = triMesh.normals(); - auto normalsIndex = m_wedges.getWedgeAttribIndex( "in_normal" ); + auto& normals = triMesh.normals(); #pragma omp parallel for for ( size_t i = 0; i < triMesh.vertices().size(); ++i ) { - m_wedges.setWedgeData( i, normalsIndex, normals[i] ); + m_wedges.setWedgeData( i, m_normalsIndex, normals[i] ); } } diff --git a/src/Core/Geometry/TopologicalMesh.hpp b/src/Core/Geometry/TopologicalMesh.hpp index a96d71f2573..ccc5302f580 100644 --- a/src/Core/Geometry/TopologicalMesh.hpp +++ b/src/Core/Geometry/TopologicalMesh.hpp @@ -368,6 +368,7 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT m_floatAttrib; VectorArray m_vector2Attrib; @@ -563,6 +564,7 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT> m_vec3Pph; [[deprecated]] std::vector> m_vec4Pph; + int m_normalsIndex {-1}; + std::map, std::vector> m_faceVertexNormalWedges; + friend class TMOperations; }; diff --git a/src/Core/Geometry/TopologicalMesh.inl b/src/Core/Geometry/TopologicalMesh.inl index 4ca2af2c42e..f6bc063e745 100644 --- a/src/Core/Geometry/TopologicalMesh.inl +++ b/src/Core/Geometry/TopologicalMesh.inl @@ -284,7 +284,9 @@ void TopologicalMesh::initWithWedge( const TriangleMesh& triMesh, NonManifoldFac face_vhandles[j] = vh; if ( hasNormals ) face_normals[j] = triMesh.normals()[inMeshVertexIndex]; - face_wedges[j] = WedgeIndex {inMeshVertexIndex}; + face_wedges[j] = + WedgeIndex {static_cast( inMeshVertexIndex )}; + m_wedges.m_data[inMeshVertexIndex].getWedgeData().m_vertexHandle = vh; } // remove consecutive equal vertex @@ -372,6 +374,47 @@ void TopologicalMesh::initWithWedge( const TriangleMesh& triMesh, NonManifoldFac face_normals.clear(); } command.postProcess( *this ); + m_normalsIndex = m_wedges.getWedgeAttribIndex( "in_normal" ); + + m_faceVertexNormalWedges.clear(); + + for ( auto itr = vertices_begin(), stop = vertices_end(); itr != stop; ++itr ) + { + std::unordered_map, std::set>, + hash_vec> + newNormals; + + auto vh = *itr; + + for ( ConstVertexIHalfedgeIter vh_it = cvih_iter( vh ); vh_it.is_valid(); ++vh_it ) + { + const auto& widx = property( m_wedgeIndexPph, *vh_it ); + if ( widx.isValid() && !m_wedges.getWedge( widx ).isDeleted() ) + { + auto oldNormal = m_wedges.getWedgeData( widx, m_normalsIndex ); + newNormals[oldNormal].first.insert( face_handle( *vh_it ) ); + newNormals[oldNormal].second.insert( widx ); + } + } + + for ( const auto& pair : newNormals ) + { + for ( const auto& fh : pair.second.first ) + { + // std::cout << "( " << fh.idx() << ", " << vh.idx() << " ) : "; + auto& v = m_faceVertexNormalWedges[std::make_pair( fh, vh )]; + v.insert( v.end(), pair.second.second.begin(), pair.second.second.end() ); + // for ( auto widx : m_faceVertexNormalWedges[std::make_pair( fh, vh + // )] ) + // { + // + // std::cout << widx << " "; + // } + // std::cout << "\n"; + } + } + } LOG( logINFO ) << "TopologicalMesh: load end with " << m_wedges.size() << " wedges "; } @@ -509,9 +552,22 @@ TopologicalMesh::getVector4PropsHandles() const { inline void TopologicalMesh::updateWedgeNormals() { // - update_face_normals(); - auto normalsIndex = m_wedges.getWedgeAttribIndex( "in_normal" ); + // update_face_normals(); + FaceIter f_it( faces_sbegin() ), f_end( faces_end() ); + for ( ; f_it != f_end; ++f_it ) + { + auto fv_it = this->cfv_iter( *f_it ); + const auto& p0 = point( *fv_it ); + ++fv_it; + const auto& p1 = point( *fv_it ); + ++fv_it; + const auto& p2 = point( *fv_it ); + ++fv_it; + const Normal n = Ra::Core::Geometry::triangleNormal( p0, p1, p2 ); + set_normal( *f_it, n ); + } + /// \todo precompute this association, BUGGY FOR THE MOMENT for ( auto itr = vertices_begin(), stop = vertices_end(); itr != stop; ++itr ) { std::unordered_map( widx, normalsIndex ); + auto oldNormal = m_wedges.getWedgeData( widx, m_normalsIndex ); auto newNormal = normal( face_handle( *vh_it ) ); newNormals[oldNormal].first += newNormal; newNormals[oldNormal].second.insert( widx ); @@ -537,10 +593,34 @@ inline void TopologicalMesh::updateWedgeNormals() { pair.second.first /= pair.second.second.size(); for ( auto widx : pair.second.second ) { - m_wedges.setWedgeData( widx, normalsIndex, pair.first ); + m_wedges.setWedgeData( widx, m_normalsIndex, pair.first.normalized() ); } } } + /// THIS ONE IS BUGGY + /* + for ( auto& w : m_wedges.m_data ) + { + + w.getWedgeData().m_vector3Attrib[m_normalsIndex] = Normal {}; + } + for ( auto f_itr = faces_begin(), stop = faces_end(); f_itr != stop; ++f_itr ) + { + for ( auto fv_itr = cfv_iter( *f_itr ); fv_itr.is_valid(); ++fv_itr ) + { + for ( const auto& widx : m_faceVertexNormalWedges[std::make_pair( *f_itr, *fv_itr )] + ) + { + m_wedges.m_data[widx].getWedgeData().m_vector3Attrib[m_normalsIndex] += + normal( *fv_itr ); + } + } + } + for ( auto& w : m_wedges.m_data ) + { + w.getWedgeData().m_vector3Attrib[m_normalsIndex].normalize(); + } + */ } inline void TopologicalMesh::createNormalPropOnFaces( OpenMesh::FPropHandleT& fProp ) { From 1c442bca4046b8ee157e74782d1f1eae191f09ff Mon Sep 17 00:00:00 2001 From: dlyr Date: Fri, 26 Feb 2021 11:56:56 +0100 Subject: [PATCH 07/37] [core] Topo: move template specialization to the top. --- src/Core/Geometry/TopologicalMesh.inl | 213 ++++++++++++-------------- 1 file changed, 102 insertions(+), 111 deletions(-) diff --git a/src/Core/Geometry/TopologicalMesh.inl b/src/Core/Geometry/TopologicalMesh.inl index f6bc063e745..442a4042af3 100644 --- a/src/Core/Geometry/TopologicalMesh.inl +++ b/src/Core/Geometry/TopologicalMesh.inl @@ -9,6 +9,108 @@ namespace Ra { namespace Core { namespace Geometry { +//////////////////////////////////////////////////////////////////////////////// +/////////////////// WedgeData ////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +// return 1 : equals, 2: strict less, 3: strict greater +template +int TopologicalMesh::WedgeData::compareVector( const T& a, const T& b ) { + for ( int i = 0; i < T::RowsAtCompileTime; i++ ) + { + if ( a[i] < b[i] ) return 2; + if ( a[i] > b[i] ) return 3; + } + // (a == b) + return 1; +} + +inline bool TopologicalMesh::WedgeData::operator==( const TopologicalMesh::WedgeData& lhs ) const { + return + // do not have this yet, not sure we need to test them + // m_inputTriangleMeshIndex == lhs.m_inputTriangleMeshIndex && + // m_outputTriangleMeshIndex == lhs.m_outputTriangleMeshIndex && + m_position == lhs.m_position && m_floatAttrib == lhs.m_floatAttrib && + m_vector2Attrib == lhs.m_vector2Attrib && m_vector3Attrib == lhs.m_vector3Attrib && + m_vector4Attrib == lhs.m_vector4Attrib; +} + +inline bool TopologicalMesh::WedgeData::operator<( const TopologicalMesh::WedgeData& lhs ) const { + + CORE_ASSERT( ( m_floatAttrib.size() == lhs.m_floatAttrib.size() ) && + ( m_vector2Attrib.size() == lhs.m_vector2Attrib.size() ) && + ( m_vector3Attrib.size() == lhs.m_vector3Attrib.size() ) && + ( m_vector4Attrib.size() == lhs.m_vector4Attrib.size() ), + "Could only compare wedge with same number of attributes" ); + + { + int comp = compareVector( m_position, lhs.m_position ); + if ( comp == 2 ) return true; + if ( comp == 3 ) return false; + } + for ( size_t i = 0; i < m_floatAttrib.size(); i++ ) + { + if ( m_floatAttrib[i] < lhs.m_floatAttrib[i] ) + return true; + else if ( m_floatAttrib[i] > lhs.m_floatAttrib[i] ) + return false; + } + + for ( size_t i = 0; i < m_vector2Attrib.size(); i++ ) + { + int comp = compareVector( m_vector2Attrib[i], lhs.m_vector2Attrib[i] ); + if ( comp == 2 ) return true; + if ( comp == 3 ) return false; + } + for ( size_t i = 0; i < m_vector3Attrib.size(); i++ ) + { + int comp = compareVector( m_vector3Attrib[i], lhs.m_vector3Attrib[i] ); + if ( comp == 2 ) return true; + if ( comp == 3 ) return false; + } + for ( size_t i = 0; i < m_vector4Attrib.size(); i++ ) + { + int comp = compareVector( m_vector4Attrib[i], lhs.m_vector4Attrib[i] ); + if ( comp == 2 ) return true; + if ( comp == 3 ) return false; + } + return false; +} + +bool TopologicalMesh::WedgeData::operator!=( const TopologicalMesh::WedgeData& lhs ) const { + return !( *this == lhs ); +} + +#define GET_ATTRIB_ARRAY_HELPER( TYPE, NAME ) \ + template <> \ + inline VectorArray& TopologicalMesh::WedgeData::getAttribArray() { \ + return m_##NAME##Attrib; \ + } \ + template <> \ + inline const VectorArray& TopologicalMesh::WedgeData::getAttribArray() const { \ + return m_##NAME##Attrib; \ + } + +GET_ATTRIB_ARRAY_HELPER( float, float ) +GET_ATTRIB_ARRAY_HELPER( Vector2, vector2 ) +GET_ATTRIB_ARRAY_HELPER( Vector3, vector3 ) +GET_ATTRIB_ARRAY_HELPER( Vector4, vector4 ) +#undef GET_ATTRIB_ARRAY_HELPER + +template +inline VectorArray& TopologicalMesh::WedgeData::getAttribArray() { + static_assert( sizeof( T ) == -1, "this type is not supported" ); +} + +struct hash_vec { + std::size_t operator()( const Vector3& lvalue ) const { + size_t hx = std::hash()( lvalue[0] ); + size_t hy = std::hash()( lvalue[1] ); + size_t hz = std::hash()( lvalue[2] ); + return ( hx ^ ( hy << 1 ) ) ^ hz; + } +}; + template inline TopologicalMesh::TopologicalMesh( const TriangleMesh& triMesh, NonManifoldFaceCommand command ) : @@ -16,15 +118,6 @@ inline TopologicalMesh::TopologicalMesh( const TriangleMesh& triMesh, LOG( logINFO ) << "TopologicalMesh: load triMesh with " << triMesh.getIndices().size() << " faces and " << triMesh.vertices().size() << " vertices."; - - struct hash_vec { - size_t operator()( const Vector3& lvalue ) const { - size_t hx = std::hash()( lvalue[0] ); - size_t hy = std::hash()( lvalue[1] ); - size_t hz = std::hash()( lvalue[2] ); - return ( hx ^ ( hy << 1 ) ) ^ hz; - } - }; // use a hashmap for fast search of existing vertex position using VertexMap = std::unordered_map; VertexMap vertexHandles; @@ -210,15 +303,6 @@ void TopologicalMesh::initWithWedge( const TriangleMesh& triMesh, NonManifoldFac LOG( logINFO ) << "TopologicalMesh: load triMesh with " << triMesh.getIndices().size() << " faces and " << triMesh.vertices().size() << " vertices."; - ///\todo use a kdtree - struct hash_vec { - size_t operator()( const Vector3& lvalue ) const { - size_t hx = std::hash()( lvalue[0] ); - size_t hy = std::hash()( lvalue[1] ); - size_t hz = std::hash()( lvalue[2] ); - return ( hx ^ ( hy << 1 ) ) ^ hz; - } - }; // use a hashmap for fast search of existing vertex position using VertexMap = std::unordered_map; VertexMap vertexHandles; @@ -1116,99 +1200,6 @@ inline void TopologicalMesh::WedgeCollection::garbageCollection() { m_data.end() ); } -//////////////////////////////////////////////////////////////////////////////// -/////////////////// WedgeData ////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// - -// return 1 : equals, 2: strict less, 3: strict greater -template -int TopologicalMesh::WedgeData::compareVector( const T& a, const T& b ) { - for ( int i = 0; i < T::RowsAtCompileTime; i++ ) - { - if ( a[i] < b[i] ) return 2; - if ( a[i] > b[i] ) return 3; - } - // (a == b) - return 1; -} - -inline bool TopologicalMesh::WedgeData::operator==( const TopologicalMesh::WedgeData& lhs ) const { - return - // do not have this yet, not sure we need to test them - // m_inputTriangleMeshIndex == lhs.m_inputTriangleMeshIndex && - // m_outputTriangleMeshIndex == lhs.m_outputTriangleMeshIndex && - m_position == lhs.m_position && m_floatAttrib == lhs.m_floatAttrib && - m_vector2Attrib == lhs.m_vector2Attrib && m_vector3Attrib == lhs.m_vector3Attrib && - m_vector4Attrib == lhs.m_vector4Attrib; -} - -inline bool TopologicalMesh::WedgeData::operator<( const TopologicalMesh::WedgeData& lhs ) const { - - CORE_ASSERT( ( m_floatAttrib.size() == lhs.m_floatAttrib.size() ) && - ( m_vector2Attrib.size() == lhs.m_vector2Attrib.size() ) && - ( m_vector3Attrib.size() == lhs.m_vector3Attrib.size() ) && - ( m_vector4Attrib.size() == lhs.m_vector4Attrib.size() ), - "Could only compare wedge with same number of attributes" ); - - { - int comp = compareVector( m_position, lhs.m_position ); - if ( comp == 2 ) return true; - if ( comp == 3 ) return false; - } - for ( size_t i = 0; i < m_floatAttrib.size(); i++ ) - { - if ( m_floatAttrib[i] < lhs.m_floatAttrib[i] ) - return true; - else if ( m_floatAttrib[i] > lhs.m_floatAttrib[i] ) - return false; - } - - for ( size_t i = 0; i < m_vector2Attrib.size(); i++ ) - { - int comp = compareVector( m_vector2Attrib[i], lhs.m_vector2Attrib[i] ); - if ( comp == 2 ) return true; - if ( comp == 3 ) return false; - } - for ( size_t i = 0; i < m_vector3Attrib.size(); i++ ) - { - int comp = compareVector( m_vector3Attrib[i], lhs.m_vector3Attrib[i] ); - if ( comp == 2 ) return true; - if ( comp == 3 ) return false; - } - for ( size_t i = 0; i < m_vector4Attrib.size(); i++ ) - { - int comp = compareVector( m_vector4Attrib[i], lhs.m_vector4Attrib[i] ); - if ( comp == 2 ) return true; - if ( comp == 3 ) return false; - } - return false; -} - -bool TopologicalMesh::WedgeData::operator!=( const TopologicalMesh::WedgeData& lhs ) const { - return !( *this == lhs ); -} - -#define GET_ATTRIB_ARRAY_HELPER( TYPE, NAME ) \ - template <> \ - inline VectorArray& TopologicalMesh::WedgeData::getAttribArray() { \ - return m_##NAME##Attrib; \ - } \ - template <> \ - inline const VectorArray& TopologicalMesh::WedgeData::getAttribArray() const { \ - return m_##NAME##Attrib; \ - } - -GET_ATTRIB_ARRAY_HELPER( float, float ) -GET_ATTRIB_ARRAY_HELPER( Vector2, vector2 ) -GET_ATTRIB_ARRAY_HELPER( Vector3, vector3 ) -GET_ATTRIB_ARRAY_HELPER( Vector4, vector4 ) -#undef GET_ATTRIB_ARRAY_HELPER - -template -inline VectorArray& TopologicalMesh::WedgeData::getAttribArray() { - static_assert( sizeof( T ) == -1, "this type is not supported" ); -} - } // namespace Geometry } // namespace Core } // namespace Ra From 0877bbfd1a26d3e4773032355c22c13880981eb8 Mon Sep 17 00:00:00 2001 From: dlyr Date: Fri, 26 Feb 2021 11:57:13 +0100 Subject: [PATCH 08/37] [core] Topo/Core mesh "fast" updates. --- src/Core/Geometry/TopologicalMesh.cpp | 2 +- src/Core/Geometry/TopologicalMesh.inl | 68 +++++---------------------- 2 files changed, 14 insertions(+), 56 deletions(-) diff --git a/src/Core/Geometry/TopologicalMesh.cpp b/src/Core/Geometry/TopologicalMesh.cpp index 9bb53e4abb0..cb79010d9a1 100644 --- a/src/Core/Geometry/TopologicalMesh.cpp +++ b/src/Core/Geometry/TopologicalMesh.cpp @@ -464,7 +464,7 @@ void TopologicalMesh::updatePositions( #pragma omp parallel for for ( size_t i = 0; i < vertices.size(); ++i ) { - m_wedges.setWedgePosition( i, vertices[i] ); + m_wedges.m_data[i].getWedgeData().m_position = vertices[i]; point( m_wedges.m_data[i].getWedgeData().m_vertexHandle ) = vertices[i]; } } diff --git a/src/Core/Geometry/TopologicalMesh.inl b/src/Core/Geometry/TopologicalMesh.inl index 442a4042af3..ea25cafc53b 100644 --- a/src/Core/Geometry/TopologicalMesh.inl +++ b/src/Core/Geometry/TopologicalMesh.inl @@ -486,20 +486,11 @@ void TopologicalMesh::initWithWedge( const TriangleMesh& triMesh, NonManifoldFac { for ( const auto& fh : pair.second.first ) { - // std::cout << "( " << fh.idx() << ", " << vh.idx() << " ) : "; auto& v = m_faceVertexNormalWedges[std::make_pair( fh, vh )]; v.insert( v.end(), pair.second.second.begin(), pair.second.second.end() ); - // for ( auto widx : m_faceVertexNormalWedges[std::make_pair( fh, vh - // )] ) - // { - // - // std::cout << widx << " "; - // } - // std::cout << "\n"; } } } - LOG( logINFO ) << "TopologicalMesh: load end with " << m_wedges.size() << " wedges "; } @@ -651,60 +642,27 @@ inline void TopologicalMesh::updateWedgeNormals() { set_normal( *f_it, n ); } - /// \todo precompute this association, BUGGY FOR THE MOMENT - for ( auto itr = vertices_begin(), stop = vertices_end(); itr != stop; ++itr ) + for ( auto& w : m_wedges.m_data ) { - std::unordered_map>, - hash_vec> - newNormals; - - auto vh = *itr; + w.getWedgeData().m_vector3Attrib[m_normalsIndex] = Normal {0_ra, 0_ra, 0_ra}; + } - for ( ConstVertexIHalfedgeIter vh_it = cvih_iter( vh ); vh_it.is_valid(); ++vh_it ) - { - auto widx = property( m_wedgeIndexPph, *vh_it ); - if ( widx.isValid() && !m_wedges.getWedge( widx ).isDeleted() ) - { - auto oldNormal = m_wedges.getWedgeData( widx, m_normalsIndex ); - auto newNormal = normal( face_handle( *vh_it ) ); - newNormals[oldNormal].first += newNormal; - newNormals[oldNormal].second.insert( widx ); - } - } - for ( auto pair : newNormals ) + for ( auto v_itr = vertices_begin(), stop = vertices_end(); v_itr != stop; ++v_itr ) + { + for ( ConstVertexFaceIter f_itr = cvf_iter( *v_itr ); f_itr.is_valid(); ++f_itr ) { - pair.second.first /= pair.second.second.size(); - for ( auto widx : pair.second.second ) + for ( const auto& widx : m_faceVertexNormalWedges[std::make_pair( *f_itr, *v_itr )] ) { - m_wedges.setWedgeData( widx, m_normalsIndex, pair.first.normalized() ); + m_wedges.m_data[widx].getWedgeData().m_vector3Attrib[m_normalsIndex] += + normal( *f_itr ); } } } - /// THIS ONE IS BUGGY - /* - for ( auto& w : m_wedges.m_data ) - { - w.getWedgeData().m_vector3Attrib[m_normalsIndex] = Normal {}; - } - for ( auto f_itr = faces_begin(), stop = faces_end(); f_itr != stop; ++f_itr ) - { - for ( auto fv_itr = cfv_iter( *f_itr ); fv_itr.is_valid(); ++fv_itr ) - { - for ( const auto& widx : m_faceVertexNormalWedges[std::make_pair( *f_itr, *fv_itr )] - ) - { - m_wedges.m_data[widx].getWedgeData().m_vector3Attrib[m_normalsIndex] += - normal( *fv_itr ); - } - } - } - for ( auto& w : m_wedges.m_data ) - { - w.getWedgeData().m_vector3Attrib[m_normalsIndex].normalize(); - } - */ + for ( auto& w : m_wedges.m_data ) + { + w.getWedgeData().m_vector3Attrib[m_normalsIndex].normalize(); + } } inline void TopologicalMesh::createNormalPropOnFaces( OpenMesh::FPropHandleT& fProp ) { From f117a69f11eee29b33dd2105854a42565d535ed5 Mon Sep 17 00:00:00 2001 From: dlyr Date: Fri, 26 Feb 2021 12:19:25 +0100 Subject: [PATCH 09/37] [core] Topo/Core mesh updates: switch to vector when possible. --- src/Core/Geometry/TopologicalMesh.cpp | 6 +++ src/Core/Geometry/TopologicalMesh.hpp | 3 +- src/Core/Geometry/TopologicalMesh.inl | 56 +++++++++++++++------------ 3 files changed, 40 insertions(+), 25 deletions(-) diff --git a/src/Core/Geometry/TopologicalMesh.cpp b/src/Core/Geometry/TopologicalMesh.cpp index cb79010d9a1..0db9e0b09e6 100644 --- a/src/Core/Geometry/TopologicalMesh.cpp +++ b/src/Core/Geometry/TopologicalMesh.cpp @@ -419,6 +419,12 @@ void TopologicalMesh::updateTriangleMesh( Ra::Core::Geometry::TriangleMesh& out void TopologicalMesh::updateTriangleMeshNormals( AttribArrayGeometry::NormalAttribHandle::Container& normals ) { + if ( !has_halfedge_normals() ) + { + LOG( logERROR ) << "TopologicalMesh has no normals, nothing set"; + return; + } + #pragma omp parallel for for ( unsigned int widx = 0; widx < m_wedges.size(); ++widx ) { diff --git a/src/Core/Geometry/TopologicalMesh.hpp b/src/Core/Geometry/TopologicalMesh.hpp index ccc5302f580..95846b4f617 100644 --- a/src/Core/Geometry/TopologicalMesh.hpp +++ b/src/Core/Geometry/TopologicalMesh.hpp @@ -731,7 +731,8 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT> m_vec4Pph; int m_normalsIndex {-1}; - std::map, std::vector> m_faceVertexNormalWedges; + // vertex handle idx -> face handle idx -> wedge idx with the same normal + std::vector>> m_vertexFaceWedgesWithSameNormals; friend class TMOperations; }; diff --git a/src/Core/Geometry/TopologicalMesh.inl b/src/Core/Geometry/TopologicalMesh.inl index ea25cafc53b..e6b01791cbc 100644 --- a/src/Core/Geometry/TopologicalMesh.inl +++ b/src/Core/Geometry/TopologicalMesh.inl @@ -458,36 +458,40 @@ void TopologicalMesh::initWithWedge( const TriangleMesh& triMesh, NonManifoldFac face_normals.clear(); } command.postProcess( *this ); - m_normalsIndex = m_wedges.getWedgeAttribIndex( "in_normal" ); - - m_faceVertexNormalWedges.clear(); - - for ( auto itr = vertices_begin(), stop = vertices_end(); itr != stop; ++itr ) + if ( hasNormals ) { - std::unordered_map, std::set>, - hash_vec> - newNormals; + m_normalsIndex = m_wedges.getWedgeAttribIndex( "in_normal" ); - auto vh = *itr; + m_vertexFaceWedgesWithSameNormals.clear(); + m_vertexFaceWedgesWithSameNormals.resize( n_vertices() ); - for ( ConstVertexIHalfedgeIter vh_it = cvih_iter( vh ); vh_it.is_valid(); ++vh_it ) + for ( auto itr = vertices_begin(), stop = vertices_end(); itr != stop; ++itr ) { - const auto& widx = property( m_wedgeIndexPph, *vh_it ); - if ( widx.isValid() && !m_wedges.getWedge( widx ).isDeleted() ) + std::unordered_map, std::set>, + hash_vec> + normalSharedByWedges; + + auto vh = *itr; + + for ( ConstVertexIHalfedgeIter vh_it = cvih_iter( vh ); vh_it.is_valid(); ++vh_it ) { - auto oldNormal = m_wedges.getWedgeData( widx, m_normalsIndex ); - newNormals[oldNormal].first.insert( face_handle( *vh_it ) ); - newNormals[oldNormal].second.insert( widx ); + const auto& widx = property( m_wedgeIndexPph, *vh_it ); + if ( widx.isValid() && !m_wedges.getWedge( widx ).isDeleted() ) + { + auto oldNormal = m_wedges.getWedgeData( widx, m_normalsIndex ); + normalSharedByWedges[oldNormal].first.insert( face_handle( *vh_it ) ); + normalSharedByWedges[oldNormal].second.insert( widx ); + } } - } - for ( const auto& pair : newNormals ) - { - for ( const auto& fh : pair.second.first ) + for ( const auto& pair : normalSharedByWedges ) { - auto& v = m_faceVertexNormalWedges[std::make_pair( fh, vh )]; - v.insert( v.end(), pair.second.second.begin(), pair.second.second.end() ); + for ( const auto& fh : pair.second.first ) + { + auto& v = m_vertexFaceWedgesWithSameNormals[vh.idx()][fh.idx()]; + v.insert( v.end(), pair.second.second.begin(), pair.second.second.end() ); + } } } } @@ -626,7 +630,11 @@ TopologicalMesh::getVector4PropsHandles() const { } inline void TopologicalMesh::updateWedgeNormals() { - // + if ( !has_halfedge_normals() ) + { + LOG( logERROR ) << "TopologicalMesh has no normals, nothing set"; + return; + } // update_face_normals(); FaceIter f_it( faces_sbegin() ), f_end( faces_end() ); for ( ; f_it != f_end; ++f_it ) @@ -651,7 +659,7 @@ inline void TopologicalMesh::updateWedgeNormals() { { for ( ConstVertexFaceIter f_itr = cvf_iter( *v_itr ); f_itr.is_valid(); ++f_itr ) { - for ( const auto& widx : m_faceVertexNormalWedges[std::make_pair( *f_itr, *v_itr )] ) + for ( const auto& widx : m_vertexFaceWedgesWithSameNormals[v_itr->idx()][f_itr->idx()] ) { m_wedges.m_data[widx].getWedgeData().m_vector3Attrib[m_normalsIndex] += normal( *f_itr ); From ecc8bdec998561fd8608451d1314080e8353a630 Mon Sep 17 00:00:00 2001 From: dlyr Date: Wed, 17 Mar 2021 15:38:56 +0100 Subject: [PATCH 10/37] [core] Topo: make conversion from PolyMesh (wedges only). --- src/Core/Geometry/TopologicalMesh.cpp | 132 +++++++++++------------ src/Core/Geometry/TopologicalMesh.hpp | 43 ++++++-- src/Core/Geometry/TopologicalMesh.inl | 145 +++++++++++++++++--------- 3 files changed, 196 insertions(+), 124 deletions(-) diff --git a/src/Core/Geometry/TopologicalMesh.cpp b/src/Core/Geometry/TopologicalMesh.cpp index 0db9e0b09e6..8f99a557fdb 100644 --- a/src/Core/Geometry/TopologicalMesh.cpp +++ b/src/Core/Geometry/TopologicalMesh.cpp @@ -5,7 +5,6 @@ #include -#include #include #include @@ -164,33 +163,10 @@ void copyAttribToCore( TriangleMesh& triMesh, const HandleAndValueVector& dat } } -//! [Default command implementation] -struct DefaultNonManifoldFaceCommand { - /// \brief details string is printed along with the message - DefaultNonManifoldFaceCommand( std::string details = {} ) : m_details {details} {} - /// \brief Initalize with input Ra::Core::Geometry::TriangleMesh - inline void initialize( const TriangleMesh& /*triMesh*/ ) {} - /// \brief Process non-manifold face - inline void process( const std::vector& /*face_vhandles*/ ) { - LOG( logWARNING ) << "Invalid face handle returned : face not added " + m_details; - /// TODO memorize invalid faces for post processing ... - /// see - /// https://www.graphics.rwth-aachen.de/media/openflipper_static/Daily-Builds/Doc/Free/Developer/OBJImporter_8cc_source.html - /// for an exemple of loading - } - /// \brief If needed, apply post-processing on the Ra::Core::Geometry::TopologicalMesh - inline void postProcess( TopologicalMesh& /*tm*/ ) {} - //! [Default command implementation] - private: - std::string m_details; -}; - -void TopologicalMesh::initWithWedge( const TriangleMesh& triMesh ) { - initWithWedge( triMesh, DefaultNonManifoldFaceCommand( "[initWithWedges]" ) ); -} - TopologicalMesh::TopologicalMesh( const TriangleMesh& triMesh ) : - TopologicalMesh( triMesh, DefaultNonManifoldFaceCommand( "[default ctor (props)]" ) ) {} + TopologicalMesh( + triMesh, + DefaultNonManifoldFaceCommand( "[default ctor (props)]" ) ) {} TopologicalMesh::TopologicalMesh() { add_property( m_inputTriangleMeshIndexPph ); @@ -322,13 +298,13 @@ void copyWedgeDataToAttribContainer( AlignedStdVector::Contai } } -template -void moveContainerToMesh( TriangleMesh& out, +template +void moveContainerToMesh( IndexedGeometry& out, const std::vector& names, AlignedStdVector::Container>& wedgeAttribData ) { for ( size_t i = 0; i < wedgeAttribData.size(); ++i ) { - auto attrHandle = out.addAttrib( names[i] ); + auto attrHandle = out.template addAttrib( names[i] ); out.getAttrib( attrHandle ).setData( std::move( wedgeAttribData[i] ) ); } } @@ -388,6 +364,66 @@ TriangleMesh TopologicalMesh::toTriangleMeshFromWedges() { return out; } +PolyMesh TopologicalMesh::toPolyMeshFromWedges() { + // first cleanup deleted element + garbage_collection(); + + PolyMesh out; + PolyMesh::IndexContainerType indices; + + /// add attribs to out + std::vector> wedgeFloatAttribHandles; + std::vector> wedgeVector2AttribHandles; + std::vector> wedgeVector3AttribHandles; + std::vector> wedgeVector4AttribHandles; + + TriangleMesh::PointAttribHandle::Container wedgePosition; + AlignedStdVector::Container> wedgeFloatAttribData( + m_wedges.m_floatAttribNames.size() ); + AlignedStdVector::Container> wedgeVector2AttribData( + m_wedges.m_vector2AttribNames.size() ); + AlignedStdVector::Container> wedgeVector3AttribData( + m_wedges.m_vector3AttribNames.size() ); + AlignedStdVector::Container> wedgeVector4AttribData( + m_wedges.m_vector4AttribNames.size() ); + + /// Wedges are output vertices ! + for ( WedgeIndex widx {0}; widx < WedgeIndex( m_wedges.size() ); ++widx ) + { + const auto& wd = m_wedges.getWedgeData( widx ); + wedgePosition.push_back( wd.m_position ); + copyWedgeDataToAttribContainer( wedgeFloatAttribData, wd.m_floatAttrib ); + copyWedgeDataToAttribContainer( wedgeVector2AttribData, wd.m_vector2Attrib ); + copyWedgeDataToAttribContainer( wedgeVector3AttribData, wd.m_vector3Attrib ); + copyWedgeDataToAttribContainer( wedgeVector4AttribData, wd.m_vector4Attrib ); + } + + out.setVertices( std::move( wedgePosition ) ); + moveContainerToMesh( out, m_wedges.m_floatAttribNames, wedgeFloatAttribData ); + moveContainerToMesh( out, m_wedges.m_vector2AttribNames, wedgeVector2AttribData ); + moveContainerToMesh( out, m_wedges.m_vector3AttribNames, wedgeVector3AttribData ); + moveContainerToMesh( out, m_wedges.m_vector4AttribNames, wedgeVector4AttribData ); + + for ( TopologicalMesh::FaceIter f_it = faces_sbegin(); f_it != faces_end(); ++f_it ) + { + int i = 0; + PolyMesh::IndexType faceIndices( valence( *f_it ) ); + // iterator over vertex (through halfedge to get access to halfedge normals) + for ( TopologicalMesh::ConstFaceHalfedgeIter fh_it = cfh_iter( *f_it ); fh_it.is_valid(); + ++fh_it ) + { + faceIndices( i ) = property( m_wedgeIndexPph, *fh_it ); + i++; + } + // LOG( logDEBUG ) << "add polymesh face " << faceIndices.transpose(); + indices.push_back( faceIndices ); + } + + out.setIndices( std::move( indices ) ); + + return out; +} + void TopologicalMesh::updateTriangleMesh( Ra::Core::Geometry::TriangleMesh& out ) { TriangleMesh::PointAttribHandle::Container wedgePosition; AlignedStdVector::Container> wedgeFloatAttribData( @@ -1018,42 +1054,6 @@ void TopologicalMesh::delete_face( FaceHandle _fh, bool _delete_isolated_vertice base::delete_face( _fh, _delete_isolated_vertices ); } -void TopologicalMesh::InitWedgeProps::operator()( AttribBase* attr ) const { - if ( attr->getSize() != m_triMesh.vertices().size() ) - { LOG( logWARNING ) << "[TopologicalMesh] Skip badly sized attribute " << attr->getName(); } - else if ( attr->getName() != std::string( "in_position" ) ) - { - if ( attr->isFloat() ) - { - m_topo->m_wedges.m_wedgeFloatAttribHandles.push_back( - m_triMesh.getAttribHandle( attr->getName() ) ); - m_topo->m_wedges.addProp( attr->getName() ); - } - else if ( attr->isVector2() ) - { - m_topo->m_wedges.m_wedgeVector2AttribHandles.push_back( - m_triMesh.getAttribHandle( attr->getName() ) ); - m_topo->m_wedges.addProp( attr->getName() ); - } - else if ( attr->isVector3() ) - { - m_topo->m_wedges.m_wedgeVector3AttribHandles.push_back( - m_triMesh.getAttribHandle( attr->getName() ) ); - m_topo->m_wedges.addProp( attr->getName() ); - } - else if ( attr->isVector4() ) - { - m_topo->m_wedges.m_wedgeVector4AttribHandles.push_back( - m_triMesh.getAttribHandle( attr->getName() ) ); - m_topo->m_wedges.addProp( attr->getName() ); - } - else - LOG( logWARNING ) - << "Warning, mesh attribute " << attr->getName() - << " type is not supported (only float, vec2, vec3 nor vec4 are supported)"; - } -} - /////////////// WEDGES RELATED STUFF ///////////////// TopologicalMesh::WedgeIndex diff --git a/src/Core/Geometry/TopologicalMesh.hpp b/src/Core/Geometry/TopologicalMesh.hpp index 95846b4f617..1169a122e66 100644 --- a/src/Core/Geometry/TopologicalMesh.hpp +++ b/src/Core/Geometry/TopologicalMesh.hpp @@ -84,9 +84,11 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT - void initWithWedge( const Ra::Core::Geometry::TriangleMesh& triMesh, + + template + void initWithWedge( const Ra::Core::Geometry::IndexedGeometry& mesh ); + template + void initWithWedge( const Ra::Core::Geometry::IndexedGeometry& triMesh, NonManifoldFaceCommand command ); /** @@ -108,6 +110,7 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT + class InitWedgeProps { public: - InitWedgeProps( TopologicalMesh* topo, const TriangleMesh& triMesh ) : + InitWedgeProps( TopologicalMesh* topo, + const Ra::Core::Geometry::IndexedGeometry& triMesh ) : m_topo( topo ), m_triMesh( triMesh ) {} void operator()( AttribBase* attr ) const; private: TopologicalMesh* m_topo; - const TriangleMesh& m_triMesh; + const Ra::Core::Geometry::IndexedGeometry& m_triMesh; }; class WedgeCollection; @@ -682,13 +687,13 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT - inline void copyAttribToWedgeData( const TriangleMesh& mesh, + template + inline void copyAttribToWedgeData( const Ra::Core::Geometry::IndexedGeometry& mesh, unsigned int vindex, const std::vector>& attrHandleVec, VectorArray* to ); - - inline void copyMeshToWedgeData( const TriangleMesh& mesh, + template + inline void copyMeshToWedgeData( const Ra::Core::Geometry::IndexedGeometry& mesh, unsigned int vindex, const std::vector>& wprop_float, const std::vector>& wprop_vec2, @@ -735,6 +740,24 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT>> m_vertexFaceWedgesWithSameNormals; friend class TMOperations; + + //! [Default command implementation] + template + struct DefaultNonManifoldFaceCommand { + /// \brief details string is printed along with the message + DefaultNonManifoldFaceCommand( std::string details = {} ) : m_details {details} {} + /// \brief Initalize with input Ra::Core::Geometry::TriangleMesh + inline void initialize( const Ra::Core::Geometry::IndexedGeometry& ) {} + /// \brief Process non-manifold face + inline void process( const std::vector& /*face_vhandles*/ ) { + LOG( logWARNING ) << "Invalid face handle returned : face not added " + m_details; + } + /// \brief If needed, apply post-processing on the Ra::Core::Geometry::TopologicalMesh + inline void postProcess( TopologicalMesh& ) {} + //! [Default command implementation] + private: + std::string m_details; + }; }; // heplers diff --git a/src/Core/Geometry/TopologicalMesh.inl b/src/Core/Geometry/TopologicalMesh.inl index e6b01791cbc..53d61328ddc 100644 --- a/src/Core/Geometry/TopologicalMesh.inl +++ b/src/Core/Geometry/TopologicalMesh.inl @@ -8,6 +8,8 @@ namespace Ra { namespace Core { namespace Geometry { +template +using PropPair = std::pair, OpenMesh::HPropHandleT>; //////////////////////////////////////////////////////////////////////////////// /////////////////// WedgeData ////////////////////////////// @@ -123,9 +125,9 @@ inline TopologicalMesh::TopologicalMesh( const TriangleMesh& triMesh, VertexMap vertexHandles; std::vector> vprop_float; - std::vector, OpenMesh::HPropHandleT>> vprop_vec2; - std::vector, OpenMesh::HPropHandleT>> vprop_vec3; - std::vector, OpenMesh::HPropHandleT>> vprop_vec4; + std::vector> vprop_vec2; + std::vector> vprop_vec3; + std::vector> vprop_vec4; // loop over all attribs and build correspondance pair triMesh.vertexAttribs().for_each_attrib( @@ -152,7 +154,7 @@ inline TopologicalMesh::TopologicalMesh( const TriangleMesh& triMesh, // loop over all attribs and build correspondance pair triMesh.vertexAttribs().for_each_attrib( InitWedgeProps {this, triMesh} ); - size_t num_triangles = triMesh.getIndices().size(); + size_t num_faces = triMesh.getIndices().size(); command.initialize( triMesh ); @@ -163,16 +165,19 @@ inline TopologicalMesh::TopologicalMesh( const TriangleMesh& triMesh, release_vertex_normals(); release_halfedge_normals(); } - for ( unsigned int i = 0; i < num_triangles; i++ ) + + for ( unsigned int i = 0; i < num_faces; i++ ) { - std::vector face_vhandles( 3 ); - std::vector face_normals( 3 ); - std::vector face_vertexIndex( 3 ); - std::vector face_wedges( 3 ); - const auto& triangle = triMesh.getIndices()[i]; - for ( size_t j = 0; j < 3; ++j ) + const auto& face = triMesh.getIndices()[i]; + const size_t num_vert = face.size(); + std::vector face_vhandles( num_vert ); + std::vector face_normals( num_vert ); + std::vector face_vertexIndex( num_vert ); + std::vector face_wedges( num_vert ); + + for ( size_t j = 0; j < num_vert; ++j ) { - unsigned int inMeshVertexIndex = triangle[j]; + unsigned int inMeshVertexIndex = face[j]; const Vector3& p = triMesh.vertices()[inMeshVertexIndex]; typename VertexMap::iterator vtr = vertexHandles.find( p ); @@ -193,13 +198,13 @@ inline TopologicalMesh::TopologicalMesh( const TriangleMesh& triMesh, WedgeData wd; wd.m_position = p; - copyMeshToWedgeData( triMesh, - inMeshVertexIndex, - m_wedges.m_wedgeFloatAttribHandles, - m_wedges.m_wedgeVector2AttribHandles, - m_wedges.m_wedgeVector3AttribHandles, - m_wedges.m_wedgeVector4AttribHandles, - &wd ); + copyMeshToWedgeData( triMesh, + inMeshVertexIndex, + m_wedges.m_wedgeFloatAttribHandles, + m_wedges.m_wedgeVector2AttribHandles, + m_wedges.m_wedgeVector3AttribHandles, + m_wedges.m_wedgeVector4AttribHandles, + &wd ); face_wedges[j] = m_wedges.add( wd ); } @@ -297,35 +302,40 @@ inline TopologicalMesh::TopologicalMesh( const TriangleMesh& triMesh, garbage_collection(); } -template -void TopologicalMesh::initWithWedge( const TriangleMesh& triMesh, NonManifoldFaceCommand command ) { +template +void TopologicalMesh::initWithWedge( const IndexedGeometry& mesh ) { + initWithWedge( mesh, DefaultNonManifoldFaceCommand( "[initWithWedges]" ) ); +} - LOG( logINFO ) << "TopologicalMesh: load triMesh with " << triMesh.getIndices().size() - << " faces and " << triMesh.vertices().size() << " vertices."; +template +void TopologicalMesh::initWithWedge( const IndexedGeometry& mesh, + NonManifoldFaceCommand command ) { + LOG( logINFO ) << "TopologicalMesh: load mesh with " << mesh.getIndices().size() + << " faces and " << mesh.vertices().size() << " vertices."; // use a hashmap for fast search of existing vertex position using VertexMap = std::unordered_map; VertexMap vertexHandles; // loop over all attribs and build correspondance pair - triMesh.vertexAttribs().for_each_attrib( InitWedgeProps {this, triMesh} ); + mesh.vertexAttribs().for_each_attrib( InitWedgeProps {this, mesh} ); - size_t num_triangles = triMesh.getIndices().size(); + size_t num_triangles = mesh.getIndices().size(); - for ( size_t i = 0; i < triMesh.vertices().size(); ++i ) + for ( size_t i = 0; i < mesh.vertices().size(); ++i ) { // create an empty wedge, with 0 ref Wedge w; WedgeData wd; - wd.m_position = triMesh.vertices()[i]; - copyMeshToWedgeData( triMesh, - i, - m_wedges.m_wedgeFloatAttribHandles, - m_wedges.m_wedgeVector2AttribHandles, - m_wedges.m_wedgeVector3AttribHandles, - m_wedges.m_wedgeVector4AttribHandles, - &wd ); + wd.m_position = mesh.vertices()[i]; + copyMeshToWedgeData( mesh, + i, + m_wedges.m_wedgeFloatAttribHandles, + m_wedges.m_wedgeVector2AttribHandles, + m_wedges.m_wedgeVector3AttribHandles, + m_wedges.m_wedgeVector4AttribHandles, + &wd ); // here ref is not incremented w.setWedgeData( std::move( wd ) ); // the newly added wedge is not referenced yet, will be done with `newReference` when @@ -335,7 +345,7 @@ void TopologicalMesh::initWithWedge( const TriangleMesh& triMesh, NonManifoldFac LOG( logINFO ) << "TopologicalMesh: have " << m_wedges.size() << " wedges "; - const bool hasNormals = !triMesh.normals().empty(); + const bool hasNormals = !mesh.normals().empty(); if ( !hasNormals ) { release_face_normals(); @@ -343,18 +353,19 @@ void TopologicalMesh::initWithWedge( const TriangleMesh& triMesh, NonManifoldFac release_halfedge_normals(); } - command.initialize( triMesh ); + command.initialize( mesh ); for ( unsigned int i = 0; i < num_triangles; i++ ) { - std::vector face_vhandles( 3 ); - std::vector face_normals( 3 ); - std::vector face_wedges( 3 ); - const auto& triangle = triMesh.getIndices()[i]; + const auto& face = mesh.getIndices()[i]; + const size_t num_vert = face.size(); + std::vector face_vhandles( num_vert ); + std::vector face_normals( num_vert ); + std::vector face_wedges( num_vert ); - for ( size_t j = 0; j < 3; ++j ) + for ( size_t j = 0; j < num_vert; ++j ) { - unsigned int inMeshVertexIndex = triangle[j]; - const Vector3& p = triMesh.vertices()[inMeshVertexIndex]; + unsigned int inMeshVertexIndex = face[j]; + const Vector3& p = mesh.vertices()[inMeshVertexIndex]; typename VertexMap::iterator vtr = vertexHandles.find( p ); TopologicalMesh::VertexHandle vh; @@ -367,7 +378,7 @@ void TopologicalMesh::initWithWedge( const TriangleMesh& triMesh, NonManifoldFac { vh = vtr->second; } face_vhandles[j] = vh; - if ( hasNormals ) face_normals[j] = triMesh.normals()[inMeshVertexIndex]; + if ( hasNormals ) face_normals[j] = mesh.normals()[inMeshVertexIndex]; face_wedges[j] = WedgeIndex {static_cast( inMeshVertexIndex )}; m_wedges.m_data[inMeshVertexIndex].getWedgeData().m_vertexHandle = vh; @@ -498,14 +509,14 @@ void TopologicalMesh::initWithWedge( const TriangleMesh& triMesh, NonManifoldFac LOG( logINFO ) << "TopologicalMesh: load end with " << m_wedges.size() << " wedges "; } -template -void TopologicalMesh::copyAttribToWedgeData( const TriangleMesh& mesh, +template +void TopologicalMesh::copyAttribToWedgeData( const IndexedGeometry& mesh, unsigned int vindex, const std::vector>& attrHandleVec, VectorArray* to ) { for ( auto handle : attrHandleVec ) { - auto& attr = mesh.getAttrib( handle ); + auto& attr = mesh.template getAttrib( handle ); to->push_back( attr.data()[vindex] ); } } @@ -530,7 +541,8 @@ void TopologicalMesh::addAttribPairToTopo( const TriangleMesh& triMesh, } } -void TopologicalMesh::copyMeshToWedgeData( const TriangleMesh& mesh, +template +void TopologicalMesh::copyMeshToWedgeData( const IndexedGeometry& mesh, unsigned int vindex, const std::vector>& wprop_float, const std::vector>& wprop_vec2, @@ -1044,6 +1056,43 @@ TopologicalMesh::getWedgeIndexPph() const { return m_wedgeIndexPph; } +template +void TopologicalMesh::InitWedgeProps::operator()( AttribBase* attr ) const { + if ( attr->getSize() != m_triMesh.vertices().size() ) + { LOG( logWARNING ) << "[TopologicalMesh] Skip badly sized attribute " << attr->getName(); } + else if ( attr->getName() != std::string( "in_position" ) ) + { + if ( attr->isFloat() ) + { + m_topo->m_wedges.m_wedgeFloatAttribHandles.push_back( + m_triMesh.template getAttribHandle( attr->getName() ) ); + m_topo->m_wedges.addProp( attr->getName() ); + } + else if ( attr->isVector2() ) + { + m_topo->m_wedges.m_wedgeVector2AttribHandles.push_back( + m_triMesh.template getAttribHandle( attr->getName() ) ); + m_topo->m_wedges.addProp( attr->getName() ); + } + else if ( attr->isVector3() ) + { + m_topo->m_wedges.m_wedgeVector3AttribHandles.push_back( + m_triMesh.template getAttribHandle( attr->getName() ) ); + m_topo->m_wedges.addProp( attr->getName() ); + } + else if ( attr->isVector4() ) + { + m_topo->m_wedges.m_wedgeVector4AttribHandles.push_back( + m_triMesh.template getAttribHandle( attr->getName() ) ); + m_topo->m_wedges.addProp( attr->getName() ); + } + else + LOG( logWARNING ) + << "Warning, mesh attribute " << attr->getName() + << " type is not supported (only float, vec2, vec3 nor vec4 are supported)"; + } +} + //////////////////////////////////////////////////////////////////////////////// /////////////////// WEDGES RELATED STUFF ////////////////////////////// /////////////////// WedgeCollection ////////////////////////////// From 7396c613e9ade586a7141c5241619a13f1e970bc Mon Sep 17 00:00:00 2001 From: dlyr Date: Wed, 17 Mar 2021 15:38:37 +0100 Subject: [PATCH 11/37] [tests] Topo: make conversion from PolyMesh (wedges only). --- tests/unittest/Core/topomesh.cpp | 172 +++++++++++++++++++++++-------- 1 file changed, 129 insertions(+), 43 deletions(-) diff --git a/tests/unittest/Core/topomesh.cpp b/tests/unittest/Core/topomesh.cpp index de7522229a3..b32fb23b4a3 100644 --- a/tests/unittest/Core/topomesh.cpp +++ b/tests/unittest/Core/topomesh.cpp @@ -110,19 +110,21 @@ class WedgeDataAndIdx bool operator!=( const WedgeDataAndIdx& lhs ) const { return !( *this == lhs ); } }; -#define COPY_TO_WEDGES_VECTOR_HELPER( UPTYPE, REALTYPE ) \ - if ( attr->is##UPTYPE() ) \ - { \ - auto data = \ - meshOne.getAttrib( meshOne.getAttribHandle( attr->getName() ) ).data(); \ - for ( size_t i = 0; i < size; ++i ) \ - { \ - wedgesMeshOne[i].m_data.getAttribArray().push_back( data[i] ); \ - } \ +#define COPY_TO_WEDGES_VECTOR_HELPER( UPTYPE, REALTYPE ) \ + if ( attr->is##UPTYPE() ) \ + { \ + auto data = \ + meshOne.getAttrib( meshOne.template getAttribHandle( attr->getName() ) ) \ + .data(); \ + for ( size_t i = 0; i < size; ++i ) \ + { \ + wedgesMeshOne[i].m_data.getAttribArray().push_back( data[i] ); \ + } \ } +template void copyToWedgesVector( size_t size, - const TriangleMesh& meshOne, + const IndexedGeometry& meshOne, AlignedStdVector& wedgesMeshOne, AttribBase* attr ) { @@ -140,6 +142,7 @@ void copyToWedgesVector( size_t size, wedgesMeshOne[i].m_data.m_position = data[i]; } } + COPY_TO_WEDGES_VECTOR_HELPER( Float, float ); COPY_TO_WEDGES_VECTOR_HELPER( Vector2, Vector2 ); COPY_TO_WEDGES_VECTOR_HELPER( Vector3, Vector3 ); @@ -148,13 +151,18 @@ void copyToWedgesVector( size_t size, } #undef COPY_TO_WEDGES_VECTOR_HELPER -bool isSameMeshWedge( const Ra::Core::Geometry::TriangleMesh& meshOne, - const Ra::Core::Geometry::TriangleMesh& meshTwo ) { +template +bool isSameMeshWedge( const Ra::Core::Geometry::IndexedGeometry& meshOne, + const Ra::Core::Geometry::IndexedGeometry& meshTwo ) { using namespace Ra::Core; using namespace Ra::Core::Geometry; // Check length + // LOG( logDEBUG ) << meshOne.vertices().size() << " / " << meshTwo.vertices().size(); + // LOG( logDEBUG ) << meshOne.normals().size() << " / " << meshTwo.normals().size(); + // LOG( logDEBUG ) << meshOne.getIndices().size() << " / " << meshTwo.getIndices().size(); + if ( meshOne.vertices().size() != meshTwo.vertices().size() ) return false; if ( meshOne.normals().size() != meshTwo.normals().size() ) return false; if ( meshOne.getIndices().size() != meshTwo.getIndices().size() ) return false; @@ -171,22 +179,28 @@ bool isSameMeshWedge( const Ra::Core::Geometry::TriangleMesh& meshOne, wedgesMeshTwo.push_back( wd ); } using namespace std::placeholders; - auto f1 = - std::bind( copyToWedgesVector, size, std::cref( meshOne ), std::ref( wedgesMeshOne ), _1 ); + auto f1 = std::bind( + copyToWedgesVector, size, std::cref( meshOne ), std::ref( wedgesMeshOne ), _1 ); meshOne.vertexAttribs().for_each_attrib( f1 ); - auto f2 = - std::bind( copyToWedgesVector, size, std::cref( meshTwo ), std::ref( wedgesMeshTwo ), _1 ); + auto f2 = std::bind( + copyToWedgesVector, size, std::cref( meshTwo ), std::ref( wedgesMeshTwo ), _1 ); meshTwo.vertexAttribs().for_each_attrib( f2 ); std::sort( wedgesMeshOne.begin(), wedgesMeshOne.end() ); std::sort( wedgesMeshTwo.begin(), wedgesMeshTwo.end() ); - if ( wedgesMeshOne != wedgesMeshTwo ) return false; + if ( wedgesMeshOne != wedgesMeshTwo ) + { + // LOG( logDEBUG ) << "not same wedges"; + return false; + } std::vector newMeshOneIdx( wedgesMeshOne.size() ); std::vector newMeshTwoIdx( wedgesMeshOne.size() ); - size_t curIdx = 0; + + size_t curIdx = 0; + newMeshOneIdx[wedgesMeshOne[0].m_idx] = 0; newMeshTwoIdx[wedgesMeshTwo[0].m_idx] = 0; @@ -194,31 +208,50 @@ bool isSameMeshWedge( const Ra::Core::Geometry::TriangleMesh& meshOne, { if ( wedgesMeshOne[i] != wedgesMeshOne[i - 1] ) ++curIdx; newMeshOneIdx[wedgesMeshOne[i].m_idx] = curIdx; + // std::cout << wedgesMeshOne[i].m_idx << " : " << curIdx << "\n"; } - + // std::cout << "***\n"; curIdx = 0; for ( size_t i = 1; i < wedgesMeshTwo.size(); ++i ) { if ( wedgesMeshTwo[i] != wedgesMeshTwo[i - 1] ) ++curIdx; newMeshTwoIdx[wedgesMeshTwo[i].m_idx] = curIdx; + // std::cout << wedgesMeshTwo[i].m_idx << " : " << curIdx << "\n"; } - auto indices1 = meshOne.getIndices(); - auto indices2 = meshTwo.getIndices(); + typename Ra::Core::Geometry::IndexedGeometry::IndexContainerType indices1 = + meshOne.getIndices(); + typename Ra::Core::Geometry::IndexedGeometry::IndexContainerType indices2 = + meshTwo.getIndices(); - for ( auto& triangle : indices1 ) + for ( auto& face : indices1 ) + { + // std::cout << "face "; + for ( int i = 0; i < face.size(); ++i ) + { + face( i ) = newMeshOneIdx[face( i )]; + // std::cout << face( i ) << " "; + } + // std::cout << "\n"; + } + // std::cout << "***\n"; + for ( auto& face : indices2 ) { - triangle[0] = newMeshOneIdx[triangle[0]]; - triangle[1] = newMeshOneIdx[triangle[1]]; - triangle[2] = newMeshOneIdx[triangle[2]]; + + // std::cout << "face "; + for ( int i = 0; i < face.size(); ++i ) + { + face( i ) = newMeshTwoIdx[face( i )]; + // std::cout << face( i ) << " "; + } + // std::cout << "\n"; } - for ( auto& triangle : indices2 ) + if ( indices1 != indices2 ) { - triangle[0] = newMeshTwoIdx[triangle[0]]; - triangle[1] = newMeshTwoIdx[triangle[1]]; - triangle[2] = newMeshTwoIdx[triangle[2]]; + // LOG( logDEBUG ) << "not same indices"; + return false; } - return indices1 == indices2; + return true; } TEST_CASE( "Core/Geometry/TopologicalMesh", "[Core][Core/Geometry][TopologicalMesh]" ) { @@ -518,6 +551,67 @@ void test_split( TopologicalMesh& topo, TopologicalMesh::EdgeHandle eh, float f REQUIRE( Math::areApproxEqual( ( psplit - wd.m_position ).squaredNorm(), 0.f ) ); } +void test_poly() { + Ra::Core::Geometry::PolyMesh polyMesh; + polyMesh.setVertices( { + // quad + {-1.1_ra, -0_ra, 0_ra}, + {1.1_ra, -0_ra, 0_ra}, + {1_ra, 1_ra, 0_ra}, + {-1_ra, 1_ra, 0_ra}, + // hepta + {2_ra, 2_ra, 0_ra}, + {2_ra, 3_ra, 0_ra}, + {0_ra, 4_ra, 0_ra}, + {-2_ra, 3_ra, 0_ra}, + {-2_ra, 2_ra, 0_ra}, + // degen + {-1.1_ra, -2_ra, 0_ra}, + {-0.5_ra, -2_ra, 0_ra}, + {-0.3_ra, -2_ra, 0_ra}, + {0.0_ra, -2_ra, 0_ra}, + {0.001_ra, -2_ra, 0_ra}, + {0.3_ra, -2_ra, 0_ra}, + {0.5_ra, -2_ra, 0_ra}, + {1.1_ra, -2_ra, 0_ra}, + // degen2 + {-1_ra, -3_ra, 0_ra}, + {1_ra, -3_ra, 0_ra}, + + } ); + + Vector3Array normals; + normals.resize( polyMesh.vertices().size() ); + std::transform( + polyMesh.vertices().cbegin(), + polyMesh.vertices().cend(), + normals.begin(), + []( const Vector3& v ) { return ( v + Vector3( 0_ra, 0_ra, 1_ra ) ).normalized(); } ); + polyMesh.setNormals( normals ); + + auto quad = VectorNui( 4 ); + quad << 0, 1, 2, 3; + auto hepta = VectorNui( 7 ); + hepta << 3, 2, 4, 5, 6, 7, 8; + auto degen = VectorNui( 10 ); + degen << 1, 0, 9, 10, 11, 12, 13, 14, 15, 16; + auto degen2 = VectorNui( 10 ); + degen2 << 14, 13, 12, 11, 10, 9, 17, 18, 16, 15; + polyMesh.setIndices( {quad, hepta, degen, degen2} ); + + TopologicalMesh topologicalMesh; + + topologicalMesh.initWithWedge( polyMesh ); + auto newMesh = topologicalMesh.toPolyMeshFromWedges(); + REQUIRE( isSameMeshWedge( newMesh, polyMesh ) ); +} + +TEST_CASE( "Core/Geometry/TopologicalMesh/PolyMesh", + "[Core][Core/Geometry][TopologicalMesh][PolyMesh]" ) { + + test_poly(); +} + /// \todo TEST_CASE( "Core/Geometry/TopologicalMesh/Subdivider", /// "[Core][Core/Geometry][TopologicalMesh]" ) { // using Catmull = @@ -569,15 +663,12 @@ TEST_CASE( "Core/Geometry/TopologicalMesh/Manifold", "[Core][Core/Geometry][Topo SECTION( "Non manifold faces" ) { struct MyNonManifoldCommand { inline MyNonManifoldCommand( int target ) : targetNonManifoldFaces( target ) {} - inline void initialize( const TriangleMesh& /*triMesh*/ ) {} - inline void - process( const std::vector& /*face_vhandles*/ ) { + inline void initialize( const IndexedGeometry& ) {} + inline void process( const std::vector& ) { LOG( logINFO ) << "Non Manifold face found"; nonManifoldFaces++; } - inline void postProcess( TopologicalMesh& /*tm*/ ) { - // Todo : For each non manifold face, remove the vertices that are not part of a - // face of the topomesh For the test, this will reduce the mesh_2 to mesh1 + inline void postProcess( TopologicalMesh& ) { REQUIRE( nonManifoldFaces == targetNonManifoldFaces ); LOG( logINFO ) << "Process non-manifold faces"; } @@ -727,17 +818,12 @@ TEST_CASE( "Core/Geometry/TopologicalMesh/Manifold", "[Core][Core/Geometry][Topo inline MyNonManifoldCommand( std::vector>& faulty ) : m_faulty( faulty ) {} - inline void initialize( const TriangleMesh& /*triMesh*/ ) {} + inline void initialize( const IndexedGeometry& ) {} inline void process( const std::vector& face_vhandles ) { - LOG( logINFO ) << "Non Manifold face found"; m_faulty.push_back( face_vhandles ); nonManifoldFaces++; } - inline void postProcess( TopologicalMesh& /*tm*/ ) { - // Todo : For each non manifold face, remove the vertices that are not part of a - // face of the topomesh For the test, this will reduce the mesh_2 to mesh1 - LOG( logINFO ) << "Process non-manifold faces"; - } + inline void postProcess( TopologicalMesh& ) {} std::vector>& m_faulty; int nonManifoldFaces {0}; }; From d8758a57695c8f488477dfe7fd9231f827d9fc61 Mon Sep 17 00:00:00 2001 From: dlyr Date: Fri, 17 Jul 2020 22:36:23 +0200 Subject: [PATCH 12/37] [tests] Remove deprecated topo tests. remove deprecated tests on normals --- tests/unittest/Core/topomesh.cpp | 110 ++++--------------------------- 1 file changed, 12 insertions(+), 98 deletions(-) diff --git a/tests/unittest/Core/topomesh.cpp b/tests/unittest/Core/topomesh.cpp index b32fb23b4a3..29a4ff2a08a 100644 --- a/tests/unittest/Core/topomesh.cpp +++ b/tests/unittest/Core/topomesh.cpp @@ -260,21 +260,10 @@ TEST_CASE( "Core/Geometry/TopologicalMesh", "[Core][Core/Geometry][TopologicalMe using Ra::Core::Geometry::TriangleMesh; auto testConverter = []( const TriangleMesh& mesh ) { - auto topologicalMesh = TopologicalMesh( mesh ); - auto topologicalMeshWedge = TopologicalMesh {}; - topologicalMeshWedge.initWithWedge( mesh ); - auto newMeshWedge = topologicalMesh.toTriangleMeshFromWedges(); - auto newMesh = topologicalMesh.toTriangleMesh(); - auto newMeshWedgeWedge = topologicalMeshWedge.toTriangleMeshFromWedges(); - auto newMeshWedgeWithout = topologicalMeshWedge.toTriangleMesh(); + auto topologicalMesh = TopologicalMesh( mesh ); + auto newMesh = topologicalMesh.toTriangleMesh(); REQUIRE( isSameMesh( mesh, newMesh ) ); - REQUIRE( isSameMesh( mesh, newMeshWedge ) ); - REQUIRE( isSameMesh( mesh, newMeshWedgeWedge ) ); - REQUIRE( isSameMesh( mesh, newMeshWedgeWithout ) ); - REQUIRE( isSameMeshWedge( mesh, newMeshWedge ) ); - REQUIRE( isSameMeshWedge( mesh, newMeshWedgeWedge ) ); REQUIRE( topologicalMesh.checkIntegrity() ); - REQUIRE( topologicalMeshWedge.checkIntegrity() ); }; SECTION( "Closed mesh" ) { @@ -334,53 +323,22 @@ TEST_CASE( "Core/Geometry/TopologicalMesh", "[Core][Core/Geometry][TopologicalMe attrib4.unlock(); attrib5.unlock(); - auto topologicalMesh = TopologicalMesh( mesh ); - auto topologicalMeshWedge = TopologicalMesh {}; - topologicalMeshWedge.initWithWedge( mesh ); - auto newMesh = topologicalMesh.toTriangleMesh(); - auto newMeshWedge = topologicalMesh.toTriangleMeshFromWedges(); - auto newMeshWedgeWedge = topologicalMeshWedge.toTriangleMeshFromWedges(); - auto newMeshWedgeWithout = topologicalMeshWedge.toTriangleMesh(); + auto topologicalMesh = TopologicalMesh( mesh ); + auto newMesh = topologicalMesh.toTriangleMesh(); REQUIRE( isSameMesh( mesh, newMesh ) ); - REQUIRE( isSameMesh( mesh, newMeshWedge ) ); - REQUIRE( isSameMesh( mesh, newMeshWedgeWedge ) ); - REQUIRE( isSameMesh( mesh, newMeshWedgeWithout ) ); - REQUIRE( isSameMeshWedge( mesh, newMeshWedge ) ); - REQUIRE( isSameMeshWedge( mesh, newMeshWedgeWedge ) ); REQUIRE( topologicalMesh.checkIntegrity() ); - REQUIRE( topologicalMeshWedge.checkIntegrity() ); // oversize attrib not suported REQUIRE( !newMesh.hasAttrib( "vector5_attrib" ) ); - REQUIRE( !newMeshWedge.hasAttrib( "vector5_attrib" ) ); - REQUIRE( !newMeshWedgeWedge.hasAttrib( "vector5_attrib" ) ); - REQUIRE( !newMeshWedgeWithout.hasAttrib( "vector5_attrib" ) ); REQUIRE( newMesh.hasAttrib( "vector2_attrib" ) ); - REQUIRE( newMeshWedge.hasAttrib( "vector2_attrib" ) ); - REQUIRE( newMeshWedgeWedge.hasAttrib( "vector2_attrib" ) ); REQUIRE( newMesh.hasAttrib( "vector4_attrib" ) ); - REQUIRE( newMeshWedge.hasAttrib( "vector4_attrib" ) ); - REQUIRE( newMeshWedgeWedge.hasAttrib( "vector4_attrib" ) ); - - // When init with wedge, and converted from propos (without wedges) wedge, attribs are lost. - REQUIRE( !newMeshWedgeWithout.hasAttrib( "vector2_attrib" ) ); - REQUIRE( !newMeshWedgeWithout.hasAttrib( "vector4_attrib" ) ); // empty attrib not converted REQUIRE( !newMesh.hasAttrib( "evector2_attrib" ) ); - REQUIRE( !newMeshWedge.hasAttrib( "evector2_attrib" ) ); - REQUIRE( !newMeshWedgeWedge.hasAttrib( "veector2_attrib" ) ); - REQUIRE( !newMeshWedgeWithout.hasAttrib( "veector2_attrib" ) ); REQUIRE( !newMesh.hasAttrib( "evector4_attrib" ) ); - REQUIRE( !newMeshWedge.hasAttrib( "evector4_attrib" ) ); - REQUIRE( !newMeshWedgeWedge.hasAttrib( "veector4_attrib" ) ); - REQUIRE( !newMeshWedgeWithout.hasAttrib( "veector4_attrib" ) ); REQUIRE( !newMesh.hasAttrib( "evector5_attrib" ) ); - REQUIRE( !newMeshWedge.hasAttrib( "evector5_attrib" ) ); - REQUIRE( !newMeshWedgeWedge.hasAttrib( "evector5_attrib" ) ); - REQUIRE( !newMeshWedgeWithout.hasAttrib( "evector5_attrib" ) ); } SECTION( "Edit topo mesh" ) { @@ -388,14 +346,11 @@ TEST_CASE( "Core/Geometry/TopologicalMesh", "[Core][Core/Geometry][TopologicalMe auto topologicalMesh = TopologicalMesh( mesh ); auto newMesh = topologicalMesh.toTriangleMesh(); - auto newMesh2 = topologicalMesh.toTriangleMeshFromWedges(); topologicalMesh.setWedgeData( TopologicalMesh::WedgeIndex {0}, "in_normal", Vector3( 0, 0, 0 ) ); - auto newMesh3 = topologicalMesh.toTriangleMeshFromWedges(); + auto newMesh3 = topologicalMesh.toTriangleMesh(); REQUIRE( isSameMesh( mesh, newMesh ) ); - REQUIRE( isSameMesh( mesh, newMesh2 ) ); - REQUIRE( isSameMeshWedge( mesh, newMesh2 ) ); REQUIRE( !isSameMeshWedge( mesh, newMesh3 ) ); REQUIRE( topologicalMesh.checkIntegrity() ); } @@ -403,19 +358,14 @@ TEST_CASE( "Core/Geometry/TopologicalMesh", "[Core][Core/Geometry][TopologicalMe SECTION( "Test skip empty attributes" ) { auto mesh = Ra::Core::Geometry::makeCylinder( Vector3( 0, 0, 0 ), Vector3( 0, 0, 1 ), 1 ); mesh.addAttrib( "empty" ); - auto topologicalMesh = TopologicalMesh( mesh ); - auto topologicalMeshWedge = TopologicalMesh {}; - topologicalMeshWedge.initWithWedge( mesh ); - auto newMesh = topologicalMesh.toTriangleMesh(); - auto newMeshWedge = topologicalMesh.toTriangleMeshFromWedges(); - auto newMeshWedgeWedge = topologicalMeshWedge.toTriangleMeshFromWedges(); + auto topologicalMesh = TopologicalMesh( mesh ); + auto newMesh = topologicalMesh.toTriangleMesh(); REQUIRE( !newMesh.hasAttrib( "empty" ) ); - REQUIRE( !newMeshWedge.hasAttrib( "empty" ) ); - REQUIRE( !newMeshWedgeWedge.hasAttrib( "empty" ) ); REQUIRE( topologicalMesh.checkIntegrity() ); - REQUIRE( topologicalMeshWedge.checkIntegrity() ); } + /// \todo update to wedges + /* SECTION( "Test normals" ) { auto mesh = Ra::Core::Geometry::makeBox(); auto topologicalMesh = TopologicalMesh( mesh ); @@ -450,7 +400,7 @@ TEST_CASE( "Core/Geometry/TopologicalMesh", "[Core][Core/Geometry][TopologicalMe REQUIRE( check2 ); REQUIRE( topologicalMesh.checkIntegrity() ); } - + */ SECTION( "Test without normals" ) { VectorArray vertices = { {0_ra, 0_ra, 0_ra}, {0_ra, 1_ra, 0_ra}, {1_ra, 1_ra, 0_ra}, {1_ra, 0_ra, 0_ra}}; @@ -461,14 +411,8 @@ TEST_CASE( "Core/Geometry/TopologicalMesh", "[Core][Core/Geometry][TopologicalMe mesh.setVertices( std::move( vertices ) ); mesh.setIndices( std::move( indices ) ); TopologicalMesh topo1 {mesh}; - TopologicalMesh topo2; - topo2.initWithWedge( mesh ); - REQUIRE( topo1.checkIntegrity() ); - REQUIRE( topo2.checkIntegrity() ); - TriangleMesh mesh1 = topo1.toTriangleMesh(); - TriangleMesh mesh2 = topo2.toTriangleMeshFromWedges(); // there is no normals at all. REQUIRE( !topo1.has_halfedge_normals() ); @@ -489,26 +433,11 @@ TEST_CASE( "Core/Geometry/TopologicalMesh", "[Core][Core/Geometry][TopologicalMe // nor on faces nor if we try to create them REQUIRE( !topo1.has_face_normals() ); OpenMesh::FPropHandleT fProp; - topo1.createNormalPropOnFaces( fProp ); - auto vh = *topo1.vertices_begin(); - auto he1 = topo1.halfedge_handle( vh ); - auto he2 = topo1.next_halfedge_handle( he1 ); - auto fh = topo1.face_handle( he1 ); - REQUIRE( !fProp.is_valid() ); - REQUIRE( !topo1.has_face_normals() ); - // even if we try to copy them, but no access error - topo1.copyNormal( he1, he2 ); - topo1.copyNormalFromFace( fh, he1, fProp ); - topo1.interpolateNormalOnFaces( fh, fProp ); - REQUIRE( !topo1.has_halfedge_normals() ); REQUIRE( mesh.vertexAttribs().hasSameAttribs( mesh1.vertexAttribs() ) ); - REQUIRE( mesh.vertexAttribs().hasSameAttribs( mesh2.vertexAttribs() ) ); REQUIRE( isSameMesh( mesh, mesh1 ) ); - REQUIRE( isSameMesh( mesh, mesh2 ) ); REQUIRE( mesh1.normals().size() == 0 ); - REQUIRE( mesh2.normals().size() == 0 ); } } @@ -600,7 +529,6 @@ void test_poly() { polyMesh.setIndices( {quad, hepta, degen, degen2} ); TopologicalMesh topologicalMesh; - topologicalMesh.initWithWedge( polyMesh ); auto newMesh = topologicalMesh.toPolyMeshFromWedges(); REQUIRE( isSameMeshWedge( newMesh, polyMesh ) ); @@ -701,25 +629,12 @@ TEST_CASE( "Core/Geometry/TopologicalMesh/Manifold", "[Core][Core/Geometry][Topo MyNonManifoldCommand command ) { // test with functor TopologicalMesh topoWithCommand {candidateMesh, command}; - TopologicalMesh topoWedgeWithCommand; - topoWedgeWithCommand.initWithWedge( candidateMesh, command ); - auto convertedMeshWithCommand = topoWithCommand.toTriangleMesh(); - auto convertedMeshWithCommandFromWedge = topoWithCommand.toTriangleMeshFromWedges(); - auto convertedMeshWedgeWithCommand = topoWedgeWithCommand.toTriangleMeshFromWedges(); + auto convertedMeshWithCommand = topoWithCommand.toTriangleMesh(); REQUIRE( isSameMesh( referenceMesh, convertedMeshWithCommand ) ); - REQUIRE( isSameMesh( referenceMesh, convertedMeshWedgeWithCommand ) ); - REQUIRE( isSameMesh( referenceMesh, convertedMeshWithCommandFromWedge ) ); // test without functor TopologicalMesh topoWithoutCommand {candidateMesh}; - TopologicalMesh topoWedgeWithoutCommand {}; - topoWedgeWithoutCommand.initWithWedge( candidateMesh ); auto convertedMeshWithoutCommand = topoWithoutCommand.toTriangleMesh(); - auto convertedMeshWithoutCommandFromWedge = - topoWithoutCommand.toTriangleMeshFromWedges(); - auto convertedMeshWedgeWithoutCommand = topoWedgeWithoutCommand.toTriangleMesh(); REQUIRE( isSameMesh( referenceMesh, convertedMeshWithoutCommand ) ); - REQUIRE( isSameMesh( referenceMesh, convertedMeshWedgeWithoutCommand ) ); - REQUIRE( isSameMesh( referenceMesh, convertedMeshWithoutCommandFromWedge ) ); return convertedMeshWithoutCommand; }; @@ -913,8 +828,7 @@ TEST_CASE( "Core/Geometry/TopologicalMesh/Initialization", TEST_CASE( "Core/Geometry/TopologicalMesh/MergeWedges", "[Core][Core/Geometry][TopologicalMesh]" ) { auto mesh = Ra::Core::Geometry::makeSharpBox(); - auto topo = TopologicalMesh {}; - topo.initWithWedge( mesh ); + auto topo = TopologicalMesh {mesh}; std::set wedgesIndices; for ( auto itr = topo.halfedges_begin(), stop = topo.halfedges_end(); itr != stop; ++itr ) From 1ae0187a61ef098d48b069f124010da4f50bc50d Mon Sep 17 00:00:00 2001 From: dlyr Date: Wed, 17 Mar 2021 15:51:49 +0100 Subject: [PATCH 13/37] [core] huge remove of deprecated, need to update tests. --- src/Core/Geometry/CatmullClarkSubdivider.cpp | 28 +- src/Core/Geometry/LoopSubdivider.cpp | 12 +- src/Core/Geometry/TopologicalMesh.cpp | 291 +---------- src/Core/Geometry/TopologicalMesh.hpp | 201 -------- src/Core/Geometry/TopologicalMesh.inl | 486 +------------------ 5 files changed, 23 insertions(+), 995 deletions(-) diff --git a/src/Core/Geometry/CatmullClarkSubdivider.cpp b/src/Core/Geometry/CatmullClarkSubdivider.cpp index 9b04d269e8e..7d3d5e393ec 100644 --- a/src/Core/Geometry/CatmullClarkSubdivider.cpp +++ b/src/Core/Geometry/CatmullClarkSubdivider.cpp @@ -9,8 +9,7 @@ bool CatmullClarkSubdivider::prepare( TopologicalMesh& mesh ) { mesh.add_property( m_epH ); mesh.add_property( m_fpH ); mesh.add_property( m_creaseWeights ); - mesh.createAllPropsOnFaces( - m_normalPropF, m_floatPropsF, m_vec2PropsF, m_vec3PropsF, m_vec4PropsF ); + ///\todo mesh.createAllPropsOnFaces( m_normalPropF ); mesh.add_property( m_hV ); for ( uint i = 0; i < mesh.n_halfedges(); ++i ) { @@ -30,7 +29,7 @@ bool CatmullClarkSubdivider::cleanup( TopologicalMesh& mesh ) { mesh.remove_property( m_epH ); mesh.remove_property( m_fpH ); mesh.remove_property( m_creaseWeights ); - mesh.clearAllProps( m_normalPropF, m_floatPropsF, m_vec2PropsF, m_vec3PropsF, m_vec4PropsF ); + ///\todo mesh.clearAllProps( m_normalPropF ); mesh.remove_property( m_hV ); return true; } @@ -78,8 +77,7 @@ bool CatmullClarkSubdivider::subdivide( TopologicalMesh& mesh, #pragma omp critical { m_newFaceVertexOps[iter].push_back( V_OPS( vh, ops ) ); } // deal with properties - mesh.interpolateAllPropsOnFaces( - fh, m_normalPropF, m_floatPropsF, m_vec2PropsF, m_vec3PropsF, m_vec4PropsF ); + ///\todo mesh.interpolateAllPropsOnFaces( fh, m_normalPropF ); } // Compute position for new (edge-) vertices and store them in the edge property @@ -166,8 +164,8 @@ bool CatmullClarkSubdivider::subdivide( TopologicalMesh& mesh, mesh.set_next_halfedge_handle( heh6, heh2 ); // deal with properties - mesh.copyAllProps( heh3, heh5 ); - mesh.copyAllProps( heh1, heh6 ); + ///\todo mesh.copyAllProps( heh3, heh5 ); + ///\todo mesh.copyAllProps( heh1, heh6 ); m_triangulationPropOps.push_back( {heh5, {{1, heh3}}} ); m_triangulationPropOps.push_back( {heh6, {{1, heh1}}} ); } @@ -200,14 +198,13 @@ void CatmullClarkSubdivider::split_face( TopologicalMesh& mesh, mesh.set_face_handle( hold, fh ); // deal with properties for vh - mesh.copyAllPropsFromFace( - fh, hold, m_normalPropF, m_floatPropsF, m_vec2PropsF, m_vec3PropsF, m_vec4PropsF ); + ///\todo mesh.copyAllPropsFromFace( fh, hold, m_normalPropF ); // go around new vertex to build topology hold = mesh.opposite_halfedge_handle( hold ); // deal with properties for hold - mesh.copyAllProps( hend, hold ); + ///\todo mesh.copyAllProps( hend, hold ); m_newFacePropOps[iter].push_back( {hold, {{1, hend}}} ); const Scalar inv_val = Scalar( 1 ) / valence; @@ -231,8 +228,7 @@ void CatmullClarkSubdivider::split_face( TopologicalMesh& mesh, mesh.set_next_halfedge_handle( hold, hh ); // deal with properties for hnew - mesh.copyAllPropsFromFace( - fh, hnew, m_normalPropF, m_floatPropsF, m_vec2PropsF, m_vec3PropsF, m_vec4PropsF ); + ///\todo mesh.copyAllPropsFromFace( fh, hnew, m_normalPropF ); // prepare for next face hh = mesh.next_halfedge_handle( hnext ); @@ -240,7 +236,7 @@ void CatmullClarkSubdivider::split_face( TopologicalMesh& mesh, mesh.set_next_halfedge_handle( hnext, hnew ); // this has to be done after hh ! // deal with properties for hold - mesh.copyAllProps( hnext, hold ); + ///\todo mesh.copyAllProps( hnext, hold ); m_newFacePropOps[iter].push_back( {hold, {{1, hnext}}} ); p_ops[i] = {inv_val, hh}; } @@ -310,7 +306,7 @@ void CatmullClarkSubdivider::split_edge( TopologicalMesh& mesh, mesh.set_halfedge_handle( mesh.face_handle( opp_new_heh ), opp_new_heh ); // deal with custom properties - mesh.interpolateAllProps( t_heh, opp_heh, opp_new_heh, 0.5 ); + ///\todo mesh.interpolateAllProps( t_heh, opp_heh, opp_new_heh, 0.5 ); m_newEdgePropOps[iter].push_back( {opp_new_heh, {{0.5, t_heh}, {0.5, opp_heh}}} ); } @@ -320,10 +316,10 @@ void CatmullClarkSubdivider::split_edge( TopologicalMesh& mesh, mesh.set_halfedge_handle( mesh.face_handle( heh ), heh ); // deal with custom properties - mesh.copyAllProps( heh, new_heh ); + ///\todo mesh.copyAllProps( heh, new_heh ); m_newEdgePropOps[iter].push_back( {new_heh, {{1, heh}}} ); HeHandle heh_prev = mesh.prev_halfedge_handle( heh ); - mesh.interpolateAllProps( heh_prev, new_heh, heh, 0.5 ); + ///\todo mesh.interpolateAllProps( heh_prev, new_heh, heh, 0.5 ); m_newEdgePropOps[iter].push_back( {heh, {{0.5, heh_prev}, {0.5, new_heh}}} ); } diff --git a/src/Core/Geometry/LoopSubdivider.cpp b/src/Core/Geometry/LoopSubdivider.cpp index 7076a28f00f..a752154fb3b 100644 --- a/src/Core/Geometry/LoopSubdivider.cpp +++ b/src/Core/Geometry/LoopSubdivider.cpp @@ -183,8 +183,8 @@ void LoopSubdivider::corner_cutting( TopologicalMesh& mesh, mesh.set_halfedge_handle( fh_new, heh1 ); // deal with custom properties - mesh.copyAllProps( heh1, heh4 ); - mesh.copyAllProps( heh5, heh3 ); + ///\todo mesh.copyAllProps( heh1, heh4 ); + ///\todo mesh.copyAllProps( heh5, heh3 ); m_newFacePropOps[iter].push_back( {heh4, {{1, heh1}}} ); m_newFacePropOps[iter].push_back( {heh3, {{1, heh5}}} ); } @@ -237,7 +237,9 @@ void LoopSubdivider::split_edge( TopologicalMesh& mesh, mesh.set_halfedge_handle( mesh.face_handle( opp_new_heh ), opp_new_heh ); // deal with custom properties - mesh.interpolateAllProps( t_heh, opp_heh, opp_new_heh, 0.5 ); + + /// \todo + // mesh.interpolateAllProps( t_heh, opp_heh, opp_new_heh, 0.5 ); m_newEdgePropOps[iter].push_back( {opp_new_heh, {{0.5, t_heh}, {0.5, opp_heh}}} ); } @@ -247,10 +249,10 @@ void LoopSubdivider::split_edge( TopologicalMesh& mesh, mesh.set_halfedge_handle( mesh.face_handle( heh ), heh ); // deal with custom properties - mesh.copyAllProps( heh, new_heh ); + /// \todo mesh.copyAllProps( heh, new_heh ); m_newEdgePropOps[iter].push_back( {new_heh, {{1, heh}}} ); HeHandle heh_prev = mesh.prev_halfedge_handle( heh ); - mesh.interpolateAllProps( heh_prev, new_heh, heh, 0.5 ); + /// \todo mesh.interpolateAllProps( heh_prev, new_heh, heh, 0.5 ); m_newEdgePropOps[iter].push_back( {heh, {{0.5, heh_prev}, {0.5, new_heh}}} ); } diff --git a/src/Core/Geometry/TopologicalMesh.cpp b/src/Core/Geometry/TopologicalMesh.cpp index 8f99a557fdb..bf4da0e70da 100644 --- a/src/Core/Geometry/TopologicalMesh.cpp +++ b/src/Core/Geometry/TopologicalMesh.cpp @@ -126,43 +126,6 @@ void printWedgesInfo( const Ra::Core::Geometry::TopologicalMesh& topo ) { LOG( Utils::logINFO ) << wedgeInfo( topo, topo.property( topo.getWedgeIndexPph(), *itr ) ); } } - -template -void addAttribPairToCore( TriangleMesh& triMesh, - const TopologicalMesh* topoMesh, - OpenMesh::HPropHandleT oh, - std::vector

& vprop ) { - AttribHandle h = triMesh.addAttrib( topoMesh->property( oh ).name() ); - vprop.push_back( std::make_pair( h, oh ) ); -} - -template -using HandleAndValueVector = std::vector, T>, - Eigen::aligned_allocator, T>>>; - -template -void copyAttribToCoreVertex( HandleAndValueVector& data, - const TopologicalMesh* topoMesh, - const std::vector

& vprop, - TopologicalMesh::HalfedgeHandle heh ) { - for ( auto pp : vprop ) - { - data.push_back( std::make_pair( pp.first, topoMesh->property( pp.second, heh ) ) ); - } -} - -template -void copyAttribToCore( TriangleMesh& triMesh, const HandleAndValueVector& data ) { - - for ( auto pp : data ) - { - auto& attr = triMesh.getAttrib( pp.first ); - auto& attrData = attr.getDataWithLock(); - attrData.push_back( pp.second ); - attr.unlock(); - } -} - TopologicalMesh::TopologicalMesh( const TriangleMesh& triMesh ) : TopologicalMesh( triMesh, @@ -174,119 +137,7 @@ TopologicalMesh::TopologicalMesh() { } TriangleMesh TopologicalMesh::toTriangleMesh() { - struct VertexDataInternal { - Vector3 _vertex; - Vector3 _normal; - - HandleAndValueVector _float; - HandleAndValueVector _vec2; - HandleAndValueVector _vec3; - HandleAndValueVector _vec4; - - EIGEN_MAKE_ALIGNED_OPERATOR_NEW - - bool operator==( const VertexDataInternal& lhs ) const { - return _vertex == lhs._vertex && _normal == lhs._normal && _float == lhs._float && - _vec2 == lhs._vec2 && _vec3 == lhs._vec3 && _vec4 == lhs._vec4; - } - }; - - struct hash_vec { - size_t operator()( const VertexDataInternal& lvalue ) const { - size_t hx = std::hash()( lvalue._vertex[0] ); - size_t hy = std::hash()( lvalue._vertex[1] ); - size_t hz = std::hash()( lvalue._vertex[2] ); - return ( hx ^ ( hy << 1 ) ) ^ hz; - } - }; - - TriangleMesh out; - - using VertexMap = std::unordered_map; - - VertexMap vertexHandles; - - if ( !get_property_handle( m_outputTriangleMeshIndexPph, "OutputTriangleMeshIndices" ) ) - { add_property( m_outputTriangleMeshIndexPph, "OutputTriangleMeshIndices" ); } - std::vector> vprop_float; - std::vector> vprop_vec2; - std::vector> vprop_vec3; - std::vector> vprop_vec4; - - // loop over all attribs and build correspondance pair - vprop_float.reserve( m_floatPph.size() ); - for ( auto oh : m_floatPph ) - addAttribPairToCore( out, this, oh, vprop_float ); - vprop_vec2.reserve( m_vec2Pph.size() ); - for ( auto oh : m_vec2Pph ) - addAttribPairToCore( out, this, oh, vprop_vec2 ); - vprop_vec3.reserve( m_vec3Pph.size() ); - for ( auto oh : m_vec3Pph ) - addAttribPairToCore( out, this, oh, vprop_vec3 ); - vprop_vec4.reserve( m_vec4Pph.size() ); - for ( auto oh : m_vec4Pph ) - addAttribPairToCore( out, this, oh, vprop_vec4 ); - - // iterator over all faces - unsigned int vertexIndex = 0; - - // out will have at least n_vertices vertices and normals. - TriangleMesh::PointAttribHandle::Container vertices; - TriangleMesh::NormalAttribHandle::Container normals; - TriangleMesh::IndexContainerType indices; - - vertices.reserve( n_vertices() ); - normals.reserve( n_vertices() ); - indices.reserve( n_faces() ); - - for ( TopologicalMesh::FaceIter f_it = faces_sbegin(); f_it != faces_end(); ++f_it ) - { - int tindices[3]; - int i = 0; - - // iterator over vertex (through halfedge to get access to halfedge normals) - for ( TopologicalMesh::ConstFaceHalfedgeIter fh_it = cfh_iter( *f_it ); fh_it.is_valid(); - ++fh_it ) - { - VertexDataInternal v; - CORE_ASSERT( i < 3, "Non-triangular face found." ); - v._vertex = point( to_vertex_handle( *fh_it ) ); - - if ( has_halfedge_normals() ) - { v._normal = normal( to_vertex_handle( *fh_it ), *f_it ); } - copyAttribToCoreVertex( v._float, this, vprop_float, *fh_it ); - copyAttribToCoreVertex( v._vec2, this, vprop_vec2, *fh_it ); - copyAttribToCoreVertex( v._vec3, this, vprop_vec3, *fh_it ); - copyAttribToCoreVertex( v._vec4, this, vprop_vec4, *fh_it ); - - int vi; - VertexMap::iterator vtr = vertexHandles.find( v ); - if ( vtr == vertexHandles.end() ) - { - vi = int( vertexIndex++ ); - vertexHandles.insert( vtr, VertexMap::value_type( v, vi ) ); - vertices.push_back( v._vertex ); - if ( has_halfedge_normals() ) { normals.push_back( v._normal ); } - copyAttribToCore( out, v._float ); - copyAttribToCore( out, v._vec2 ); - copyAttribToCore( out, v._vec3 ); - copyAttribToCore( out, v._vec4 ); - } - else - { vi = vtr->second; } - tindices[i] = vi; - property( m_outputTriangleMeshIndexPph, *fh_it ) = vi; - i++; - } - indices.emplace_back( tindices[0], tindices[1], tindices[2] ); - } - out.setVertices( std::move( vertices ) ); - if ( has_halfedge_normals() ) { out.setNormals( std::move( normals ) ); } - out.setIndices( std::move( indices ) ); - CORE_ASSERT( vertexIndex == vertices.size(), - "Inconsistent number of faces in generated TriangleMesh." ); - - return out; + return toTriangleMeshFromWedges(); } template @@ -520,144 +371,6 @@ void TopologicalMesh::updateNormals( const Ra::Core::Geometry::TriangleMesh& tri } } -bool TopologicalMesh::splitEdge( TopologicalMesh::EdgeHandle eh, Scalar f ) { - // Global schema of operation - /* - TRIANGLES ONLY - before after - A A - / F0 \ / F2 | F0 \ - / \ / | \ - /h1 h0\ /h1 e2|e0 h0\ - / he0 \ / he2 | he0 \ - V1 -------- V0 V1 ------ V ------ V0 - \ he1 / \ he3 | he1 / - \o1 o0/ \o1 e3|e1 o0/ - \ / \ | / - \ F1 / \ F3 | F1 / - B B - - */ - - // incorrect factor - if ( f < 0 || f > 1 ) { return false; } - - // get existing topology data - HalfedgeHandle he0 = halfedge_handle( eh, 0 ); - HalfedgeHandle he1 = halfedge_handle( eh, 1 ); - VertexHandle v0 = to_vertex_handle( he0 ); - VertexHandle v1 = to_vertex_handle( he1 ); - FaceHandle F0 = face_handle( he0 ); - FaceHandle F1 = face_handle( he1 ); - - // not triangles or holes - if ( ( !is_boundary( he0 ) && valence( F0 ) != 3 ) || - ( !is_boundary( he1 ) && valence( F1 ) != 3 ) ) - { return false; } - - // add the new vertex - const Point p = Point( f * point( v0 ) + ( Scalar( 1. ) - f ) * point( v1 ) ); - VertexHandle v = add_vertex( p ); - - // create the new faces and reconnect the topology - HalfedgeHandle he3 = new_edge( v, v1 ); - HalfedgeHandle he2 = opposite_halfedge_handle( he3 ); - set_halfedge_handle( v, he0 ); - set_vertex_handle( he1, v ); - - // does F0 exist - if ( !is_boundary( he0 ) ) - { - HalfedgeHandle h0 = next_halfedge_handle( he0 ); - HalfedgeHandle h1 = next_halfedge_handle( h0 ); - // create new edge - VertexHandle A = to_vertex_handle( h0 ); - HalfedgeHandle e2 = new_edge( v, A ); - HalfedgeHandle e0 = opposite_halfedge_handle( e2 ); - // split F0 - FaceHandle F2 = new_face(); - set_halfedge_handle( F0, he0 ); - set_halfedge_handle( F2, h1 ); - // update F0 - set_face_handle( h0, F0 ); - set_face_handle( e0, F0 ); - set_face_handle( he0, F0 ); - set_next_halfedge_handle( he0, h0 ); - set_next_halfedge_handle( h0, e0 ); - set_next_halfedge_handle( e0, he0 ); - // update F2 - set_face_handle( h1, F2 ); - set_face_handle( he2, F2 ); - set_face_handle( e2, F2 ); - set_next_halfedge_handle( e2, h1 ); - set_next_halfedge_handle( h1, he2 ); - set_next_halfedge_handle( he2, e2 ); - // deal with custom properties - // interpolate at he2 - interpolateAllProps( h1, he0, he2, 0.5 ); - // copy at e0, and e2 - copyAllProps( he2, e0 ); - } - else - { - HalfedgeHandle h1 = prev_halfedge_handle( he0 ); - set_next_halfedge_handle( h1, he2 ); - set_next_halfedge_handle( he2, he0 ); - // next halfedge handle of he0 already is h0 - // halfedge handle of V already is he0 - } - - // does F1 exist - if ( !is_boundary( he1 ) ) - { - HalfedgeHandle o1 = next_halfedge_handle( he1 ); - HalfedgeHandle o0 = next_halfedge_handle( o1 ); - // create new edge - VertexHandle B = to_vertex_handle( o1 ); - HalfedgeHandle e1 = new_edge( v, B ); - HalfedgeHandle e3 = opposite_halfedge_handle( e1 ); - // split F1 - FaceHandle F3 = new_face(); - set_halfedge_handle( F3, o1 ); - set_halfedge_handle( F1, he1 ); - // update F1 - set_face_handle( o1, F3 ); - set_face_handle( e3, F3 ); - set_face_handle( he3, F3 ); - set_next_halfedge_handle( he3, o1 ); - set_next_halfedge_handle( o1, e3 ); - set_next_halfedge_handle( e3, he3 ); - // update F3 - set_face_handle( o0, F1 ); - set_face_handle( he1, F1 ); - set_face_handle( e1, F1 ); - set_next_halfedge_handle( he1, e1 ); - set_next_halfedge_handle( e1, o0 ); - set_next_halfedge_handle( o0, he1 ); - // deal with custom properties - // first copy at he3 - copyAllProps( he1, he3 ); - // interpolate at he1 - interpolateAllProps( o0, he3, he1, 0.5 ); - // copy at e1, and e3 - copyAllProps( he1, e3 ); - copyAllProps( o1, e1 ); - } - else - { - HalfedgeHandle o1 = next_halfedge_handle( he1 ); - // next halfedge handle of o0 already is he1 - set_next_halfedge_handle( he1, he3 ); - set_next_halfedge_handle( he3, o1 ); - // halfedge handle of V already is he0 - } - - // ensure consistency at v1 - if ( halfedge_handle( v1 ) == he0 ) { set_halfedge_handle( v1, he2 ); } - - return true; -} - template void interpolate( const VectorArray& in1, const VectorArray& in2, @@ -809,7 +522,7 @@ void TopologicalMesh::split_copy( EdgeHandle _eh, VertexHandle _vh ) { } } -bool TopologicalMesh::splitEdgeWedge( TopologicalMesh::EdgeHandle eh, Scalar f ) { +bool TopologicalMesh::splitEdge( TopologicalMesh::EdgeHandle eh, Scalar f ) { // Global schema of operation /* TRIANGLES ONLY diff --git a/src/Core/Geometry/TopologicalMesh.hpp b/src/Core/Geometry/TopologicalMesh.hpp index 1169a122e66..deb222595ad 100644 --- a/src/Core/Geometry/TopologicalMesh.hpp +++ b/src/Core/Geometry/TopologicalMesh.hpp @@ -151,14 +151,6 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT& getOutputTriangleMeshIndexPropHandle() const; - /** - * \name Const access to handles of the HalfEdge properties coming from - * the TriangleMesh attributes. - */ - ///@{ - [[deprecated]] inline const std::vector>& - getFloatPropsHandles() const; - [[deprecated]] inline const std::vector>& - getVector2PropsHandles() const; - [[deprecated]] inline const std::vector>& - getVector3PropsHandles() const; - [[deprecated]] inline const std::vector>& - getVector4PropsHandles() const; - ///@} - /** * \name Dealing with normals * Utils to deal with normals when modifying the mesh topology. @@ -194,167 +171,6 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT& fProp ); - - /** - * Remove face property \a prop from \a mesh. - * \note Invalidates the property handle. - */ - inline void clearProp( OpenMesh::FPropHandleT& fProp ); - - /** - * Copy the normal property from \a input_heh to \a copy_heh. - */ - inline void copyNormal( HalfedgeHandle input_heh, HalfedgeHandle copy_heh ); - - /** Copy the face normal property \a fProp from \a fh to \a heh. - * \note \a fProp must have been previously created through createNormalPropOnFaces(). - */ - inline void - copyNormalFromFace( FaceHandle fh, HalfedgeHandle heh, OpenMesh::FPropHandleT fProp ); - - /** - * Interpolate normal property on edge center (after edge split). - */ - inline void - interpolateNormal( HalfedgeHandle in_a, HalfedgeHandle in_b, HalfedgeHandle out, Scalar f ); - - /** Interpolate normal property on face center. - * \note \a fProp must have been previously created through createNormalPropOnFaces(). - */ - inline void interpolateNormalOnFaces( FaceHandle fh, OpenMesh::FPropHandleT fProp ); - ///@} - - /** - * \name Dealing with custom properties - * Utils to deal with custom properties of any type when modifying the mesh topology. - */ - ///@{ - - /** - * Create a new property for each \a input properties of \a mesh on faces. - * \note This new property will have to be propagated onto the newly created - * halfedges with copyProps(). - */ - template - void createPropsOnFaces( const std::vector>& input, - std::vector>& output ); - - /** - * Remove \a props from \a mesh. - * \note Clears \a props. - */ - template - void clearProps( std::vector>& props ); - - /** - * Copy \a props properties from \a input_heh to \a copy_heh. - */ - template - void copyProps( HalfedgeHandle input_heh, - HalfedgeHandle copy_heh, - const std::vector>& props ); - - /** - * Copy face properties \a props from \a fh to \a heh. - * \note \a fProps must have been previously created through createPropsOnFaces(). - */ - template - void copyPropsFromFace( FaceHandle fh, - HalfedgeHandle heh, - const std::vector>& fProps, - const std::vector>& hProps ); - - /** - * Interpolate \a props on edge center (after edge split). - */ - template - void interpolateProps( HalfedgeHandle in_a, - HalfedgeHandle in_b, - HalfedgeHandle out, - Scalar f, - const std::vector>& props ); - - /** - * Interpolate \a hprops on face center. - * \note \a fProps must have been previously created through createPropsOnFaces(). - */ - template - void interpolatePropsOnFaces( FaceHandle fh, - const std::vector>& hProps, - const std::vector>& fProps ); - ///@} - /** - * \name Deal with all attributes* Utils to deal with the normal and - custom properties when modifying the mesh topology.*/ - - ///@{ - - /** - * Create a new property for each property of \a mesh on faces. - * Outputs the new face properties handles in the corresponding output parameters. - * \note These new properties will have to be propagated onto the newly created - * halfedges with copyAllProps(). - */ - inline void createAllPropsOnFaces( OpenMesh::FPropHandleT& normalProp, - std::vector>& floatProps, - std::vector>& vec2Props, - std::vector>& vec3Props, - std::vector>& vec4Props ); - - /** - * Remove all the given properties from \a mesh. - * \note Invalidates \a normalProp and clears the given property containers. - */ - inline void clearAllProps( OpenMesh::FPropHandleT& normalProp, - std::vector>& floatProps, - std::vector>& vec2Props, - std::vector>& vec3Props, - std::vector>& vec4Props ); - - /** - * Copy all properties from \a input_heh to \a copy_heh. - */ - inline void copyAllProps( HalfedgeHandle input_heh, HalfedgeHandle copy_heh ); - - /** - * Copy all given face properties from \a fh to \a heh. - * \note Each property must have been previously created either all at once - * through createAllPropsOnFaces(), or individually through - * createNormalPropOnFaces() and createPropsOnFaces(). - */ - inline void copyAllPropsFromFace( FaceHandle fh, - HalfedgeHandle heh, - OpenMesh::FPropHandleT normalProp, - std::vector>& floatProps, - std::vector>& vec2Props, - std::vector>& vec3Props, - std::vector>& vec4Props ); - - /** - * Interpolate all properties on edge center (after edge split). - */ - inline void - interpolateAllProps( HalfedgeHandle in_a, HalfedgeHandle in_b, HalfedgeHandle out, Scalar f ); - - /** - * Interpolate \a hprops on face center. - * \note Each property must have been previously created either all at once - * through createAllPropsOnFaces(), or individually through - * createNormalPropOnFaces() and createPropsOnFaces(). - */ - inline void - interpolateAllPropsOnFaces( FaceHandle fh, - OpenMesh::FPropHandleT normalProp, - std::vector>& floatProps, - std::vector>& vec2Props, - std::vector>& vec3Props, - std::vector>& vec4Props ); ///@} /** @@ -412,7 +228,6 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT using PropPair = std::pair, OpenMesh::HPropHandleT>; - template - [[deprecated]] inline void copyAttribToTopo( const TriangleMesh& triMesh, - const std::vector>& vprop, - TopologicalMesh::HalfedgeHandle heh, - unsigned int vindex ); - - template - [[deprecated]] inline void addAttribPairToTopo( const TriangleMesh& triMesh, - AttribManager::pointer_type attr, - std::vector>& vprop, - std::vector>& pph ); - void split_copy( EdgeHandle _eh, VertexHandle _vh ); void split( EdgeHandle _eh, VertexHandle _vh ); @@ -730,10 +533,6 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT m_inputTriangleMeshIndexPph; OpenMesh::HPropHandleT m_outputTriangleMeshIndexPph; - [[deprecated]] std::vector> m_floatPph; - [[deprecated]] std::vector> m_vec2Pph; - [[deprecated]] std::vector> m_vec3Pph; - [[deprecated]] std::vector> m_vec4Pph; int m_normalsIndex {-1}; // vertex handle idx -> face handle idx -> wedge idx with the same normal diff --git a/src/Core/Geometry/TopologicalMesh.inl b/src/Core/Geometry/TopologicalMesh.inl index 53d61328ddc..dc50fde0e91 100644 --- a/src/Core/Geometry/TopologicalMesh.inl +++ b/src/Core/Geometry/TopologicalMesh.inl @@ -117,189 +117,7 @@ template inline TopologicalMesh::TopologicalMesh( const TriangleMesh& triMesh, NonManifoldFaceCommand command ) : TopologicalMesh() { - - LOG( logINFO ) << "TopologicalMesh: load triMesh with " << triMesh.getIndices().size() - << " faces and " << triMesh.vertices().size() << " vertices."; - // use a hashmap for fast search of existing vertex position - using VertexMap = std::unordered_map; - VertexMap vertexHandles; - - std::vector> vprop_float; - std::vector> vprop_vec2; - std::vector> vprop_vec3; - std::vector> vprop_vec4; - - // loop over all attribs and build correspondance pair - triMesh.vertexAttribs().for_each_attrib( - [&triMesh, this, &vprop_float, &vprop_vec2, &vprop_vec3, &vprop_vec4]( const auto& attr ) { - // skip builtin attribs - if ( attr->getName() != std::string( "in_position" ) && - attr->getName() != std::string( "in_normal" ) ) - { - if ( attr->isFloat() ) - addAttribPairToTopo( triMesh, attr, vprop_float, m_floatPph ); - else if ( attr->isVector2() ) - addAttribPairToTopo( triMesh, attr, vprop_vec2, m_vec2Pph ); - else if ( attr->isVector3() ) - addAttribPairToTopo( triMesh, attr, vprop_vec3, m_vec3Pph ); - else if ( attr->isVector4() ) - addAttribPairToTopo( triMesh, attr, vprop_vec4, m_vec4Pph ); - else - LOG( logWARNING ) - << "Warning, mesh attribute " << attr->getName() - << " type is not supported (only float, vec2, vec3 nor vec4 are supported)"; - } - } ); - - // loop over all attribs and build correspondance pair - triMesh.vertexAttribs().for_each_attrib( InitWedgeProps {this, triMesh} ); - - size_t num_faces = triMesh.getIndices().size(); - - command.initialize( triMesh ); - - const bool hasNormals = !triMesh.normals().empty(); - if ( !hasNormals ) - { - release_face_normals(); - release_vertex_normals(); - release_halfedge_normals(); - } - - for ( unsigned int i = 0; i < num_faces; i++ ) - { - const auto& face = triMesh.getIndices()[i]; - const size_t num_vert = face.size(); - std::vector face_vhandles( num_vert ); - std::vector face_normals( num_vert ); - std::vector face_vertexIndex( num_vert ); - std::vector face_wedges( num_vert ); - - for ( size_t j = 0; j < num_vert; ++j ) - { - unsigned int inMeshVertexIndex = face[j]; - const Vector3& p = triMesh.vertices()[inMeshVertexIndex]; - - typename VertexMap::iterator vtr = vertexHandles.find( p ); - - TopologicalMesh::VertexHandle vh; - if ( vtr == vertexHandles.end() ) - { - vh = add_vertex( p ); - vertexHandles.insert( vtr, typename VertexMap::value_type( p, vh ) ); - } - else - { vh = vtr->second; } - - face_vhandles[j] = vh; - face_vertexIndex[j] = inMeshVertexIndex; - if ( hasNormals ) face_normals[j] = triMesh.normals()[inMeshVertexIndex]; - - WedgeData wd; - wd.m_position = p; - - copyMeshToWedgeData( triMesh, - inMeshVertexIndex, - m_wedges.m_wedgeFloatAttribHandles, - m_wedges.m_wedgeVector2AttribHandles, - m_wedges.m_wedgeVector3AttribHandles, - m_wedges.m_wedgeVector4AttribHandles, - &wd ); - - face_wedges[j] = m_wedges.add( wd ); - } - - // take care of degen, see below in method initWithWedge for comments - // copied from initFromWedges EXECPT THE TWO LINES WITH COMMENT - // x-----------------------------------------------------------------------------------x - { - auto begin = face_vhandles.begin(); - if ( face_vhandles.size() > 2 ) - { - auto end = face_vhandles.end() - 1; - auto wedgeEnd = face_wedges.end() - 1; - auto normalEnd = face_normals.end() - 1; - - while ( begin != end && *begin == *end ) - { - end--; - // WARNING explicit del wedge (not needed in initWithWedges) - m_wedges.del( *wedgeEnd ); - wedgeEnd--; - normalEnd--; - } - face_vhandles.erase( end + 1, face_vhandles.end() ); - face_wedges.erase( wedgeEnd + 1, face_wedges.end() ); - face_normals.erase( normalEnd + 1, face_normals.end() ); - } - } - - { - auto first = face_vhandles.begin(); - auto wedgeFirst = face_wedges.begin(); - auto normalFirst = face_normals.begin(); - auto last = face_vhandles.end(); - - if ( first != last ) - { - auto result = first; - auto wedgeResult = wedgeFirst; - auto normalResult = normalFirst; - while ( ++first != last ) - { - if ( !( *result == *first ) ) - { - ++result; - ++wedgeResult; - ++normalResult; - if ( result != first ) - { - *result = std::move( *first ); - // WARNING explicit del wedge (not needed in initWithWedges) - m_wedges.del( *wedgeResult ); - *wedgeResult = std::move( *wedgeFirst ); - *normalResult = std::move( *normalFirst ); - } - } - } - face_vhandles.erase( result + 1, face_vhandles.end() ); - face_wedges.erase( wedgeResult + 1, face_wedges.end() ); - face_normals.erase( normalResult + 1, face_normals.end() ); - } - } - TopologicalMesh::FaceHandle fh; - // skip 2 vertex face - if ( face_vhandles.size() > 2 ) fh = add_face( face_vhandles ); - // x-----------------------------------------------------------------------------------x - - if ( fh.is_valid() ) - { - for ( size_t vindex = 0; vindex < face_vhandles.size(); vindex++ ) - { - TopologicalMesh::HalfedgeHandle heh = halfedge_handle( face_vhandles[vindex], fh ); - if ( hasNormals ) set_normal( heh, face_normals[vindex] ); - property( m_inputTriangleMeshIndexPph, heh ) = face_vertexIndex[vindex]; - copyAttribToTopo( triMesh, vprop_float, heh, face_vertexIndex[vindex] ); - copyAttribToTopo( triMesh, vprop_vec2, heh, face_vertexIndex[vindex] ); - copyAttribToTopo( triMesh, vprop_vec3, heh, face_vertexIndex[vindex] ); - copyAttribToTopo( triMesh, vprop_vec4, heh, face_vertexIndex[vindex] ); - property( m_wedgeIndexPph, heh ) = face_wedges[vindex]; - } - } - else - { - for ( auto wedgeIndex : face_wedges ) - m_wedges.del( wedgeIndex ); - command.process( face_vhandles ); - } - face_vhandles.clear(); - face_normals.clear(); - face_vertexIndex.clear(); - } - command.postProcess( *this ); - - // grabage collect since some wedge might already be deleted - garbage_collection(); + initWithWedge( triMesh, command ); } template @@ -379,8 +197,7 @@ void TopologicalMesh::initWithWedge( const IndexedGeometry& mesh, face_vhandles[j] = vh; if ( hasNormals ) face_normals[j] = mesh.normals()[inMeshVertexIndex]; - face_wedges[j] = - WedgeIndex {static_cast( inMeshVertexIndex )}; + face_wedges[j] = WedgeIndex {inMeshVertexIndex}; m_wedges.m_data[inMeshVertexIndex].getWedgeData().m_vertexHandle = vh; } @@ -521,26 +338,6 @@ void TopologicalMesh::copyAttribToWedgeData( const IndexedGeometry& mesh, } } -template -void TopologicalMesh::addAttribPairToTopo( const TriangleMesh& triMesh, - AttribManager::pointer_type attr, - std::vector>& vprop, - std::vector>& pph ) { - AttribHandle h = triMesh.getAttribHandle( attr->getName() ); - if ( attr->getSize() == triMesh.vertices().size() ) - { - OpenMesh::HPropHandleT oh; - this->add_property( oh, attr->getName() ); - vprop.push_back( std::make_pair( h, oh ) ); - pph.push_back( oh ); - } - else - { - LOG( logWARNING ) << "[TopologicalMesh] Skip badly sized attribute " << attr->getName() - << "."; - } -} - template void TopologicalMesh::copyMeshToWedgeData( const IndexedGeometry& mesh, unsigned int vindex, @@ -556,17 +353,6 @@ void TopologicalMesh::copyMeshToWedgeData( const IndexedGeometry& mesh, copyAttribToWedgeData( mesh, vindex, wprop_vec4, &wd->m_vector4Attrib ); } -template -void TopologicalMesh::copyAttribToTopo( const TriangleMesh& triMesh, - const std::vector>& vprop, - TopologicalMesh::HalfedgeHandle heh, - unsigned int vindex ) { - for ( auto pp : vprop ) - { - this->property( pp.second, heh ) = triMesh.getAttrib( pp.first ).data()[vindex]; - } -} - inline const TopologicalMesh::Normal& TopologicalMesh::normal( VertexHandle vh, FaceHandle fh ) const { // find halfedge that point to vh and member of fh @@ -589,18 +375,6 @@ inline void TopologicalMesh::set_normal( VertexHandle vh, FaceHandle fh, const N set_normal( halfedge_handle( vh, fh ), n ); } -inline void TopologicalMesh::propagate_normal_to_halfedges( VertexHandle vh ) { - if ( !has_halfedge_normals() ) - { - LOG( logERROR ) << "TopologicalMesh has no normals, nothing set"; - return; - } - for ( VertexIHalfedgeIter vih_it = vih_iter( vh ); vih_it.is_valid(); ++vih_it ) - { - set_normal( *vih_it, normal( vh ) ); - } -} - inline TopologicalMesh::HalfedgeHandle TopologicalMesh::halfedge_handle( VertexHandle vh, FaceHandle fh ) const { for ( ConstVertexIHalfedgeIter vih_it = cvih_iter( vh ); vih_it.is_valid(); ++vih_it ) @@ -621,26 +395,6 @@ TopologicalMesh::getOutputTriangleMeshIndexPropHandle() const { return m_outputTriangleMeshIndexPph; } -inline const std::vector>& -TopologicalMesh::getFloatPropsHandles() const { - return m_floatPph; -} - -inline const std::vector>& -TopologicalMesh::getVector2PropsHandles() const { - return m_vec2Pph; -} - -inline const std::vector>& -TopologicalMesh::getVector3PropsHandles() const { - return m_vec3Pph; -} - -inline const std::vector>& -TopologicalMesh::getVector4PropsHandles() const { - return m_vec4Pph; -} - inline void TopologicalMesh::updateWedgeNormals() { if ( !has_halfedge_normals() ) { @@ -685,242 +439,6 @@ inline void TopologicalMesh::updateWedgeNormals() { } } -inline void TopologicalMesh::createNormalPropOnFaces( OpenMesh::FPropHandleT& fProp ) { - if ( !has_halfedge_normals() ) - { - LOG( logERROR ) << "TopologicalMesh has no normals, nothing set"; - return; - } - auto nph = halfedge_normals_pph(); - add_property( fProp, property( nph ).name() + "_subdiv_copy_F" ); -} - -inline void TopologicalMesh::clearProp( OpenMesh::FPropHandleT& fProp ) { - remove_property( fProp ); -} - -inline void TopologicalMesh::copyNormal( HalfedgeHandle input_heh, HalfedgeHandle copy_heh ) { - if ( !has_halfedge_normals() ) - { - LOG( logERROR ) << "TopologicalMesh has no normals, nothing set"; - return; - } - auto nph = halfedge_normals_pph(); - property( nph, copy_heh ) = property( nph, input_heh ); -} - -inline void TopologicalMesh::copyNormalFromFace( FaceHandle fh, - HalfedgeHandle heh, - OpenMesh::FPropHandleT fProp ) { - if ( !has_halfedge_normals() ) - { - LOG( logERROR ) << "TopologicalMesh has no normals, nothing set"; - return; - } - auto nph = halfedge_normals_pph(); - property( nph, heh ) = property( fProp, fh ); -} - -inline void TopologicalMesh::interpolateNormal( HalfedgeHandle in_a, - HalfedgeHandle in_b, - HalfedgeHandle out, - Scalar f ) { - auto nph = halfedge_normals_pph(); - property( nph, out ) = - ( ( 1 - f ) * property( nph, in_a ) + f * property( nph, in_b ) ).normalized(); -} - -inline void TopologicalMesh::interpolateNormalOnFaces( FaceHandle fh, - OpenMesh::FPropHandleT fProp ) { - if ( !has_halfedge_normals() ) - { - LOG( logERROR ) << "TopologicalMesh has no normals, nothing set"; - return; - } - auto nph = halfedge_normals_pph(); - - // init sum to first - auto heh = halfedge_handle( fh ); - property( fProp, fh ) = property( nph, heh ); - heh = next_halfedge_handle( heh ); - - // sum others - for ( size_t i = 1; i < valence( fh ); ++i ) - { - property( fProp, fh ) += property( nph, heh ); - heh = next_halfedge_handle( heh ); - } - - // normalize - property( fProp, fh ) = property( fProp, fh ).normalized(); -} - -template -void TopologicalMesh::createPropsOnFaces( const std::vector>& input, - std::vector>& output ) { - output.reserve( input.size() ); - for ( const auto& oh : input ) - { - OpenMesh::FPropHandleT oh_; - add_property( oh_, property( oh ).name() + "_subdiv_copy_F" ); - output.push_back( oh_ ); - } -} - -template -void TopologicalMesh::clearProps( std::vector>& props ) { - for ( auto& oh : props ) - { - remove_property( oh ); - } - props.clear(); -} - -template -void TopologicalMesh::copyProps( HalfedgeHandle input_heh, - HalfedgeHandle copy_heh, - const std::vector>& props ) { - for ( const auto& oh : props ) - { - property( oh, copy_heh ) = property( oh, input_heh ); - } -} - -template -void TopologicalMesh::copyPropsFromFace( FaceHandle fh, - HalfedgeHandle heh, - const std::vector>& fProps, - const std::vector>& hProps ) { - for ( uint i = 0; i < fProps.size(); ++i ) - { - auto hp = hProps[i]; - auto fp = fProps[i]; - property( hp, heh ) = property( fp, fh ); - } -} - -template -void TopologicalMesh::interpolateProps( HalfedgeHandle in_a, - HalfedgeHandle in_b, - HalfedgeHandle out, - Scalar f, - const std::vector>& props ) { - // interpolate properties - for ( const auto& oh : props ) - { - property( oh, out ) = ( 1 - f ) * property( oh, in_a ) + f * property( oh, in_b ); - } -} - -template -void TopologicalMesh::interpolatePropsOnFaces( - FaceHandle fh, - const std::vector>& hProps, - const std::vector>& fProps ) { - auto heh = halfedge_handle( fh ); - const size_t v = valence( fh ); - - // init sum to first - for ( size_t j = 0; j < fProps.size(); ++j ) - { - auto hp = hProps[j]; - auto fp = fProps[j]; - property( fp, fh ) = property( hp, heh ); - } - heh = next_halfedge_handle( heh ); - // sum others - for ( size_t i = 1; i < v; ++i ) - { - for ( size_t j = 0; j < fProps.size(); ++j ) - { - auto hp = hProps[j]; - auto fp = fProps[j]; - property( fp, fh ) += property( hp, heh ); - } - heh = next_halfedge_handle( heh ); - } - // normalize - for ( size_t j = 0; j < fProps.size(); ++j ) - { - auto fp = fProps[j]; - property( fp, fh ) = property( fp, fh ) / v; - } -} - -inline void -TopologicalMesh::createAllPropsOnFaces( OpenMesh::FPropHandleT& normalProp, - std::vector>& floatProps, - std::vector>& vec2Props, - std::vector>& vec3Props, - std::vector>& vec4Props ) { - createNormalPropOnFaces( normalProp ); - createPropsOnFaces( getFloatPropsHandles(), floatProps ); - createPropsOnFaces( getVector2PropsHandles(), vec2Props ); - createPropsOnFaces( getVector3PropsHandles(), vec3Props ); - createPropsOnFaces( getVector4PropsHandles(), vec4Props ); -} - -inline void -TopologicalMesh::clearAllProps( OpenMesh::FPropHandleT& normalProp, - std::vector>& floatProps, - std::vector>& vec2Props, - std::vector>& vec3Props, - std::vector>& vec4Props ) { - clearProp( normalProp ); - clearProps( floatProps ); - clearProps( vec2Props ); - clearProps( vec3Props ); - clearProps( vec4Props ); -} - -inline void TopologicalMesh::copyAllProps( HalfedgeHandle input_heh, HalfedgeHandle copy_heh ) { - copyNormal( input_heh, copy_heh ); - copyProps( input_heh, copy_heh, getFloatPropsHandles() ); - copyProps( input_heh, copy_heh, getVector2PropsHandles() ); - copyProps( input_heh, copy_heh, getVector3PropsHandles() ); - copyProps( input_heh, copy_heh, getVector4PropsHandles() ); -} - -inline void -TopologicalMesh::copyAllPropsFromFace( FaceHandle fh, - HalfedgeHandle heh, - OpenMesh::FPropHandleT normalProp, - std::vector>& floatProps, - std::vector>& vec2Props, - std::vector>& vec3Props, - std::vector>& vec4Props ) { - copyNormalFromFace( fh, heh, normalProp ); - copyPropsFromFace( fh, heh, floatProps, getFloatPropsHandles() ); - copyPropsFromFace( fh, heh, vec2Props, getVector2PropsHandles() ); - copyPropsFromFace( fh, heh, vec3Props, getVector3PropsHandles() ); - copyPropsFromFace( fh, heh, vec4Props, getVector4PropsHandles() ); -} - -inline void TopologicalMesh::interpolateAllProps( HalfedgeHandle in_a, - HalfedgeHandle in_b, - HalfedgeHandle out, - Scalar f ) { - interpolateNormal( in_a, in_b, out, f ); - interpolateProps( in_a, in_b, out, f, getFloatPropsHandles() ); - interpolateProps( in_a, in_b, out, f, getVector2PropsHandles() ); - interpolateProps( in_a, in_b, out, f, getVector3PropsHandles() ); - interpolateProps( in_a, in_b, out, f, getVector4PropsHandles() ); -} - -inline void TopologicalMesh::interpolateAllPropsOnFaces( - FaceHandle fh, - OpenMesh::FPropHandleT normalProp, - std::vector>& floatProps, - std::vector>& vec2Props, - std::vector>& vec3Props, - std::vector>& vec4Props ) { - interpolateNormalOnFaces( fh, normalProp ); - interpolatePropsOnFaces( fh, getFloatPropsHandles(), floatProps ); - interpolatePropsOnFaces( fh, getVector2PropsHandles(), vec2Props ); - interpolatePropsOnFaces( fh, getVector3PropsHandles(), vec3Props ); - interpolatePropsOnFaces( fh, getVector4PropsHandles(), vec4Props ); -} - inline std::set TopologicalMesh::getVertexWedges( OpenMesh::VertexHandle vh ) const { std::set ret; From 964e9c205696932bfe3d1c981d35f31587feb6f9 Mon Sep 17 00:00:00 2001 From: dlyr Date: Wed, 17 Mar 2021 16:15:21 +0100 Subject: [PATCH 14/37] [core] Topo: Wedge modifier. --- src/Core/Geometry/TopologicalMesh.cpp | 8 ++---- src/Core/Geometry/TopologicalMesh.hpp | 13 ++++++++-- src/Core/Geometry/TopologicalMesh.inl | 36 +++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 8 deletions(-) diff --git a/src/Core/Geometry/TopologicalMesh.cpp b/src/Core/Geometry/TopologicalMesh.cpp index bf4da0e70da..bb5d9f0299f 100644 --- a/src/Core/Geometry/TopologicalMesh.cpp +++ b/src/Core/Geometry/TopologicalMesh.cpp @@ -136,10 +136,6 @@ TopologicalMesh::TopologicalMesh() { add_property( m_wedgeIndexPph ); } -TriangleMesh TopologicalMesh::toTriangleMesh() { - return toTriangleMeshFromWedges(); -} - template void copyWedgeDataToAttribContainer( AlignedStdVector::Container>& c, const VectorArray& wd ) { @@ -160,7 +156,7 @@ void moveContainerToMesh( IndexedGeometry& out, } } -TriangleMesh TopologicalMesh::toTriangleMeshFromWedges() { +TriangleMesh TopologicalMesh::toTriangleMesh() { // first cleanup deleted element garbage_collection(); @@ -215,7 +211,7 @@ TriangleMesh TopologicalMesh::toTriangleMeshFromWedges() { return out; } -PolyMesh TopologicalMesh::toPolyMeshFromWedges() { +PolyMesh TopologicalMesh::toPolyMesh() { // first cleanup deleted element garbage_collection(); diff --git a/src/Core/Geometry/TopologicalMesh.hpp b/src/Core/Geometry/TopologicalMesh.hpp index deb222595ad..8a0d862eb25 100644 --- a/src/Core/Geometry/TopologicalMesh.hpp +++ b/src/Core/Geometry/TopologicalMesh.hpp @@ -109,8 +109,7 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT template inline bool setWedgeData( const WedgeIndex& idx, const std::string& name, const T& value ); + + /// change WedgeData member name to value. + /// wd is moidified accordingly. + /// \return false if name is not of type T + /// \retrun true on sucess + template + inline bool + setWedgeAttrib( TopologicalMesh::WedgeData& wd, const std::string& name, const T& value ); + inline bool setWedgePosition( const WedgeIndex& idx, const Vector3& value ); template inline void setWedgeData( const TopologicalMesh::WedgeIndex& idx, diff --git a/src/Core/Geometry/TopologicalMesh.inl b/src/Core/Geometry/TopologicalMesh.inl index dc50fde0e91..6302111965c 100644 --- a/src/Core/Geometry/TopologicalMesh.inl +++ b/src/Core/Geometry/TopologicalMesh.inl @@ -375,6 +375,22 @@ inline void TopologicalMesh::set_normal( VertexHandle vh, FaceHandle fh, const N set_normal( halfedge_handle( vh, fh ), n ); } +inline void TopologicalMesh::propagate_normal_to_wedges( VertexHandle vh ) { + if ( !has_halfedge_normals() ) + { + LOG( logERROR ) << "TopologicalMesh has no normals, nothing set"; + return; + } + for ( VertexIHalfedgeIter vih_it = vih_iter( vh ); vih_it.is_valid(); ++vih_it ) + { + auto wd = getWedgeData( property( getWedgeIndexPph(), *vih_it ) ); + + m_wedges.setWedgeAttrib( wd, "in_normal", normal( vh ) ); + + replaceWedge( *vih_it, wd ); + } +} + inline TopologicalMesh::HalfedgeHandle TopologicalMesh::halfedge_handle( VertexHandle vh, FaceHandle fh ) const { for ( ConstVertexIHalfedgeIter vih_it = cvih_iter( vh ); vih_it.is_valid(); ++vih_it ) @@ -733,6 +749,26 @@ inline void TopologicalMesh::WedgeCollection::garbageCollection() { m_data.end() ); } +template +inline bool TopologicalMesh::WedgeCollection::setWedgeAttrib( TopologicalMesh::WedgeData& wd, + const std::string& name, + const T& value ) { + auto nameArray = getNameArray(); + auto itr = std::find( nameArray.begin(), nameArray.end(), name ); + if ( itr != nameArray.end() ) + { + auto attrIndex = std::distance( nameArray.begin(), itr ); + wd.getAttribArray()[attrIndex] = value; + return true; + } + else + { + LOG( logERROR ) << "Warning, set wedge: no wedge attrib named " << name << " of type " + << typeid( T ).name(); + } + return false; +} + } // namespace Geometry } // namespace Core } // namespace Ra From f1b3b5fc03e75ccecb43a3e12f73549d2cf4b988 Mon Sep 17 00:00:00 2001 From: dlyr Date: Wed, 17 Mar 2021 16:19:21 +0100 Subject: [PATCH 15/37] [core] Make topo ctor templated by index type (tri/poly). --- src/Core/Geometry/TopologicalMesh.cpp | 4 --- src/Core/Geometry/TopologicalMesh.hpp | 45 ++++++++++++++++++--------- src/Core/Geometry/TopologicalMesh.inl | 14 ++++++--- 3 files changed, 41 insertions(+), 22 deletions(-) diff --git a/src/Core/Geometry/TopologicalMesh.cpp b/src/Core/Geometry/TopologicalMesh.cpp index bb5d9f0299f..f21667ba6dc 100644 --- a/src/Core/Geometry/TopologicalMesh.cpp +++ b/src/Core/Geometry/TopologicalMesh.cpp @@ -126,10 +126,6 @@ void printWedgesInfo( const Ra::Core::Geometry::TopologicalMesh& topo ) { LOG( Utils::logINFO ) << wedgeInfo( topo, topo.property( topo.getWedgeIndexPph(), *itr ) ); } } -TopologicalMesh::TopologicalMesh( const TriangleMesh& triMesh ) : - TopologicalMesh( - triMesh, - DefaultNonManifoldFaceCommand( "[default ctor (props)]" ) ) {} TopologicalMesh::TopologicalMesh() { add_property( m_inputTriangleMeshIndexPph ); diff --git a/src/Core/Geometry/TopologicalMesh.hpp b/src/Core/Geometry/TopologicalMesh.hpp index 8a0d862eb25..dbd14a59047 100644 --- a/src/Core/Geometry/TopologicalMesh.hpp +++ b/src/Core/Geometry/TopologicalMesh.hpp @@ -63,6 +63,18 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT + explicit TopologicalMesh( const Ra::Core::Geometry::IndexedGeometry& mesh ); + /** * Construct a topological mesh from a triangle mesh. * This operation merges vertex with same position, but keeps vertex @@ -75,27 +87,16 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT - explicit TopologicalMesh( const Ra::Core::Geometry::TriangleMesh& triMesh, + template + explicit TopologicalMesh( const Ra::Core::Geometry::IndexedGeometry& mesh, NonManifoldFaceCommand command ); - /** - * \brief Convenience constructor - * \see TopologicalMesh( const Ra::Core::Geometry::TriangleMesh&, NonManifoldFaceCommand) - */ - explicit TopologicalMesh( const Ra::Core::Geometry::TriangleMesh& triMesh ); - template void initWithWedge( const Ra::Core::Geometry::IndexedGeometry& mesh ); template - void initWithWedge( const Ra::Core::Geometry::IndexedGeometry& triMesh, + void initWithWedge( const Ra::Core::Geometry::IndexedGeometry& mesh, NonManifoldFaceCommand command ); - /** - * Construct an empty topological mesh, only init mandatory properties. - */ - explicit TopologicalMesh(); - /** * Return a triangleMesh from the topological mesh. * \note This is a costly operation. @@ -306,6 +307,10 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT& getVec4AttribNames() const; inline const std::vector& getVec3AttribNames() const; @@ -493,6 +498,18 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT m_floatAttribNames; std::vector m_vector2AttribNames; diff --git a/src/Core/Geometry/TopologicalMesh.inl b/src/Core/Geometry/TopologicalMesh.inl index 6302111965c..ae99d52e2d0 100644 --- a/src/Core/Geometry/TopologicalMesh.inl +++ b/src/Core/Geometry/TopologicalMesh.inl @@ -113,11 +113,15 @@ struct hash_vec { } }; -template -inline TopologicalMesh::TopologicalMesh( const TriangleMesh& triMesh, - NonManifoldFaceCommand command ) : +template +TopologicalMesh::TopologicalMesh( const Ra::Core::Geometry::IndexedGeometry& mesh ) : + TopologicalMesh( mesh, DefaultNonManifoldFaceCommand( "[default ctor (props)]" ) ) {} + +template +TopologicalMesh::TopologicalMesh( const IndexedGeometry& mesh, + NonManifoldFaceCommand command ) : TopologicalMesh() { - initWithWedge( triMesh, command ); + initWithWedge( mesh, command ); } template @@ -129,6 +133,8 @@ template void TopologicalMesh::initWithWedge( const IndexedGeometry& mesh, NonManifoldFaceCommand command ) { + clean(); + LOG( logINFO ) << "TopologicalMesh: load mesh with " << mesh.getIndices().size() << " faces and " << mesh.vertices().size() << " vertices."; // use a hashmap for fast search of existing vertex position From 13f1086d9df53a208d9d2c647cc849b59e417dc5 Mon Sep 17 00:00:00 2001 From: dlyr Date: Sat, 27 Feb 2021 12:31:17 +0100 Subject: [PATCH 16/37] [core] Topo reorganize declarations (hpp/inl). --- src/Core/Geometry/TopologicalMesh.hpp | 229 ++++++----- src/Core/Geometry/TopologicalMesh.inl | 522 ++++++++++++++------------ 2 files changed, 391 insertions(+), 360 deletions(-) diff --git a/src/Core/Geometry/TopologicalMesh.hpp b/src/Core/Geometry/TopologicalMesh.hpp index dbd14a59047..6f89525b0e9 100644 --- a/src/Core/Geometry/TopologicalMesh.hpp +++ b/src/Core/Geometry/TopologicalMesh.hpp @@ -54,14 +54,16 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT; using base::PolyMesh_ArrayKernelT; - using Index = Ra::Core::Utils::Index; using Vector3 = Ra::Core::Vector3; + using Index = Ra::Core::Utils::Index; class Wedge; + class WedgeCollection; public: EIGEN_MAKE_ALIGNED_OPERATOR_NEW - using WedgeIndex = Index; + class WedgeData; + using WedgeIndex = Ra::Core::Utils::Index; /** * Construct an empty topological mesh, only initialize mandatory properties. @@ -144,7 +146,6 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT m_floatAttrib; - VectorArray m_vector2Attrib; - VectorArray m_vector3Attrib; - VectorArray m_vector4Attrib; - - template - inline VectorArray& getAttribArray(); - template - inline const VectorArray& getAttribArray() const; - - explicit WedgeData() = default; - inline bool operator==( const WedgeData& lhs ) const; - inline bool operator!=( const WedgeData& lhs ) const; - inline bool operator<( const WedgeData& lhs ) const; - friend Wedge; - - private: - // return 1 : equals, 2: strict less, 3: strict greater - template - static int compareVector( const T& a, const T& b ); - }; - /** * \name Topological operations */ @@ -339,24 +309,45 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT - class InitWedgeProps + /** + * Inner class WedgeData represents the actual data per wedge, including position. + * + * At any time m_position as to be equal to the wedge's vertex point. + * All wedges have the same set of attributes. + * Access and management is delegated to TopologicalMesh and WedgeCollection + */ + class WedgeData { public: - InitWedgeProps( TopologicalMesh* topo, - const Ra::Core::Geometry::IndexedGeometry& triMesh ) : - m_topo( topo ), m_triMesh( triMesh ) {} - void operator()( AttribBase* attr ) const; + EIGEN_MAKE_ALIGNED_OPERATOR_NEW + + explicit WedgeData() = default; + inline bool operator==( const WedgeData& lhs ) const; + inline bool operator!=( const WedgeData& lhs ) const; + inline bool operator<( const WedgeData& lhs ) const; + + template + inline VectorArray& getAttribArray(); + template + inline const VectorArray& getAttribArray() const; + friend Wedge; + + // Index m_inputTriangleMeshIndex; + // Index m_outputTriangleMeshIndex; + VertexHandle m_vertexHandle; + Vector3 m_position {}; + VectorArray m_floatAttrib; + VectorArray m_vector2Attrib; + VectorArray m_vector3Attrib; + VectorArray m_vector4Attrib; private: - TopologicalMesh* m_topo; - const Ra::Core::Geometry::IndexedGeometry& m_triMesh; + // return 1 : equals, 2: strict less, 3: strict greater + template + static int compareVector( const T& a, const T& b ); }; - class WedgeCollection; - // + private: /** * This private class manage wedge data and refcount, to maintain deleted status * @@ -364,12 +355,6 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT - inline const std::vector& getNameArray() const; - - template - inline std::vector& getNameArray(); - /** * Add wd to the wedge collection, and return the index. * If a wedge with same data is already present, it's index is returned, @@ -425,38 +410,35 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT inline const T& getWedgeData( const WedgeIndex& idx, const std::string& name ) const; template inline T& getWedgeData( const WedgeIndex& idx, int attribIndex ); + unsigned int getWedgeRefCount( const WedgeIndex& idx ) const; + /// \see TopologicalMesh::setWedgeData inline void setWedgeData( const WedgeIndex& idx, const WedgeData& wd ); /// \see TopologicalMesh::setWedgeData template inline bool setWedgeData( const WedgeIndex& idx, const std::string& name, const T& value ); + template + inline void setWedgeData( const TopologicalMesh::WedgeIndex& idx, + const int& attribIndex, + const T& value ); /// change WedgeData member name to value. /// wd is moidified accordingly. @@ -466,19 +448,15 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT - inline void setWedgeData( const TopologicalMesh::WedgeIndex& idx, - const int& attribIndex, - const T& value ); + inline int getWedgeAttribIndex( const std::string& name ); + + inline bool setWedgePosition( const WedgeIndex& idx, const Vector3& value ); + + /// management template - inline int getWedgeAttribIndex( const std::string& name ) { - auto nameArray = getNameArray(); - auto itr = std::find( nameArray.begin(), nameArray.end(), name ); - if ( itr != nameArray.end() ) { return std::distance( nameArray.begin(), itr ); } - return 0; - } + inline const std::vector& getNameArray() const; // name is supposed to be unique within all attribs // not checks are performed @@ -488,28 +466,19 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT computeCleanupOffset() const; - - /// remove unreferenced wedge, halfedges need to be reindexed. - inline void garbageCollection(); - /// \todo removeDuplicateWedge /// merge wedges with same data /// return old->new index correspondance to update wedgeIndexPph /// inline void removeDuplicateWedge + inline size_t size() const { return m_data.size(); } - inline void clean() { - m_data.clear(); - m_floatAttribNames.clear(); - m_vector2AttribNames.clear(); - m_vector3AttribNames.clear(); - m_vector4AttribNames.clear(); - m_wedgeFloatAttribHandles.clear(); - m_wedgeVector2AttribHandles.clear(); - m_wedgeVector3AttribHandles.clear(); - m_wedgeVector4AttribHandles.clear(); - } + /// remove unreferenced wedge, halfedges need to be reindexed. + inline void garbageCollection(); + + inline void clean(); + ///\ todo private: /// attrib names associated to vertex/wedges, getted from CoreMesh, if any, std::vector m_floatAttribNames; std::vector m_vector2AttribNames; @@ -522,10 +491,44 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT> m_wedgeVector3AttribHandles; std::vector> m_wedgeVector4AttribHandles; - // private: + template + inline std::vector& getNameArray(); AlignedStdVector m_data; }; + // internal function to build Core Mesh attribs correspondance to wedge attribs. + template + class InitWedgeProps + { + public: + InitWedgeProps( TopologicalMesh* topo, + const Ra::Core::Geometry::IndexedGeometry& triMesh ) : + m_topo( topo ), m_triMesh( triMesh ) {} + void operator()( AttribBase* attr ) const; + + private: + TopologicalMesh* m_topo; + const Ra::Core::Geometry::IndexedGeometry& m_triMesh; + }; + + //! [Default command implementation] + template + struct DefaultNonManifoldFaceCommand { + /// \brief details string is printed along with the message + DefaultNonManifoldFaceCommand( std::string details = {} ) : m_details {details} {} + /// \brief Initalize with input Ra::Core::Geometry::TriangleMesh + inline void initialize( const Ra::Core::Geometry::IndexedGeometry& ) {} + /// \brief Process non-manifold face + inline void process( const std::vector& /*face_vhandles*/ ) { + LOG( logWARNING ) << "Invalid face handle returned : face not added " + m_details; + } + /// \brief If needed, apply post-processing on the Ra::Core::Geometry::TopologicalMesh + inline void postProcess( TopologicalMesh& ) {} + //! [Default command implementation] + private: + std::string m_details; + }; + WedgeData interpolateWedgeAttributes( const WedgeData&, const WedgeData&, Scalar alpha ); template @@ -565,24 +568,6 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT>> m_vertexFaceWedgesWithSameNormals; friend class TMOperations; - - //! [Default command implementation] - template - struct DefaultNonManifoldFaceCommand { - /// \brief details string is printed along with the message - DefaultNonManifoldFaceCommand( std::string details = {} ) : m_details {details} {} - /// \brief Initalize with input Ra::Core::Geometry::TriangleMesh - inline void initialize( const Ra::Core::Geometry::IndexedGeometry& ) {} - /// \brief Process non-manifold face - inline void process( const std::vector& /*face_vhandles*/ ) { - LOG( logWARNING ) << "Invalid face handle returned : face not added " + m_details; - } - /// \brief If needed, apply post-processing on the Ra::Core::Geometry::TopologicalMesh - inline void postProcess( TopologicalMesh& ) {} - //! [Default command implementation] - private: - std::string m_details; - }; }; // heplers diff --git a/src/Core/Geometry/TopologicalMesh.inl b/src/Core/Geometry/TopologicalMesh.inl index ae99d52e2d0..cee5056e9e3 100644 --- a/src/Core/Geometry/TopologicalMesh.inl +++ b/src/Core/Geometry/TopologicalMesh.inl @@ -15,18 +15,6 @@ using PropPair = std::pair, OpenMesh::HPropHandleT>; /////////////////// WedgeData ////////////////////////////// //////////////////////////////////////////////////////////////////////////////// -// return 1 : equals, 2: strict less, 3: strict greater -template -int TopologicalMesh::WedgeData::compareVector( const T& a, const T& b ) { - for ( int i = 0; i < T::RowsAtCompileTime; i++ ) - { - if ( a[i] < b[i] ) return 2; - if ( a[i] > b[i] ) return 3; - } - // (a == b) - return 1; -} - inline bool TopologicalMesh::WedgeData::operator==( const TopologicalMesh::WedgeData& lhs ) const { return // do not have this yet, not sure we need to test them @@ -37,6 +25,10 @@ inline bool TopologicalMesh::WedgeData::operator==( const TopologicalMesh::Wedge m_vector4Attrib == lhs.m_vector4Attrib; } +bool TopologicalMesh::WedgeData::operator!=( const TopologicalMesh::WedgeData& lhs ) const { + return !( *this == lhs ); +} + inline bool TopologicalMesh::WedgeData::operator<( const TopologicalMesh::WedgeData& lhs ) const { CORE_ASSERT( ( m_floatAttrib.size() == lhs.m_floatAttrib.size() ) && @@ -79,10 +71,6 @@ inline bool TopologicalMesh::WedgeData::operator<( const TopologicalMesh::WedgeD return false; } -bool TopologicalMesh::WedgeData::operator!=( const TopologicalMesh::WedgeData& lhs ) const { - return !( *this == lhs ); -} - #define GET_ATTRIB_ARRAY_HELPER( TYPE, NAME ) \ template <> \ inline VectorArray& TopologicalMesh::WedgeData::getAttribArray() { \ @@ -104,6 +92,272 @@ inline VectorArray& TopologicalMesh::WedgeData::getAttribArray() { static_assert( sizeof( T ) == -1, "this type is not supported" ); } +// return 1 : equals, 2: strict less, 3: strict greater +template +int TopologicalMesh::WedgeData::compareVector( const T& a, const T& b ) { + for ( int i = 0; i < T::RowsAtCompileTime; i++ ) + { + if ( a[i] < b[i] ) return 2; + if ( a[i] > b[i] ) return 3; + } + // (a == b) + return 1; +} + +//////////////////////////////////////////////////////////////////////////////// +/////////////////// Wedge ////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +// all in class for the moment + +//////////////////////////////////////////////////////////////////////////////// +/////////////////// WedgeCollection ////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +inline void TopologicalMesh::WedgeCollection::del( const TopologicalMesh::WedgeIndex& idx ) { + if ( idx.isValid() ) m_data[idx].decrementRefCount(); +} + +inline TopologicalMesh::WedgeIndex +TopologicalMesh::WedgeCollection::newReference( const TopologicalMesh::WedgeIndex& idx ) { + if ( idx.isValid() ) m_data[idx].incrementRefCount(); + return idx; +} + +inline const TopologicalMesh::Wedge& +TopologicalMesh::WedgeCollection::getWedge( const TopologicalMesh::WedgeIndex& idx ) const { + return m_data[idx]; +} + +inline const TopologicalMesh::WedgeData& +TopologicalMesh::WedgeCollection::getWedgeData( const WedgeIndex& idx ) const { + CORE_ASSERT( idx.isValid() && !m_data[idx].isDeleted(), + "access to invalid or deleted wedge is prohibited" ); + + return m_data[idx].getWedgeData(); +} + +template +inline const T& +TopologicalMesh::WedgeCollection::getWedgeData( const TopologicalMesh::WedgeIndex& idx, + const std::string& name ) const { + if ( idx.isValid() ) + { + auto nameArray = getNameArray(); + auto itr = std::find( nameArray.begin(), nameArray.end(), name ); + if ( itr != nameArray.end() ) + { + auto attrIndex = std::distance( nameArray.begin(), itr ); + return m_data[idx].getWedgeData().getAttribArray()[attrIndex]; + } + else + { + LOG( logERROR ) << "Warning, set wedge: no wedge attrib named " << name << " of type " + << typeid( T ).name(); + } + } + static T dummy; + return dummy; +} + +template +inline T& TopologicalMesh::WedgeCollection::getWedgeData( const TopologicalMesh::WedgeIndex& idx, + int attribIndex ) { + return m_data[idx].getWedgeData().getAttribArray()[attribIndex]; +} + +inline unsigned int +TopologicalMesh::WedgeCollection::getWedgeRefCount( const WedgeIndex& idx ) const { + CORE_ASSERT( idx.isValid(), "access to invalid or deleted wedge is prohibited" ); + return m_data[idx].getRefCount(); +} + +inline void TopologicalMesh::WedgeCollection::setWedgeData( const TopologicalMesh::WedgeIndex& idx, + const TopologicalMesh::WedgeData& wd ) { + if ( !( wd.m_floatAttrib.size() == m_floatAttribNames.size() && + wd.m_vector2Attrib.size() == m_vector2AttribNames.size() && + wd.m_vector3Attrib.size() == m_vector3AttribNames.size() && + wd.m_vector4Attrib.size() == m_vector4AttribNames.size() ) ) + { + LOG( logWARNING ) << "Warning, topological mesh set wedge: number of attribs inconsistency"; + } + if ( idx.isValid() ) m_data[idx].setWedgeData( wd ); +} + +template +inline bool TopologicalMesh::WedgeCollection::setWedgeData( const TopologicalMesh::WedgeIndex& idx, + const std::string& name, + const T& value ) { + if ( idx.isValid() ) + { + auto nameArray = getNameArray(); + auto itr = std::find( nameArray.begin(), nameArray.end(), name ); + if ( itr != nameArray.end() ) + { + auto attrIndex = std::distance( nameArray.begin(), itr ); + m_data[idx].getWedgeData().getAttribArray()[attrIndex] = value; + return true; + } + else + { + LOG( logERROR ) << "Warning, set wedge: no wedge attrib named " << name << " of type " + << typeid( T ).name(); + } + } + return false; +} + +template +inline void TopologicalMesh::WedgeCollection::setWedgeData( const TopologicalMesh::WedgeIndex& idx, + const int& attrIndex, + const T& value ) { + m_data[idx].getWedgeData().getAttribArray()[attrIndex] = value; +} + +template +inline bool TopologicalMesh::WedgeCollection::setWedgeAttrib( TopologicalMesh::WedgeData& wd, + const std::string& name, + const T& value ) { + auto nameArray = getNameArray(); + auto itr = std::find( nameArray.begin(), nameArray.end(), name ); + if ( itr != nameArray.end() ) + { + auto attrIndex = std::distance( nameArray.begin(), itr ); + wd.getAttribArray()[attrIndex] = value; + return true; + } + else + { + LOG( logERROR ) << "Warning, set wedge: no wedge attrib named " << name << " of type " + << typeid( T ).name(); + } + return false; +} + +template +inline int TopologicalMesh::WedgeCollection::getWedgeAttribIndex( const std::string& name ) { + auto nameArray = getNameArray(); + auto itr = std::find( nameArray.begin(), nameArray.end(), name ); + if ( itr != nameArray.end() ) { return std::distance( nameArray.begin(), itr ); } + return 0; +} + +inline bool +TopologicalMesh::WedgeCollection::setWedgePosition( const TopologicalMesh::WedgeIndex& idx, + const Vector3& value ) { + if ( idx.isValid() ) + { + m_data[idx].getWedgeData().m_position = value; + return true; + } + return false; +} + +#define GET_NAME_ARRAY_HELPER( TYPE, NAME ) \ + template <> \ + inline const std::vector& TopologicalMesh::WedgeCollection::getNameArray() \ + const { \ + return m_##NAME##AttribNames; \ + } \ + template <> \ + inline std::vector& TopologicalMesh::WedgeCollection::getNameArray() { \ + return m_##NAME##AttribNames; \ + } + +GET_NAME_ARRAY_HELPER( float, float ) +GET_NAME_ARRAY_HELPER( Vector2, vector2 ) +GET_NAME_ARRAY_HELPER( Vector3, vector3 ) +GET_NAME_ARRAY_HELPER( Vector4, vector4 ) + +#undef GET_NAME_ARRAY_HELPER +// These template functions are defined above for supported types. +// For unsupported types they simply generate a compile error. +template +inline const std::vector& TopologicalMesh::WedgeCollection::getNameArray() const { + + LOG( logWARNING ) << "Warning, mesh attribute " << typeid( T ).name() + << " is not supported (only float, vec2, vec3 nor vec4 are supported)"; + static_assert( sizeof( T ) == -1, "this type is not supported" ); + return m_floatAttribNames; +} + +template +inline std::vector& TopologicalMesh::WedgeCollection::getNameArray() { + + LOG( logWARNING ) << "Warning, mesh attribute " << typeid( T ).name() + << " is not supported (only float, vec2, vec3 nor vec4 are supported)"; + static_assert( sizeof( T ) == -1, "this type is not supported" ); + return m_floatAttribNames; +} +template +void TopologicalMesh::WedgeCollection::addProp( const std::string& name ) { + if ( name != std::string( "in_position" ) ) { getNameArray().push_back( name ); } +} + +inline void TopologicalMesh::WedgeCollection::garbageCollection() { + m_data.erase( std::remove_if( m_data.begin(), + m_data.end(), + []( const Wedge& w ) { return w.isDeleted(); } ), + m_data.end() ); +} + +inline void TopologicalMesh::WedgeCollection::clean() { + m_data.clear(); + m_floatAttribNames.clear(); + m_vector2AttribNames.clear(); + m_vector3AttribNames.clear(); + m_vector4AttribNames.clear(); + m_wedgeFloatAttribHandles.clear(); + m_wedgeVector2AttribHandles.clear(); + m_wedgeVector3AttribHandles.clear(); + m_wedgeVector4AttribHandles.clear(); +} + +//////////////////////////////////////////////////////////////////////////////// +/////////////////// InitWedgeProps ////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +template +void TopologicalMesh::InitWedgeProps::operator()( AttribBase* attr ) const { + if ( attr->getSize() != m_triMesh.vertices().size() ) + { LOG( logWARNING ) << "[TopologicalMesh] Skip badly sized attribute " << attr->getName(); } + else if ( attr->getName() != std::string( "in_position" ) ) + { + if ( attr->isFloat() ) + { + m_topo->m_wedges.m_wedgeFloatAttribHandles.push_back( + m_triMesh.template getAttribHandle( attr->getName() ) ); + m_topo->m_wedges.addProp( attr->getName() ); + } + else if ( attr->isVector2() ) + { + m_topo->m_wedges.m_wedgeVector2AttribHandles.push_back( + m_triMesh.template getAttribHandle( attr->getName() ) ); + m_topo->m_wedges.addProp( attr->getName() ); + } + else if ( attr->isVector3() ) + { + m_topo->m_wedges.m_wedgeVector3AttribHandles.push_back( + m_triMesh.template getAttribHandle( attr->getName() ) ); + m_topo->m_wedges.addProp( attr->getName() ); + } + else if ( attr->isVector4() ) + { + m_topo->m_wedges.m_wedgeVector4AttribHandles.push_back( + m_triMesh.template getAttribHandle( attr->getName() ) ); + m_topo->m_wedges.addProp( attr->getName() ); + } + else + LOG( logWARNING ) + << "Warning, mesh attribute " << attr->getName() + << " type is not supported (only float, vec2, vec3 nor vec4 are supported)"; + } +} + +//////////////////////////////////////////////////////////////////////////////// +/////////////////// TopologicalMesh ////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + struct hash_vec { std::size_t operator()( const Vector3& lvalue ) const { size_t hx = std::hash()( lvalue[0] ); @@ -478,48 +732,15 @@ TopologicalMesh::getWedgeIndex( OpenMesh::HalfedgeHandle heh ) const { return property( getWedgeIndexPph(), heh ); } -inline const TopologicalMesh::WedgeData& -TopologicalMesh::getWedgeData( const WedgeIndex& idx ) const { - return m_wedges.getWedgeData( idx ); -} - -template -inline const T& TopologicalMesh::getWedgeData( const TopologicalMesh::WedgeIndex& idx, - const std::string& name ) const { - return m_wedges.getWedgeData( idx, name ); -} - -template -inline const T& -TopologicalMesh::WedgeCollection::getWedgeData( const TopologicalMesh::WedgeIndex& idx, - const std::string& name ) const { - if ( idx.isValid() ) - { - auto nameArray = getNameArray(); - auto itr = std::find( nameArray.begin(), nameArray.end(), name ); - if ( itr != nameArray.end() ) - { - auto attrIndex = std::distance( nameArray.begin(), itr ); - return m_data[idx].getWedgeData().getAttribArray()[attrIndex]; - } - else - { - LOG( logERROR ) << "Warning, set wedge: no wedge attrib named " << name << " of type " - << typeid( T ).name(); - } - } - static T dummy; - return dummy; +inline unsigned int TopologicalMesh::getWedgeRefCount( const WedgeIndex& idx ) const { + return m_wedges.getWedgeRefCount( idx ); } template -inline T& TopologicalMesh::WedgeCollection::getWedgeData( const TopologicalMesh::WedgeIndex& idx, - int attribIndex ) { - return m_data[idx].getWedgeData().getAttribArray()[attribIndex]; -} - -inline unsigned int TopologicalMesh::getWedgeRefCount( const WedgeIndex& idx ) const { - return m_wedges.getWedgeRefCount( idx ); +inline bool TopologicalMesh::setWedgeData( const TopologicalMesh::WedgeIndex& idx, + const std::string& name, + const T& value ) { + return m_wedges.setWedgeData( idx, name, value ); } inline void TopologicalMesh::setWedgeData( TopologicalMesh::WedgeIndex widx, @@ -527,11 +748,15 @@ inline void TopologicalMesh::setWedgeData( TopologicalMesh::WedgeIndex widx, m_wedges.setWedgeData( widx, wedge ); } +inline const TopologicalMesh::WedgeData& +TopologicalMesh::getWedgeData( const WedgeIndex& idx ) const { + return m_wedges.getWedgeData( idx ); +} + template -inline bool TopologicalMesh::setWedgeData( const TopologicalMesh::WedgeIndex& idx, - const std::string& name, - const T& value ) { - return m_wedges.setWedgeData( idx, name, value ); +inline const T& TopologicalMesh::getWedgeData( const TopologicalMesh::WedgeIndex& idx, + const std::string& name ) const { + return m_wedges.getWedgeData( idx, name ); } inline void TopologicalMesh::replaceWedge( OpenMesh::HalfedgeHandle he, const WedgeData& wd ) { @@ -596,185 +821,6 @@ TopologicalMesh::getWedgeIndexPph() const { return m_wedgeIndexPph; } -template -void TopologicalMesh::InitWedgeProps::operator()( AttribBase* attr ) const { - if ( attr->getSize() != m_triMesh.vertices().size() ) - { LOG( logWARNING ) << "[TopologicalMesh] Skip badly sized attribute " << attr->getName(); } - else if ( attr->getName() != std::string( "in_position" ) ) - { - if ( attr->isFloat() ) - { - m_topo->m_wedges.m_wedgeFloatAttribHandles.push_back( - m_triMesh.template getAttribHandle( attr->getName() ) ); - m_topo->m_wedges.addProp( attr->getName() ); - } - else if ( attr->isVector2() ) - { - m_topo->m_wedges.m_wedgeVector2AttribHandles.push_back( - m_triMesh.template getAttribHandle( attr->getName() ) ); - m_topo->m_wedges.addProp( attr->getName() ); - } - else if ( attr->isVector3() ) - { - m_topo->m_wedges.m_wedgeVector3AttribHandles.push_back( - m_triMesh.template getAttribHandle( attr->getName() ) ); - m_topo->m_wedges.addProp( attr->getName() ); - } - else if ( attr->isVector4() ) - { - m_topo->m_wedges.m_wedgeVector4AttribHandles.push_back( - m_triMesh.template getAttribHandle( attr->getName() ) ); - m_topo->m_wedges.addProp( attr->getName() ); - } - else - LOG( logWARNING ) - << "Warning, mesh attribute " << attr->getName() - << " type is not supported (only float, vec2, vec3 nor vec4 are supported)"; - } -} - -//////////////////////////////////////////////////////////////////////////////// -/////////////////// WEDGES RELATED STUFF ////////////////////////////// -/////////////////// WedgeCollection ////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// - -inline void TopologicalMesh::WedgeCollection::del( const TopologicalMesh::WedgeIndex& idx ) { - if ( idx.isValid() ) m_data[idx].decrementRefCount(); -} - -inline TopologicalMesh::WedgeIndex -TopologicalMesh::WedgeCollection::newReference( const TopologicalMesh::WedgeIndex& idx ) { - if ( idx.isValid() ) m_data[idx].incrementRefCount(); - return idx; -} - -inline const TopologicalMesh::Wedge& -TopologicalMesh::WedgeCollection::getWedge( const TopologicalMesh::WedgeIndex& idx ) const { - return m_data[idx]; -} - -inline void TopologicalMesh::WedgeCollection::setWedgeData( const TopologicalMesh::WedgeIndex& idx, - const TopologicalMesh::WedgeData& wd ) { - if ( !( wd.m_floatAttrib.size() == m_floatAttribNames.size() && - wd.m_vector2Attrib.size() == m_vector2AttribNames.size() && - wd.m_vector3Attrib.size() == m_vector3AttribNames.size() && - wd.m_vector4Attrib.size() == m_vector4AttribNames.size() ) ) - { - LOG( logWARNING ) << "Warning, topological mesh set wedge: number of attribs inconsistency"; - } - if ( idx.isValid() ) m_data[idx].setWedgeData( wd ); -} - -#define GET_NAME_ARRAY_HELPER( TYPE, NAME ) \ - template <> \ - inline const std::vector& TopologicalMesh::WedgeCollection::getNameArray() \ - const { \ - return m_##NAME##AttribNames; \ - } \ - template <> \ - inline std::vector& TopologicalMesh::WedgeCollection::getNameArray() { \ - return m_##NAME##AttribNames; \ - } - -GET_NAME_ARRAY_HELPER( float, float ) -GET_NAME_ARRAY_HELPER( Vector2, vector2 ) -GET_NAME_ARRAY_HELPER( Vector3, vector3 ) -GET_NAME_ARRAY_HELPER( Vector4, vector4 ) - -#undef GET_NAME_ARRAY_HELPER -// These template functions are defined above for supported types. -// For unsupported types they simply generate a compile error. -template -inline const std::vector& TopologicalMesh::WedgeCollection::getNameArray() const { - - LOG( logWARNING ) << "Warning, mesh attribute " << typeid( T ).name() - << " is not supported (only float, vec2, vec3 nor vec4 are supported)"; - static_assert( sizeof( T ) == -1, "this type is not supported" ); - return m_floatAttribNames; -} - -template -inline std::vector& TopologicalMesh::WedgeCollection::getNameArray() { - - LOG( logWARNING ) << "Warning, mesh attribute " << typeid( T ).name() - << " is not supported (only float, vec2, vec3 nor vec4 are supported)"; - static_assert( sizeof( T ) == -1, "this type is not supported" ); - return m_floatAttribNames; -} - -template -inline bool TopologicalMesh::WedgeCollection::setWedgeData( const TopologicalMesh::WedgeIndex& idx, - const std::string& name, - const T& value ) { - if ( idx.isValid() ) - { - auto nameArray = getNameArray(); - auto itr = std::find( nameArray.begin(), nameArray.end(), name ); - if ( itr != nameArray.end() ) - { - auto attrIndex = std::distance( nameArray.begin(), itr ); - m_data[idx].getWedgeData().getAttribArray()[attrIndex] = value; - return true; - } - else - { - LOG( logERROR ) << "Warning, set wedge: no wedge attrib named " << name << " of type " - << typeid( T ).name(); - } - } - return false; -} - -template -inline void TopologicalMesh::WedgeCollection::setWedgeData( const TopologicalMesh::WedgeIndex& idx, - const int& attrIndex, - const T& value ) { - m_data[idx].getWedgeData().getAttribArray()[attrIndex] = value; -} - -inline bool -TopologicalMesh::WedgeCollection::setWedgePosition( const TopologicalMesh::WedgeIndex& idx, - const Vector3& value ) { - if ( idx.isValid() ) - { - m_data[idx].getWedgeData().m_position = value; - return true; - } - return false; -} - -template -void TopologicalMesh::WedgeCollection::addProp( const std::string& name ) { - if ( name != std::string( "in_position" ) ) { getNameArray().push_back( name ); } -} - -inline void TopologicalMesh::WedgeCollection::garbageCollection() { - m_data.erase( std::remove_if( m_data.begin(), - m_data.end(), - []( const Wedge& w ) { return w.isDeleted(); } ), - m_data.end() ); -} - -template -inline bool TopologicalMesh::WedgeCollection::setWedgeAttrib( TopologicalMesh::WedgeData& wd, - const std::string& name, - const T& value ) { - auto nameArray = getNameArray(); - auto itr = std::find( nameArray.begin(), nameArray.end(), name ); - if ( itr != nameArray.end() ) - { - auto attrIndex = std::distance( nameArray.begin(), itr ); - wd.getAttribArray()[attrIndex] = value; - return true; - } - else - { - LOG( logERROR ) << "Warning, set wedge: no wedge attrib named " << name << " of type " - << typeid( T ).name(); - } - return false; -} - } // namespace Geometry } // namespace Core } // namespace Ra From edf8fbf481da60a467889d06d407fc31736a396a Mon Sep 17 00:00:00 2001 From: dlyr Date: Sat, 27 Feb 2021 13:32:25 +0100 Subject: [PATCH 17/37] [core] remove deprecated unused using decl. --- src/Core/Geometry/TopologicalMesh.hpp | 3 --- src/Core/Geometry/TopologicalMesh.inl | 2 -- 2 files changed, 5 deletions(-) diff --git a/src/Core/Geometry/TopologicalMesh.hpp b/src/Core/Geometry/TopologicalMesh.hpp index 6f89525b0e9..e76944ba824 100644 --- a/src/Core/Geometry/TopologicalMesh.hpp +++ b/src/Core/Geometry/TopologicalMesh.hpp @@ -550,9 +550,6 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT, T>, Eigen::aligned_allocator, T>>>; - template - using PropPair = std::pair, OpenMesh::HPropHandleT>; - void split_copy( EdgeHandle _eh, VertexHandle _vh ); void split( EdgeHandle _eh, VertexHandle _vh ); diff --git a/src/Core/Geometry/TopologicalMesh.inl b/src/Core/Geometry/TopologicalMesh.inl index cee5056e9e3..360a30ef757 100644 --- a/src/Core/Geometry/TopologicalMesh.inl +++ b/src/Core/Geometry/TopologicalMesh.inl @@ -8,8 +8,6 @@ namespace Ra { namespace Core { namespace Geometry { -template -using PropPair = std::pair, OpenMesh::HPropHandleT>; //////////////////////////////////////////////////////////////////////////////// /////////////////// WedgeData ////////////////////////////// From b5de901d2633c4a080eb3be9d34c951068550c70 Mon Sep 17 00:00:00 2001 From: dlyr Date: Sat, 27 Feb 2021 13:39:30 +0100 Subject: [PATCH 18/37] [core] rename addProp to addAttrib form wedge collection. --- src/Core/Geometry/TopologicalMesh.hpp | 2 +- src/Core/Geometry/TopologicalMesh.inl | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Core/Geometry/TopologicalMesh.hpp b/src/Core/Geometry/TopologicalMesh.hpp index e76944ba824..9226e3c087a 100644 --- a/src/Core/Geometry/TopologicalMesh.hpp +++ b/src/Core/Geometry/TopologicalMesh.hpp @@ -461,7 +461,7 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT - void addProp( const std::string& name ); + void addAttrib( const std::string& name ); /// return the offset ot apply to each wedgeindex so that /// after garbageCollection all indices are valid and coherent. diff --git a/src/Core/Geometry/TopologicalMesh.inl b/src/Core/Geometry/TopologicalMesh.inl index 360a30ef757..532734f06ef 100644 --- a/src/Core/Geometry/TopologicalMesh.inl +++ b/src/Core/Geometry/TopologicalMesh.inl @@ -288,7 +288,7 @@ inline std::vector& TopologicalMesh::WedgeCollection::getNameArray( return m_floatAttribNames; } template -void TopologicalMesh::WedgeCollection::addProp( const std::string& name ) { +void TopologicalMesh::WedgeCollection::addAttrib( const std::string& name ) { if ( name != std::string( "in_position" ) ) { getNameArray().push_back( name ); } } @@ -325,25 +325,25 @@ void TopologicalMesh::InitWedgeProps::operator()( AttribBase* attr ) const { { m_topo->m_wedges.m_wedgeFloatAttribHandles.push_back( m_triMesh.template getAttribHandle( attr->getName() ) ); - m_topo->m_wedges.addProp( attr->getName() ); + m_topo->m_wedges.addAttrib( attr->getName() ); } else if ( attr->isVector2() ) { m_topo->m_wedges.m_wedgeVector2AttribHandles.push_back( m_triMesh.template getAttribHandle( attr->getName() ) ); - m_topo->m_wedges.addProp( attr->getName() ); + m_topo->m_wedges.addAttrib( attr->getName() ); } else if ( attr->isVector3() ) { m_topo->m_wedges.m_wedgeVector3AttribHandles.push_back( m_triMesh.template getAttribHandle( attr->getName() ) ); - m_topo->m_wedges.addProp( attr->getName() ); + m_topo->m_wedges.addAttrib( attr->getName() ); } else if ( attr->isVector4() ) { m_topo->m_wedges.m_wedgeVector4AttribHandles.push_back( m_triMesh.template getAttribHandle( attr->getName() ) ); - m_topo->m_wedges.addProp( attr->getName() ); + m_topo->m_wedges.addAttrib( attr->getName() ); } else LOG( logWARNING ) From e5d96a0d4ce8e21ad306343bc149504d4b2a9f2a Mon Sep 17 00:00:00 2001 From: dlyr Date: Sat, 27 Feb 2021 13:46:33 +0100 Subject: [PATCH 19/37] [core] rename setWedgeData to setWedgeAttrib to set one attrib. --- src/Core/Geometry/TopologicalMesh.cpp | 2 +- src/Core/Geometry/TopologicalMesh.hpp | 18 ++++----- src/Core/Geometry/TopologicalMesh.inl | 56 ++++++++++++++------------- 3 files changed, 38 insertions(+), 38 deletions(-) diff --git a/src/Core/Geometry/TopologicalMesh.cpp b/src/Core/Geometry/TopologicalMesh.cpp index f21667ba6dc..c7f0288f6d0 100644 --- a/src/Core/Geometry/TopologicalMesh.cpp +++ b/src/Core/Geometry/TopologicalMesh.cpp @@ -359,7 +359,7 @@ void TopologicalMesh::updateNormals( const Ra::Core::Geometry::TriangleMesh& tri #pragma omp parallel for for ( size_t i = 0; i < triMesh.vertices().size(); ++i ) { - m_wedges.setWedgeData( i, m_normalsIndex, normals[i] ); + m_wedges.setWedgeAttrib( i, m_normalsIndex, normals[i] ); } } diff --git a/src/Core/Geometry/TopologicalMesh.hpp b/src/Core/Geometry/TopologicalMesh.hpp index 9226e3c087a..cd12753f537 100644 --- a/src/Core/Geometry/TopologicalMesh.hpp +++ b/src/Core/Geometry/TopologicalMesh.hpp @@ -154,8 +154,7 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT - template - inline bool setWedgeData( const WedgeIndex& idx, const std::string& name, const T& value ); - template - inline void setWedgeData( const TopologicalMesh::WedgeIndex& idx, - const int& attribIndex, - const T& value ); - /// change WedgeData member name to value. /// wd is moidified accordingly. /// \return false if name is not of type T @@ -447,6 +438,13 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT inline bool setWedgeAttrib( TopologicalMesh::WedgeData& wd, const std::string& name, const T& value ); + template + inline bool + setWedgeAttrib( const WedgeIndex& idx, const std::string& name, const T& value ); + template + inline void setWedgeAttrib( const TopologicalMesh::WedgeIndex& idx, + const int& attribIndex, + const T& value ); template inline int getWedgeAttribIndex( const std::string& name ); diff --git a/src/Core/Geometry/TopologicalMesh.inl b/src/Core/Geometry/TopologicalMesh.inl index 532734f06ef..c3c2ea1d66b 100644 --- a/src/Core/Geometry/TopologicalMesh.inl +++ b/src/Core/Geometry/TopologicalMesh.inl @@ -183,9 +183,30 @@ inline void TopologicalMesh::WedgeCollection::setWedgeData( const TopologicalMes } template -inline bool TopologicalMesh::WedgeCollection::setWedgeData( const TopologicalMesh::WedgeIndex& idx, - const std::string& name, - const T& value ) { +inline bool TopologicalMesh::WedgeCollection::setWedgeAttrib( TopologicalMesh::WedgeData& wd, + const std::string& name, + const T& value ) { + auto nameArray = getNameArray(); + auto itr = std::find( nameArray.begin(), nameArray.end(), name ); + if ( itr != nameArray.end() ) + { + auto attrIndex = std::distance( nameArray.begin(), itr ); + wd.getAttribArray()[attrIndex] = value; + return true; + } + else + { + LOG( logERROR ) << "Warning, set wedge: no wedge attrib named " << name << " of type " + << typeid( T ).name(); + } + return false; +} + +template +inline bool +TopologicalMesh::WedgeCollection::setWedgeAttrib( const TopologicalMesh::WedgeIndex& idx, + const std::string& name, + const T& value ) { if ( idx.isValid() ) { auto nameArray = getNameArray(); @@ -206,32 +227,13 @@ inline bool TopologicalMesh::WedgeCollection::setWedgeData( const TopologicalMes } template -inline void TopologicalMesh::WedgeCollection::setWedgeData( const TopologicalMesh::WedgeIndex& idx, - const int& attrIndex, - const T& value ) { +inline void +TopologicalMesh::WedgeCollection::setWedgeAttrib( const TopologicalMesh::WedgeIndex& idx, + const int& attrIndex, + const T& value ) { m_data[idx].getWedgeData().getAttribArray()[attrIndex] = value; } -template -inline bool TopologicalMesh::WedgeCollection::setWedgeAttrib( TopologicalMesh::WedgeData& wd, - const std::string& name, - const T& value ) { - auto nameArray = getNameArray(); - auto itr = std::find( nameArray.begin(), nameArray.end(), name ); - if ( itr != nameArray.end() ) - { - auto attrIndex = std::distance( nameArray.begin(), itr ); - wd.getAttribArray()[attrIndex] = value; - return true; - } - else - { - LOG( logERROR ) << "Warning, set wedge: no wedge attrib named " << name << " of type " - << typeid( T ).name(); - } - return false; -} - template inline int TopologicalMesh::WedgeCollection::getWedgeAttribIndex( const std::string& name ) { auto nameArray = getNameArray(); @@ -738,7 +740,7 @@ template inline bool TopologicalMesh::setWedgeData( const TopologicalMesh::WedgeIndex& idx, const std::string& name, const T& value ) { - return m_wedges.setWedgeData( idx, name, value ); + return m_wedges.setWedgeAttrib( idx, name, value ); } inline void TopologicalMesh::setWedgeData( TopologicalMesh::WedgeIndex widx, From be82741560241c422e2ecd2bab91a97f334318f5 Mon Sep 17 00:00:00 2001 From: dlyr Date: Sat, 27 Feb 2021 13:49:11 +0100 Subject: [PATCH 20/37] [core] more deprecation, is "mostly" handled by wedges, need new helpers function. --- src/Core/Geometry/TopologicalMesh.hpp | 12 ------------ src/Core/Geometry/TopologicalMesh.inl | 22 ---------------------- 2 files changed, 34 deletions(-) diff --git a/src/Core/Geometry/TopologicalMesh.hpp b/src/Core/Geometry/TopologicalMesh.hpp index cd12753f537..6df7af5a48f 100644 --- a/src/Core/Geometry/TopologicalMesh.hpp +++ b/src/Core/Geometry/TopologicalMesh.hpp @@ -135,18 +135,6 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT& mesh, copyAttribToWedgeData( mesh, vindex, wprop_vec4, &wd->m_vector4Attrib ); } -inline const TopologicalMesh::Normal& TopologicalMesh::normal( VertexHandle vh, - FaceHandle fh ) const { - // find halfedge that point to vh and member of fh - if ( !has_halfedge_normals() ) - { - LOG( logERROR ) << "TopologicalMesh has no normals, return dummy ref to (0,0,0)"; - static TopologicalMesh::Normal dummy {0_ra, 0_ra, 0_ra}; - return dummy; - } - return normal( halfedge_handle( vh, fh ) ); -} - -inline void TopologicalMesh::set_normal( VertexHandle vh, FaceHandle fh, const Normal& n ) { - if ( !has_halfedge_normals() ) - { - LOG( logERROR ) << "TopologicalMesh has no normals, nothing set"; - return; - } - - set_normal( halfedge_handle( vh, fh ), n ); -} - inline void TopologicalMesh::propagate_normal_to_wedges( VertexHandle vh ) { if ( !has_halfedge_normals() ) { From 7d7e161e3bc91a05f464efde001ac0cf0ca76455 Mon Sep 17 00:00:00 2001 From: dlyr Date: Sat, 27 Feb 2021 14:57:42 +0100 Subject: [PATCH 21/37] [core] topo remove omp parallel for (windows error) --- src/Core/Geometry/TopologicalMesh.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Core/Geometry/TopologicalMesh.cpp b/src/Core/Geometry/TopologicalMesh.cpp index c7f0288f6d0..75be39821be 100644 --- a/src/Core/Geometry/TopologicalMesh.cpp +++ b/src/Core/Geometry/TopologicalMesh.cpp @@ -304,7 +304,6 @@ void TopologicalMesh::updateTriangleMeshNormals( return; } -#pragma omp parallel for for ( unsigned int widx = 0; widx < m_wedges.size(); ++widx ) { normals[widx] = m_wedges.getWedgeData( widx, m_normalsIndex ); @@ -346,7 +345,6 @@ void TopologicalMesh::updatePositions( const Ra::Core::Geometry::TriangleMesh& t void TopologicalMesh::updatePositions( const AttribArrayGeometry::PointAttribHandle::Container& vertices ) { -#pragma omp parallel for for ( size_t i = 0; i < vertices.size(); ++i ) { m_wedges.m_data[i].getWedgeData().m_position = vertices[i]; @@ -356,7 +354,7 @@ void TopologicalMesh::updatePositions( void TopologicalMesh::updateNormals( const Ra::Core::Geometry::TriangleMesh& triMesh ) { auto& normals = triMesh.normals(); -#pragma omp parallel for + for ( size_t i = 0; i < triMesh.vertices().size(); ++i ) { m_wedges.setWedgeAttrib( i, m_normalsIndex, normals[i] ); From 181674187f24d2deb1791086a41085c898081410 Mon Sep 17 00:00:00 2001 From: dlyr Date: Tue, 2 Mar 2021 00:15:57 +0100 Subject: [PATCH 22/37] [core] topo add newWedge function and some aliases. --- src/Core/Geometry/TopologicalMesh.hpp | 24 +++++++++++--- src/Core/Geometry/TopologicalMesh.inl | 45 ++++++++++++++++++++++----- 2 files changed, 58 insertions(+), 11 deletions(-) diff --git a/src/Core/Geometry/TopologicalMesh.hpp b/src/Core/Geometry/TopologicalMesh.hpp index 6df7af5a48f..78c8b574974 100644 --- a/src/Core/Geometry/TopologicalMesh.hpp +++ b/src/Core/Geometry/TopologicalMesh.hpp @@ -237,6 +237,8 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT inline bool setWedgeData( const WedgeIndex& idx, const std::string& name, const T& value ); + inline WedgeData newWedgeData() { return m_wedges.newWedgeData(); } + /** * Replace the wedge data associated with an halfedge. * The old wedge is "deleted". If wedge data correspond to an already @@ -244,6 +246,11 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT + inline int addWedgeAttrib( const std::string& name, T value = {} ) { + return m_wedges.addAttrib( name, value ); + } + /** * Replace the wedge index associated with an halfedge. * The old wedge is "deleted". The new wedge reference count is incremented. @@ -446,8 +453,13 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT - void addAttrib( const std::string& name ); + int addAttribName( const std::string& name ); + + // add attrib to all wedges with default value value + template + int addAttrib( const std::string& name, const T& value = {} ); /// return the offset ot apply to each wedgeindex so that /// after garbageCollection all indices are valid and coherent. @@ -464,6 +476,9 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT m_floatAttribNames; @@ -472,6 +487,7 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT m_vector4AttribNames; /// attrib handle from the CoreMesh given at construction, if any. + /// used by TopologicalMesh::update() std::vector> m_wedgeFloatAttribHandles; std::vector> m_wedgeVector2AttribHandles; std::vector> m_wedgeVector3AttribHandles; @@ -484,11 +500,11 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT - class InitWedgeProps + class InitWedgeAttribs { public: - InitWedgeProps( TopologicalMesh* topo, - const Ra::Core::Geometry::IndexedGeometry& triMesh ) : + InitWedgeAttribs( TopologicalMesh* topo, + const Ra::Core::Geometry::IndexedGeometry& triMesh ) : m_topo( topo ), m_triMesh( triMesh ) {} void operator()( AttribBase* attr ) const; diff --git a/src/Core/Geometry/TopologicalMesh.inl b/src/Core/Geometry/TopologicalMesh.inl index 1f1caf2e5b3..421144591b3 100644 --- a/src/Core/Geometry/TopologicalMesh.inl +++ b/src/Core/Geometry/TopologicalMesh.inl @@ -290,8 +290,22 @@ inline std::vector& TopologicalMesh::WedgeCollection::getNameArray( return m_floatAttribNames; } template -void TopologicalMesh::WedgeCollection::addAttrib( const std::string& name ) { +int TopologicalMesh::WedgeCollection::addAttribName( const std::string& name ) { if ( name != std::string( "in_position" ) ) { getNameArray().push_back( name ); } + return getNameArray().size() - 1; +} + +template +int TopologicalMesh::WedgeCollection::addAttrib( const std::string& name, const T& value ) { + + auto index = addAttribName( name ); + for ( auto& w : m_data ) + { + CORE_ASSERT( index = w.getWedgeData().getAttribArray().size(), + "inconsistent wedge attrib" ); + w.getWedgeData().getAttribArray().push_back( value ); + } + return index; } inline void TopologicalMesh::WedgeCollection::garbageCollection() { @@ -313,12 +327,29 @@ inline void TopologicalMesh::WedgeCollection::clean() { m_wedgeVector4AttribHandles.clear(); } +template +void init( VectorArray& vec, const std::vector names ) { + for ( size_t i = 0; i < names.size(); ++i ) + { + vec.emplace_back(); + } +} +// return a new wedgeData with uninit values. +inline TopologicalMesh::WedgeData TopologicalMesh::WedgeCollection::newWedgeData() { + WedgeData ret; + init( ret.getAttribArray(), m_floatAttribNames ); + init( ret.getAttribArray(), m_vector2AttribNames ); + init( ret.getAttribArray(), m_vector3AttribNames ); + init( ret.getAttribArray(), m_vector4AttribNames ); + return ret; +} + //////////////////////////////////////////////////////////////////////////////// /////////////////// InitWedgeProps ////////////////////////////// //////////////////////////////////////////////////////////////////////////////// template -void TopologicalMesh::InitWedgeProps::operator()( AttribBase* attr ) const { +void TopologicalMesh::InitWedgeAttribs::operator()( AttribBase* attr ) const { if ( attr->getSize() != m_triMesh.vertices().size() ) { LOG( logWARNING ) << "[TopologicalMesh] Skip badly sized attribute " << attr->getName(); } else if ( attr->getName() != std::string( "in_position" ) ) @@ -327,25 +358,25 @@ void TopologicalMesh::InitWedgeProps::operator()( AttribBase* attr ) const { { m_topo->m_wedges.m_wedgeFloatAttribHandles.push_back( m_triMesh.template getAttribHandle( attr->getName() ) ); - m_topo->m_wedges.addAttrib( attr->getName() ); + m_topo->m_wedges.addAttribName( attr->getName() ); } else if ( attr->isVector2() ) { m_topo->m_wedges.m_wedgeVector2AttribHandles.push_back( m_triMesh.template getAttribHandle( attr->getName() ) ); - m_topo->m_wedges.addAttrib( attr->getName() ); + m_topo->m_wedges.addAttribName( attr->getName() ); } else if ( attr->isVector3() ) { m_topo->m_wedges.m_wedgeVector3AttribHandles.push_back( m_triMesh.template getAttribHandle( attr->getName() ) ); - m_topo->m_wedges.addAttrib( attr->getName() ); + m_topo->m_wedges.addAttribName( attr->getName() ); } else if ( attr->isVector4() ) { m_topo->m_wedges.m_wedgeVector4AttribHandles.push_back( m_triMesh.template getAttribHandle( attr->getName() ) ); - m_topo->m_wedges.addAttrib( attr->getName() ); + m_topo->m_wedges.addAttribName( attr->getName() ); } else LOG( logWARNING ) @@ -396,7 +427,7 @@ void TopologicalMesh::initWithWedge( const IndexedGeometry& mesh, VertexMap vertexHandles; // loop over all attribs and build correspondance pair - mesh.vertexAttribs().for_each_attrib( InitWedgeProps {this, mesh} ); + mesh.vertexAttribs().for_each_attrib( InitWedgeAttribs {this, mesh} ); size_t num_triangles = mesh.getIndices().size(); From a7161c8b234c9b88315da1b00f900c192795de20 Mon Sep 17 00:00:00 2001 From: dlyr Date: Tue, 2 Mar 2021 18:47:34 +0100 Subject: [PATCH 23/37] [core] topo improve newWedgeData. --- src/Core/Geometry/TopologicalMesh.hpp | 9 +++++++-- src/Core/Geometry/TopologicalMesh.inl | 11 ++++++++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/Core/Geometry/TopologicalMesh.hpp b/src/Core/Geometry/TopologicalMesh.hpp index 78c8b574974..261b71d8513 100644 --- a/src/Core/Geometry/TopologicalMesh.hpp +++ b/src/Core/Geometry/TopologicalMesh.hpp @@ -237,7 +237,10 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT inline bool setWedgeData( const WedgeIndex& idx, const std::string& name, const T& value ); - inline WedgeData newWedgeData() { return m_wedges.newWedgeData(); } + inline WedgeData newWedgeData() const { return m_wedges.newWedgeData(); } + inline WedgeData newWedgeData( HalfedgeHandle he ) const { + return m_wedges.newWedgeData( to_vertex_handle( he ), point( to_vertex_handle( he ) ) ); + } /** * Replace the wedge data associated with an halfedge. @@ -477,7 +480,9 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT& vec, const std::vector names ) { } } // return a new wedgeData with uninit values. -inline TopologicalMesh::WedgeData TopologicalMesh::WedgeCollection::newWedgeData() { +inline TopologicalMesh::WedgeData TopologicalMesh::WedgeCollection::newWedgeData() const { WedgeData ret; init( ret.getAttribArray(), m_floatAttribNames ); init( ret.getAttribArray(), m_vector2AttribNames ); @@ -344,6 +344,15 @@ inline TopologicalMesh::WedgeData TopologicalMesh::WedgeCollection::newWedgeData return ret; } +inline TopologicalMesh::WedgeData +TopologicalMesh::WedgeCollection::newWedgeData( TopologicalMesh::VertexHandle vh, + TopologicalMesh::Point p ) const { + WedgeData ret = newWedgeData(); + ret.m_vertexHandle = vh; + ret.m_position = p; + return ret; +} + //////////////////////////////////////////////////////////////////////////////// /////////////////// InitWedgeProps ////////////////////////////// //////////////////////////////////////////////////////////////////////////////// From 2825c78e3dba2985152ae75f50ab062f6664d472 Mon Sep 17 00:00:00 2001 From: dlyr Date: Wed, 17 Mar 2021 16:15:27 +0100 Subject: [PATCH 24/37] [tests] call splitEdge instead of alias splitEdgeWedge. [tests] topo clean test naming. [tests] add wedge management tests, wip to triangulate. [tests] Add topo triangulate. [tests] newWedgeData(he). [tests] topo unit tests check integrity of triangulated. --- tests/unittest/Core/topomesh.cpp | 170 ++++++++++++++++++++++++------- 1 file changed, 133 insertions(+), 37 deletions(-) diff --git a/tests/unittest/Core/topomesh.cpp b/tests/unittest/Core/topomesh.cpp index 29a4ff2a08a..2957b36456b 100644 --- a/tests/unittest/Core/topomesh.cpp +++ b/tests/unittest/Core/topomesh.cpp @@ -348,10 +348,11 @@ TEST_CASE( "Core/Geometry/TopologicalMesh", "[Core][Core/Geometry][TopologicalMe auto newMesh = topologicalMesh.toTriangleMesh(); topologicalMesh.setWedgeData( TopologicalMesh::WedgeIndex {0}, "in_normal", Vector3( 0, 0, 0 ) ); - auto newMesh3 = topologicalMesh.toTriangleMesh(); + auto newMeshModified = topologicalMesh.toTriangleMesh(); REQUIRE( isSameMesh( mesh, newMesh ) ); - REQUIRE( !isSameMeshWedge( mesh, newMesh3 ) ); + REQUIRE( isSameMeshWedge( mesh, newMesh ) ); + REQUIRE( !isSameMeshWedge( mesh, newMeshModified ) ); REQUIRE( topologicalMesh.checkIntegrity() ); } @@ -364,8 +365,6 @@ TEST_CASE( "Core/Geometry/TopologicalMesh", "[Core][Core/Geometry][TopologicalMe REQUIRE( topologicalMesh.checkIntegrity() ); } - /// \todo update to wedges - /* SECTION( "Test normals" ) { auto mesh = Ra::Core::Geometry::makeBox(); auto topologicalMesh = TopologicalMesh( mesh ); @@ -382,7 +381,7 @@ TEST_CASE( "Core/Geometry/TopologicalMesh", "[Core][Core/Geometry][TopologicalMe v_it != topologicalMesh.vertices_end(); ++v_it ) { - topologicalMesh.propagate_normal_to_halfedges( *v_it ); + topologicalMesh.propagate_normal_to_wedges( *v_it ); } auto newMesh = topologicalMesh.toTriangleMesh(); @@ -400,7 +399,7 @@ TEST_CASE( "Core/Geometry/TopologicalMesh", "[Core][Core/Geometry][TopologicalMe REQUIRE( check2 ); REQUIRE( topologicalMesh.checkIntegrity() ); } - */ + SECTION( "Test without normals" ) { VectorArray vertices = { {0_ra, 0_ra, 0_ra}, {0_ra, 1_ra, 0_ra}, {1_ra, 1_ra, 0_ra}, {1_ra, 0_ra, 0_ra}}; @@ -425,7 +424,7 @@ TEST_CASE( "Core/Geometry/TopologicalMesh", "[Core][Core/Geometry][TopologicalMe auto n = topo1.normal( *vitr, *fitr ); REQUIRE( Math::areApproxEqual( n.squaredNorm(), 0_ra ) ); } - topo1.propagate_normal_to_halfedges( *vitr ); + topo1.propagate_normal_to_wedges( *vitr ); REQUIRE( !topo1.has_halfedge_normals() ); REQUIRE( !topo1.has_face_normals() ); } @@ -452,7 +451,7 @@ void test_split( TopologicalMesh& topo, TopologicalMesh::EdgeHandle eh, float f float f0 = topo.getWedgeData( *( topo.getVertexWedges( v0 ) ).begin() ).m_floatAttrib[0]; auto p1 = topo.point( v1 ); float f1 = topo.getWedgeData( *( topo.getVertexWedges( v1 ) ).begin() ).m_floatAttrib[0]; - topo.splitEdgeWedge( eh, f ); + topo.splitEdge( eh, f ); // check validity REQUIRE( topo.is_valid_handle( he0 ) ); @@ -530,7 +529,7 @@ void test_poly() { TopologicalMesh topologicalMesh; topologicalMesh.initWithWedge( polyMesh ); - auto newMesh = topologicalMesh.toPolyMeshFromWedges(); + auto newMesh = topologicalMesh.toPolyMesh(); REQUIRE( isSameMeshWedge( newMesh, polyMesh ) ); } @@ -790,39 +789,33 @@ TEST_CASE( "Core/Geometry/TopologicalMesh/Manifold", "[Core][Core/Geometry][Topo TEST_CASE( "Core/Geometry/TopologicalMesh/Initialization", "[Core][Core/Geometry][TopologicalMesh]" ) { - Ra::Core::Geometry::TopologicalMesh topologicalMesh; - Ra::Core::Geometry::TopologicalMesh::VertexHandle vhandle[3]; - Ra::Core::Geometry::TopologicalMesh::FaceHandle fhandle; - - vhandle[0] = - topologicalMesh.add_vertex( Ra::Core::Geometry::TopologicalMesh::Point( 1, -1, -1 ) ); - vhandle[1] = - topologicalMesh.add_vertex( Ra::Core::Geometry::TopologicalMesh::Point( 1, -1, 1 ) ); - vhandle[2] = - topologicalMesh.add_vertex( Ra::Core::Geometry::TopologicalMesh::Point( -1, -1, 1 ) ); - - std::vector face_vhandles; + TopologicalMesh topo; + TopologicalMesh::VertexHandle vhandle[3]; + TopologicalMesh::FaceHandle fhandle; + + vhandle[0] = topo.add_vertex( TopologicalMesh::Point( 1, -1, -1 ) ); + vhandle[1] = topo.add_vertex( TopologicalMesh::Point( 1, -1, 1 ) ); + vhandle[2] = topo.add_vertex( TopologicalMesh::Point( -1, -1, 1 ) ); + + std::vector face_vhandles; face_vhandles.push_back( vhandle[0] ); face_vhandles.push_back( vhandle[1] ); face_vhandles.push_back( vhandle[2] ); - fhandle = topologicalMesh.add_face( face_vhandles ); + fhandle = topo.add_face( face_vhandles ); // newly created face have invalid wedges on halfedges - auto heh = topologicalMesh.halfedge_handle( fhandle ); - REQUIRE( topologicalMesh.property( topologicalMesh.getWedgeIndexPph(), heh ).isInvalid() ); - heh = topologicalMesh.next_halfedge_handle( heh ); - REQUIRE( topologicalMesh.property( topologicalMesh.getWedgeIndexPph(), heh ).isInvalid() ); - heh = topologicalMesh.next_halfedge_handle( heh ); - REQUIRE( topologicalMesh.property( topologicalMesh.getWedgeIndexPph(), heh ).isInvalid() ); - - std::cout << "faces: " << topologicalMesh.n_faces() << std::endl; - REQUIRE( topologicalMesh.n_faces() == 1 ); - - topologicalMesh.request_face_status(); - topologicalMesh.delete_face( fhandle, false ); - topologicalMesh.garbage_collection(); - std::cout << "faces: " << topologicalMesh.n_faces() << std::endl; - REQUIRE( topologicalMesh.n_faces() == 0 ); + auto heh = topo.halfedge_handle( fhandle ); + REQUIRE( topo.property( topo.getWedgeIndexPph(), heh ).isInvalid() ); + heh = topo.next_halfedge_handle( heh ); + REQUIRE( topo.property( topo.getWedgeIndexPph(), heh ).isInvalid() ); + heh = topo.next_halfedge_handle( heh ); + REQUIRE( topo.property( topo.getWedgeIndexPph(), heh ).isInvalid() ); + REQUIRE( topo.n_faces() == 1 ); + + topo.request_face_status(); + topo.delete_face( fhandle, false ); + topo.garbage_collection(); + REQUIRE( topo.n_faces() == 0 ); } TEST_CASE( "Core/Geometry/TopologicalMesh/MergeWedges", "[Core][Core/Geometry][TopologicalMesh]" ) { @@ -866,3 +859,106 @@ TEST_CASE( "Core/Geometry/TopologicalMesh/MergeWedges", "[Core][Core/Geometry][T REQUIRE( wedgesIndices.size() == 8 ); REQUIRE( topo.checkIntegrity() ); } + +template +void testAttrib( const IndexedGeometry& mesh, const std::string& name, float value ) { + + auto attribHandle = mesh.template getAttribHandle( name ); + REQUIRE( attribHandle.idx().isValid() ); + auto& attrib = mesh.getAttrib( attribHandle ); + for ( const auto& v : attrib.data() ) + { + REQUIRE( v == value ); + } +} + +TEST_CASE( "Core/Geometry/TopologicalMesh/Triangulate", "[Core][Core/Geometry][TopologicalMesh]" ) { + TopologicalMesh topo {}; + TopologicalMesh::VertexHandle vhandle[4]; + TopologicalMesh::FaceHandle fhandle; + + vhandle[0] = topo.add_vertex( TopologicalMesh::Point( -1, -1, 1 ) ); + vhandle[1] = topo.add_vertex( TopologicalMesh::Point( 1, -1, 1 ) ); + vhandle[2] = topo.add_vertex( TopologicalMesh::Point( 1, 1, 1 ) ); + vhandle[3] = topo.add_vertex( TopologicalMesh::Point( -1, 1, 1 ) ); + + std::vector face_vhandles; + face_vhandles.push_back( vhandle[0] ); + face_vhandles.push_back( vhandle[1] ); + face_vhandles.push_back( vhandle[2] ); + face_vhandles.push_back( vhandle[3] ); + fhandle = topo.add_face( face_vhandles ); + + REQUIRE( topo.n_faces() == 1 ); + + auto index1 = topo.addWedgeAttrib( "test1", 1.f ); + REQUIRE( index1 == 0 ); + REQUIRE( topo.getFloatAttribNames().size() == 1 ); + REQUIRE( topo.getFloatAttribNames()[0] == "test1" ); + + for ( const auto& he : topo.halfedges() ) + { + if ( topo.is_boundary( he ) ) continue; + + auto wd = topo.newWedgeData(); + + // need to set position and vertex handle for new wedges + wd.m_vertexHandle = topo.to_vertex_handle( he ); + wd.m_position = topo.point( wd.m_vertexHandle ); + + REQUIRE( wd.m_floatAttrib.size() == 1 ); + wd.m_floatAttrib[index1] = 2.f; + topo.replaceWedge( he, wd ); + } + REQUIRE( topo.checkIntegrity() ); + + auto index2 = topo.addWedgeAttrib( "test2", 2.f ); + REQUIRE( index2 == 1 ); + for ( const auto& he : topo.halfedges() ) + { + if ( topo.is_boundary( he ) ) continue; + // our we require the wedge to be already set for this he + auto wd = topo.newWedgeData( he ); + + REQUIRE( wd.m_vertexHandle == topo.to_vertex_handle( he ) ); + REQUIRE( wd.m_position == topo.point( wd.m_vertexHandle ) ); + + REQUIRE( wd.m_floatAttrib.size() == 2 ); + wd.m_floatAttrib[index2] = 3.f; + topo.replaceWedge( he, wd ); + } + + auto index3 = topo.addWedgeAttrib( "test3", 3.f ); + REQUIRE( index3 == 2 ); + for ( const auto& he : topo.halfedges() ) + { + if ( topo.is_boundary( he ) ) continue; + + auto wedgeIndex = topo.getWedgeIndex( he ); + REQUIRE( topo.getWedgeRefCount( wedgeIndex ) == 1 ); + auto wedgeData = topo.getWedgeData( wedgeIndex ); + + REQUIRE( wedgeData.m_floatAttrib[index1] == 0.f ); + REQUIRE( wedgeData.m_floatAttrib[index2] == 3.f ); + REQUIRE( wedgeData.m_floatAttrib[index3] == 3.f ); + } + + auto poly = topo.toPolyMesh(); + REQUIRE( poly.vertices().size() == 4 ); + REQUIRE( poly.getIndices().size() == 1 ); + REQUIRE( poly.getIndices()[0].size() == 4 ); + testAttrib( poly, "test1", 0.f ); + testAttrib( poly, "test2", 3.f ); + testAttrib( poly, "test3", 3.f ); + + topo.triangulate(); + topo.checkIntegrity(); + auto tri = topo.toTriangleMesh(); + REQUIRE( tri.vertices().size() == 4 ); + REQUIRE( tri.getIndices().size() == 2 ); + REQUIRE( tri.getIndices()[0].size() == 3 ); + REQUIRE( tri.getIndices()[1].size() == 3 ); + testAttrib( tri, "test1", 0.f ); + testAttrib( tri, "test2", 3.f ); + testAttrib( tri, "test3", 3.f ); +} From 0a620c06a7a26ce98748cce2a432c1191b7ecaff Mon Sep 17 00:00:00 2001 From: dlyr Date: Sun, 7 Mar 2021 07:29:06 +0100 Subject: [PATCH 25/37] [core] More checks in topo integrity. --- src/Core/Geometry/TopologicalMesh.cpp | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/Core/Geometry/TopologicalMesh.cpp b/src/Core/Geometry/TopologicalMesh.cpp index 75be39821be..a1cd60bb548 100644 --- a/src/Core/Geometry/TopologicalMesh.cpp +++ b/src/Core/Geometry/TopologicalMesh.cpp @@ -75,7 +75,17 @@ bool TopologicalMesh::checkIntegrity() const { bool ret = true; for ( auto he_itr {halfedges_begin()}; he_itr != halfedges_end(); ++he_itr ) { + if ( status( *he_itr ).deleted() ) continue; + auto widx = property( m_wedgeIndexPph, *he_itr ); + + if ( is_boundary( *he_itr ) != widx.isInvalid() ) + { + LOG( logWARNING ) + << "topological mesh wedge inconsistency, boundary he != invalid Wedge"; + ret = false; + } + if ( widx.isValid() ) { count[widx]++; @@ -84,10 +94,11 @@ bool TopologicalMesh::checkIntegrity() const { { LOG( logWARNING ) << "topological mesh wedge inconsistency, wedge and to position " "differ for widx " - << widx << ", have " + << widx << ", have (" << m_wedges.getWedgeData( widx ).m_position.transpose() - << "instead of " - << point( to_vertex_handle( *he_itr ) ).transpose(); + << ") instead of (" + << point( to_vertex_handle( *he_itr ) ).transpose() << ")"; + ret = false; } } } @@ -96,8 +107,8 @@ bool TopologicalMesh::checkIntegrity() const { { if ( m_wedges.getWedge( WedgeIndex {widx} ).getRefCount() != count[widx] ) { - LOG( logWARNING ) << "topological mesh wedge count inconsistency, have " << count[widx] - << " instead of " + LOG( logWARNING ) << "topological mesh wedge count inconsistency, real count is " + << count[widx] << " wedge ref count is " << m_wedges.getWedge( WedgeIndex {widx} ).getRefCount() << " for wedge id " << widx; ret = false; From f24e7d83a6ce9bae8b2bb616d08cef74b64826a5 Mon Sep 17 00:00:00 2001 From: dlyr Date: Sun, 7 Mar 2021 07:29:27 +0100 Subject: [PATCH 26/37] [core] Add topo triangulate fixup. --- src/Core/Geometry/TopologicalMesh.cpp | 58 +++++++++++++++++++++++++++ src/Core/Geometry/TopologicalMesh.hpp | 2 + 2 files changed, 60 insertions(+) diff --git a/src/Core/Geometry/TopologicalMesh.cpp b/src/Core/Geometry/TopologicalMesh.cpp index a1cd60bb548..3e3cdff8fe3 100644 --- a/src/Core/Geometry/TopologicalMesh.cpp +++ b/src/Core/Geometry/TopologicalMesh.cpp @@ -117,6 +117,64 @@ bool TopologicalMesh::checkIntegrity() const { return ret; } +void TopologicalMesh::triangulate() { + + auto fix = [this]( HalfedgeHandle next_he, const std::vector& old_heh ) { + // tagged if already fixed + auto to_vh = to_vertex_handle( next_he ); + // find ref in old_he to copy wedge idx + + auto ref = std::find_if( + old_heh.begin(), old_heh.end(), [this, to_vh]( const HalfedgeHandle& he ) { + return to_vertex_handle( he ) == to_vh; + } ); + if ( ref != old_heh.end() ) + { + property( m_wedgeIndexPph, next_he ) = + m_wedges.newReference( property( m_wedgeIndexPph, *ref ) ); + } + else + { LOG( logERROR ) << "triangulate::fix reference halfedge not found"; } + status( next_he ).set_tagged( true ); + }; + + FaceIter f_it( faces_begin() ), f_end( faces_end() ); + for ( ; f_it != f_end; ++f_it ) + { + // save original halfedge of the face + std::vector old_heh; + ConstFaceHalfedgeIter fh_itr = cfh_iter( *f_it ); + for ( ; fh_itr.is_valid(); ++fh_itr ) + { + old_heh.push_back( *fh_itr ); + } + auto size = old_heh.size(); + // if ( size <= 3 ) continue; + + // base openmesh triangulate + base::triangulate( *f_it ); + + // fix newly created he + for ( size_t i = 0; i < size; ++i ) + { + auto next_he = next_halfedge_handle( old_heh[i] ); + // if next_he is not the same as next in old_heh, then it's a new one. + // fix tag halfedge so that it is not fixed two times (in case opposite halfedge is also + // parsed in this loop. + if ( !status( next_he ).tagged() && next_he != old_heh[( i + 1 ) % size] ) + { + fix( next_he, old_heh ); + fix( opposite_halfedge_handle( next_he ), old_heh ); + } + } + } + // untag everything + for ( auto& he : halfedges() ) + { + status( he ).set_tagged( false ); + } +} + void printWedgesInfo( const Ra::Core::Geometry::TopologicalMesh& topo ) { using namespace Ra::Core; diff --git a/src/Core/Geometry/TopologicalMesh.hpp b/src/Core/Geometry/TopologicalMesh.hpp index 261b71d8513..9630e8560dd 100644 --- a/src/Core/Geometry/TopologicalMesh.hpp +++ b/src/Core/Geometry/TopologicalMesh.hpp @@ -306,6 +306,8 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT Date: Fri, 5 Mar 2021 15:28:01 +0100 Subject: [PATCH 27/37] [core] Topo to line Mesh. --- src/Core/Geometry/TopologicalMesh.cpp | 58 +++++++++++++++++++++++++++ src/Core/Geometry/TopologicalMesh.hpp | 2 + 2 files changed, 60 insertions(+) diff --git a/src/Core/Geometry/TopologicalMesh.cpp b/src/Core/Geometry/TopologicalMesh.cpp index 3e3cdff8fe3..6716229b951 100644 --- a/src/Core/Geometry/TopologicalMesh.cpp +++ b/src/Core/Geometry/TopologicalMesh.cpp @@ -276,6 +276,64 @@ TriangleMesh TopologicalMesh::toTriangleMesh() { return out; } +LineMesh TopologicalMesh::toLineMesh() { + // first cleanup deleted element + garbage_collection(); + + LineMesh out; + LineMesh::IndexContainerType indices; + + TriangleMesh::PointAttribHandle::Container wedgePosition; + AlignedStdVector::Container> wedgeFloatAttribData( + m_wedges.m_floatAttribNames.size() ); + AlignedStdVector::Container> wedgeVector2AttribData( + m_wedges.m_vector2AttribNames.size() ); + AlignedStdVector::Container> wedgeVector3AttribData( + m_wedges.m_vector3AttribNames.size() ); + AlignedStdVector::Container> wedgeVector4AttribData( + m_wedges.m_vector4AttribNames.size() ); + + /// Wedges are output vertices ! + for ( WedgeIndex widx {0}; widx < WedgeIndex( m_wedges.size() ); ++widx ) + { + const auto& wd = m_wedges.getWedgeData( widx ); + wedgePosition.push_back( wd.m_position ); + copyWedgeDataToAttribContainer( wedgeFloatAttribData, wd.m_floatAttrib ); + copyWedgeDataToAttribContainer( wedgeVector2AttribData, wd.m_vector2Attrib ); + copyWedgeDataToAttribContainer( wedgeVector3AttribData, wd.m_vector3Attrib ); + copyWedgeDataToAttribContainer( wedgeVector4AttribData, wd.m_vector4Attrib ); + } + + out.setVertices( std::move( wedgePosition ) ); + moveContainerToMesh( out, m_wedges.m_floatAttribNames, wedgeFloatAttribData ); + moveContainerToMesh( out, m_wedges.m_vector2AttribNames, wedgeVector2AttribData ); + moveContainerToMesh( out, m_wedges.m_vector3AttribNames, wedgeVector3AttribData ); + moveContainerToMesh( out, m_wedges.m_vector4AttribNames, wedgeVector4AttribData ); + + for ( TopologicalMesh::EdgeIter e_it = edges_sbegin(); e_it != edges_end(); ++e_it ) + { + int tindices[2]; + + // take care of boundaries + auto he0 = halfedge_handle( *e_it, 0 ); + if ( OpenMesh::ArrayKernel::is_boundary( he0 ) ) + { he0 = prev_halfedge_handle( opposite_halfedge_handle( he0 ) ); } + if ( OpenMesh::ArrayKernel::is_boundary( he0 ) ) continue; + auto he1 = halfedge_handle( *e_it, 1 ); + if ( OpenMesh::ArrayKernel::is_boundary( he1 ) ) + { he1 = prev_halfedge_handle( opposite_halfedge_handle( he1 ) ); } + if ( OpenMesh::ArrayKernel::is_boundary( he1 ) ) continue; + + tindices[0] = property( m_wedgeIndexPph, he0 ); + tindices[1] = property( m_wedgeIndexPph, he1 ); + + indices.emplace_back( tindices[0], tindices[1] ); + } + + out.setIndices( std::move( indices ) ); + + return out; +} PolyMesh TopologicalMesh::toPolyMesh() { // first cleanup deleted element garbage_collection(); diff --git a/src/Core/Geometry/TopologicalMesh.hpp b/src/Core/Geometry/TopologicalMesh.hpp index 9630e8560dd..388dc14d9c1 100644 --- a/src/Core/Geometry/TopologicalMesh.hpp +++ b/src/Core/Geometry/TopologicalMesh.hpp @@ -114,6 +114,8 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT Date: Thu, 11 Mar 2021 14:05:38 +0100 Subject: [PATCH 28/37] [core] fix topo wedge collapse core topo use modified version from open mesh collapse. move to collapse internal to private collapse fix loop wedge. detect feature for collapse. --- src/Core/Geometry/TopologicalMesh.cpp | 363 +++++++++++++++++++++++--- src/Core/Geometry/TopologicalMesh.hpp | 9 +- 2 files changed, 330 insertions(+), 42 deletions(-) diff --git a/src/Core/Geometry/TopologicalMesh.cpp b/src/Core/Geometry/TopologicalMesh.cpp index 6716229b951..c9b310b6514 100644 --- a/src/Core/Geometry/TopologicalMesh.cpp +++ b/src/Core/Geometry/TopologicalMesh.cpp @@ -75,18 +75,21 @@ bool TopologicalMesh::checkIntegrity() const { bool ret = true; for ( auto he_itr {halfedges_begin()}; he_itr != halfedges_end(); ++he_itr ) { - if ( status( *he_itr ).deleted() ) continue; - auto widx = property( m_wedgeIndexPph, *he_itr ); + if ( status( *he_itr ).deleted() ) { continue; } + if ( is_boundary( *he_itr ) != widx.isInvalid() ) { - LOG( logWARNING ) - << "topological mesh wedge inconsistency, boundary he != invalid Wedge"; + LOG( logWARNING ) << "topological mesh wedge inconsistency, boundary he (" + << ( is_boundary( *he_itr ) ? "true," : "false," ) << he_itr->idx() + << ") != invalid Wedge (" << ( widx.isInvalid() ? "true," : "false," ) + << widx << ") ref " + << ( widx.isValid() ? m_wedges.getWedge( widx ).getRefCount() : 0 ); ret = false; } - if ( widx.isValid() ) + if ( widx.isValid() ) // i.e. non boudnary { count[widx]++; @@ -107,10 +110,10 @@ bool TopologicalMesh::checkIntegrity() const { { if ( m_wedges.getWedge( WedgeIndex {widx} ).getRefCount() != count[widx] ) { - LOG( logWARNING ) << "topological mesh wedge count inconsistency, real count is " - << count[widx] << " wedge ref count is " + LOG( logWARNING ) << "topological mesh wedge count inconsistency, topo count [ " + << count[widx] << " ] != wedge count [ " << m_wedges.getWedge( WedgeIndex {widx} ).getRefCount() - << " for wedge id " << widx; + << " ] for id " << widx; ret = false; } } @@ -777,6 +780,7 @@ bool TopologicalMesh::splitEdge( TopologicalMesh::EdgeHandle eh, Scalar f ) { return true; } +/* void TopologicalMesh::collapseWedge( TopologicalMesh::HalfedgeHandle heh ) { HalfedgeHandle h = heh; HalfedgeHandle hn = next_halfedge_handle( h ); @@ -786,62 +790,339 @@ void TopologicalMesh::collapseWedge( TopologicalMesh::HalfedgeHandle heh ) { HalfedgeHandle on = next_halfedge_handle( o ); HalfedgeHandle op = prev_halfedge_handle( o ); - // FaceHandle fh = face_handle( h ); - // FaceHandle fo = face_handle( o ); - VertexHandle vh = to_vertex_handle( h ); VertexHandle vo = to_vertex_handle( o ); - auto position = m_wedges.getWedgeData( property( m_wedgeIndexPph, heh ) ).m_position; - auto widx = property( m_wedgeIndexPph, heh ); + auto widx = getWedgeIndex( heh ); + auto position = getWedgeData( widx ).m_position; + + { + auto rwidx = getWedgeIndex( op ); + auto lwidx = widx; + auto olwidx = getWedgeIndex( hp ); + auto orwidx = getWedgeIndex( o ); + HalfedgeHandle ring_itr = hp; + while ( ring_itr != o ) + { + auto twidx = getWedgeIndex( ring_itr ); + if(twidx == orwidx){ + replaceWedgeIndex( ring_itr, rwidx ); + } + if(twidx == olwidx){ + replaceWedgeIndex( ring_itr, lwidx ); + } + ring_itr = prev_halfedge_handle( opposite_halfedge_handle( ring_itr ) ); + } + } - CORE_ASSERT( widx.isValid(), "try to collapse onto an invalid wedge" ); - CORE_ASSERT( !isFeatureVertex( vo ), "try to collapse a feature vertex" ); + base::collapse( h ); - for ( VertexIHalfedgeIter vih_it( vih_iter( vo ) ); vih_it.is_valid(); ++vih_it ) + for ( VertexIHalfedgeIter vih_it( vih_iter( vh ) ); vih_it.is_valid(); ++vih_it ) { // delete and set to new widx - m_wedges.del( property( m_wedgeIndexPph, *vih_it ) ); - property( m_wedgeIndexPph, *vih_it ) = m_wedges.newReference( widx ); + if ( !status( *vih_it ).deleted() ) { + m_wedges.setWedgePosition( property( m_wedgeIndexPph, *vih_it ), position ); + } } - // but remove one ref for the deleted opposite he - m_wedges.del( property( m_wedgeIndexPph, o ) ); +} +*/ + +//----------------------------------------------------------------------------- +void TopologicalMesh::collapse( HalfedgeHandle _hh, bool keepFrom ) { + HalfedgeHandle h0 = _hh; + HalfedgeHandle h1 = next_halfedge_handle( h0 ); + HalfedgeHandle o0 = opposite_halfedge_handle( h0 ); + HalfedgeHandle o1 = next_halfedge_handle( o0 ); + + // remove edge + collapse_edge( h0, keepFrom ); + + // remove loops + if ( next_halfedge_handle( next_halfedge_handle( h1 ) ) == h1 ) + collapse_loop( next_halfedge_handle( h1 ) ); + if ( next_halfedge_handle( next_halfedge_handle( o1 ) ) == o1 ) collapse_loop( o1 ); +} + +//----------------------------------------------------------------------------- +void TopologicalMesh::collapse_edge( HalfedgeHandle _hh, bool keepFrom ) { + HalfedgeHandle h = _hh; + HalfedgeHandle hn = next_halfedge_handle( h ); + HalfedgeHandle hp = prev_halfedge_handle( h ); + + HalfedgeHandle o = opposite_halfedge_handle( h ); + HalfedgeHandle on = next_halfedge_handle( o ); + HalfedgeHandle ono = opposite_halfedge_handle( on ); + HalfedgeHandle op = prev_halfedge_handle( o ); + + FaceHandle fh = face_handle( h ); + FaceHandle fo = face_handle( o ); + + VertexHandle vh = to_vertex_handle( h ); + VertexHandle vo = to_vertex_handle( o ); - // and delete wedge of the remove he - // first if h is not boundary, copy the wedgeIndex of hn to hp to it - if ( !is_boundary( h ) ) + auto widx = getWedgeIndex( h ); + if ( widx.isInvalid() ) // i.e. h is boundary + widx = getWedgeIndex( op ); + auto otherWidx = getWedgeIndex( op ); + if ( otherWidx.isInvalid() ) // i.e. h is boundary + otherWidx = getWedgeIndex( h ); + +// halfedge -> vertex + +// manual iter for from fixup +#if 1 + auto currentWidx = widx; + auto ringWidx = WedgeIndex {}; + int phase = 0; + HalfedgeHandle start = prev_halfedge_handle( opposite_halfedge_handle( hp ) ); + HalfedgeHandle vih = start; + do + { + set_vertex_handle( vih, vh ); + if ( !is_boundary( vih ) ) + { + if ( !keepFrom ) + { + if ( phase == 0 ) + { + CORE_ASSERT( ringWidx.isInvalid(), "" ); + phase = 1; + ringWidx = getWedgeIndex( vih ); + } + if ( phase == 1 && ringWidx != getWedgeIndex( vih ) ) + { + CORE_ASSERT( ringWidx.isValid(), "" ); + CORE_ASSERT( getWedgeIndex( vih ).isValid(), "" ); + phase = 2; + currentWidx = otherWidx; + } + replaceWedgeIndex( vih, currentWidx ); + } + else + { m_wedges.setWedgePosition( getWedgeIndex( vih ), point( vh ) ); } + } + vih = prev_halfedge_handle( opposite_halfedge_handle( vih ) ); + } while ( vih != start ); +#else + // auto version from openmesh + for ( VertexIHalfedgeIter vih_it( vih_iter( vo ) ); vih_it.is_valid(); ++vih_it ) { - property( m_wedgeIndexPph, hp ) = - m_wedges.newReference( property( m_wedgeIndexPph, opposite_halfedge_handle( hn ) ) ); + set_vertex_handle( *vih_it, vh ); + if ( !is_boundary( *vih_it ) ) + { + if ( !keepFrom ) { replaceWedgeIndex( *vih_it, widx ); } + else + { m_wedges.setWedgePosition( getWedgeIndex( *vih_it ), point( vh ) ); } + } } - m_wedges.del( property( m_wedgeIndexPph, hn ) ); - m_wedges.del( property( m_wedgeIndexPph, opposite_halfedge_handle( hn ) ) ); +#endif + + // halfedge -> halfedge + set_next_halfedge_handle( hp, hn ); + if ( !is_boundary( hp ) ) + if ( !keepFrom ) replaceWedgeIndex( hp, widx ); + + set_next_halfedge_handle( op, on ); - if ( !is_boundary( o ) ) + if ( keepFrom ) { - property( m_wedgeIndexPph, on ) = - m_wedges.newReference( property( m_wedgeIndexPph, opposite_halfedge_handle( op ) ) ); + if ( !is_boundary( op ) ) replaceWedgeIndex( op, getWedgeIndex( ono ) ); } - m_wedges.del( property( m_wedgeIndexPph, op ) ); - m_wedges.del( property( m_wedgeIndexPph, opposite_halfedge_handle( op ) ) ); + // face -> halfedge + if ( fh.is_valid() ) set_halfedge_handle( fh, hn ); + if ( fo.is_valid() ) set_halfedge_handle( fo, on ); - base::collapse( h ); + // vertex -> halfedge + if ( halfedge_handle( vh ) == o ) set_halfedge_handle( vh, hn ); + adjust_outgoing_halfedge( vh ); + set_isolated( vo ); - for ( VertexIHalfedgeIter vih_it( vih_iter( vh ) ); vih_it.is_valid(); ++vih_it ) + // delete stuff + status( edge_handle( h ) ).set_deleted( true ); + + status( vo ).set_deleted( true ); + + m_wedges.del( getWedgeIndex( h ) ); + m_wedges.del( getWedgeIndex( o ) ); + + if ( has_halfedge_status() ) { - // delete and set to new widx - m_wedges.setWedgePosition( property( m_wedgeIndexPph, *vih_it ), position ); + status( h ).set_deleted( true ); + status( o ).set_deleted( true ); } } -void TopologicalMesh::garbage_collection() { - for ( HalfedgeIter he_it = halfedges_begin(); he_it != halfedges_end(); ++he_it ) +//----------------------------------------------------------------------------- +void TopologicalMesh::collapse_loop( HalfedgeHandle _hh ) { + HalfedgeHandle h0 = _hh; + HalfedgeHandle h1 = next_halfedge_handle( h0 ); + + HalfedgeHandle o0 = opposite_halfedge_handle( h0 ); + HalfedgeHandle o1 = opposite_halfedge_handle( h1 ); + + VertexHandle v0 = to_vertex_handle( h0 ); + VertexHandle v1 = to_vertex_handle( h1 ); + + FaceHandle fh = face_handle( h0 ); + FaceHandle fo = face_handle( o0 ); + + // is it a loop ? + assert( ( next_halfedge_handle( h1 ) == h0 ) && ( h1 != o0 ) ); + + // halfedge -> halfedge + set_next_halfedge_handle( h1, next_halfedge_handle( o0 ) ); + replaceWedgeIndex( h1, getWedgeIndex( o0 ) ); + set_next_halfedge_handle( prev_halfedge_handle( o0 ), h1 ); + + // halfedge -> face + set_face_handle( h1, fo ); + + // vertex -> halfedge + set_halfedge_handle( v0, h1 ); + adjust_outgoing_halfedge( v0 ); + set_halfedge_handle( v1, o1 ); + adjust_outgoing_halfedge( v1 ); + + // face -> halfedge + if ( fo.is_valid() && halfedge_handle( fo ) == o0 ) { set_halfedge_handle( fo, h1 ); } + + // delete stuff + if ( fh.is_valid() ) + { + set_halfedge_handle( fh, InvalidHalfedgeHandle ); + status( fh ).set_deleted( true ); + } + status( edge_handle( h0 ) ).set_deleted( true ); + + m_wedges.del( getWedgeIndex( h0 ) ); + m_wedges.del( getWedgeIndex( o0 ) ); + + if ( has_halfedge_status() ) + { + status( h0 ).set_deleted( true ); + status( o0 ).set_deleted( true ); + } +} + +void TopologicalMesh::collapseWedge( TopologicalMesh::HalfedgeHandle heh, bool keepFromWedges ) { + collapse( heh, keepFromWedges ); + ///\todo remove when seems to work + checkIntegrity(); +} + +void TopologicalMesh::collapseWedge2( TopologicalMesh::HalfedgeHandle heh, bool keepFromWedges ) { + LOG( logINFO ) << "in " << keepFromWedges; + checkIntegrity(); + + HalfedgeHandle h = heh; + HalfedgeHandle hn = next_halfedge_handle( h ); + HalfedgeHandle hp = prev_halfedge_handle( h ); + HalfedgeHandle hpo = opposite_halfedge_handle( hp ); + + HalfedgeHandle o = opposite_halfedge_handle( h ); + HalfedgeHandle on = next_halfedge_handle( o ); + HalfedgeHandle ono = opposite_halfedge_handle( on ); + HalfedgeHandle op = prev_halfedge_handle( o ); + + if ( is_boundary( hn ) ) { CORE_ASSERT( getWedgeIndex( hn ).isInvalid(), "" ); } + if ( is_boundary( hp ) ) { CORE_ASSERT( getWedgeIndex( hp ).isInvalid(), "" ); } + if ( is_boundary( hpo ) ) { CORE_ASSERT( getWedgeIndex( hpo ).isInvalid(), "" ); } + if ( is_boundary( on ) ) { CORE_ASSERT( getWedgeIndex( on ).isInvalid(), "" ); } + if ( is_boundary( op ) ) { CORE_ASSERT( getWedgeIndex( op ).isInvalid(), "" ); } + if ( is_boundary( ono ) ) { CORE_ASSERT( getWedgeIndex( ono ).isInvalid(), "" ); } + + VertexHandle vh = to_vertex_handle( h ); + VertexHandle vo = to_vertex_handle( o ); + + auto widx = getWedgeIndex( h ); + + auto position = getWedgeData( widx ).m_position; + + bool searchFeatureEdge = getWedgeIndex( op ) != getWedgeIndex( h ); + auto owidx = getWedgeIndex( op ); + HalfedgeHandle ring_itr = prev_halfedge_handle( opposite_halfedge_handle( hp ) ); + auto currentWidx = widx; + auto ringWidx = getWedgeIndex( ring_itr ); + + if ( !keepFromWedges ) { - // already done in collapseWedge - // if ( status( *he_it ).deleted() ) { m_wedges.del(property( - // m_wedgeIndexPph, *he_it )); } + while ( ring_itr != ono ) + { + if ( !is_boundary( ring_itr ) ) replaceWedgeIndex( ring_itr, currentWidx ); + ring_itr = prev_halfedge_handle( opposite_halfedge_handle( ring_itr ) ); + if ( searchFeatureEdge && ( ringWidx != getWedgeIndex( ring_itr ) ) ) + { + searchFeatureEdge = false; + currentWidx = owidx; + } + ringWidx = getWedgeIndex( ring_itr ); + } } + base::collapse( h ); + + // checks in case OpenMesh collapse change + CORE_ASSERT( status( h ).deleted(), "" ); + CORE_ASSERT( status( vo ).deleted(), "" ); + CORE_ASSERT( status( o ).deleted(), "" ); + // delete wedge of deleted he during base collapse or fix WedgeIndex + + m_wedges.del( getWedgeIndex( h ) ); + m_wedges.del( getWedgeIndex( o ) ); + + if ( status( hp ).deleted() ) + { + CORE_ASSERT( !status( hn ).deleted(), "" ); + if ( !is_boundary( hn ) ) + replaceWedgeIndex( hn, getWedgeIndex( hpo ) ); + else + { CORE_ASSERT( getWedgeIndex( hn ).isInvalid(), "" ); } + CORE_ASSERT( status( hpo ).deleted(), "" ); + m_wedges.del( getWedgeIndex( hp ) ); + m_wedges.del( getWedgeIndex( hpo ) ); + } + else + { + if ( !keepFromWedges ) { replaceWedgeIndex( hp, widx ); } + } + + if ( status( on ).deleted() ) + { + if ( !keepFromWedges ) {} + else + { + if ( !is_boundary( op ) ) + replaceWedgeIndex( op, getWedgeIndex( ono ) ); + else + { CORE_ASSERT( getWedgeIndex( op ).isInvalid(), "" ); } + } + CORE_ASSERT( status( ono ).deleted(), "" ); + m_wedges.del( getWedgeIndex( on ) ); + m_wedges.del( getWedgeIndex( ono ) ); + } + else + { + if ( !keepFromWedges ) { replaceWedgeIndex( ono, currentWidx ); } + } + + // fix position around the "to" vertex + for ( VertexIHalfedgeIter vih_it( vih_iter( vh ) ); vih_it.is_valid(); ++vih_it ) + { + if ( !status( *vih_it ).deleted() && !is_boundary( *vih_it ) ) + { + m_wedges.setWedgePosition( getWedgeIndex( *vih_it ), position ); + // std::cout << " set " << getWedgeIndex( *vih_it ) << " " << position.transpose() + // << "\n"; + } + } + + LOG( logINFO ) << "out"; + checkIntegrity(); + LOG( logINFO ) << "done"; +} +void TopologicalMesh::garbage_collection() { + // Wedge Ref count is already up to date, do not del again ! + auto offset = m_wedges.computeCleanupOffset(); for ( HalfedgeIter he_it = halfedges_begin(); he_it != halfedges_end(); ++he_it ) { diff --git a/src/Core/Geometry/TopologicalMesh.hpp b/src/Core/Geometry/TopologicalMesh.hpp index 388dc14d9c1..aaec8621a40 100644 --- a/src/Core/Geometry/TopologicalMesh.hpp +++ b/src/Core/Geometry/TopologicalMesh.hpp @@ -197,7 +197,7 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT Date: Sat, 13 Mar 2021 18:41:45 +0100 Subject: [PATCH 29/37] [core] fix mergeEqualWedge for boundaries. --- src/Core/Geometry/TopologicalMesh.inl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Core/Geometry/TopologicalMesh.inl b/src/Core/Geometry/TopologicalMesh.inl index e7986ff6d82..131562647c3 100644 --- a/src/Core/Geometry/TopologicalMesh.inl +++ b/src/Core/Geometry/TopologicalMesh.inl @@ -800,7 +800,8 @@ inline void TopologicalMesh::mergeEqualWedges( OpenMesh::VertexHandle vh ) { for ( auto itr = vih_iter( vh ); itr.is_valid(); ++itr ) { // replace will search if wedge already present and use it, so merge occurs. - replaceWedge( *itr, getWedgeData( property( getWedgeIndexPph(), *itr ) ) ); + if ( !is_boundary( *itr ) ) + replaceWedge( *itr, getWedgeData( property( getWedgeIndexPph(), *itr ) ) ); } } From f36f6e3611c948f9c74155e7807bb26f411d6a2c Mon Sep 17 00:00:00 2001 From: dlyr Date: Mon, 15 Mar 2021 17:03:32 +0100 Subject: [PATCH 30/37] [core] rename addWedgeData to addWedgeAttrib, when one attrib only. --- src/Core/Geometry/TopologicalMesh.hpp | 10 ++++++++++ src/Core/Geometry/TopologicalMesh.inl | 26 ++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/src/Core/Geometry/TopologicalMesh.hpp b/src/Core/Geometry/TopologicalMesh.hpp index aaec8621a40..c7354ead72c 100644 --- a/src/Core/Geometry/TopologicalMesh.hpp +++ b/src/Core/Geometry/TopologicalMesh.hpp @@ -218,6 +218,9 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT const T& getWedgeData( const WedgeIndex& idx, const std::string& name ) const; + template + const T& getWedgeAttrib( const WedgeIndex& idx, const std::string& name ) const; + /** * Return the wedge refcount, for debug purpose. */ @@ -239,6 +242,9 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT inline bool setWedgeData( const WedgeIndex& idx, const std::string& name, const T& value ); + template + inline bool setWedgeAttrib( const WedgeIndex& idx, const std::string& name, const T& value ); + inline WedgeData newWedgeData() const { return m_wedges.newWedgeData(); } inline WedgeData newWedgeData( HalfedgeHandle he ) const { return m_wedges.newWedgeData( to_vertex_handle( he ), point( to_vertex_handle( he ) ) ); @@ -434,6 +440,10 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT inline T& getWedgeData( const WedgeIndex& idx, int attribIndex ); + template + inline const T& getWedgeAttrib( const WedgeIndex& idx, const std::string& name ) const; + template + inline T& getWedgeAttrib( const WedgeIndex& idx, int attribIndex ); unsigned int getWedgeRefCount( const WedgeIndex& idx ) const; diff --git a/src/Core/Geometry/TopologicalMesh.inl b/src/Core/Geometry/TopologicalMesh.inl index 131562647c3..39ad33a2fa3 100644 --- a/src/Core/Geometry/TopologicalMesh.inl +++ b/src/Core/Geometry/TopologicalMesh.inl @@ -139,6 +139,13 @@ template inline const T& TopologicalMesh::WedgeCollection::getWedgeData( const TopologicalMesh::WedgeIndex& idx, const std::string& name ) const { + return getWedgeAttrib( idx, name ); +} + +template +inline const T& +TopologicalMesh::WedgeCollection::getWedgeAttrib( const TopologicalMesh::WedgeIndex& idx, + const std::string& name ) const { if ( idx.isValid() ) { auto nameArray = getNameArray(); @@ -161,6 +168,12 @@ TopologicalMesh::WedgeCollection::getWedgeData( const TopologicalMesh::WedgeInde template inline T& TopologicalMesh::WedgeCollection::getWedgeData( const TopologicalMesh::WedgeIndex& idx, int attribIndex ) { + return getWedgeAttrib( idx, attribIndex ); +} + +template +inline T& TopologicalMesh::WedgeCollection::getWedgeAttrib( const TopologicalMesh::WedgeIndex& idx, + int attribIndex ) { return m_data[idx].getWedgeData().getAttribArray()[attribIndex]; } @@ -758,6 +771,13 @@ template inline bool TopologicalMesh::setWedgeData( const TopologicalMesh::WedgeIndex& idx, const std::string& name, const T& value ) { + return setWedgeAttrib( idx, name, value ); +} + +template +inline bool TopologicalMesh::setWedgeAttrib( const TopologicalMesh::WedgeIndex& idx, + const std::string& name, + const T& value ) { return m_wedges.setWedgeAttrib( idx, name, value ); } @@ -774,6 +794,12 @@ TopologicalMesh::getWedgeData( const WedgeIndex& idx ) const { template inline const T& TopologicalMesh::getWedgeData( const TopologicalMesh::WedgeIndex& idx, const std::string& name ) const { + return getWedgeAttrib( idx, name ); +} + +template +inline const T& TopologicalMesh::getWedgeAttrib( const TopologicalMesh::WedgeIndex& idx, + const std::string& name ) const { return m_wedges.getWedgeData( idx, name ); } From 4c930bcbedcd66e006c44ca4163304f625e5354b Mon Sep 17 00:00:00 2001 From: dlyr Date: Tue, 16 Mar 2021 15:24:06 +0100 Subject: [PATCH 31/37] [core] clean and add deprecated. --- src/Core/Geometry/TopologicalMesh.cpp | 188 ++------------------------ src/Core/Geometry/TopologicalMesh.hpp | 16 ++- 2 files changed, 23 insertions(+), 181 deletions(-) diff --git a/src/Core/Geometry/TopologicalMesh.cpp b/src/Core/Geometry/TopologicalMesh.cpp index c9b310b6514..60fd5c1ac90 100644 --- a/src/Core/Geometry/TopologicalMesh.cpp +++ b/src/Core/Geometry/TopologicalMesh.cpp @@ -780,53 +780,6 @@ bool TopologicalMesh::splitEdge( TopologicalMesh::EdgeHandle eh, Scalar f ) { return true; } -/* -void TopologicalMesh::collapseWedge( TopologicalMesh::HalfedgeHandle heh ) { - HalfedgeHandle h = heh; - HalfedgeHandle hn = next_halfedge_handle( h ); - HalfedgeHandle hp = prev_halfedge_handle( h ); - - HalfedgeHandle o = opposite_halfedge_handle( h ); - HalfedgeHandle on = next_halfedge_handle( o ); - HalfedgeHandle op = prev_halfedge_handle( o ); - - VertexHandle vh = to_vertex_handle( h ); - VertexHandle vo = to_vertex_handle( o ); - - auto widx = getWedgeIndex( heh ); - auto position = getWedgeData( widx ).m_position; - - { - auto rwidx = getWedgeIndex( op ); - auto lwidx = widx; - auto olwidx = getWedgeIndex( hp ); - auto orwidx = getWedgeIndex( o ); - HalfedgeHandle ring_itr = hp; - while ( ring_itr != o ) - { - auto twidx = getWedgeIndex( ring_itr ); - if(twidx == orwidx){ - replaceWedgeIndex( ring_itr, rwidx ); - } - if(twidx == olwidx){ - replaceWedgeIndex( ring_itr, lwidx ); - } - ring_itr = prev_halfedge_handle( opposite_halfedge_handle( ring_itr ) ); - } - } - - base::collapse( h ); - - for ( VertexIHalfedgeIter vih_it( vih_iter( vh ) ); vih_it.is_valid(); ++vih_it ) - { - // delete and set to new widx - if ( !status( *vih_it ).deleted() ) { - m_wedges.setWedgePosition( property( m_wedgeIndexPph, *vih_it ), position ); - } - } -} -*/ - //----------------------------------------------------------------------------- void TopologicalMesh::collapse( HalfedgeHandle _hh, bool keepFrom ) { HalfedgeHandle h0 = _hh; @@ -867,10 +820,9 @@ void TopologicalMesh::collapse_edge( HalfedgeHandle _hh, bool keepFrom ) { if ( otherWidx.isInvalid() ) // i.e. h is boundary otherWidx = getWedgeIndex( h ); -// halfedge -> vertex + // halfedge -> vertex -// manual iter for from fixup -#if 1 + // manual iter for from fixup auto currentWidx = widx; auto ringWidx = WedgeIndex {}; int phase = 0; @@ -903,19 +855,17 @@ void TopologicalMesh::collapse_edge( HalfedgeHandle _hh, bool keepFrom ) { } vih = prev_halfedge_handle( opposite_halfedge_handle( vih ) ); } while ( vih != start ); -#else - // auto version from openmesh - for ( VertexIHalfedgeIter vih_it( vih_iter( vo ) ); vih_it.is_valid(); ++vih_it ) - { - set_vertex_handle( *vih_it, vh ); - if ( !is_boundary( *vih_it ) ) - { - if ( !keepFrom ) { replaceWedgeIndex( *vih_it, widx ); } - else - { m_wedges.setWedgePosition( getWedgeIndex( *vih_it ), point( vh ) ); } - } - } -#endif + // Reference version from openmesh + // for ( VertexIHalfedgeIter vih_it( vih_iter( vo ) ); vih_it.is_valid(); ++vih_it ) + // { + // set_vertex_handle( *vih_it, vh ); + // if ( !is_boundary( *vih_it ) ) + // { + // if ( !keepFrom ) { replaceWedgeIndex( *vih_it, widx ); } + // else + // { m_wedges.setWedgePosition( getWedgeIndex( *vih_it ), point( vh ) ); } + // } + // } // halfedge -> halfedge set_next_halfedge_handle( hp, hn ); @@ -1006,120 +956,8 @@ void TopologicalMesh::collapse_loop( HalfedgeHandle _hh ) { void TopologicalMesh::collapseWedge( TopologicalMesh::HalfedgeHandle heh, bool keepFromWedges ) { collapse( heh, keepFromWedges ); - ///\todo remove when seems to work - checkIntegrity(); } -void TopologicalMesh::collapseWedge2( TopologicalMesh::HalfedgeHandle heh, bool keepFromWedges ) { - LOG( logINFO ) << "in " << keepFromWedges; - checkIntegrity(); - - HalfedgeHandle h = heh; - HalfedgeHandle hn = next_halfedge_handle( h ); - HalfedgeHandle hp = prev_halfedge_handle( h ); - HalfedgeHandle hpo = opposite_halfedge_handle( hp ); - - HalfedgeHandle o = opposite_halfedge_handle( h ); - HalfedgeHandle on = next_halfedge_handle( o ); - HalfedgeHandle ono = opposite_halfedge_handle( on ); - HalfedgeHandle op = prev_halfedge_handle( o ); - - if ( is_boundary( hn ) ) { CORE_ASSERT( getWedgeIndex( hn ).isInvalid(), "" ); } - if ( is_boundary( hp ) ) { CORE_ASSERT( getWedgeIndex( hp ).isInvalid(), "" ); } - if ( is_boundary( hpo ) ) { CORE_ASSERT( getWedgeIndex( hpo ).isInvalid(), "" ); } - if ( is_boundary( on ) ) { CORE_ASSERT( getWedgeIndex( on ).isInvalid(), "" ); } - if ( is_boundary( op ) ) { CORE_ASSERT( getWedgeIndex( op ).isInvalid(), "" ); } - if ( is_boundary( ono ) ) { CORE_ASSERT( getWedgeIndex( ono ).isInvalid(), "" ); } - - VertexHandle vh = to_vertex_handle( h ); - VertexHandle vo = to_vertex_handle( o ); - - auto widx = getWedgeIndex( h ); - - auto position = getWedgeData( widx ).m_position; - - bool searchFeatureEdge = getWedgeIndex( op ) != getWedgeIndex( h ); - auto owidx = getWedgeIndex( op ); - HalfedgeHandle ring_itr = prev_halfedge_handle( opposite_halfedge_handle( hp ) ); - auto currentWidx = widx; - auto ringWidx = getWedgeIndex( ring_itr ); - - if ( !keepFromWedges ) - { - while ( ring_itr != ono ) - { - if ( !is_boundary( ring_itr ) ) replaceWedgeIndex( ring_itr, currentWidx ); - ring_itr = prev_halfedge_handle( opposite_halfedge_handle( ring_itr ) ); - if ( searchFeatureEdge && ( ringWidx != getWedgeIndex( ring_itr ) ) ) - { - searchFeatureEdge = false; - currentWidx = owidx; - } - ringWidx = getWedgeIndex( ring_itr ); - } - } - - base::collapse( h ); - - // checks in case OpenMesh collapse change - CORE_ASSERT( status( h ).deleted(), "" ); - CORE_ASSERT( status( vo ).deleted(), "" ); - CORE_ASSERT( status( o ).deleted(), "" ); - // delete wedge of deleted he during base collapse or fix WedgeIndex - - m_wedges.del( getWedgeIndex( h ) ); - m_wedges.del( getWedgeIndex( o ) ); - - if ( status( hp ).deleted() ) - { - CORE_ASSERT( !status( hn ).deleted(), "" ); - if ( !is_boundary( hn ) ) - replaceWedgeIndex( hn, getWedgeIndex( hpo ) ); - else - { CORE_ASSERT( getWedgeIndex( hn ).isInvalid(), "" ); } - CORE_ASSERT( status( hpo ).deleted(), "" ); - m_wedges.del( getWedgeIndex( hp ) ); - m_wedges.del( getWedgeIndex( hpo ) ); - } - else - { - if ( !keepFromWedges ) { replaceWedgeIndex( hp, widx ); } - } - - if ( status( on ).deleted() ) - { - if ( !keepFromWedges ) {} - else - { - if ( !is_boundary( op ) ) - replaceWedgeIndex( op, getWedgeIndex( ono ) ); - else - { CORE_ASSERT( getWedgeIndex( op ).isInvalid(), "" ); } - } - CORE_ASSERT( status( ono ).deleted(), "" ); - m_wedges.del( getWedgeIndex( on ) ); - m_wedges.del( getWedgeIndex( ono ) ); - } - else - { - if ( !keepFromWedges ) { replaceWedgeIndex( ono, currentWidx ); } - } - - // fix position around the "to" vertex - for ( VertexIHalfedgeIter vih_it( vih_iter( vh ) ); vih_it.is_valid(); ++vih_it ) - { - if ( !status( *vih_it ).deleted() && !is_boundary( *vih_it ) ) - { - m_wedges.setWedgePosition( getWedgeIndex( *vih_it ), position ); - // std::cout << " set " << getWedgeIndex( *vih_it ) << " " << position.transpose() - // << "\n"; - } - } - - LOG( logINFO ) << "out"; - checkIntegrity(); - LOG( logINFO ) << "done"; -} void TopologicalMesh::garbage_collection() { // Wedge Ref count is already up to date, do not del again ! diff --git a/src/Core/Geometry/TopologicalMesh.hpp b/src/Core/Geometry/TopologicalMesh.hpp index c7354ead72c..e6b3640ea24 100644 --- a/src/Core/Geometry/TopologicalMesh.hpp +++ b/src/Core/Geometry/TopologicalMesh.hpp @@ -197,7 +197,9 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT - const T& getWedgeData( const WedgeIndex& idx, const std::string& name ) const; + [[deprecated( "use getWedgeAttrib() instead." )]] const T& + getWedgeData( const WedgeIndex& idx, const std::string& name ) const; template const T& getWedgeAttrib( const WedgeIndex& idx, const std::string& name ) const; @@ -240,12 +243,16 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT - inline bool setWedgeData( const WedgeIndex& idx, const std::string& name, const T& value ); + [[deprecated( "use setWedgeAttrib() instead." )]] inline bool + setWedgeData( const WedgeIndex& idx, const std::string& name, const T& value ); template inline bool setWedgeAttrib( const WedgeIndex& idx, const std::string& name, const T& value ); + /** return a WedgeData with all attrib initialized to default values */ inline WedgeData newWedgeData() const { return m_wedges.newWedgeData(); } + /** return a WedgeData with position (and vertex handle) initialized from the value of he's to + * vertex. */ inline WedgeData newWedgeData( HalfedgeHandle he ) const { return m_wedges.newWedgeData( to_vertex_handle( he ), point( to_vertex_handle( he ) ) ); } @@ -356,11 +363,8 @@ class RA_CORE_API TopologicalMesh : public OpenMesh::PolyMesh_ArrayKernelT Date: Fri, 12 Mar 2021 08:39:15 +0100 Subject: [PATCH 32/37] [tests] wip topo merge unit test --- tests/unittest/Core/topomesh.cpp | 62 ++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/tests/unittest/Core/topomesh.cpp b/tests/unittest/Core/topomesh.cpp index 2957b36456b..1fa05985273 100644 --- a/tests/unittest/Core/topomesh.cpp +++ b/tests/unittest/Core/topomesh.cpp @@ -962,3 +962,65 @@ TEST_CASE( "Core/Geometry/TopologicalMesh/Triangulate", "[Core][Core/Geometry][T testAttrib( tri, "test2", 3.f ); testAttrib( tri, "test3", 3.f ); } + +optional +findHalfedge( TopologicalMesh& topo, const Vector3& from, const Vector3& to ) { + bool found; + TopologicalMesh::HalfedgeHandle he; + for ( auto he_iter = topo.halfedges_begin(); he_iter != topo.halfedges_end(); ++he_iter ) + { + + if ( topo.point( topo.to_vertex_handle( he_iter ) ) == from && + topo.point( topo.from_vertex_handle( he_iter ) ) == to ) + { + found = true; + he = *he_iter; + } + } + if ( found ) return he; + return {}; +} + +TEST_CASE( "Core/TopologicalMesh/CollapseWedge" ) { + Vector3Array points { + {00_ra, 00_ra, 00_ra}, + {10_ra, 00_ra, 00_ra}, + {05_ra, 05_ra, 00_ra}, + {05_ra, 10_ra, 00_ra}, + {15_ra, 05_ra, 00_ra}, + {10_ra, 12_ra, 00_ra}, + {10_ra, 15_ra, 00_ra}, + {15_ra, 10_ra, 00_ra}, + }; + Vector3Array colors = {{0_ra, 0_ra, 0_ra}, + {0_ra, 0_ra, 0_ra}, + {1_ra, 1_ra, 1_ra}, + {2_ra, 2_ra, 2_ra}, + {3_ra, 3_ra, 3_ra}, + {4_ra, 4_ra, 4_ra}, + {5_ra, 5_ra, 5_ra}, + {6_ra, 6_ra, 6_ra}, + {7_ra, 7_ra, 7_ra}, + {8_ra, 8_ra, 8_ra}, + {9_ra, 9_ra, 9_ra}, + {10_ra, 10_ra, 10_ra}, + {11_ra, 11_ra, 11_ra}}; + + VectorArray indices1 { + {0, 1, 2}, {0, 2, 3}, {1, 5, 2}, {2, 5, 3}, {1, 4, 5}, {5, 7, 6}, {4, 7, 5}}; + + SECTION( "simple collapse" ) { + TriangleMesh mesh1; + mesh1.setVertices( points ); + mesh1.addAttrib( "color", Vector3Array {colors.begin(), colors.begin() + points.size()} ); + mesh1.setIndices( indices1 ); + TopologicalMesh topo1 {mesh1}; + // search for he + TopologicalMesh::HalfedgeHandle he; + auto optHe = findHalfedge( topo1, points[5], points[2] ); + REQUIRE( optHe ); + topo1.collapseWedge( *optHe ); + optHe = findHalfedge( topo1, points[5], points[2] ); + REQUIRE( !optHe ); + } +} From 2bff2b68c06f507c4ff2d5223a273c50677b0a51 Mon Sep 17 00:00:00 2001 From: dlyr Date: Tue, 16 Mar 2021 15:24:49 +0100 Subject: [PATCH 33/37] [tests] update topo collapse unittest. --- tests/unittest/Core/topomesh.cpp | 233 +++++++++++++++++++++++++------ 1 file changed, 192 insertions(+), 41 deletions(-) diff --git a/tests/unittest/Core/topomesh.cpp b/tests/unittest/Core/topomesh.cpp index 1fa05985273..cee787f558e 100644 --- a/tests/unittest/Core/topomesh.cpp +++ b/tests/unittest/Core/topomesh.cpp @@ -419,11 +419,6 @@ TEST_CASE( "Core/Geometry/TopologicalMesh", "[Core][Core/Geometry][TopologicalMe for ( auto vitr = topo1.vertices_begin(), vend = topo1.vertices_end(); vitr != vend; ++vitr ) { - for ( auto fitr = topo1.vf_iter( *vitr ); fitr.is_valid(); ++fitr ) - { - auto n = topo1.normal( *vitr, *fitr ); - REQUIRE( Math::areApproxEqual( n.squaredNorm(), 0_ra ) ); - } topo1.propagate_normal_to_wedges( *vitr ); REQUIRE( !topo1.has_halfedge_normals() ); REQUIRE( !topo1.has_face_normals() ); @@ -982,45 +977,201 @@ findHalfedge( TopologicalMesh& topo, const Vector3& from, const Vector3& to ) { } TEST_CASE( "Core/TopologicalMesh/CollapseWedge" ) { - Vector3Array points { - {00_ra, 00_ra, 00_ra}, - {10_ra, 00_ra, 00_ra}, - {05_ra, 05_ra, 00_ra}, - {05_ra, 10_ra, 00_ra}, - {15_ra, 05_ra, 00_ra}, - {10_ra, 12_ra, 00_ra}, - {10_ra, 15_ra, 00_ra}, - {15_ra, 10_ra, 00_ra}, + using namespace Ra::Core; + using namespace Ra::Core::Utils; + using namespace Ra::Core::Geometry; + auto findHalfedge = []( TopologicalMesh& topo, + const Vector3& from, + const Vector3& to ) -> optional { + bool found; + TopologicalMesh::HalfedgeHandle he; + for ( auto he_iter = topo.halfedges_begin(); he_iter != topo.halfedges_end(); ++he_iter ) + { + + if ( topo.point( topo.to_vertex_handle( he_iter ) ) == to && + topo.point( topo.from_vertex_handle( he_iter ) ) == from ) + { + found = true; + he = *he_iter; + } + } + if ( found ) return he; + return {}; + }; + + Vector3Array points1 { + {00._ra, 00._ra, 00._ra}, + {10._ra, 00._ra, 00._ra}, + {05._ra, 05._ra, 00._ra}, + {05._ra, 10._ra, 00._ra}, + {15._ra, 05._ra, 00._ra}, + {10._ra, 08._ra, 00._ra}, + {10._ra, 12._ra, 00._ra}, + {15._ra, 10._ra, 00._ra}, }; - Vector3Array colors = {{0_ra, 0_ra, 0_ra}, - {0_ra, 0_ra, 0_ra}, - {1_ra, 1_ra, 1_ra}, - {2_ra, 2_ra, 2_ra}, - {3_ra, 3_ra, 3_ra}, - {4_ra, 4_ra, 4_ra}, - {5_ra, 5_ra, 5_ra}, - {6_ra, 6_ra, 6_ra}, - {7_ra, 7_ra, 7_ra}, - {8_ra, 8_ra, 8_ra}, - {9_ra, 9_ra, 9_ra}, - {10_ra, 10_ra, 10_ra}, - {11_ra, 11_ra, 11_ra}}; - - VectorArray indices1 { - {0, 1, 2}, {0, 2, 3}, {1, 5, 2}, {2, 5, 3}, {1, 4, 5}, {5, 7, 6}, {4, 7, 5}}; - - SECTION( "simple collapse" ) { + Vector3Array points2 = {points1[0], points1[0], points1[1], points1[1], points1[1], points1[2], + points1[2], points1[2], points1[2], points1[3], points1[3], points1[3], + points1[4], points1[4], points1[5], points1[5], points1[5], points1[5], + points1[5], points1[5], points1[6], points1[6], points1[7], points1[7]}; + + Vector4Array colors1 = { + {0_ra, 0_ra, 0_ra, 1_ra}, {1_ra, 1_ra, 1_ra, 1_ra}, {2_ra, 2_ra, 2_ra, 1_ra}, + {3_ra, 3_ra, 3_ra, 1_ra}, {4_ra, 4_ra, 4_ra, 1_ra}, {5_ra, 5_ra, 5_ra, 1_ra}, + {6_ra, 6_ra, 6_ra, 1_ra}, {7_ra, 7_ra, 7_ra, 1_ra}, {8_ra, 8_ra, 8_ra, 1_ra}, + {9_ra, 9_ra, 9_ra, 1_ra}, {10_ra, 10_ra, 10_ra, 1_ra}, {11_ra, 11_ra, 11_ra, 1_ra}, + {12_ra, 12_ra, 12_ra, 1_ra}, {13_ra, 13_ra, 13_ra, 1_ra}, {14_ra, 14_ra, 14_ra, 1_ra}, + {15_ra, 15_ra, 15_ra, 1_ra}, {16_ra, 16_ra, 16_ra, 1_ra}, {17_ra, 17_ra, 17_ra, 1_ra}, + {18_ra, 18_ra, 18_ra, 1_ra}, {19_ra, 19_ra, 19_ra, 1_ra}, {20_ra, 20_ra, 20_ra, 1_ra}, + {21_ra, 21_ra, 21_ra, 1_ra}, {22_ra, 22_ra, 22_ra, 1_ra}, {23_ra, 23_ra, 23_ra, 1_ra}, + }; + + Vector3uArray indices1 { + {0, 2, 1}, {0, 3, 2}, {1, 2, 5}, {2, 3, 5}, {1, 5, 4}, {3, 6, 5}, {5, 6, 7}, {4, 5, 7}}; + + Vector3uArray indices3 = {{0, 2, 1}, {1, 2, 5}, {1, 5, 4}, {3, 6, 5}, {5, 6, 7}, {4, 5, 7}}; + + Vector3uArray indices4 = { + {0, 2, 5}, {3, 14, 6}, {4, 12, 15}, {11, 18, 20}, {17, 22, 21}, {16, 13, 23}}; + + Vector3uArray indices2 {{0, 5, 2}, + {1, 9, 8}, + {3, 6, 14}, + {7, 10, 19}, + {4, 15, 12}, + {11, 20, 18}, + {17, 21, 22}, + {16, 23, 13}}; + Vector4Array colors2 {24, Color::White()}; + for ( const auto& face : indices2 ) + { + colors2[face[0]] = colors1[face[0]]; + colors2[face[1]] = colors1[face[0]]; + colors2[face[2]] = colors1[face[0]]; + } + + Vector4Array colors3 {24, Color::White()}; + std::vector topFaceIndices {1, 3, 5, 6}; + std::vector bottomFaceIndices {0, 2, 4, 7}; + + for ( const auto& faceIndex : topFaceIndices ) + { + colors3[indices2[faceIndex][0]] = colors1[0]; + colors3[indices2[faceIndex][1]] = colors1[0]; + colors3[indices2[faceIndex][2]] = colors1[0]; + } + for ( const auto& faceIndex : bottomFaceIndices ) + { + colors3[indices2[faceIndex][0]] = colors1[1]; + colors3[indices2[faceIndex][1]] = colors1[1]; + colors3[indices2[faceIndex][2]] = colors1[1]; + } + + Vector4Array colors4 {24, Color::White()}; + + std::vector> splitContinuousWedges {// 0 + {0}, + {1}, + // 1 + {2, 3, 4}, + // 2 + {8, 7}, + {5, 6}, + // 3 + {9, 10, 11}, + // 4 + {12, 13}, + // 5 + {14, 15, 16}, + {17, 18, 19}, + // 6 + {20, 21}, + // 7 + {22, 23}}; + + for ( size_t i = 0; i < splitContinuousWedges.size(); ++i ) + { + for ( const auto& widx : splitContinuousWedges[i] ) + { + colors4[widx] = colors1[i]; + } + } + + ///\todo add more checks on resulting topology and wedges after collapse + auto addMergeScene = [findHalfedge]( const Vector3Array& points, + const Vector4Array& colors, + const Vector3uArray& indices, + Vector3 from, + Vector3 to ) { TriangleMesh mesh1; + TopologicalMesh topo1; + optional optHe; + mesh1.setVertices( points ); - mesh1.addAttrib( "color", Vector3Array {colors.begin(), colors.begin() + points.size()} ); - mesh1.setIndices( indices1 ); - TopologicalMesh topo1 {mesh1}; - // search for he - TopologicalMesh::HalfedgeHandle he; - auto optHe = findHalfedge( topo1, points[5], points[2] ); + mesh1.addAttrib( "color", Vector4Array {colors.begin(), colors.begin() + points.size()} ); + mesh1.setIndices( indices ); + + topo1 = TopologicalMesh {mesh1}; + topo1.mergeEqualWedges(); + topo1.garbage_collection(); + + topo1.checkIntegrity(); + optHe = findHalfedge( topo1, from, to ); + REQUIRE( optHe ); + + topo1.collapse( *optHe ); + REQUIRE( topo1.checkIntegrity() ); + + topo1 = TopologicalMesh {mesh1}; + optHe = findHalfedge( topo1, from, to ); REQUIRE( optHe ); - topo1.collapseWedge( *optHe ); - optHe = findHalfedge( topo1, points[5], points[2] ); - REQUIRE( !optHe ); + + topo1.collapse( *optHe, true ); + REQUIRE( topo1.checkIntegrity() ); + + std::swap( from, to ); + + topo1 = TopologicalMesh {mesh1}; + topo1.mergeEqualWedges(); + topo1.garbage_collection(); + optHe = findHalfedge( topo1, from, to ); + REQUIRE( optHe ); + + topo1.collapse( *optHe ); + REQUIRE( topo1.checkIntegrity() ); + + topo1 = TopologicalMesh {mesh1}; + optHe = findHalfedge( topo1, from, to ); + REQUIRE( optHe ); + + topo1.collapse( *optHe, true ); + REQUIRE( topo1.checkIntegrity() ); + }; + + SECTION( "With continuous wedges." ) { + addMergeScene( points1, colors1, indices1, points1[5], points1[2] ); + } + + SECTION( "with top/bottom wedges" ) { + addMergeScene( points2, colors3, indices2, points1[5], points1[2] ); + } + + SECTION( "with continuous top/bottom wedges" ) { + addMergeScene( points2, colors4, indices2, points1[5], points1[2] ); + } + SECTION( "with flat face wedges" ) { + addMergeScene( points2, colors2, indices2, points1[5], points1[2] ); + } + + SECTION( "boundary With continuous wedges." ) { + addMergeScene( points1, colors1, indices3, points1[5], points1[2] ); + } + SECTION( "boundary with top/bottom wedges" ) { + addMergeScene( points2, colors3, indices4, points1[5], points1[2] ); + } + SECTION( "boundary with continuous top/bottom wedges" ) { + addMergeScene( points2, colors4, indices4, points1[5], points1[2] ); + } + SECTION( "boundary with flat face wedges" ) { + addMergeScene( points2, colors2, indices4, points1[5], points1[2] ); } } From 8b2c7acabe27d32f0d1e2463c1648d45b793ab69 Mon Sep 17 00:00:00 2001 From: dlyr Date: Sun, 7 Mar 2021 07:30:13 +0100 Subject: [PATCH 34/37] [tests] Draw primitive triangulate, and remove degen faces. --- .../DrawPrimitivesApp/minimalradium.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/ExampleApps/DrawPrimitivesApp/minimalradium.cpp b/tests/ExampleApps/DrawPrimitivesApp/minimalradium.cpp index da964733931..734e6d2bdee 100644 --- a/tests/ExampleApps/DrawPrimitivesApp/minimalradium.cpp +++ b/tests/ExampleApps/DrawPrimitivesApp/minimalradium.cpp @@ -645,6 +645,25 @@ void MinimalComponent::initialize() { Eigen::UniformScaling( 0.06_ra )} ); addRenderObject( renderObject1 ); + + Ra::Core::Geometry::TopologicalMesh topo {poly1->getCoreGeometry()}; + topo.triangulate(); + topo.checkIntegrity(); + auto triangulated = topo.toTriangleMesh(); + std::shared_ptr poly2( new Mesh( "Poly", std::move( triangulated ) ) ); + poly2->getCoreGeometry().addAttrib( + "in_color", + Vector4Array {poly2->getNumVertices(), + colorBoost * Utils::Color {0_ra, 0.6_ra, 0.1_ra}} ); + + auto renderObject2 = RenderObject::createRenderObject( + "triangulated", this, RenderObjectType::Geometry, poly2, {} ); + renderObject2->setMaterial( blinnPhongMaterial ); + renderObject2->setLocalTransform( + Transform {Translation( Vector3( cellCorner ) + toCellCenter ) * + Eigen::UniformScaling( 0.03_ra )} ); + + addRenderObject( renderObject2 ); } if ( ENABLE_LOGO ) From 3a988b95c64a95321f728b7129cae1a3452b7000 Mon Sep 17 00:00:00 2001 From: dlyr Date: Fri, 12 Mar 2021 08:39:28 +0100 Subject: [PATCH 35/37] [tests] draw prim wedge collapse --- .../DrawPrimitivesApp/minimalradium.cpp | 174 ++++++++++++++++++ 1 file changed, 174 insertions(+) diff --git a/tests/ExampleApps/DrawPrimitivesApp/minimalradium.cpp b/tests/ExampleApps/DrawPrimitivesApp/minimalradium.cpp index 734e6d2bdee..9596d061992 100644 --- a/tests/ExampleApps/DrawPrimitivesApp/minimalradium.cpp +++ b/tests/ExampleApps/DrawPrimitivesApp/minimalradium.cpp @@ -40,6 +40,7 @@ const bool ENABLE_DISKS = true; const bool ENABLE_NORMALS = true; const bool ENABLE_POLYS = true; const bool ENABLE_LOGO = true; +const bool ENABLE_COLLAPSE = true; using namespace Ra; using namespace Ra::Core; @@ -728,6 +729,179 @@ void MinimalComponent::initialize() { } } } + + if ( ENABLE_COLLAPSE ) + { + + using namespace Ra::Core; + using namespace Ra::Core::Utils; + using namespace Ra::Core::Geometry; + auto findHalfedge = []( TopologicalMesh& topo, + const Vector3& from, + const Vector3& to ) -> optional { + bool found; + TopologicalMesh::HalfedgeHandle he; + for ( auto he_iter = topo.halfedges_begin(); he_iter != topo.halfedges_end(); + ++he_iter ) + { + + if ( topo.point( topo.to_vertex_handle( he_iter ) ) == to && + topo.point( topo.from_vertex_handle( he_iter ) ) == from ) + { + found = true; + he = *he_iter; + } + } + if ( found ) return he; + return {}; + }; + + auto addMesh = [this, colorBoost, shadedRt, plainRt]( Vector3 pos, TopologicalMesh topo1 ) { + topo1.checkIntegrity(); + auto mesh1 = topo1.toTriangleMesh(); + std::shared_ptr poly( new Mesh( "TEST", std::move( mesh1 ) ) ); + + auto renderObject2 = RenderObject::createRenderObject( + "TEST", this, RenderObjectType::Geometry, poly, plainRt ); + renderObject2->setLocalTransform( Transform { + Translation( Vector3( pos ) ) * Eigen::UniformScaling( 0.02_ra )} ); + + addRenderObject( renderObject2 ); + }; + + Vector3Array points { + {00._ra, 00._ra, 00._ra}, + {10._ra, 00._ra, 00._ra}, + {05._ra, 05._ra, 00._ra}, + {05._ra, 10._ra, 00._ra}, + {15._ra, 05._ra, 00._ra}, + {10._ra, 08._ra, 00._ra}, + {10._ra, 12._ra, 00._ra}, + {15._ra, 10._ra, 00._ra}, + }; + Vector3Array points2 = {points[0], points[0], points[1], points[1], points[1], points[2], + points[2], points[2], points[2], points[3], points[3], points[3], + points[4], points[4], points[5], points[5], points[5], points[5], + points[5], points[5], points[6], points[6], points[7], points[7]}; + + Vector4Array colors = { + {0_ra, 0_ra, 0_ra, 1_ra}, {1_ra, 1_ra, 1_ra, 1_ra}, {2_ra, 2_ra, 2_ra, 1_ra}, + {3_ra, 3_ra, 3_ra, 1_ra}, {4_ra, 4_ra, 4_ra, 1_ra}, {5_ra, 5_ra, 5_ra, 1_ra}, + {6_ra, 6_ra, 6_ra, 1_ra}, {7_ra, 7_ra, 7_ra, 1_ra}, {8_ra, 8_ra, 8_ra, 1_ra}, + {9_ra, 9_ra, 9_ra, 1_ra}, {10_ra, 10_ra, 10_ra, 1_ra}, {11_ra, 11_ra, 11_ra, 1_ra}, + {12_ra, 12_ra, 12_ra, 1_ra}, {13_ra, 13_ra, 13_ra, 1_ra}, {14_ra, 14_ra, 14_ra, 1_ra}, + {15_ra, 15_ra, 15_ra, 1_ra}, {16_ra, 16_ra, 16_ra, 1_ra}, {17_ra, 17_ra, 17_ra, 1_ra}, + {18_ra, 18_ra, 18_ra, 1_ra}, {19_ra, 19_ra, 19_ra, 1_ra}, {20_ra, 20_ra, 20_ra, 1_ra}, + {21_ra, 21_ra, 21_ra, 1_ra}, {22_ra, 22_ra, 22_ra, 1_ra}, {23_ra, 23_ra, 23_ra, 1_ra}, + }; + + for ( auto& c : colors ) + { + c = colorBoost * Vector4 {dis01( gen ), dis01( gen ), dis01( gen ), 1_ra}; + } + + VectorArray indices1 { + {0, 2, 1}, {0, 3, 2}, {1, 2, 5}, {2, 3, 5}, {1, 5, 4}, {3, 6, 5}, {5, 6, 7}, {4, 5, 7}}; + Vector3uArray indices3 = {{0, 2, 1}, {1, 2, 5}, {1, 5, 4}, {3, 6, 5}, {5, 6, 7}, {4, 5, 7}}; + + Vector3uArray indices4 = { + {0, 2, 5}, {3, 14, 6}, {4, 12, 15}, {11, 18, 20}, {17, 22, 21}, {16, 13, 23}}; + + VectorArray indices2 {{0, 5, 2}, + {1, 9, 8}, + {3, 6, 14}, + {7, 10, 19}, + {4, 15, 12}, + {11, 20, 18}, + {17, 21, 22}, + {16, 23, 13}}; + Vector4Array colors2 {24, Color::White()}; + for ( const auto& face : indices2 ) + { + colors2[face[0]] = colors[face[0]]; + colors2[face[1]] = colors[face[0]]; + colors2[face[2]] = colors[face[0]]; + } + TriangleMesh mesh1; + + TopologicalMesh topo1; + optional optHe; + Vector3 pos; + + auto addMergeScene = + [findHalfedge, addMesh, &cellCorner, toCellCenter, cellSize, nCellX, nCellY]( + const Vector3Array& points, + const Vector4Array& colors, + const Vector3uArray& indices1, + const Vector3& from, + const Vector3& to ) { + TriangleMesh mesh1; + + TopologicalMesh topo1; + optional optHe; + Vector3 pos; + + mesh1.setVertices( points ); + mesh1.addAttrib( Mesh::getAttribName( Mesh::VERTEX_COLOR ), + Vector4Array {colors.begin(), colors.begin() + points.size()} ); + mesh1.setIndices( indices1 ); + topo1 = TopologicalMesh {mesh1}; + optHe = findHalfedge( topo1, from, to ); + + pos = cellCorner + toCellCenter; + addMesh( pos, topo1 ); + + updateCellCorner( cellCorner, cellSize, nCellX, nCellY ); + pos = cellCorner + toCellCenter; + topo1.collapseWedge( *optHe ); + addMesh( pos, topo1 ); + + topo1 = TopologicalMesh {mesh1}; + optHe = findHalfedge( topo1, from, to ); + pos = cellCorner + toCellCenter + Vector3 {0_ra, .25_ra, 0_ra}; + topo1.collapseWedge( *optHe, true ); + addMesh( pos, topo1 ); + }; + + // With "continuous" wedges. + addMergeScene( points, colors, indices1, points[5], points[2] ); + + updateCellCorner( cellCorner, cellSize, nCellX, nCellY ); + + // with "flat face" wedges + addMergeScene( points2, colors2, indices2, points[5], points[2] ); + + updateCellCorner( cellCorner, cellSize, nCellX, nCellY ); + + // boundary + // With "continuous" wedges. + addMergeScene( points, colors, indices3, points[5], points[2] ); + + updateCellCorner( cellCorner, cellSize, nCellX, nCellY ); + // with "flat face" wedges + addMergeScene( points2, colors2, indices4, points[5], points[2] ); + + // other way round + updateCellCorner( cellCorner, cellSize, nCellX, nCellY ); + + // With "continuous" wedges. + addMergeScene( points, colors, indices1, points[2], points[5] ); + + updateCellCorner( cellCorner, cellSize, nCellX, nCellY ); + + // with "flat face" wedges + addMergeScene( points2, colors2, indices2, points[2], points[5] ); + + updateCellCorner( cellCorner, cellSize, nCellX, nCellY ); + // + // // boundary + // // With "continuous" wedges. + addMergeScene( points, colors, indices3, points[2], points[5] ); + // + updateCellCorner( cellCorner, cellSize, nCellX, nCellY ); + // // with "flat face" wedges + addMergeScene( points2, colors2, indices4, points[2], points[5] ); + } } /// This system will be added to the engine. Every frame it will From 2589dcef346fc65ea795295c35aa89d84d88bc3f Mon Sep 17 00:00:00 2001 From: dlyr Date: Sat, 13 Mar 2021 18:42:09 +0100 Subject: [PATCH 36/37] [tests] DrawPrimitives more examples of collapse. --- .../DrawPrimitivesApp/minimalradium.cpp | 112 +++++++++++++----- 1 file changed, 82 insertions(+), 30 deletions(-) diff --git a/tests/ExampleApps/DrawPrimitivesApp/minimalradium.cpp b/tests/ExampleApps/DrawPrimitivesApp/minimalradium.cpp index 9596d061992..4644f5e7476 100644 --- a/tests/ExampleApps/DrawPrimitivesApp/minimalradium.cpp +++ b/tests/ExampleApps/DrawPrimitivesApp/minimalradium.cpp @@ -822,85 +822,137 @@ void MinimalComponent::initialize() { colors2[face[1]] = colors[face[0]]; colors2[face[2]] = colors[face[0]]; } - TriangleMesh mesh1; - TopologicalMesh topo1; - optional optHe; - Vector3 pos; + Vector4Array colors3 {24, Color::White()}; + std::vector topFaceIndices {1, 3, 5, 6}; + std::vector bottomFaceIndices {0, 2, 4, 7}; + + for ( const auto& faceIndex : topFaceIndices ) + { + colors3[indices2[faceIndex][0]] = colors[0]; + colors3[indices2[faceIndex][1]] = colors[0]; + colors3[indices2[faceIndex][2]] = colors[0]; + } + for ( const auto& faceIndex : bottomFaceIndices ) + { + colors3[indices2[faceIndex][0]] = colors[1]; + colors3[indices2[faceIndex][1]] = colors[1]; + colors3[indices2[faceIndex][2]] = colors[1]; + } + Vector4Array colors4 {24, Color::White()}; + + std::vector> splitContinuousWedges {// 0 + {0}, + {1}, + // 1 + {2, 3, 4}, + // 2 + {8, 7}, + {5, 6}, + // 3 + {9, 10, 11}, + // 4 + {12, 13}, + // 5 + {14, 15, 16}, + {17, 18, 19}, + // 6 + {20, 21}, + // 7 + {22, 23}}; + + for ( size_t i = 0; i < splitContinuousWedges.size(); ++i ) + { + for ( const auto& widx : splitContinuousWedges[i] ) + { + colors4[widx] = colors[i]; + } + } auto addMergeScene = [findHalfedge, addMesh, &cellCorner, toCellCenter, cellSize, nCellX, nCellY]( const Vector3Array& points, const Vector4Array& colors, const Vector3uArray& indices1, - const Vector3& from, - const Vector3& to ) { + Vector3 from, + Vector3 to ) { TriangleMesh mesh1; - TopologicalMesh topo1; optional optHe; Vector3 pos; + pos = cellCorner + toCellCenter; + Vector3 up {0_ra, .25_ra, 0_ra}; mesh1.setVertices( points ); mesh1.addAttrib( Mesh::getAttribName( Mesh::VERTEX_COLOR ), Vector4Array {colors.begin(), colors.begin() + points.size()} ); mesh1.setIndices( indices1 ); topo1 = TopologicalMesh {mesh1}; + topo1.mergeEqualWedges(); + topo1.garbage_collection(); + topo1.checkIntegrity(); optHe = findHalfedge( topo1, from, to ); - pos = cellCorner + toCellCenter; addMesh( pos, topo1 ); - updateCellCorner( cellCorner, cellSize, nCellX, nCellY ); - pos = cellCorner + toCellCenter; + pos += up; + topo1.collapseWedge( *optHe ); + addMesh( pos, topo1 ); + + topo1 = TopologicalMesh {mesh1}; + optHe = findHalfedge( topo1, from, to ); + pos += up; + topo1.collapseWedge( *optHe, true ); + addMesh( pos, topo1 ); + + std::swap( from, to ); + topo1 = TopologicalMesh {mesh1}; + topo1.mergeEqualWedges(); + + optHe = findHalfedge( topo1, from, to ); + + pos += up; topo1.collapseWedge( *optHe ); addMesh( pos, topo1 ); topo1 = TopologicalMesh {mesh1}; optHe = findHalfedge( topo1, from, to ); - pos = cellCorner + toCellCenter + Vector3 {0_ra, .25_ra, 0_ra}; + pos += up; topo1.collapseWedge( *optHe, true ); addMesh( pos, topo1 ); }; // With "continuous" wedges. addMergeScene( points, colors, indices1, points[5], points[2] ); + updateCellCorner( cellCorner, cellSize, nCellX, nCellY ); + // with "top/bottom" wedges + addMergeScene( points2, colors3, indices2, points[5], points[2] ); + updateCellCorner( cellCorner, cellSize, nCellX, nCellY ); + + // with continuous"top/bottom" wedges + addMergeScene( points2, colors4, indices2, points[5], points[2] ); updateCellCorner( cellCorner, cellSize, nCellX, nCellY ); // with "flat face" wedges addMergeScene( points2, colors2, indices2, points[5], points[2] ); - updateCellCorner( cellCorner, cellSize, nCellX, nCellY ); // boundary // With "continuous" wedges. addMergeScene( points, colors, indices3, points[5], points[2] ); - updateCellCorner( cellCorner, cellSize, nCellX, nCellY ); - // with "flat face" wedges - addMergeScene( points2, colors2, indices4, points[5], points[2] ); - // other way round + // with "top/bottom" wedges + addMergeScene( points2, colors3, indices4, points[5], points[2] ); updateCellCorner( cellCorner, cellSize, nCellX, nCellY ); - // With "continuous" wedges. - addMergeScene( points, colors, indices1, points[2], points[5] ); - + // with continuous"top/bottom" wedges + addMergeScene( points2, colors4, indices4, points[5], points[2] ); updateCellCorner( cellCorner, cellSize, nCellX, nCellY ); // with "flat face" wedges - addMergeScene( points2, colors2, indices2, points[2], points[5] ); - - updateCellCorner( cellCorner, cellSize, nCellX, nCellY ); - // - // // boundary - // // With "continuous" wedges. - addMergeScene( points, colors, indices3, points[2], points[5] ); - // - updateCellCorner( cellCorner, cellSize, nCellX, nCellY ); - // // with "flat face" wedges - addMergeScene( points2, colors2, indices4, points[2], points[5] ); + addMergeScene( points2, colors2, indices4, points[5], points[2] ); } } From 4a1be9cb58dec34012736d2246ae62087e81ee57 Mon Sep 17 00:00:00 2001 From: dlyr Date: Tue, 16 Mar 2021 08:21:24 +0100 Subject: [PATCH 37/37] [tests] Update DrawPrimitive for collapse. --- .../DrawPrimitivesApp/minimalradium.cpp | 73 ++++++++++--------- 1 file changed, 38 insertions(+), 35 deletions(-) diff --git a/tests/ExampleApps/DrawPrimitivesApp/minimalradium.cpp b/tests/ExampleApps/DrawPrimitivesApp/minimalradium.cpp index 4644f5e7476..f06d36e4128 100644 --- a/tests/ExampleApps/DrawPrimitivesApp/minimalradium.cpp +++ b/tests/ExampleApps/DrawPrimitivesApp/minimalradium.cpp @@ -732,6 +732,8 @@ void MinimalComponent::initialize() { if ( ENABLE_COLLAPSE ) { + updateCellCorner( cellCorner, cellSize, nCellX, nCellY ); + updateCellCorner( cellCorner, cellSize, nCellX, nCellY ); using namespace Ra::Core; using namespace Ra::Core::Utils; @@ -756,15 +758,16 @@ void MinimalComponent::initialize() { return {}; }; - auto addMesh = [this, colorBoost, shadedRt, plainRt]( Vector3 pos, TopologicalMesh topo1 ) { + auto addMesh = [this, colorBoost, plainMaterial]( Vector3 pos, TopologicalMesh topo1 ) { topo1.checkIntegrity(); auto mesh1 = topo1.toTriangleMesh(); std::shared_ptr poly( new Mesh( "TEST", std::move( mesh1 ) ) ); auto renderObject2 = RenderObject::createRenderObject( - "TEST", this, RenderObjectType::Geometry, poly, plainRt ); + "TEST", this, RenderObjectType::Geometry, poly, {} ); + renderObject2->setMaterial( plainMaterial ); renderObject2->setLocalTransform( Transform { - Translation( Vector3( pos ) ) * Eigen::UniformScaling( 0.02_ra )} ); + Translation( Vector3( pos ) ) * Eigen::UniformScaling( 0.003_ra )} ); addRenderObject( renderObject2 ); }; @@ -800,21 +803,21 @@ void MinimalComponent::initialize() { c = colorBoost * Vector4 {dis01( gen ), dis01( gen ), dis01( gen ), 1_ra}; } - VectorArray indices1 { + Vector3uArray indices1 { {0, 2, 1}, {0, 3, 2}, {1, 2, 5}, {2, 3, 5}, {1, 5, 4}, {3, 6, 5}, {5, 6, 7}, {4, 5, 7}}; Vector3uArray indices3 = {{0, 2, 1}, {1, 2, 5}, {1, 5, 4}, {3, 6, 5}, {5, 6, 7}, {4, 5, 7}}; Vector3uArray indices4 = { {0, 2, 5}, {3, 14, 6}, {4, 12, 15}, {11, 18, 20}, {17, 22, 21}, {16, 13, 23}}; - VectorArray indices2 {{0, 5, 2}, - {1, 9, 8}, - {3, 6, 14}, - {7, 10, 19}, - {4, 15, 12}, - {11, 20, 18}, - {17, 21, 22}, - {16, 23, 13}}; + Vector3uArray indices2 {{0, 5, 2}, + {1, 9, 8}, + {3, 6, 14}, + {7, 10, 19}, + {4, 15, 12}, + {11, 20, 18}, + {17, 21, 22}, + {16, 23, 13}}; Vector4Array colors2 {24, Color::White()}; for ( const auto& face : indices2 ) { @@ -871,6 +874,7 @@ void MinimalComponent::initialize() { auto addMergeScene = [findHalfedge, addMesh, &cellCorner, toCellCenter, cellSize, nCellX, nCellY]( + Vector3 pos, const Vector3Array& points, const Vector4Array& colors, const Vector3uArray& indices1, @@ -879,9 +883,7 @@ void MinimalComponent::initialize() { TriangleMesh mesh1; TopologicalMesh topo1; optional optHe; - Vector3 pos; - pos = cellCorner + toCellCenter; - Vector3 up {0_ra, .25_ra, 0_ra}; + Vector3 up {0_ra, .05_ra, 0_ra}; mesh1.setVertices( points ); mesh1.addAttrib( Mesh::getAttribName( Mesh::VERTEX_COLOR ), @@ -896,13 +898,13 @@ void MinimalComponent::initialize() { addMesh( pos, topo1 ); pos += up; - topo1.collapseWedge( *optHe ); + topo1.collapse( *optHe ); addMesh( pos, topo1 ); topo1 = TopologicalMesh {mesh1}; optHe = findHalfedge( topo1, from, to ); pos += up; - topo1.collapseWedge( *optHe, true ); + topo1.collapse( *optHe, true ); addMesh( pos, topo1 ); std::swap( from, to ); @@ -912,47 +914,48 @@ void MinimalComponent::initialize() { optHe = findHalfedge( topo1, from, to ); pos += up; - topo1.collapseWedge( *optHe ); + topo1.collapse( *optHe ); addMesh( pos, topo1 ); topo1 = TopologicalMesh {mesh1}; optHe = findHalfedge( topo1, from, to ); pos += up; - topo1.collapseWedge( *optHe, true ); + topo1.collapse( *optHe, true ); addMesh( pos, topo1 ); }; - + Vector3 dx = Vector3( cellSize / 8_ra, 0_ra, 0_ra ); + Vector3 pos = cellCorner; + pos[2] += toCellCenter[2]; // With "continuous" wedges. - addMergeScene( points, colors, indices1, points[5], points[2] ); - updateCellCorner( cellCorner, cellSize, nCellX, nCellY ); + addMergeScene( pos, points, colors, indices1, points[5], points[2] ); // with "top/bottom" wedges - addMergeScene( points2, colors3, indices2, points[5], points[2] ); - updateCellCorner( cellCorner, cellSize, nCellX, nCellY ); + addMergeScene( pos, points2, colors3, indices2, points[5], points[2] ); + pos += dx; // with continuous"top/bottom" wedges - addMergeScene( points2, colors4, indices2, points[5], points[2] ); - updateCellCorner( cellCorner, cellSize, nCellX, nCellY ); + addMergeScene( pos, points2, colors4, indices2, points[5], points[2] ); + pos += dx; // with "flat face" wedges - addMergeScene( points2, colors2, indices2, points[5], points[2] ); - updateCellCorner( cellCorner, cellSize, nCellX, nCellY ); + addMergeScene( pos, points2, colors2, indices2, points[5], points[2] ); + pos += dx; // boundary // With "continuous" wedges. - addMergeScene( points, colors, indices3, points[5], points[2] ); - updateCellCorner( cellCorner, cellSize, nCellX, nCellY ); + addMergeScene( pos, points, colors, indices3, points[5], points[2] ); + pos += dx; // with "top/bottom" wedges - addMergeScene( points2, colors3, indices4, points[5], points[2] ); - updateCellCorner( cellCorner, cellSize, nCellX, nCellY ); + addMergeScene( pos, points2, colors3, indices4, points[5], points[2] ); + pos += dx; // with continuous"top/bottom" wedges - addMergeScene( points2, colors4, indices4, points[5], points[2] ); - updateCellCorner( cellCorner, cellSize, nCellX, nCellY ); + addMergeScene( pos, points2, colors4, indices4, points[5], points[2] ); + pos += dx; // with "flat face" wedges - addMergeScene( points2, colors2, indices4, points[5], points[2] ); + addMergeScene( pos, points2, colors2, indices4, points[5], points[2] ); } }