Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 41 additions & 5 deletions source/MRMesh/MRMeshDecimate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "MRMeshDelone.h"
#include "MRMeshSubdivide.h"
#include "MRMeshRelax.h"
#include "MRLineSegm.h"
#include "MRPch/MRTBB.h"
#include <queue>

Expand Down Expand Up @@ -410,6 +411,30 @@ VertId MeshDecimator::collapse_( EdgeId edgeToCollapse, const Vector3f & collaps
std::swap( po, pd );
}

auto smallShift = [maxBdShiftSq = sqr( settings_.maxBdShift )]( const LineSegm3f & segm, const Vector3f & p )
{
return ( closestPointOnLineSegm( p, segm ) - p ).lengthSq() <= maxBdShiftSq;
};
if ( ( !vl || !vr ) && settings_.maxBdShift < FLT_MAX )
{
if ( !smallShift( LineSegm3f{ mesh_.orgPnt( edgeToCollapse ), mesh_.destPnt( edgeToCollapse ) }, collapsePos ) )
return {}; // new vertex is too far from collapsing boundary edge
if ( !vr )
{
if ( !smallShift( LineSegm3f{ mesh_.orgPnt( mesh_.topology.prevLeftBd( edgeToCollapse ) ), collapsePos }, po ) )
return {}; // origin of collapsing boundary edge is too far from new boundary segment
if ( !smallShift( LineSegm3f{ mesh_.destPnt( mesh_.topology.nextLeftBd( edgeToCollapse ) ), collapsePos }, pd ) )
return {}; // destination of collapsing boundary edge is too far from new boundary segment
}
if ( !vl )
{
if ( !smallShift( LineSegm3f{ mesh_.orgPnt( mesh_.topology.prevLeftBd( edgeToCollapse.sym() ) ), collapsePos }, pd ) )
return {}; // destination of collapsing boundary edge is too far from new boundary segment
if ( !smallShift( LineSegm3f{ mesh_.destPnt( mesh_.topology.nextLeftBd( edgeToCollapse.sym() ) ), collapsePos }, po ) )
return {}; // origin of collapsing boundary edge is too far from new boundary segment
}
}

