55 mGlobalCandidatesLimitPoint = settings.
value( QStringLiteral(
"rendering/label_candidates_limit_points" ), 0,
QgsSettings::Core ).toInt();
56 mGlobalCandidatesLimitLine = settings.
value( QStringLiteral(
"rendering/label_candidates_limit_lines" ), 0,
QgsSettings::Core ).toInt();
57 mGlobalCandidatesLimitPolygon = settings.
value( QStringLiteral(
"rendering/label_candidates_limit_polygons" ), 0,
QgsSettings::Core ).toInt();
69 for (
auto it = mLayers.begin(); it != mLayers.end(); ++it )
71 if ( it->second.get() == layer )
84 Q_ASSERT( mLayers.find( provider ) == mLayers.end() );
86 std::unique_ptr< Layer > layer = std::make_unique< Layer >( provider, layerName, arrangement, defaultPriority, active, toLabel,
this );
87 Layer *res = layer.get();
106 std::vector< FeaturePart * > allObstacleParts;
107 std::unique_ptr< Problem > prob = std::make_unique< Problem >( maxCoordinateExtentForSpatialIndices );
112 bbx[0] = bbx[3] = prob->mMapExtentBounds[0] = extent.
xMinimum();
113 bby[0] = bby[1] = prob->mMapExtentBounds[1] = extent.
yMinimum();
114 bbx[1] = bbx[2] = prob->mMapExtentBounds[2] = extent.
xMaximum();
115 bby[2] = bby[3] = prob->mMapExtentBounds[3] = extent.
yMaximum();
119 std::list< std::unique_ptr< Feats > > features;
125 int obstacleCount = 0;
129 std::size_t previousFeatureCount = 0;
130 int previousObstacleCount = 0;
132 QStringList layersWithFeaturesInBBox;
134 QMutexLocker palLocker( &mMutex );
136 double step = !mLayers.empty() ? 100.0 / mLayers.size() : 1;
138 for (
const auto &it : mLayers )
144 Layer *layer = it.second.get();
156 feedback->emit candidateCreationAboutToBegin( it.first );
170 QMutexLocker locker( &layer->
mMutex );
173 std::size_t featureIndex = 0;
175 for (
const std::unique_ptr< FeaturePart > &featurePart : std::as_const( layer->
mFeatureParts ) )
178 feedback->
setProgress( index * step + featureIndex * featureStep );
185 for (
int i = 0; i < featurePart->getNumSelfObstacles(); i++ )
189 allObstacleParts.emplace_back( selfObstacle );
191 if ( !featurePart->getSelfObstacle( i )->getHoleOf() )
198 std::vector< std::unique_ptr< LabelPosition > > candidates = featurePart->createCandidates(
this );
204 candidates.erase( std::remove_if( candidates.begin(), candidates.end(), [&mapBoundaryPrepared,
this]( std::unique_ptr< LabelPosition > &candidate )
206 if ( showPartialLabels() )
207 return !candidate->intersects( mapBoundaryPrepared.get() );
209 return !candidate->within( mapBoundaryPrepared.get() );
210 } ), candidates.end() );
215 if ( !candidates.empty() )
217 for ( std::unique_ptr< LabelPosition > &candidate : candidates )
219 candidate->insertIntoIndex( allCandidatesFirstRound );
220 candidate->setGlobalId( mNextCandidateId++ );
226 std::unique_ptr< Feats > ft = std::make_unique< Feats >();
227 ft->feature = featurePart.get();
229 ft->candidates = std::move( candidates );
230 ft->priority = featurePart->calculatePriority();
231 features.emplace_back( std::move( ft ) );
236 std::unique_ptr< LabelPosition > unplacedPosition = featurePart->createCandidatePointOnSurface( featurePart.get() );
237 if ( !unplacedPosition )
240 if ( featurePart->feature()->allowDegradedPlacement() )
243 unplacedPosition->insertIntoIndex( allCandidatesFirstRound );
244 unplacedPosition->setGlobalId( mNextCandidateId++ );
245 candidates.emplace_back( std::move( unplacedPosition ) );
248 std::unique_ptr< Feats > ft = std::make_unique< Feats >();
249 ft->feature = featurePart.get();
251 ft->candidates = std::move( candidates );
252 ft->priority = featurePart->calculatePriority();
253 features.emplace_back( std::move( ft ) );
258 prob->positionsWithNoCandidates()->emplace_back( std::move( unplacedPosition ) );
272 obstacles.
insert( obstaclePart, obstaclePart->boundingBox() );
273 allObstacleParts.emplace_back( obstaclePart );
282 if ( features.size() - previousFeatureCount > 0 || obstacleCount > previousObstacleCount )
284 layersWithFeaturesInBBox << layer->
name();
286 previousFeatureCount = features.size();
287 previousObstacleCount = obstacleCount;
290 feedback->emit candidateCreationFinished( it.first );
297 prob->mLayerCount = layersWithFeaturesInBBox.size();
298 prob->labelledLayersName = layersWithFeaturesInBBox;
300 prob->mFeatureCount = features.size();
301 prob->mTotalCandidates = 0;
302 prob->mFeatNbLp.resize( prob->mFeatureCount );
303 prob->mFeatStartId.resize( prob->mFeatureCount );
304 prob->mInactiveCost.resize( prob->mFeatureCount );
306 if ( !features.empty() )
309 feedback->emit obstacleCostingAboutToBegin();
312 step = !allObstacleParts.empty() ? 100.0 / allObstacleParts.size() : 1;
314 for (
FeaturePart *obstaclePart : allObstacleParts )
323 allCandidatesFirstRound.
intersects( obstaclePart->boundingBox(), [obstaclePart,
this](
const LabelPosition * candidatePosition ) ->
bool
331 if ( candidatePosition->getFeaturePart()->feature()->overlapHandling() == Qgis::LabelOverlapHandling::AllowOverlapAtNoCost
332 || ( !obstaclePart->getHoleOf() && candidatePosition->getFeaturePart()->hasSameLabelFeatureAs( obstaclePart ) )
333 || ( obstaclePart->getHoleOf() && !candidatePosition->getFeaturePart()->hasSameLabelFeatureAs( dynamic_cast< FeaturePart * >( obstaclePart->getHoleOf() ) ) ) )
345 feedback->emit obstacleCostingFinished();
352 step = prob->mFeatureCount != 0 ? 100.0 / prob->mFeatureCount : 1;
354 feedback->emit calculatingConflictsAboutToBegin();
357 for ( std::size_t i = 0; i < prob->mFeatureCount; i++ )
362 std::unique_ptr< Feats > feat = std::move( features.front() );
363 features.pop_front();
365 prob->mFeatStartId[i] = idlp;
366 prob->mInactiveCost[i] = std::pow( 2, 10 - 10 * feat->priority );
368 std::size_t maxCandidates = 0;
369 switch ( feat->feature->getGeosType() )
373 maxCandidates = feat->feature->maximumPointCandidates();
376 case GEOS_LINESTRING:
377 maxCandidates = feat->feature->maximumLineCandidates();
381 maxCandidates = std::max(
static_cast< std::size_t
>( 16 ), feat->feature->maximumPolygonCandidates() );
388 auto pruneHardConflicts = [&]
390 switch ( mPlacementVersion )
401 feat->candidates.erase( std::remove_if( feat->candidates.begin() + 1, feat->candidates.end(), [ & ]( std::unique_ptr< LabelPosition > &candidate )
403 if ( candidate->hasHardObstacleConflict() )
408 } ), feat->candidates.end() );
410 if ( feat->candidates.size() == 1 && feat->candidates[ 0 ]->hasHardObstacleConflict() )
412 switch ( feat->feature->feature()->overlapHandling() )
418 prob->positionsWithNoCandidates()->emplace_back( std::move( feat->candidates.front() ) );
419 feat->candidates.clear();
436 switch ( feat->feature->feature()->overlapHandling() )
439 pruneHardConflicts();
447 if ( feat->candidates.empty() )
460 switch ( feat->feature->feature()->overlapHandling() )
466 pruneHardConflicts();
471 if ( maxCandidates > 0 && feat->candidates.size() > maxCandidates )
473 feat->candidates.resize( maxCandidates );
480 prob->mFeatNbLp[i] =
static_cast< int >( feat->candidates.size() );
481 prob->mTotalCandidates +=
static_cast< int >( feat->candidates.size() );
484 for ( std::unique_ptr< LabelPosition > &candidate : feat->candidates )
486 candidate->insertIntoIndex( prob->allCandidatesIndex() );
487 candidate->setProblemIds(
static_cast< int >( i ), idlp++ );
489 features.emplace_back( std::move( feat ) );
493 feedback->emit calculatingConflictsFinished();
501 feedback->emit finalizingCandidatesAboutToBegin();
504 step = !features.empty() ? 100.0 / features.size() : 1;
505 while ( !features.empty() )
509 feedback->setProgress( step * index );
514 std::unique_ptr< Feats > feat = std::move( features.front() );
515 features.pop_front();
517 for ( std::unique_ptr< LabelPosition > &candidate : feat->candidates )
519 std::unique_ptr< LabelPosition > lp = std::move( candidate );
521 lp->resetNumOverlaps();
529 lp->getBoundingBox( amin, amax );
530 prob->allCandidatesIndex().intersects(
QgsRectangle( amin[0], amin[1], amax[0], amax[1] ), [&lp,
this](
const LabelPosition * lp2 )->
bool
532 if ( candidatesAreConflicting( lp.get(), lp2 ) )
534 lp->incrementNumOverlaps();
541 nbOverlaps += lp->getNumOverlaps();
543 prob->addCandidatePosition( std::move( lp ) );
551 feedback->emit finalizingCandidatesFinished();
554 prob->mAllNblp = prob->mTotalCandidates;
555 prob->mNbOverlap = nbOverlaps;
561 void Pal::registerCancellationCallback( Pal::FnIsCanceled fnCanceled,
void *context )
563 fnIsCanceled = fnCanceled;
564 fnIsCanceledContext = context;
573 return QList<LabelPosition *>();
576 feedback->emit reductionAboutToBegin();
581 feedback->emit reductionFinished();
584 feedback->emit solvingPlacementAboutToBegin();
592 return QList<LabelPosition *>();
596 feedback->emit solvingPlacementFinished();
601 void Pal::setMinIt(
int min_it )
607 void Pal::setMaxIt(
int max_it )
613 void Pal::setPopmusicR(
int r )
619 void Pal::setEjChainDeg(
int degree )
621 this->mEjChainDeg = degree;
624 void Pal::setTenure(
int tenure )
626 this->mTenure = tenure;
629 void Pal::setCandListSize(
double fact )
631 this->mCandListSize = fact;
636 this->mShowPartialLabels = show;
641 return mPlacementVersion;
656 auto it = mCandidateConflicts.constFind( key );
657 if ( it != mCandidateConflicts.constEnd() )
661 mCandidateConflicts.insert( key, res );
665 int Pal::getMinIt()
const
670 int Pal::getMaxIt()
const
677 return mShowPartialLabels;