106  std::unique_ptr< QgsScopedRuntimeProfile > extractionProfile;
 
  109    extractionProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr( 
"Placing labels" ), QStringLiteral( 
"rendering" ) );
 
  120  std::vector< FeaturePart * > allObstacleParts;
 
  121  std::unique_ptr< Problem > prob = std::make_unique< Problem >( maxCoordinateExtentForSpatialIndices );
 
  126  bbx[0] = bbx[3] = prob->mMapExtentBounds[0] = extent.
xMinimum();
 
  127  bby[0] = bby[1] = prob->mMapExtentBounds[1] = extent.
yMinimum();
 
  128  bbx[1] = bbx[2] = prob->mMapExtentBounds[2] = extent.
xMaximum();
 
  129  bby[2] = bby[3] = prob->mMapExtentBounds[3] = extent.
yMaximum();
 
  133  std::list< std::unique_ptr< Feats > > features;
 
  137  geos::prepared_unique_ptr mapBoundaryPrepared( GEOSPrepare_r( 
QgsGeosContext::get(), mapBoundaryGeos.get() ) );
 
  139  int obstacleCount = 0;
 
  143  std::size_t previousFeatureCount = 0;
 
  144  int previousObstacleCount = 0;
 
  146  QStringList layersWithFeaturesInBBox;
 
  148  QMutexLocker palLocker( &mMutex );
 
  150  double step = !mLayers.empty() ? 100.0 / mLayers.size() : 1;
 
  152  std::unique_ptr< QgsScopedRuntimeProfile > candidateProfile;
 
  155    candidateProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr( 
"Generating label candidates" ), QStringLiteral( 
"rendering" ) );
 
  158  for ( 
const auto &it : mLayers )
 
  164    Layer *layer = it.second.get();
 
  176      feedback->emit candidateCreationAboutToBegin( it.first );
 
  178    std::unique_ptr< QgsScopedRuntimeProfile > layerProfile;
 
  181      layerProfile = std::make_unique< QgsScopedRuntimeProfile >( it.first->providerId(), QStringLiteral( 
"rendering" ) );
 
  196    QMutexLocker locker( &layer->
mMutex );
 
  199    std::size_t featureIndex = 0;
 
  201    for ( 
const std::unique_ptr< FeaturePart > &featurePart : std::as_const( layer->
mFeatureParts ) )
 
  204        feedback->
setProgress( index * step + featureIndex * featureStep );
 
  211      for ( 
int i = 0; i < featurePart->getNumSelfObstacles(); i++ )
 
  215        allObstacleParts.emplace_back( selfObstacle );
 
  217        if ( !featurePart->getSelfObstacle( i )->getHoleOf() )
 
  224      std::vector< std::unique_ptr< LabelPosition > > candidates = featurePart->createCandidates( 
this );
 
  230      candidates.erase( std::remove_if( candidates.begin(), candidates.end(), [&mapBoundaryPrepared, 
this]( std::unique_ptr< LabelPosition > &candidate )
 
  232        if ( showPartialLabels() )
 
  233          return !candidate->intersects( mapBoundaryPrepared.get() );
 
  235          return !candidate->within( mapBoundaryPrepared.get() );
 
  236      } ), candidates.end() );
 
  241      if ( !candidates.empty() )
 
  243        for ( std::unique_ptr< LabelPosition > &candidate : candidates )
 
  245          candidate->insertIntoIndex( allCandidatesFirstRound );
 
  246          candidate->setGlobalId( mNextCandidateId++ );
 
  252        std::unique_ptr< Feats > ft = std::make_unique< Feats >();
 
  253        ft->feature = featurePart.get();
 
  255        ft->candidates = std::move( candidates );
 
  256        ft->priority = featurePart->calculatePriority();
 
  257        features.emplace_back( std::move( ft ) );
 
  262        std::unique_ptr< LabelPosition > unplacedPosition = featurePart->createCandidatePointOnSurface( featurePart.get() );
 
  263        if ( !unplacedPosition )
 
  266        if ( featurePart->feature()->allowDegradedPlacement() )
 
  269          unplacedPosition->insertIntoIndex( allCandidatesFirstRound );
 
  270          unplacedPosition->setGlobalId( mNextCandidateId++ );
 
  271          candidates.emplace_back( std::move( unplacedPosition ) );
 
  274          std::unique_ptr< Feats > ft = std::make_unique< Feats >();
 
  275          ft->feature = featurePart.get();
 
  277          ft->candidates = std::move( candidates );
 
  278          ft->priority = featurePart->calculatePriority();
 
  279          features.emplace_back( std::move( ft ) );
 
  284          prob->positionsWithNoCandidates()->emplace_back( std::move( unplacedPosition ) );
 
  298      obstacles.
insert( obstaclePart, obstaclePart->boundingBox() );
 
  299      allObstacleParts.emplace_back( obstaclePart );
 
  308    if ( features.size() - previousFeatureCount > 0 || obstacleCount > previousObstacleCount )
 
  310      layersWithFeaturesInBBox << layer->
name();
 
  312    previousFeatureCount = features.size();
 
  313    previousObstacleCount = obstacleCount;
 
  316      feedback->emit candidateCreationFinished( it.first );
 
  319  candidateProfile.reset();
 
  326  prob->mLayerCount = layersWithFeaturesInBBox.size();
 
  327  prob->labelledLayersName = layersWithFeaturesInBBox;
 
  329  prob->mFeatureCount = features.size();
 
  330  prob->mTotalCandidates = 0;
 
  331  prob->mFeatNbLp.resize( prob->mFeatureCount );
 
  332  prob->mFeatStartId.resize( prob->mFeatureCount );
 
  333  prob->mInactiveCost.resize( prob->mFeatureCount );
 
  335  if ( !features.empty() )
 
  338      feedback->emit obstacleCostingAboutToBegin();
 
  340    std::unique_ptr< QgsScopedRuntimeProfile > costingProfile;
 
  343      costingProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr( 
"Assigning label costs" ), QStringLiteral( 
"rendering" ) );
 
  348    step = !allObstacleParts.empty() ? 100.0 / allObstacleParts.size() : 1;
 
  350    for ( 
FeaturePart *obstaclePart : allObstacleParts )
 
  359      allCandidatesFirstRound.