float maxOldAspectRatio = settings_.maxTriangleAspectRatio;
float maxNewAspectRatio = 0;
const float edgeLenSq = ( po - pd ).lengthSq();
Expand All @@ -420,7 +445,7 @@ VertId MeshDecimator::collapse_( EdgeId edgeToCollapse, const Vector3f & collaps
originNeis_.clear();
triDblAreas_.clear();
Vector3d sumDblArea_;
bool oBd = false; // there is a boundary edge incident to org( edgeToCollapse )
EdgeId oBdEdge; // a boundary edge !right(e) incident to org( edgeToCollapse )
for ( EdgeId e : orgRing0( topology, edgeToCollapse ) )
{
const auto eDest = topology.dest( e );
Expand All @@ -434,7 +459,8 @@ VertId MeshDecimator::collapse_( EdgeId edgeToCollapse, const Vector3f & collaps
maxNewEdgeLenSq = std::max( maxNewEdgeLenSq, ( collapsePos - pDest ).lengthSq() );
if ( !topology.left( e ) )
{
oBd = true;
oBdEdge = topology.next( e );
assert( topology.isLeftBdEdge( oBdEdge ) );
continue;
}

Expand All @@ -451,9 +477,13 @@ VertId MeshDecimator::collapse_( EdgeId edgeToCollapse, const Vector3f & collaps
}
maxOldAspectRatio = std::max( maxOldAspectRatio, triangleAspectRatio( po, pDest, pDest2 ) );
}
if ( oBdEdge
&& !smallShift( LineSegm3f{ po, mesh_.destPnt( oBdEdge ) }, collapsePos )
&& !smallShift( LineSegm3f{ po, mesh_.orgPnt( topology.prevLeftBd( oBdEdge ) ) }, collapsePos ) )
return {}; // new vertex is too far from both existed boundary edges
std::sort( originNeis_.begin(), originNeis_.end() );

bool dBd = false; // there is a boundary edge incident to dest( edgeToCollapse )
EdgeId dBdEdge; // a boundary edge !right(e) incident to dest( edgeToCollapse )
for ( EdgeId e : orgRing0( topology, edgeToCollapse.sym() ) )
{
const auto eDest = topology.dest( e );
Expand All @@ -466,7 +496,8 @@ VertId MeshDecimator::collapse_( EdgeId edgeToCollapse, const Vector3f & collaps
maxNewEdgeLenSq = std::max( maxNewEdgeLenSq, ( collapsePos - pDest ).lengthSq() );
if ( !topology.left( e ) )
{
dBd = true;
dBdEdge = topology.next( e );
assert( topology.isLeftBdEdge( dBdEdge ) );
continue;
}

Expand All @@ -483,8 +514,12 @@ VertId MeshDecimator::collapse_( EdgeId edgeToCollapse, const Vector3f & collaps
}
maxOldAspectRatio = std::max( maxOldAspectRatio, triangleAspectRatio( pd, pDest, pDest2 ) );
}
if ( dBdEdge
&& !smallShift( LineSegm3f{ pd, mesh_.destPnt( dBdEdge ) }, collapsePos )
&& !smallShift( LineSegm3f{ pd, mesh_.orgPnt( topology.prevLeftBd( dBdEdge ) ) }, collapsePos ) )
return {}; // new vertex is too far from both existed boundary edges

if ( vl && vr && oBd && dBd )
if ( vl && vr && oBdEdge && dBdEdge )
return {}; // prohibit collapse of an inner edge if it brings two boundaries in touch

if ( !tinyEdge && maxNewAspectRatio > maxOldAspectRatio && maxOldAspectRatio <= settings_.criticalTriAspectRatio )
Expand Down Expand Up @@ -834,6 +869,7 @@ bool remesh( MR::Mesh& mesh, const RemeshSettings & settings )
DecimateSettings decs;
decs.strategy = DecimateStrategy::ShortestEdgeFirst;
decs.maxError = settings.targetEdgeLen * uni;
decs.maxBdShift = settings.maxBdShift;
decs.region = settings.region;
decs.packMesh = settings.packMesh;
decs.progressCallback = subprogress( settings.progressCallback, 0.5f, 0.95f );
Expand Down
4 changes: 4 additions & 0 deletions source/MRMesh/MRMeshDecimate.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ struct DecimateSettings
float maxError = 0.001f;
/// Maximal possible edge length created during decimation
float maxEdgeLen = FLT_MAX;
/// Maximal shift of a boundary during one edge collapse
float maxBdShift = FLT_MAX;
/// Maximal possible aspect ratio of a triangle introduced during decimation
float maxTriangleAspectRatio = 20;
/// the algorithm will ignore dihedral angle check if one of triangles had aspect ratio equal or more than this value;
Expand Down Expand Up @@ -190,6 +192,8 @@ struct RemeshSettings
float edgeLenUniformity = 0.5f;
/// Improves local mesh triangulation by doing edge flips if it does change dihedral angle more than on this value
float maxAngleChangeAfterFlip = 30 * PI_F / 180.0f;
/// Maximal shift of a boundary during one edge collapse
float maxBdShift = FLT_MAX;
/// This option in subdivision works best for natural surfaces, where all triangles are close to equilateral and have similar area,
/// and no sharp edges in between
bool useCurvature = false;
Expand Down
1 change: 1 addition & 0 deletions source/MRMesh/MRMeshDecimateParallel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ DecimateResult decimateParallelMesh( MR::Mesh & mesh, const DecimateParallelSett
seqSettings.strategy = settings.strategy;
seqSettings.maxError = settings.maxError;
seqSettings.maxEdgeLen = settings.maxEdgeLen;
seqSettings.maxBdShift = settings.maxBdShift;
seqSettings.maxTriangleAspectRatio = settings.maxTriangleAspectRatio;
seqSettings.criticalTriAspectRatio = settings.criticalTriAspectRatio;
seqSettings.stabilizer = settings.stabilizer;
Expand Down
4 changes: 3 additions & 1 deletion source/MRMesh/MRMeshDecimateParallel.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ struct DecimateParallelSettings
/// stop the decimation as soon as the shortest edge in the mesh is greater than this value
float maxError = 0.001f;
/// Maximal possible edge length created during decimation
float maxEdgeLen = 1;
float maxEdgeLen = FLT_MAX;
/// Maximal shift of a boundary during one edge collapse
float maxBdShift = FLT_MAX;
/// Maximal possible aspect ratio of a triangle introduced during decimation
float maxTriangleAspectRatio = 20;
/// the algorithm will try to eliminate triangles with equal or larger aspect ratio, ignoring normal orientation checks
Expand Down
3 changes: 2 additions & 1 deletion source/MRMesh/MRPolylineDecimate.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include "MRMeshFwd.h"
#include <cfloat>
#include <climits>
#include <functional>

Expand All @@ -20,7 +21,7 @@ struct DecimatePolylineSettings
/// Limit from above on the maximum distance from moved vertices to original contour
float maxError = 0.001f;
/// Maximal possible edge length created during decimation
float maxEdgeLen = 1;
float maxEdgeLen = FLT_MAX;
/// Stabilizer is dimensionless coefficient.
/// The larger is stabilizer, the more Decimator will strive to retain the density of input points.
/// If stabilizer is zero, then only the shape of input line will be preserved.
Expand Down