From 4c2b4501fc557f9541c2b3668ff5ac902c65253a Mon Sep 17 00:00:00 2001 From: Fedr Date: Tue, 20 Jun 2023 15:39:33 +0300 Subject: [PATCH] Remesh and Subdivide: update notFlippable edges (#1345) --- source/MRMesh/MRMeshDecimate.cpp | 13 +++++++------ source/MRMesh/MRMeshDecimate.h | 5 +++-- source/MRMesh/MRMeshSubdivide.cpp | 2 ++ source/MRMesh/MRMeshSubdivide.h | 4 ++-- source/MRMesh/MRRegionBoundary.cpp | 9 +++++++-- source/MRMesh/MRRegionBoundary.h | 4 +++- 6 files changed, 24 insertions(+), 13 deletions(-) diff --git a/source/MRMesh/MRMeshDecimate.cpp b/source/MRMesh/MRMeshDecimate.cpp index cc7a6ed166a7..cd243b100491 100644 --- a/source/MRMesh/MRMeshDecimate.cpp +++ b/source/MRMesh/MRMeshDecimate.cpp @@ -829,18 +829,19 @@ bool remesh( MR::Mesh& mesh, const RemeshSettings & settings ) decs.progressCallback = subprogress( settings.progressCallback, 0.5f, 0.95f ); decs.preCollapse = settings.preCollapse; decimateMesh( mesh, decs ); + if ( settings.notFlippable ) + mesh.topology.excludeLoneEdges( *settings.notFlippable ); if ( !reportProgress( settings.progressCallback, 0.95f ) ) return false; if ( settings.finalRelaxIters > 0 ) { - VertBitSet innerVerts; + // even if region is not given, we need to exclude mesh boundary from relaxation + VertBitSet innerVerts = getInnerVerts( mesh.topology, settings.region ); + if ( settings.notFlippable ) + innerVerts -= getIncidentVerts( mesh.topology, *settings.notFlippable ); MeshRelaxParams rp; - if ( settings.region ) - { - innerVerts = getInnerVerts( mesh.topology, *settings.region ); - rp.region = &innerVerts; - } + rp.region = &innerVerts; rp.iterations = settings.finalRelaxIters; relax( mesh, rp, subprogress( settings.progressCallback, 0.95f, 1.0f ) ); } diff --git a/source/MRMesh/MRMeshDecimate.h b/source/MRMesh/MRMeshDecimate.h index 2f9288abdaf7..e002e352ef86 100644 --- a/source/MRMesh/MRMeshDecimate.h +++ b/source/MRMesh/MRMeshDecimate.h @@ -198,8 +198,9 @@ struct RemeshSettings int finalRelaxIters = 0; /// Region on mesh to be changed, it is updated during the operation FaceBitSet * region = nullptr; - /// Edges specified by this bit-set will never be flipped - const UndirectedEdgeBitSet* notFlippable = nullptr; + /// Edges specified by this bit-set will never be flipped, but they can be split or eliminated during decimation + /// so it is updated during the operation; also the vertices incident to these edges are exluded from relaxation + UndirectedEdgeBitSet* notFlippable = nullptr; /// whether to pack mesh at the end bool packMesh = false; /// this function is called each time edge (e) is split into (e1->e), but before the ring is made Delone diff --git a/source/MRMesh/MRMeshSubdivide.cpp b/source/MRMesh/MRMeshSubdivide.cpp index 5022adf38ef1..5a8f767f7b4f 100644 --- a/source/MRMesh/MRMeshSubdivide.cpp +++ b/source/MRMesh/MRMeshSubdivide.cpp @@ -116,6 +116,8 @@ int subdivideMesh( Mesh & mesh, const SubdivideSettings & settings ) settings.onVertCreated( newVertId ); if ( settings.onEdgeSplit ) settings.onEdgeSplit( e1, e ); + if ( settings.notFlippable && settings.notFlippable->test( e.undirected() ) ) + settings.notFlippable->autoResizeSet( e1.undirected() ); ++splitsDone; makeDeloneOriginRing( mesh, e, { .maxDeviationAfterFlip = settings.maxDeviationAfterFlip, diff --git a/source/MRMesh/MRMeshSubdivide.h b/source/MRMesh/MRMeshSubdivide.h index fc2ec4a6a8b7..334b0e2be218 100644 --- a/source/MRMesh/MRMeshSubdivide.h +++ b/source/MRMesh/MRMeshSubdivide.h @@ -24,8 +24,8 @@ struct SubdivideSettings float maxAngleChangeAfterFlip = 10; /// Region on mesh to be subdivided, it is updated during the operation FaceBitSet * region = nullptr; - /// Edges specified by this bit-set will never be flipped - const UndirectedEdgeBitSet* notFlippable = nullptr; + /// Edges specified by this bit-set will never be flipped, but they can be split so it is updated during the operation + UndirectedEdgeBitSet* notFlippable = nullptr; /// New vertices appeared during subdivision will be added here VertBitSet * newVerts = nullptr; /// If false do not touch border edges (cannot subdivide lone faces)\n diff --git a/source/MRMesh/MRRegionBoundary.cpp b/source/MRMesh/MRRegionBoundary.cpp index 0a638779a3ad..fc299885ab4c 100644 --- a/source/MRMesh/MRRegionBoundary.cpp +++ b/source/MRMesh/MRRegionBoundary.cpp @@ -238,7 +238,7 @@ VertBitSet getIncidentVerts( const MeshTopology & topology, const FaceBitSet & f return res; } -VertBitSet getInnerVerts( const MeshTopology & topology, const FaceBitSet & faces ) +VertBitSet getInnerVerts( const MeshTopology & topology, const FaceBitSet * region ) { MR_TIMER VertBitSet res = topology.getValidVerts(); @@ -247,7 +247,7 @@ VertBitSet getInnerVerts( const MeshTopology & topology, const FaceBitSet & face for ( auto e : orgRing( topology, v ) ) { auto f = topology.left( e ); - if ( !f.valid() || !faces.test( f ) ) + if ( !f.valid() || ( region && !region->test( f ) ) ) { res.reset( v ); break; @@ -257,6 +257,11 @@ VertBitSet getInnerVerts( const MeshTopology & topology, const FaceBitSet & face return res; } +VertBitSet getInnerVerts( const MeshTopology & topology, const FaceBitSet & region ) +{ + return getInnerVerts( topology, ®ion ); +} + const VertBitSet & getIncidentVerts( const MeshTopology & topology, const FaceBitSet * faces, VertBitSet & store ) { MR_TIMER diff --git a/source/MRMesh/MRRegionBoundary.h b/source/MRMesh/MRRegionBoundary.h index fa069670e6a1..5316f46e8571 100644 --- a/source/MRMesh/MRRegionBoundary.h +++ b/source/MRMesh/MRRegionBoundary.h @@ -46,7 +46,9 @@ namespace MR // otherwise performs store = getIncidentVerts( topology, *faces ) and returns reference on store [[nodiscard]] MRMESH_API const VertBitSet & getIncidentVerts( const MeshTopology & topology, const FaceBitSet * faces, VertBitSet & store ); // composes the set of all vertices not on the boundary of a hole and with all their adjacent faces in given set -[[nodiscard]] MRMESH_API VertBitSet getInnerVerts( const MeshTopology & topology, const FaceBitSet & faces ); +[[nodiscard]] MRMESH_API VertBitSet getInnerVerts( const MeshTopology & topology, const FaceBitSet * region ); +// composes the set of all vertices not on the boundary of a hole and with all their adjacent faces in given set +[[nodiscard]] MRMESH_API VertBitSet getInnerVerts( const MeshTopology & topology, const FaceBitSet & region ); // composes the set of all boundary vertices for given region (or whole mesh if !region) [[nodiscard]] MRMESH_API VertBitSet getBoundaryVerts( const MeshTopology & topology, const FaceBitSet * region = nullptr );