@@ -32,7 +32,7 @@ class RadiusCompensator
3232 // prepares raw distance map
3333 Expected<void > init ();
3434
35- // finds tool locations for each pixel and summary compensation volume for each
35+ // finds tool locations for each pixel and summary compensation cost for each
3636 Expected<void > calcCompensations ();
3737
3838 // creates compensation distance map
@@ -61,8 +61,8 @@ class RadiusCompensator
6161 // if callback returns false iterations stops
6262 void iteratePixelsInRadius_ ( const Vector2i& pixelCoord, const std::function<bool ( const Vector2i& )>& callback );
6363
64- // calculates summary compensation volume for given tool location
65- float sumCompensationVolume_ ( const Vector3f& toolCenter );
64+ // calculates summary compensation cost for given tool location
65+ float sumCompensationCost_ ( const Vector3f& toolCenter );
6666
6767 Mesh& mesh_;
6868 CompensateRadiusParams params_;
@@ -77,9 +77,13 @@ class RadiusCompensator
7777 Vector2i pixelsInRadius_;
7878
7979 std::vector<Vector3f> toolCenters_; // per pixel
80- std::vector<std::pair<float ,int >> volumes_; // <voulme, id> per pixel (this array will be sorted, thats why we need id as value and not only as key)
80+ // cost is (approx compensation Volume)/(approx compensation Projected Area) - less is better
81+ std::vector<std::pair<float ,int >> costs_; // <cost, id> per pixel (this array will be sorted, thats why we need id as value and not only as key)
8182
8283 DistanceMap compensatedDm_;
84+
85+ // tolerance of distance map height for "touching" compensations
86+ static constexpr float cDMTolearance = 1e-5f ;
8387};
8488
8589Expected<void > RadiusCompensator::init ()
@@ -113,20 +117,20 @@ Expected<void> RadiusCompensator::calcCompensations()
113117{
114118 MR_TIMER ;
115119 toolCenters_.resize ( dm_.size (), Vector3f::diagonal ( FLT_MAX ) );
116- volumes_ .resize ( dm_.size (), std::make_pair ( -1 .0f , -1 ) );
120+ costs_ .resize ( dm_.size (), std::make_pair ( -1 .0f , -1 ) );
117121 bool keepGoing = ParallelFor ( size_t ( 0 ), dm_.size (), [&] ( size_t i )
118122 {
119123 auto pixelCoord = dm_.toPos ( i );
120124 auto & toolCenter = toolCenters_[i];
121125 toolCenter = findToolCenterAtPixel_ (pixelCoord);
122126 if ( toolCenter.x != FLT_MAX )
123- volumes_ [i] = std::make_pair ( sumCompensationVolume_ ( toolCenter ), int ( i ) );
127+ costs_ [i] = std::make_pair ( sumCompensationCost_ ( toolCenter ), int ( i ) );
124128 }, subprogress ( params_.callback , 0 .05f , 0 .15f ) );
125129
126130 if ( !keepGoing )
127131 return unexpectedOperationCanceled ();
128132
129- tbb::parallel_sort ( volumes_ .begin (), volumes_ .end (), [] ( const auto & l, const auto & r )
133+ tbb::parallel_sort ( costs_ .begin (), costs_ .end (), [] ( const auto & l, const auto & r )
130134 {
131135 return l.first < r.first ;
132136 } );
@@ -143,12 +147,13 @@ Expected<void> RadiusCompensator::compensateDistanceMap()
143147 auto sb = subprogress ( params_.callback , 0 .2f , 0 .5f );
144148 compensatedDm_ = DistanceMap ( dm_.resX (), dm_.resY () );
145149 size_t i = 0 ;
146- for ( auto [volume, cId] : volumes_ )
150+ const float cTolerance = params_.toolRadius * cDMTolearance;
151+ for ( auto [cost, cId] : costs_ )
147152 {
148- if ( ( ++i % 1024 == 0 ) && !reportProgress ( sb, float ( i ) / volumes_ .size () ) )
153+ if ( ( ++i % 1024 == 0 ) && !reportProgress ( sb, float ( i ) / costs_ .size () ) )
149154 return unexpectedOperationCanceled ();
150155
151- if ( cId < 0 || volume < 0 .0f )
156+ if ( cId < 0 || cost < 0 .0f )
152157 continue ;
153158
154159 const auto & toolCenter = toolCenters_[cId];
@@ -169,10 +174,10 @@ Expected<void> RadiusCompensator::compensateDistanceMap()
169174 iteratePixelsInRadius_ ( pixelCoord, [&] ( const Vector2i& pixeli )->bool
170175 {
171176 auto realValue = dm_.getValue ( pixeli.x , pixeli.y );
172- auto & value = compensatedDm_.getValue ( pixeli.x , pixeli.y );
173- auto compValue = calcCompensatedHeightAtPixel_ ( pixeli, toolCenter );
174- if ( compValue > value && compValue >= realValue )
175- value = compValue ;
177+ auto & compValue = compensatedDm_.getValue ( pixeli.x , pixeli.y );
178+ auto newCompValue = calcCompensatedHeightAtPixel_ ( pixeli, toolCenter );
179+ if ( newCompValue > compValue && newCompValue + cTolerance >= realValue )
180+ compValue = std::max ( newCompValue, realValue ) ;
176181 return true ;
177182 } );
178183 }
@@ -208,6 +213,7 @@ Expected<void> RadiusCompensator::applyCompensation()
208213 }
209214
210215 // fix inverted faces (undercuts on original mesh)
216+ for ( int iFlipped = 0 ; iFlipped < 10 ; ++iFlipped ) // repeat until no flipped faces left, 10 - max iters
211217 {
212218 // only fix flipped areas
213219 auto sumDirArea = Vector3f ( mesh_.dirArea ( faceRegion_ ).normalized () ); // we only care about direction
@@ -221,6 +227,9 @@ Expected<void> RadiusCompensator::applyCompensation()
221227 expand ( mesh_.topology , flippedFaces, 4 );
222228 flippedFaces &= *faceRegion_;
223229
230+ if ( flippedFaces.none () )
231+ break ;
232+
224233 auto equalizingVertRegion = getInnerVerts ( mesh_.topology , flippedFaces );
225234 assert ( ( equalizingVertRegion & bounds ).none () );
226235 MeshEqualizeTriAreasParams etParams;
@@ -254,7 +263,6 @@ Expected<void> RadiusCompensator::applyCompensation()
254263 vertRegion_.reset ( v );
255264 }, subprogress ( params_.callback , 0 .65f , 0 .8f ) );
256265
257-
258266 if ( vertRegion_.any () )
259267 positionVertsSmoothlySharpBd ( mesh_, vertRegion_ );
260268
@@ -270,7 +278,7 @@ Expected<void> RadiusCompensator::postprocessMesh()
270278 auto edgeBounds = findRegionBoundaryUndirectedEdgesInsideMesh ( mesh_.topology , *faceRegion_ );
271279 RemeshSettings rParams;
272280 rParams.finalRelaxIters = 2 ;
273- rParams.targetEdgeLen = mesh_.averageEdgeLength ();
281+ rParams.targetEdgeLen = params_. remeshTargetEdgeLength <= 0 . 0f ? mesh_.averageEdgeLength () : params_. remeshTargetEdgeLength ;
274282 rParams.region = params_.region ;
275283 rParams.notFlippable = &edgeBounds;
276284 rParams.progressCallback = subprogress ( params_.callback , 0 .8f , 1 .0f );
@@ -387,19 +395,24 @@ void RadiusCompensator::iteratePixelsInRadius_( const Vector2i& pixelCoord, cons
387395 }
388396}
389397
390- float RadiusCompensator::sumCompensationVolume_ ( const Vector3f& toolCenter )
398+ float RadiusCompensator::sumCompensationCost_ ( const Vector3f& toolCenter )
391399{
392- float sumVolume = 0 .0f ;
400+ double sumVolume = 0.0 ;
401+ double sumArea = 0.0 ;
393402 auto toolPixel = Vector2i ( to2dim ( toDmXf_ ( toolCenter ) ) );
403+ const float cTolerance = cDMTolearance * params_.toolRadius ;
394404 iteratePixelsInRadius_ ( toolPixel, [&] ( const Vector2i& pixelCoord )->bool
395405 {
396406 auto value = dm_.getValue ( pixelCoord.x , pixelCoord.y );
397407 auto height = calcCompensatedHeightAtPixel_ ( pixelCoord, toolCenter );
398- if ( height > value )
399- sumVolume += ( height - value );
408+ if ( height + cTolerance >= value )
409+ {
410+ sumVolume += std::max ( height - value, 0 .0f );
411+ sumArea += 1.0 ;
412+ }
400413 return true ;
401414 } );
402- return sumVolume;
415+ return sumArea == 0.0 ? - 1 . 0f : float ( sumVolume / sumArea ) ;
403416}
404417
405418Expected<void > compensateRadius ( Mesh& mesh, const CompensateRadiusParams& params )
0 commit comments