Skip to content

Commit 2849669

Browse files
authored
detectTunnelFaces constructs co-loops in given metric (#5695)
1 parent 9010a2c commit 2849669

File tree

4 files changed

+43
-13
lines changed

4 files changed

+43
-13
lines changed

source/MRMesh/MREdgeMetric.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,25 @@ EdgeMetric edgeCurvMetric( const Mesh & mesh, float angleSinFactor, float angleS
7171
return edgeCurvMetric( mesh.topology, mesh.points, angleSinFactor, angleSinForBoundary );
7272
}
7373

74+
EdgeMetric edgeAbsCurvMetric( const MeshTopology& topology, const VertCoords& points, float angleSinFactor, float angleSinForBoundary )
75+
{
76+
const float bdFactor = exp( angleSinFactor * angleSinForBoundary );
77+
78+
return [&topology, &points, angleSinFactor, bdFactor ]( EdgeId e ) -> float
79+
{
80+
auto edgeLen = edgeLength( topology, points, e );
81+
if ( topology.isBdEdge( e, nullptr ) )
82+
return edgeLen * bdFactor;
83+
84+
return edgeLen * exp( angleSinFactor * std::abs( dihedralAngleSin( topology, points, e ) ) );
85+
};
86+
}
87+
88+
EdgeMetric edgeAbsCurvMetric( const Mesh & mesh, float angleSinFactor, float angleSinForBoundary )
89+
{
90+
return edgeAbsCurvMetric( mesh.topology, mesh.points, angleSinFactor, angleSinForBoundary );
91+
}
92+
7493
EdgeMetric edgeTableSymMetric( const MeshTopology & topology, const EdgeMetric & metric )
7594
{
7695
MR_TIMER;

source/MRMesh/MREdgeMetric.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,20 +30,24 @@ namespace MR
3030
[[nodiscard]] MRMESH_API EdgeMetric discreteMinusAbsMeanCurvatureMetric( const Mesh & mesh );
3131
[[nodiscard]] MRMESH_API EdgeMetric discreteMinusAbsMeanCurvatureMetric( const MeshTopology& topology, const VertCoords& points );
3232

33-
/// returns edge's metric that depends both on edge's length and on the angle between its left and right faces
33+
/// not-negative metric that depends both on edge's length and on the angle between its left and right faces
3434
/// \param angleSinFactor multiplier before dihedral angle sine in edge metric calculation (positive to prefer concave angles, negative - convex)
3535
/// \param angleSinForBoundary consider this dihedral angle sine for boundary edges;
3636
/// this metric is symmetric: m(e) == m(e.sym())
3737
[[nodiscard]] MRMESH_API EdgeMetric edgeCurvMetric( const Mesh & mesh, float angleSinFactor = 2, float angleSinForBoundary = 0 );
3838
[[nodiscard]] MRMESH_API EdgeMetric edgeCurvMetric( const MeshTopology& topology, const VertCoords& points, float angleSinFactor = 2, float angleSinForBoundary = 0 );
3939

40+
/// not-negative metric that depends both on edge's length and on the angle between its left and right faces (ignoring the different between convex and concave)
41+
/// \param angleSinFactor multiplier before absolute value of dihedral angle sine in edge metric calculation: zero - planar case, larger values of (PI - dihedral angle)
42+
/// \param angleSinForBoundary consider this dihedral angle sine for boundary edges;
43+
/// this metric is symmetric: m(e) == m(e.sym())
44+
[[nodiscard]] MRMESH_API EdgeMetric edgeAbsCurvMetric( const Mesh & mesh, float angleSinFactor = 2, float angleSinForBoundary = 0 );
45+
[[nodiscard]] MRMESH_API EdgeMetric edgeAbsCurvMetric( const MeshTopology& topology, const VertCoords& points, float angleSinFactor = 2, float angleSinForBoundary = 0 );
46+
4047
/// pre-computes the metric for all mesh edges to quickly return it later for any edge;
4148
/// input metric must be symmetric: metric(e) == metric(e.sym())
4249
[[nodiscard]] MRMESH_API EdgeMetric edgeTableSymMetric( const MeshTopology & topology, const EdgeMetric & metric );
4350

44-
[[deprecated]] MR_BIND_IGNORE inline EdgeMetric edgeTableMetric( const MeshTopology & topology, const EdgeMetric & metric )
45-
{ return edgeTableSymMetric( topology, metric ); }
46-
4751
/// \}
4852

4953
} // namespace MR

source/MRMesh/MRTunnelDetector.cpp

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,11 @@ Expected<EdgeLoop> findSmallestMetricCoLoop( const MeshTopology& topology, const
306306
if ( toLeft.test( e ) )
307307
return FLT_MAX;
308308
const auto m = metric0( e );
309+
if ( m < 0 )
310+
{
311+
assert( !"metric must be not-negative" );
312+
return FLT_MAX;
313+
}
309314
if ( toLeft.test( e.sym() ) )
310315
{
311316
const auto v = topology.org( e );
@@ -405,7 +410,7 @@ Expected<FaceBitSet> detectTunnelFaces( const MeshPart & mp, const DetectTunnelS
405410
MR_TIMER;
406411
auto metric = settings.metric;
407412
if ( !metric )
408-
metric = discreteMinusAbsMeanCurvatureMetric( mp.mesh );
413+
metric = settings.buildCoLoops ? edgeLengthMetric( mp.mesh ) : discreteMinusAbsMeanCurvatureMetric( mp.mesh );
409414

410415
FaceBitSet activeRegion = mp.mesh.topology.getFaceIds( mp.region );
411416
MeshPart activeMeshPart{ mp.mesh, &activeRegion };
@@ -428,7 +433,7 @@ Expected<FaceBitSet> detectTunnelFaces( const MeshPart & mp, const DetectTunnelS
428433
{
429434
ParallelFor( *basisTunnels, [&]( size_t i )
430435
{
431-
if ( auto maybeCoLoop = findShortestCoLoop( activeMeshPart, (*basisTunnels)[i] ) )
436+
if ( auto maybeCoLoop = findSmallestMetricCoLoop( mp.mesh.topology, (*basisTunnels)[i], metric, &activeRegion ) )
432437
(*basisTunnels)[i] = std::move( maybeCoLoop.value() );
433438
else
434439
{
@@ -441,10 +446,10 @@ Expected<FaceBitSet> detectTunnelFaces( const MeshPart & mp, const DetectTunnelS
441446

442447
const auto numBasisTunnels = basisTunnels->size();
443448

444-
sortPathsByLength( *basisTunnels, mp.mesh );
449+
sortPathsByMetric( *basisTunnels, metric );
445450
for ( int i = 0; i < basisTunnels->size(); ++i )
446451
{
447-
if ( calcPathLength( (*basisTunnels)[i], mp.mesh ) > settings.maxTunnelLength )
452+
if ( calcPathMetric( (*basisTunnels)[i], metric ) > settings.maxTunnelLength )
448453
{
449454
basisTunnels->erase( basisTunnels->begin() + i, basisTunnels->end() );
450455
break;
@@ -471,7 +476,7 @@ Expected<FaceBitSet> detectTunnelFaces( const MeshPart & mp, const DetectTunnelS
471476

472477
if ( settings.buildCoLoops && settings.filterEquivalentCoLoops && numSelectedTunnels > 0 )
473478
{
474-
auto maybeCoLoop = findShortestCoLoop( activeMeshPart, t );
479+
auto maybeCoLoop = findSmallestMetricCoLoop( mp.mesh.topology, t, metric, &activeRegion );
475480
if ( !maybeCoLoop )
476481
continue;
477482
}

source/MRMesh/MRTunnelDetector.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,18 +42,20 @@ MRMESH_API Expected<EdgeLoop> findShortestCoLoop( const MeshPart& mp, const Edge
4242

4343
struct DetectTunnelSettings
4444
{
45-
/// maximal length of tunnel loops to consider
45+
/// maximal summed metric of tunnel loops to detect
4646
float maxTunnelLength = FLT_MAX;
4747

4848
/// maximal number of iterations to detect all tunnels;
4949
/// on a big mesh with many tunnels even one iteration can take a while
5050
int maxIters = 1;
5151

52-
/// metric for detectBasisTunnels,
53-
/// if no metric is given then discreteMinusAbsMeanCurvatureMetric will be used
52+
/// edge metric that will be used in optimizations,
53+
/// if co-loops are enabled then this metric must be not-negative,
54+
/// if no metric is given then either discreteMinusAbsMeanCurvatureMetric (if buildCoLoops = false) or edgeLengthMetric (if buildCoLoops = true) will be used,
55+
/// using caching via edgeTableSymMetric function can improve the performance, especially in buildCoLoops = true mode
5456
EdgeMetric metric;
5557

56-
/// if true then for every basis loop, findShortestCoLoop will be called;
58+
/// if true then for every basis loop, findSmallestMetricCoLoop will be called;
5759
/// it typically results in shorter tunnels found, but requires more time per iteration, and more iterations to find all tunnels
5860
bool buildCoLoops = true;
5961

0 commit comments

Comments
 (0)