1#include <Core/Geometry/TopologicalMesh.hpp>
3#include <Core/RaCore.hpp>
4#include <Core/Utils/Log.hpp>
6#include <Eigen/StdVector>
20 const Ra::Core::Geometry::TopologicalMesh::WedgeIndex& idx ) {
23 if ( !idx.isValid() ) {
24 buffer <<
"wedge (invalid) ";
31 auto& floatAttrNames = topo.getFloatAttribNames();
32 for (
size_t i = 0; i < floatAttrNames.size(); ++i ) {
33 buffer << floatAttrNames[i];
35 buffer << wd.m_floatAttrib[i];
38 auto vec2AttrNames = topo.getVec2AttribNames();
39 for (
size_t i = 0; i < vec2AttrNames.size(); ++i ) {
40 buffer << vec2AttrNames[i];
42 buffer << wd.m_vector2Attrib[i].transpose();
45 auto vec3AttrNames = topo.getVec3AttribNames();
46 for (
size_t i = 0; i < vec3AttrNames.size(); ++i ) {
47 buffer << vec3AttrNames[i];
49 buffer << wd.m_vector3Attrib[i].transpose();
53 auto vec4AttrNames = topo.getVec4AttribNames();
54 for (
size_t i = 0; i < vec4AttrNames.size(); ++i ) {
55 buffer << vec4AttrNames[i];
57 buffer << wd.m_vector4Attrib[i].transpose();
65 return is_manifold( vh );
71 for (
auto he_itr { halfedges_begin() }; he_itr != halfedges_end(); ++he_itr ) {
72 auto widx = property( m_wedgeIndexPph, *he_itr );
74 if ( status( *he_itr ).deleted() ) {
continue; }
76 if ( is_boundary( *he_itr ) != widx.isInvalid() ) {
77 LOG( logWARNING ) <<
"topological mesh wedge inconsistency, boundary he ("
78 << ( is_boundary( *he_itr ) ?
"true," :
"false," ) << he_itr->idx()
79 <<
") != invalid Wedge (" << ( widx.isInvalid() ?
"true," :
"false," )
81 << ( widx.isValid() ? m_wedges.getWedge( widx ).getRefCount() : 0 );
89 if ( m_wedges.getWedgeData( widx ).m_position !=
90 point( to_vertex_handle( *he_itr ) ) ) {
91 LOG( logWARNING ) <<
"topological mesh wedge inconsistency, wedge and to position "
94 << m_wedges.getWedgeData( widx ).m_position.transpose()
96 << point( to_vertex_handle( *he_itr ) ).transpose() <<
")";
102 for (
int widx = 0; widx < int( m_wedges.size() ); ++widx ) {
103 if ( m_wedges.getWedge( WedgeIndex { widx } ).getRefCount() != count[widx] ) {
104 LOG( logWARNING ) <<
"topological mesh wedge count inconsistency, topo count [ "
105 << count[widx] <<
" ] != wedge count [ "
106 << m_wedges.getWedge( WedgeIndex { widx } ).getRefCount()
107 <<
" ] for id " << widx;
114void TopologicalMesh::triangulate() {
118 auto to_vh = to_vertex_handle( next_he );
122 old_heh.begin(), old_heh.end(), [
this, to_vh](
const HalfedgeHandle& he ) {
123 return to_vertex_handle( he ) == to_vh;
125 if ( ref != old_heh.end() ) {
126 property( m_wedgeIndexPph, next_he ) =
127 m_wedges.newReference( property( m_wedgeIndexPph, *ref ) );
129 else { LOG( logERROR ) <<
"triangulate::fix reference halfedge not found"; }
130 status( next_he ).set_tagged(
true );
133 FaceIter f_it( faces_begin() ), f_end( faces_end() );
134 for ( ; f_it != f_end; ++f_it ) {
137 ConstFaceHalfedgeIter fh_itr = cfh_iter( *f_it );
138 for ( ; fh_itr.is_valid(); ++fh_itr ) {
141 auto size = old_heh.
size();
145 base::triangulate( *f_it );
148 for (
size_t i = 0; i < size; ++i ) {
149 auto next_he = next_halfedge_handle( old_heh[i] );
153 if ( !status( next_he ).tagged() && next_he != old_heh[( i + 1 ) % size] ) {
154 fix( next_he, old_heh );
155 fix( opposite_halfedge_handle( next_he ), old_heh );
160 for (
auto& he : halfedges() ) {
161 status( he ).set_tagged(
false );
168 for (
auto itr = topo.vertices_sbegin(); itr != topo.vertices_end(); ++itr ) {
169 LOG( Utils::logINFO ) <<
"vertex " << *itr;
171 for (
auto wedgeIndex : wedges ) {
172 LOG( Utils::logINFO ) << wedgeInfo( topo, wedgeIndex );
176 for (
auto itr = topo.halfedges_sbegin(); itr != topo.halfedges_end(); ++itr ) {
177 LOG( Utils::logINFO ) <<
"he " << *itr
178 << ( topo.is_boundary( *itr ) ?
" boundary " :
" inner " );
179 LOG( Utils::logINFO ) << wedgeInfo( topo, topo.property( topo.getWedgeIndexPph(), *itr ) );
184 add_property( m_inputTriangleMeshIndexPph );
185 add_property( m_wedgeIndexPph );
191 for (
size_t i = 0; i < wd.
size(); ++i ) {
192 c[i].push_back( wd[i] );
200 for (
size_t i = 0; i < wedgeAttribData.size(); ++i ) {
201 auto attrHandle = out.template addAttrib<T>( names[i] );
214 TriangleMesh::PointAttribHandle::Container wedgePosition;
216 m_wedges.m_floatAttribNames.
size() );
218 m_wedges.m_vector2AttribNames.
size() );
220 m_wedges.m_vector3AttribNames.
size() );
222 m_wedges.m_vector4AttribNames.
size() );
225 for ( WedgeIndex widx { 0 }; widx < WedgeIndex { m_wedges.size() }; ++widx ) {
226 const auto& wd = m_wedges.getWedgeData( widx );
227 wedgePosition.push_back( wd.m_position );
228 copyWedgeDataToAttribContainer( wedgeFloatAttribData, wd.m_floatAttrib );
229 copyWedgeDataToAttribContainer( wedgeVector2AttribData, wd.m_vector2Attrib );
230 copyWedgeDataToAttribContainer( wedgeVector3AttribData, wd.m_vector3Attrib );
231 copyWedgeDataToAttribContainer( wedgeVector4AttribData, wd.m_vector4Attrib );
235 moveContainerToMesh<Scalar>( out, m_wedges.m_floatAttribNames, wedgeFloatAttribData );
236 moveContainerToMesh<Vector2>( out, m_wedges.m_vector2AttribNames, wedgeVector2AttribData );
237 moveContainerToMesh<Vector3>( out, m_wedges.m_vector3AttribNames, wedgeVector3AttribData );
238 moveContainerToMesh<Vector4>( out, m_wedges.m_vector4AttribNames, wedgeVector4AttribData );
240 for ( TopologicalMesh::FaceIter f_it = faces_sbegin(); f_it != faces_end(); ++f_it ) {
244 for ( TopologicalMesh::ConstFaceHalfedgeIter fh_it = cfh_iter( *f_it ); fh_it.is_valid();
246 CORE_ASSERT( i < 3,
"Non-triangular face found." );
247 tindices[i] = property( m_wedgeIndexPph, *fh_it );
250 indices.
emplace_back( tindices[0], tindices[1], tindices[2] );
265 TriangleMesh::PointAttribHandle::Container wedgePosition;
267 m_wedges.m_floatAttribNames.
size() );
269 m_wedges.m_vector2AttribNames.
size() );
271 m_wedges.m_vector3AttribNames.
size() );
273 m_wedges.m_vector4AttribNames.
size() );
276 for ( WedgeIndex widx { 0 }; widx < WedgeIndex( m_wedges.size() ); ++widx ) {
277 const auto& wd = m_wedges.getWedgeData( widx );
278 wedgePosition.push_back( wd.m_position );
279 copyWedgeDataToAttribContainer( wedgeFloatAttribData, wd.m_floatAttrib );
280 copyWedgeDataToAttribContainer( wedgeVector2AttribData, wd.m_vector2Attrib );
281 copyWedgeDataToAttribContainer( wedgeVector3AttribData, wd.m_vector3Attrib );
282 copyWedgeDataToAttribContainer( wedgeVector4AttribData, wd.m_vector4Attrib );
286 moveContainerToMesh<Scalar>( out, m_wedges.m_floatAttribNames, wedgeFloatAttribData );
287 moveContainerToMesh<Vector2>( out, m_wedges.m_vector2AttribNames, wedgeVector2AttribData );
288 moveContainerToMesh<Vector3>( out, m_wedges.m_vector3AttribNames, wedgeVector3AttribData );
289 moveContainerToMesh<Vector4>( out, m_wedges.m_vector4AttribNames, wedgeVector4AttribData );
291 for ( TopologicalMesh::EdgeIter e_it = edges_sbegin(); e_it != edges_end(); ++e_it ) {
296 if ( OpenMesh::ArrayKernel::is_boundary( he0 ) ) {
297 he0 = prev_halfedge_handle( opposite_halfedge_handle( he0 ) );
299 if ( OpenMesh::ArrayKernel::is_boundary( he0 ) )
continue;
301 if ( OpenMesh::ArrayKernel::is_boundary( he1 ) ) {
302 he1 = prev_halfedge_handle( opposite_halfedge_handle( he1 ) );
304 if ( OpenMesh::ArrayKernel::is_boundary( he1 ) )
continue;
306 tindices[0] = property( m_wedgeIndexPph, he0 );
307 tindices[1] = property( m_wedgeIndexPph, he1 );
329 TriangleMesh::PointAttribHandle::Container wedgePosition;
331 m_wedges.m_floatAttribNames.
size() );
333 m_wedges.m_vector2AttribNames.
size() );
335 m_wedges.m_vector3AttribNames.
size() );
337 m_wedges.m_vector4AttribNames.
size() );
340 for ( WedgeIndex widx { 0 }; widx < WedgeIndex( m_wedges.size() ); ++widx ) {
341 const auto& wd = m_wedges.getWedgeData( widx );
342 wedgePosition.push_back( wd.m_position );
343 copyWedgeDataToAttribContainer( wedgeFloatAttribData, wd.m_floatAttrib );
344 copyWedgeDataToAttribContainer( wedgeVector2AttribData, wd.m_vector2Attrib );
345 copyWedgeDataToAttribContainer( wedgeVector3AttribData, wd.m_vector3Attrib );
346 copyWedgeDataToAttribContainer( wedgeVector4AttribData, wd.m_vector4Attrib );
350 moveContainerToMesh<Scalar>( out, m_wedges.m_floatAttribNames, wedgeFloatAttribData );
351 moveContainerToMesh<Vector2>( out, m_wedges.m_vector2AttribNames, wedgeVector2AttribData );
352 moveContainerToMesh<Vector3>( out, m_wedges.m_vector3AttribNames, wedgeVector3AttribData );
353 moveContainerToMesh<Vector4>( out, m_wedges.m_vector4AttribNames, wedgeVector4AttribData );
355 for ( TopologicalMesh::FaceIter f_it = faces_sbegin(); f_it != faces_end(); ++f_it ) {
357 PolyMesh::IndexType faceIndices( valence( *f_it ) );
359 for ( TopologicalMesh::ConstFaceHalfedgeIter fh_it = cfh_iter( *f_it ); fh_it.is_valid();
361 faceIndices( i ) = property( m_wedgeIndexPph, *fh_it );
374 TriangleMesh::PointAttribHandle::Container wedgePosition;
376 m_wedges.m_floatAttribNames.
size() );
378 m_wedges.m_vector2AttribNames.
size() );
380 m_wedges.m_vector3AttribNames.
size() );
382 m_wedges.m_vector4AttribNames.
size() );
385 for ( WedgeIndex widx { 0 }; widx < WedgeIndex( m_wedges.size() ); ++widx ) {
386 const auto& wd = m_wedges.getWedgeData( widx );
387 wedgePosition.push_back( wd.m_position );
388 copyWedgeDataToAttribContainer( wedgeFloatAttribData, wd.m_floatAttrib );
389 copyWedgeDataToAttribContainer( wedgeVector2AttribData, wd.m_vector2Attrib );
390 copyWedgeDataToAttribContainer( wedgeVector3AttribData, wd.m_vector3Attrib );
391 copyWedgeDataToAttribContainer( wedgeVector4AttribData, wd.m_vector4Attrib );
395 moveContainerToMesh<Scalar>( out, m_wedges.m_floatAttribNames, wedgeFloatAttribData );
396 moveContainerToMesh<Vector2>( out, m_wedges.m_vector2AttribNames, wedgeVector2AttribData );
397 moveContainerToMesh<Vector3>( out, m_wedges.m_vector3AttribNames, wedgeVector3AttribData );
398 moveContainerToMesh<Vector4>( out, m_wedges.m_vector4AttribNames, wedgeVector4AttribData );
401void TopologicalMesh::updateTriangleMeshNormals(
402 AttribArrayGeometry::NormalAttribHandle::Container& normals ) {
403 if ( !has_halfedge_normals() ) {
404 LOG( logERROR ) <<
"TopologicalMesh has no normals, nothing set";
408 for (
unsigned int widx = 0; widx < m_wedges.size(); ++widx ) {
409 normals[widx] = m_wedges.getWedgeData<Normal>( widx, m_normalsIndex );
415 updateTriangleMeshNormals( normals );
420 for (
size_t i = 0; i < triMesh.
vertices().size(); ++i ) {
422 wd.m_position = triMesh.
vertices()[i];
423 copyMeshToWedgeData( triMesh,
425 m_wedges.m_wedgeFloatAttribHandles,
426 m_wedges.m_wedgeVector2AttribHandles,
427 m_wedges.m_wedgeVector3AttribHandles,
428 m_wedges.m_wedgeVector4AttribHandles,
430 m_wedges.setWedgeData( i, wd );
433 for (
auto itr = halfedges_begin(), stop = halfedges_end(); itr != stop; ++itr ) {
434 point( to_vertex_handle( *itr ) ) =
440 updatePositions( triMesh.
vertices() );
443void TopologicalMesh::updatePositions(
444 const AttribArrayGeometry::PointAttribHandle::Container& vertices ) {
446 for (
size_t i = 0; i < vertices.size(); ++i ) {
447 m_wedges.m_data[i].getWedgeData().m_position = vertices[i];
448 point( m_wedges.m_data[i].getWedgeData().m_vertexHandle ) = vertices[i];
453 auto& normals = triMesh.
normals();
455 for (
size_t i = 0; i < triMesh.
vertices().size(); ++i ) {
456 m_wedges.setWedgeAttrib<
Normal>( i, m_normalsIndex, normals[i] );
460void TopologicalMesh::updateWedgeNormals() {
461 if ( !has_halfedge_normals() ) {
462 LOG( logERROR ) <<
"TopologicalMesh has no normals, nothing set";
466 FaceIter f_it( faces_sbegin() ), f_end( faces_end() );
467 for ( ; f_it != f_end; ++f_it ) {
468 auto fv_it = this->cfv_iter( *f_it );
469 const auto& p0 = point( *fv_it );
471 const auto& p1 = point( *fv_it );
473 const auto& p2 = point( *fv_it );
475 set_normal( *f_it, ( p1 - p0 ).cross( p2 - p0 ).normalized() );
478 for (
auto& w : m_wedges.m_data ) {
479 w.getWedgeData().m_vector3Attrib[m_normalsIndex] =
Normal { 0_ra, 0_ra, 0_ra };
482 for (
auto v_itr = vertices_begin(), stop = vertices_end(); v_itr != stop; ++v_itr ) {
483 for ( ConstVertexFaceIter f_itr = cvf_iter( *v_itr ); f_itr.is_valid(); ++f_itr ) {
484 for (
const auto& widx :
485 m_vertexFaceWedgesWithSameNormals[v_itr->idx()][f_itr->idx()] ) {
486 m_wedges.m_data[widx].getWedgeData().m_vector3Attrib[m_normalsIndex] +=
492 for (
auto& w : m_wedges.m_data ) {
493 w.getWedgeData().m_vector3Attrib[m_normalsIndex].normalize();
498 for (
auto& w : m_wedges.m_data ) {
499 w.m_wedgeData.m_position = point( w.m_wedgeData.m_vertexHandle );
507 const Scalar alpha ) {
508 for (
size_t i = 0; i < in1.
size(); ++i ) {
509 out.
push_back( ( 1_ra - alpha ) * in1[i] + alpha * in2[i] );
518 interpolate( w1.m_floatAttrib, w2.m_floatAttrib, ret.m_floatAttrib, alpha );
519 interpolate( w1.m_vector2Attrib, w2.m_vector2Attrib, ret.m_vector2Attrib, alpha );
520 interpolate( w1.m_vector3Attrib, w2.m_vector3Attrib, ret.m_vector3Attrib, alpha );
521 interpolate( w1.m_vector4Attrib, w2.m_vector4Attrib, ret.m_vector4Attrib, alpha );
527void TopologicalMesh::split( EdgeHandle _eh, VertexHandle _vh ) {
531 VertexHandle v2 = to_vertex_handle( o0 );
533 HalfedgeHandle e1 = new_edge( _vh, v2 );
534 HalfedgeHandle t1 = opposite_halfedge_handle( e1 );
536 FaceHandle f0 = face_handle( h0 );
537 FaceHandle f3 = face_handle( o0 );
539 set_halfedge_handle( _vh, h0 );
540 set_vertex_handle( o0, _vh );
542 if ( !is_boundary( h0 ) ) {
543 HalfedgeHandle h1 = next_halfedge_handle( h0 );
544 HalfedgeHandle h2 = next_halfedge_handle( h1 );
546 VertexHandle v1 = to_vertex_handle( h1 );
548 HalfedgeHandle e0 = new_edge( _vh, v1 );
549 HalfedgeHandle t0 = opposite_halfedge_handle( e0 );
551 FaceHandle f1 = new_face();
552 set_halfedge_handle( f0, h0 );
553 set_halfedge_handle( f1, h2 );
555 set_face_handle( h1, f0 );
556 set_face_handle( t0, f0 );
557 set_face_handle( h0, f0 );
559 set_face_handle( h2, f1 );
560 set_face_handle( t1, f1 );
561 set_face_handle( e0, f1 );
563 set_next_halfedge_handle( h0, h1 );
564 set_next_halfedge_handle( h1, t0 );
565 set_next_halfedge_handle( t0, h0 );
567 set_next_halfedge_handle( e0, h2 );
568 set_next_halfedge_handle( h2, t1 );
569 set_next_halfedge_handle( t1, e0 );
572 set_next_halfedge_handle( prev_halfedge_handle( h0 ), t1 );
573 set_next_halfedge_handle( t1, h0 );
577 if ( !is_boundary( o0 ) ) {
578 HalfedgeHandle o1 = next_halfedge_handle( o0 );
579 HalfedgeHandle o2 = next_halfedge_handle( o1 );
581 VertexHandle v3 = to_vertex_handle( o1 );
583 HalfedgeHandle e2 = new_edge( _vh, v3 );
584 HalfedgeHandle t2 = opposite_halfedge_handle( e2 );
586 FaceHandle f2 = new_face();
587 set_halfedge_handle( f2, o1 );
588 set_halfedge_handle( f3, o0 );
590 set_face_handle( o1, f2 );
591 set_face_handle( t2, f2 );
592 set_face_handle( e1, f2 );
594 set_face_handle( o2, f3 );
595 set_face_handle( o0, f3 );
596 set_face_handle( e2, f3 );
598 set_next_halfedge_handle( e1, o1 );
599 set_next_halfedge_handle( o1, t2 );
600 set_next_halfedge_handle( t2, e1 );
602 set_next_halfedge_handle( o0, e2 );
603 set_next_halfedge_handle( e2, o2 );
604 set_next_halfedge_handle( o2, o0 );
607 set_next_halfedge_handle( e1, next_halfedge_handle( o0 ) );
608 set_next_halfedge_handle( o0, e1 );
609 set_halfedge_handle( _vh, e1 );
617void TopologicalMesh::split_copy( EdgeHandle _eh, VertexHandle _vh ) {
621 const int nf = n_faces();
628 for ( VEIter ve_it = ve_iter( _vh ); ve_it.is_valid(); ++ve_it )
629 copy_all_properties( _eh, *ve_it,
true );
631 for (
auto vh : { v0, v1 } ) {
633 const HalfedgeHandle h = find_halfedge( _vh, vh );
635 if ( !is_boundary( h ) ) {
636 FaceHandle fh0 = face_handle( h );
637 FaceHandle fh1 = face_handle( opposite_halfedge_handle( prev_halfedge_handle( h ) ) );
639 if ( fh0.idx() >= nf )
std::swap( fh0, fh1 );
642 copy_all_properties( fh0, fh1,
true );
667 if ( f < 0 || f > 1 ) {
return false; }
672 const auto v0 = to_vertex_handle( o0 );
673 const auto v1 = to_vertex_handle( h0 );
675 const auto h1 = next_halfedge_handle( h0 );
676 const auto h2 = next_halfedge_handle( h1 );
677 const auto o1 = next_halfedge_handle( o0 );
678 const auto o2 = next_halfedge_handle( o1 );
681 const Point p = Point( f * point( v1 ) + ( 1_ra - f ) * point( v0 ) );
682 VertexHandle vh = add_vertex( p );
689 if ( !is_boundary( h0 ) ) {
691 const auto hw0idx = property( m_wedgeIndexPph, h2 );
692 const auto hw1idx = property( m_wedgeIndexPph, h0 );
693 const auto hw0 = m_wedges.getWedgeData( hw0idx );
694 const auto hw1 = m_wedges.getWedgeData( hw1idx );
695 auto hvw = interpolateWedgeAttributes( hw0, hw1, f );
697 hvwidx = m_wedges.add( hvw );
699 if ( !is_boundary( o0 ) ) {
701 const auto ow0idx = property( m_wedgeIndexPph, o2 );
702 const auto ow1idx = property( m_wedgeIndexPph, o0 );
703 const auto ow0 = m_wedges.getWedgeData( ow0idx );
704 const auto ow1 = m_wedges.getWedgeData( ow1idx );
705 auto ovw = interpolateWedgeAttributes( ow1, ow0, f );
707 ovwidx = m_wedges.add( ovw );
710 split_copy( eh, vh );
712 auto r0 = find_halfedge( v0, vh );
713 auto s0 = find_halfedge( vh, v1 );
714 auto t0 = find_halfedge( v1, vh );
715 auto u0 = find_halfedge( vh, v0 );
717 auto r1 = next_halfedge_handle( r0 );
718 auto r2 = next_halfedge_handle( r1 );
720 auto s1 = next_halfedge_handle( s0 );
721 auto s2 = next_halfedge_handle( s1 );
723 auto t1 = next_halfedge_handle( t0 );
724 auto t2 = next_halfedge_handle( t1 );
726 auto u1 = next_halfedge_handle( u0 );
727 auto u2 = next_halfedge_handle( u1 );
729 CORE_ASSERT( s0 == h0,
"TopologicalMesh: splitEdgeWedge inconsistency" );
730 CORE_ASSERT( t0 == o0,
"TopologicalMesh: splitEdgeWedge inconsistency" );
732 auto updateWedgeIndex1 = [
this]( WedgeIndex widx_,
737 HalfedgeHandle h2_ ) {
741 if ( !is_boundary( r0_ ) ) {
742 CORE_ASSERT( r2_ == h2_,
"TopologicalMesh: splitEdgeWedge inconsistency" );
745 property( this->m_wedgeIndexPph, r0_ ) = this->m_wedges.newReference( widx_ );
746 property( this->m_wedgeIndexPph, r1_ ) =
747 this->m_wedges.newReference( property( this->m_wedgeIndexPph, h1_ ) );
749 else { property( this->m_wedgeIndexPph, r0_ ) = WedgeIndex {}; }
752 auto updateWedgeIndex2 = [
this]( WedgeIndex widx_,
757 HalfedgeHandle h1_ ) {
761 if ( !is_boundary( s0_ ) ) {
762 CORE_ASSERT( s1_ == h1_,
"TopologicalMesh: splitEdgeWedge inconsistency" );
764 property( this->m_wedgeIndexPph, s2_ ) = widx_;
767 property( this->m_wedgeIndexPph, s0_ ) = property( this->m_wedgeIndexPph, h0_ );
769 else { property( this->m_wedgeIndexPph, s0_ ) = WedgeIndex {}; }
773 updateWedgeIndex2( ovwidx, u0, u1, u2, o0, o1 );
775 updateWedgeIndex2( hvwidx, s0, s1, s2, h0, h1 );
776 updateWedgeIndex1( hvwidx, r0, r1, r2, h1, h2 );
777 updateWedgeIndex1( ovwidx, t0, t1, t2, o1, o2 );
784 HalfedgeHandle h0 = _hh;
785 HalfedgeHandle h1 = next_halfedge_handle( h0 );
786 HalfedgeHandle o0 = opposite_halfedge_handle( h0 );
787 HalfedgeHandle o1 = next_halfedge_handle( o0 );
790 collapse_edge( h0, keepFrom );
793 if ( next_halfedge_handle( next_halfedge_handle( h1 ) ) == h1 )
794 collapse_loop( next_halfedge_handle( h1 ) );
795 if ( next_halfedge_handle( next_halfedge_handle( o1 ) ) == o1 ) collapse_loop( o1 );
799void TopologicalMesh::collapse_edge( HalfedgeHandle _hh,
bool keepFrom ) {
800 HalfedgeHandle h = _hh;
801 HalfedgeHandle hn = next_halfedge_handle( h );
802 HalfedgeHandle hp = prev_halfedge_handle( h );
804 HalfedgeHandle o = opposite_halfedge_handle( h );
805 HalfedgeHandle on = next_halfedge_handle( o );
806 HalfedgeHandle ono = opposite_halfedge_handle( on );
807 HalfedgeHandle op = prev_halfedge_handle( o );
809 FaceHandle fh = face_handle( h );
810 FaceHandle fo = face_handle( o );
812 VertexHandle vh = to_vertex_handle( h );
813 VertexHandle vo = to_vertex_handle( o );
816 if ( widx.isInvalid() )
819 if ( otherWidx.isInvalid() )
825 auto currentWidx = widx;
826 auto ringWidx = WedgeIndex {};
828 HalfedgeHandle start = prev_halfedge_handle( opposite_halfedge_handle( hp ) );
829 HalfedgeHandle vih = start;
831 set_vertex_handle( vih, vh );
832 if ( !is_boundary( vih ) ) {
835 CORE_ASSERT( ringWidx.isInvalid(),
"" );
840 CORE_ASSERT( ringWidx.isValid(),
"" );
843 currentWidx = otherWidx;
847 else { m_wedges.setWedgePosition(
getWedgeIndex( vih ), point( vh ) ); }
849 vih = prev_halfedge_handle( opposite_halfedge_handle( vih ) );
850 }
while ( vih != start );
864 set_next_halfedge_handle( hp, hn );
865 if ( !is_boundary( hp ) )
868 set_next_halfedge_handle( op, on );
874 if ( fh.is_valid() ) set_halfedge_handle( fh, hn );
875 if ( fo.is_valid() ) set_halfedge_handle( fo, on );
879 adjust_outgoing_halfedge( vh );
883 status( edge_handle( h ) ).set_deleted(
true );
885 status( vo ).set_deleted(
true );
890 if ( has_halfedge_status() ) {
891 status( h ).set_deleted(
true );
892 status( o ).set_deleted(
true );
897void TopologicalMesh::collapse_loop( HalfedgeHandle _hh ) {
898 HalfedgeHandle h0 = _hh;
899 HalfedgeHandle h1 = next_halfedge_handle( h0 );
901 HalfedgeHandle o0 = opposite_halfedge_handle( h0 );
902 HalfedgeHandle o1 = opposite_halfedge_handle( h1 );
904 VertexHandle v0 = to_vertex_handle( h0 );
905 VertexHandle v1 = to_vertex_handle( h1 );
907 FaceHandle fh = face_handle( h0 );
908 FaceHandle fo = face_handle( o0 );
911 assert( ( next_halfedge_handle( h1 ) == h0 ) && ( h1 != o0 ) );
914 set_next_halfedge_handle( h1, next_halfedge_handle( o0 ) );
916 set_next_halfedge_handle( prev_halfedge_handle( o0 ), h1 );
919 set_face_handle( h1, fo );
922 set_halfedge_handle( v0, h1 );
923 adjust_outgoing_halfedge( v0 );
924 set_halfedge_handle( v1, o1 );
925 adjust_outgoing_halfedge( v1 );
928 if ( fo.is_valid() &&
halfedge_handle( fo ) == o0 ) { set_halfedge_handle( fo, h1 ); }
931 if ( fh.is_valid() ) {
932 set_halfedge_handle( fh, InvalidHalfedgeHandle );
933 status( fh ).set_deleted(
true );
935 status( edge_handle( h0 ) ).set_deleted(
true );
940 if ( has_halfedge_status() ) {
941 status( h0 ).set_deleted(
true );
942 status( o0 ).set_deleted(
true );
946void TopologicalMesh::collapseWedge( TopologicalMesh::HalfedgeHandle heh,
bool keepFromWedges ) {
953 auto offset = m_wedges.computeCleanupOffset();
954 for ( HalfedgeIter he_it = halfedges_begin(); he_it != halfedges_end(); ++he_it ) {
955 if ( !status( *he_it ).deleted() ) {
956 auto index = property( m_wedgeIndexPph, *he_it );
957 if ( index.isValid() ) { property( m_wedgeIndexPph, *he_it ) = index - offset[index]; }
960 m_wedges.garbageCollection();
961 base::garbage_collection();
963 for ( HalfedgeIter he_it = halfedges_begin(); he_it != halfedges_end(); ++he_it ) {
964 ON_ASSERT(
auto idx = property( m_wedgeIndexPph, *he_it ); );
965 CORE_ASSERT( !idx.isValid() || !m_wedges.getWedge( idx ).isDeleted(),
966 "references deleted wedge remains after garbage collection" );
968 for (
size_t i = 0; i < m_wedges.size(); ++i ) {
969 CORE_ASSERT( !m_wedges.getWedge( WedgeIndex { i } ).isDeleted(),
970 "deleted wedge remains after garbage collection" );
974void TopologicalMesh::delete_face( FaceHandle _fh,
bool _delete_isolated_vertices ) {
975 for (
auto itr = fh_begin( _fh ); itr.is_valid(); ++itr ) {
976 auto idx = property( m_wedgeIndexPph, *itr );
977 if ( idx.isInvalid() ) {
979 <<
"[TopologicalMesh::delete_face] halfedge has an invalid wedge index";
981 else { m_wedges.del( idx ); }
983 property( m_wedgeIndexPph, *itr ) = WedgeIndex {};
985 base::delete_face( _fh, _delete_isolated_vertices );
990TopologicalMesh::WedgeIndex
993 auto itr =
std::find( m_data.begin(), m_data.end(), Wedge { wd } );
995 if ( itr == m_data.end() ) {
997 m_data.emplace_back( wd );
1000 itr->incrementRefCount();
1006std::vector<int> TopologicalMesh::WedgeCollection::computeCleanupOffset()
const {
1008 int currentOffset = 0;
1009 for (
size_t i = 0; i < m_data.size(); ++i ) {
1010 if ( m_data[i].isDeleted() ) {
1014 else { ret[i] = currentOffset; }
NormalAttribHandle::Container & normalsWithLock()
void normalsUnlock()
Release lock on vertices normals.
void setVertices(PointAttribHandle::Container &&vertices)
Set vertices.
const NormalAttribHandle::Container & normals() const
Access the vertices normals.
const PointAttribHandle::Container & vertices() const
Access the vertices positions.
Utils::Attrib< T > & getAttrib(const Utils::AttribHandle< T > &h)
void setIndices(IndexContainerType &&indices)
AbstractGeometry with per-vertex attributes and layers of indices. Each layer represents a different ...
bool isManifold(VertexHandle vh) const
void updateTriangleMesh(Ra::Core::Geometry::MultiIndexedGeometry &mesh)
WedgeIndex getWedgeIndex(OpenMesh::HalfedgeHandle heh) const
void replaceWedgeIndex(OpenMesh::HalfedgeHandle he, const WedgeIndex &widx)
bool checkIntegrity() const
void collapse(HalfedgeHandle he, bool keepFromVertex=false)
bool splitEdge(TopologicalMesh::EdgeHandle eh, Scalar f)
std::set< WedgeIndex > getVertexWedges(OpenMesh::VertexHandle vh) const
unsigned int getWedgeRefCount(const WedgeIndex &idx) const
TriangleMesh toTriangleMesh()
void garbage_collection()
Remove deleted element from the mesh, including wedges.
const WedgeData & getWedgeData(const WedgeIndex &idx) const
void copyPointsPositionToWedges()
HalfedgeHandle halfedge_handle(VertexHandle vh, FaceHandle fh) const
T emplace_back(T... args)
This namespace contains everything "low level", related to data, datastuctures, and computation.
LineMeshPtr Normal(const Core::Vector3 &point, const Core::Vector3 &normal, const Core::Utils::Color &color, Scalar scale)
@ Geometry
"Geometry" render objects are those loaded using Radium::IO and generated by GeometrySystem
hepler function to manage enum as underlying types in VariableSet