Skip to content
Permalink
Browse files

[labeling] Avoid pruning away all candidate placements when ALL

candidates have hard label conflicts yet the "Display All"
setting is checked for the layer
  • Loading branch information
nyalldawson committed Jun 9, 2020
1 parent c8725af commit 2b91bd0cafff66f14ceb49b104bf2f2cc6ae714d
Showing with 40 additions and 20 deletions.
  1. +40 −20 src/core/pal/pal.cpp
@@ -339,34 +339,44 @@ std::unique_ptr<Problem> Pal::extract( const QgsRectangle &extent, const QgsGeom
if ( isCanceled() )
return nullptr;

switch ( mPlacementVersion )
auto pruneHardConflicts = [&]
{
case QgsLabelingEngineSettings::PlacementEngineVersion1:
break;

case QgsLabelingEngineSettings::PlacementEngineVersion2:
switch ( mPlacementVersion )
{
// v2 placement rips out candidates where the candidate cost is too high when compared to
// their inactive cost
case QgsLabelingEngineSettings::PlacementEngineVersion1:
break;

// note, we start this at the SECOND candidate (you'll see why after this loop)
feat->candidates.erase( std::remove_if( feat->candidates.begin() + 1, feat->candidates.end(), [ & ]( std::unique_ptr< LabelPosition > &candidate )
case QgsLabelingEngineSettings::PlacementEngineVersion2:
{
if ( candidate->hasHardObstacleConflict() )
// v2 placement rips out candidates where the candidate cost is too high when compared to
// their inactive cost

// note, we start this at the SECOND candidate (you'll see why after this loop)
feat->candidates.erase( std::remove_if( feat->candidates.begin() + 1, feat->candidates.end(), [ & ]( std::unique_ptr< LabelPosition > &candidate )
{
return true;
if ( candidate->hasHardObstacleConflict() )
{
return true;
}
return false;
} ), feat->candidates.end() );

if ( feat->candidates.size() == 1 && feat->candidates[ 0 ]->hasHardObstacleConflict() && !feat->feature->layer()->displayAll() )
{
// we've going to end up removing ALL candidates for this label. Oh well, that's allowed. We just need to
// make sure we move this last candidate to the unplaced labels list
prob->positionsWithNoCandidates()->emplace_back( std::move( feat->candidates.front() ) );
feat->candidates.clear();
}
return false;
} ), feat->candidates.end() );

if ( feat->candidates.size() == 1 && feat->candidates[ 0 ]->hasHardObstacleConflict() )
{
// we've ended up removing ALL candidates for this label. Oh well, that's allowed. We just need to
// make sure we move this last candidate to the unplaced labels list
prob->positionsWithNoCandidates()->emplace_back( std::move( feat->candidates.front() ) );
feat->candidates.clear();
}
}
};

// if we're not showing all labels (including conflicts) for this layer, then we prune the candidates
// upfront to avoid extra work...
if ( !feat->feature->layer()->displayAll() )
{
pruneHardConflicts();
}

if ( feat->candidates.empty() )
@@ -378,6 +388,16 @@ std::unique_ptr<Problem> Pal::extract( const QgsRectangle &extent, const QgsGeom
// sort candidates list, best label to worst
std::sort( feat->candidates.begin(), feat->candidates.end(), CostCalculator::candidateSortGrow );

// but if we ARE showing all labels (including conflicts), let's go ahead and prune them now.
// Since we've calculated all their costs and sorted them, if we've hit the situation that ALL
// candidates have conflicts, then at least when we pick the first candidate to display it will be
// the lowest cost (i.e. best possible) overlapping candidate...
if ( feat->feature->layer()->displayAll() )
{
pruneHardConflicts();
}


// only keep the 'maxCandidates' best candidates
if ( maxCandidates > 0 && feat->candidates.size() > maxCandidates )
{

0 comments on commit 2b91bd0

Please sign in to comment.
You can’t perform that action at this time.