intersects( obstaclePart->boundingBox(), [obstaclePart, 
this]( 
const LabelPosition * candidatePosition ) -> 
bool 
  368             || ( !obstaclePart->getHoleOf() && candidatePosition->getFeaturePart()->hasSameLabelFeatureAs( obstaclePart ) )
 
  369             || ( obstaclePart->getHoleOf() && !candidatePosition->getFeaturePart()->hasSameLabelFeatureAs( 
dynamic_cast< FeaturePart * 
>( obstaclePart->getHoleOf() ) ) ) )
 
  381      feedback->emit obstacleCostingFinished();
 
  382    costingProfile.reset();
 
  389    step = prob->mFeatureCount != 0 ? 100.0 / prob->mFeatureCount : 1;
 
  391      feedback->emit calculatingConflictsAboutToBegin();
 
  393    std::unique_ptr< QgsScopedRuntimeProfile > conflictProfile;
 
  396      conflictProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr( 
"Calculating conflicts" ), QStringLiteral( 
"rendering" ) );
 
  400    for ( std::size_t i = 0; i < prob->mFeatureCount; i++ ) 
 
  405      std::unique_ptr< Feats > feat = std::move( features.front() );
 
  406      features.pop_front();
 
  408      prob->mFeatStartId[i] = idlp;
 
  409      prob->mInactiveCost[i] = std::pow( 2, 10 - 10 * feat->priority );
 
  411      std::size_t maxCandidates = 0;
 
  412      switch ( feat->feature->getGeosType() )
 
  416          maxCandidates = feat->feature->maximumPointCandidates();
 
  419        case GEOS_LINESTRING:
 
  420          maxCandidates = feat->feature->maximumLineCandidates();
 
  424          maxCandidates = std::max( 
static_cast< std::size_t 
>( 16 ), feat->feature->maximumPolygonCandidates() );
 
  431      auto pruneHardConflicts = [&]
 
  433        switch ( mPlacementVersion )
 
  444            feat->candidates.erase( std::remove_if( feat->candidates.begin() + 1, feat->candidates.end(), [ & ]( std::unique_ptr< LabelPosition > &candidate )
 
  446              if ( candidate->hasHardObstacleConflict() )
 
  451            } ), feat->candidates.end() );
 
  453            if ( feat->candidates.size() == 1 && feat->candidates[ 0 ]->hasHardObstacleConflict() )
 
  455              switch ( feat->feature->feature()->overlapHandling() )
 
  461                  prob->positionsWithNoCandidates()->emplace_back( std::move( feat->candidates.front() ) );
 
  462                  feat->candidates.clear();
 
  479      switch ( feat->feature->feature()->overlapHandling() )
 
  482          pruneHardConflicts();
 
  490      if ( feat->candidates.empty() )
 
  503      switch ( feat->feature->feature()->overlapHandling() )
 
  509          pruneHardConflicts();
 
  514      if ( maxCandidates > 0 && feat->candidates.size() > maxCandidates )
 
  516        feat->candidates.resize( maxCandidates );
 
  523      prob->mFeatNbLp[i] = 
static_cast< int >( feat->candidates.size() );
 
  524      prob->mTotalCandidates += 
static_cast< int >( feat->candidates.size() );
 
  527      for ( std::unique_ptr< LabelPosition > &candidate : feat->candidates )
 
  529        candidate->insertIntoIndex( prob->allCandidatesIndex() );
 
  530        candidate->setProblemIds( 
static_cast< int >( i ), idlp++ );
 
  532      features.emplace_back( std::move( feat ) );
 
  536      feedback->emit calculatingConflictsFinished();
 
  538    conflictProfile.reset();
 
  546      feedback->emit finalizingCandidatesAboutToBegin();
 
  548    std::unique_ptr< QgsScopedRuntimeProfile > finalizingProfile;
 
  551      finalizingProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr( 
"Finalizing labels" ), QStringLiteral( 
"rendering" ) );
 
  555    step = !features.empty() ? 100.0 / features.size() : 1;
 
  556    while ( !features.empty() ) 
 
  565      std::unique_ptr< Feats > feat = std::move( features.front() );
 
  566      features.pop_front();
 
  568      for ( std::unique_ptr< LabelPosition > &candidate : feat->candidates )
 
  570        std::unique_ptr< LabelPosition > lp = std::move( candidate );
 
  572        lp->resetNumOverlaps();
 
  580        lp->getBoundingBox( amin, amax );
 
  581        prob->allCandidatesIndex().intersects( 
QgsRectangle( amin[0], amin[1], amax[0], amax[1] ), [&lp, 
this]( 
const LabelPosition * lp2 )->
bool 
  585            lp->incrementNumOverlaps();
 
  592        nbOverlaps += lp->getNumOverlaps();
 
  594        prob->addCandidatePosition( std::move( lp ) );
 
  602      feedback->emit finalizingCandidatesFinished();
 
  604    finalizingProfile.reset();
 
  607    prob->mAllNblp = prob->mTotalCandidates;
 
  608    prob->mNbOverlap = nbOverlaps;