53 mGlobalCandidatesLimitPoint = settings.
value( QStringLiteral(
"rendering/label_candidates_limit_points" ), 0,
QgsSettings::Core ).toInt();
54 mGlobalCandidatesLimitLine = settings.
value( QStringLiteral(
"rendering/label_candidates_limit_lines" ), 0,
QgsSettings::Core ).toInt();
55 mGlobalCandidatesLimitPolygon = settings.
value( QStringLiteral(
"rendering/label_candidates_limit_polygons" ), 0,
QgsSettings::Core ).toInt();
67 for (
auto it = mLayers.begin(); it != mLayers.end(); ++it )
69 if ( it->second.get() == layer )
82 Q_ASSERT( mLayers.find( provider ) == mLayers.end() );
84 std::unique_ptr< Layer > layer = qgis::make_unique< Layer >( provider, layerName, arrangement, defaultPriority, active, toLabel,
this, displayAll );
85 Layer *res = layer.get();
102 std::vector< FeaturePart * > allObstacleParts;
103 std::unique_ptr< Problem > prob = qgis::make_unique< Problem >( maxCoordinateExtentForSpatialIndices );
108 bbx[0] = bbx[3] = prob->mMapExtentBounds[0] = extent.
xMinimum();
109 bby[0] = bby[1] = prob->mMapExtentBounds[1] = extent.
yMinimum();
110 bbx[1] = bbx[2] = prob->mMapExtentBounds[2] = extent.
xMaximum();
111 bby[2] = bby[3] = prob->mMapExtentBounds[3] = extent.
yMaximum();
115 std::list< std::unique_ptr< Feats > > features;
121 int obstacleCount = 0;
125 std::size_t previousFeatureCount = 0;
126 int previousObstacleCount = 0;
128 QStringList layersWithFeaturesInBBox;
130 QMutexLocker palLocker( &mMutex );
131 for (
const auto &it : mLayers )
133 Layer *layer = it.second.get();
156 QMutexLocker locker( &layer->
mMutex );
165 for (
int i = 0; i < featurePart->getNumSelfObstacles(); i++ )
168 obstacles.insert( selfObstacle, selfObstacle->
boundingBox() );
169 allObstacleParts.emplace_back( selfObstacle );
171 if ( !featurePart->getSelfObstacle( i )->getHoleOf() )
178 std::vector< std::unique_ptr< LabelPosition > > candidates = featurePart->
createCandidates(
this );
184 candidates.erase( std::remove_if( candidates.begin(), candidates.end(), [&mapBoundaryPrepared,
this]( std::unique_ptr< LabelPosition > &candidate )
186 if ( showPartialLabels() )
187 return !candidate->intersects( mapBoundaryPrepared.get() );
189 return !candidate->within( mapBoundaryPrepared.get() );
190 } ), candidates.end() );
195 if ( !candidates.empty() )
197 for ( std::unique_ptr< LabelPosition > &candidate : candidates )
199 candidate->insertIntoIndex( allCandidatesFirstRound );
205 std::unique_ptr< Feats > ft = qgis::make_unique< Feats >();
206 ft->feature = featurePart;
208 ft->candidates = std::move( candidates );
209 ft->priority = featurePart->calculatePriority();
210 features.emplace_back( std::move( ft ) );
215 std::unique_ptr< LabelPosition > unplacedPosition = featurePart->createCandidatePointOnSurface( featurePart );
216 if ( !unplacedPosition )
222 unplacedPosition->insertIntoIndex( allCandidatesFirstRound );
223 candidates.emplace_back( std::move( unplacedPosition ) );
226 std::unique_ptr< Feats > ft = qgis::make_unique< Feats >();
227 ft->feature = featurePart;
229 ft->candidates = std::move( candidates );
230 ft->priority = featurePart->calculatePriority();
231 features.emplace_back( std::move( ft ) );
236 prob->positionsWithNoCandidates()->emplace_back( std::move( unplacedPosition ) );
250 obstacles.insert( obstaclePart, obstaclePart->boundingBox() );
251 allObstacleParts.emplace_back( obstaclePart );
260 if ( features.size() - previousFeatureCount > 0 || obstacleCount > previousObstacleCount )
262 layersWithFeaturesInBBox << layer->
name();
264 previousFeatureCount = features.size();
265 previousObstacleCount = obstacleCount;
272 prob->mLayerCount = layersWithFeaturesInBBox.size();
273 prob->labelledLayersName = layersWithFeaturesInBBox;
275 prob->mFeatureCount = features.size();
276 prob->mTotalCandidates = 0;
277 prob->mFeatNbLp.resize( prob->mFeatureCount );
278 prob->mFeatStartId.resize( prob->mFeatureCount );
279 prob->mInactiveCost.resize( prob->mFeatureCount );
281 if ( !features.empty() )
284 for (
FeaturePart *obstaclePart : allObstacleParts )
289 allCandidatesFirstRound.intersects( obstaclePart->boundingBox(), [obstaclePart,
this](
const LabelPosition * candidatePosition ) ->
bool
296 if ( ( !obstaclePart->getHoleOf() && candidatePosition->getFeaturePart()->hasSameLabelFeatureAs( obstaclePart ) )
297 || ( obstaclePart->getHoleOf() && !candidatePosition->getFeaturePart()->hasSameLabelFeatureAs( dynamic_cast< FeaturePart * >( obstaclePart->getHoleOf() ) ) ) )
314 for ( std::size_t i = 0; i < prob->mFeatureCount; i++ )
316 std::unique_ptr< Feats > feat = std::move( features.front() );
317 features.pop_front();
319 prob->mFeatStartId[i] = idlp;
320 prob->mInactiveCost[i] = std::pow( 2, 10 - 10 * feat->priority );
322 std::size_t maxCandidates = 0;
323 switch ( feat->feature->getGeosType() )
327 maxCandidates = feat->feature->maximumPointCandidates();
330 case GEOS_LINESTRING:
331 maxCandidates = feat->feature->maximumLineCandidates();
335 maxCandidates = std::max(
static_cast< std::size_t
>( 16 ), feat->feature->maximumPolygonCandidates() );
342 auto pruneHardConflicts = [&]
344 switch ( mPlacementVersion )
355 feat->candidates.erase( std::remove_if( feat->candidates.begin() + 1, feat->candidates.end(), [ & ]( std::unique_ptr< LabelPosition > &candidate )
357 if ( candidate->hasHardObstacleConflict() )
362 } ), feat->candidates.end() );
364 if ( feat->candidates.size() == 1 && feat->candidates[ 0 ]->hasHardObstacleConflict() && !feat->feature->layer()->displayAll() )
368 prob->positionsWithNoCandidates()->emplace_back( std::move( feat->candidates.front() ) );
369 feat->candidates.clear();
377 if ( !feat->feature->layer()->displayAll() )
379 pruneHardConflicts();
382 if ( feat->candidates.empty() )
395 if ( feat->feature->layer()->displayAll() )
397 pruneHardConflicts();
402 if ( maxCandidates > 0 && feat->candidates.size() > maxCandidates )
404 feat->candidates.resize( maxCandidates );
411 prob->mFeatNbLp[i] =
static_cast< int >( feat->candidates.size() );
412 prob->mTotalCandidates +=
static_cast< int >( feat->candidates.size() );
415 for ( std::unique_ptr< LabelPosition > &candidate : feat->candidates )
417 candidate->insertIntoIndex( prob->allCandidatesIndex() );
418 candidate->setProblemIds(
static_cast< int >( i ), idlp++ );
420 features.emplace_back( std::move( feat ) );
427 while ( !features.empty() )
432 std::unique_ptr< Feats > feat = std::move( features.front() );
433 features.pop_front();
435 for ( std::unique_ptr< LabelPosition > &candidate : feat->candidates )
437 std::unique_ptr< LabelPosition > lp = std::move( candidate );
439 lp->resetNumOverlaps();
447 lp->getBoundingBox( amin, amax );
448 prob->allCandidatesIndex().intersects(
QgsRectangle( amin[0], amin[1], amax[0], amax[1] ), [&lp](
const LabelPosition * lp2 )->
bool
450 if ( lp->isInConflict( lp2 ) )
452 lp->incrementNumOverlaps();
459 nbOverlaps += lp->getNumOverlaps();
461 prob->addCandidatePosition( std::move( lp ) );
468 prob->mAllNblp = prob->mTotalCandidates;
469 prob->mNbOverlap = nbOverlaps;
475 void Pal::registerCancellationCallback( Pal::FnIsCanceled fnCanceled,
void *context )
477 fnIsCanceled = fnCanceled;
478 fnIsCanceledContext = context;
483 return extract( extent, mapBoundary );
489 return QList<LabelPosition *>();
499 return QList<LabelPosition *>();
505 void Pal::setMinIt(
int min_it )
511 void Pal::setMaxIt(
int max_it )
517 void Pal::setPopmusicR(
int r )
523 void Pal::setEjChainDeg(
int degree )
525 this->mEjChainDeg = degree;
528 void Pal::setTenure(
int tenure )
530 this->mTenure = tenure;
533 void Pal::setCandListSize(
double fact )
535 this->mCandListSize = fact;
540 this->mShowPartialLabels = show;
545 return mPlacementVersion;
565 return mShowPartialLabels;
A rtree spatial index for use in the pal labeling engine.
The QgsAbstractLabelProvider class is an interface class.
A geometry is the spatial representation of a feature.
static geos::unique_ptr asGeos(const QgsGeometry &geometry, double precision=0)
Returns a geos geometry - caller takes ownership of the object (should be deleted with GEOSGeom_destr...
static GEOSContextHandle_t getGEOSHandler()
PlacementEngineVersion
Placement engine version.
@ PlacementEngineVersion1
Version 1, matches placement from QGIS <= 3.10.1.
@ PlacementEngineVersion2
Version 2 (default for new projects since QGIS 3.12)
Placement
Placement modes which determine how label candidates are generated for a feature.
A rectangle specified with double values.
double yMaximum() const SIP_HOLDGIL
Returns the y maximum value (top side of rectangle).
double xMaximum() const SIP_HOLDGIL
Returns the x maximum value (right side of rectangle).
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
double height() const SIP_HOLDGIL
Returns the height of the rectangle.
double width() const SIP_HOLDGIL
Returns the width of the rectangle.
QgsRectangle buffered(double width) const
Gets rectangle enlarged by buffer.
This class is a composition of two QSettings instances:
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
static void addObstacleCostPenalty(pal::LabelPosition *lp, pal::FeaturePart *obstacle, Pal *pal)
Increase candidate's cost according to its collision with passed feature.
static void finalizeCandidatesCosts(Feats *feat, double bbx[4], double bby[4])
Sort candidates by costs, skip the worse ones, evaluate polygon candidates.
static bool candidateSortGrow(const std::unique_ptr< pal::LabelPosition > &c1, const std::unique_ptr< pal::LabelPosition > &c2)
Sorts label candidates in ascending order of cost.
Main class to handle feature.
std::vector< std::unique_ptr< LabelPosition > > createCandidates(Pal *pal)
Generates a list of candidate positions for labels for this feature.
FeaturePart * getSelfObstacle(int i)
Gets hole (inner ring) - considered as obstacle.
Thrown when trying to access an empty data set.
LabelPosition is a candidate feature label position.
A set of features which influence the labeling process.
QList< FeaturePart * > mObstacleParts
List of obstacle parts.
QString name() const
Returns the layer's name.
bool active() const
Returns whether the layer is currently active.
bool mergeConnectedLines() const
Returns whether connected lines will be merged before labeling.
void joinConnectedFeatures()
Join connected features with the same label text.
QLinkedList< FeaturePart * > mFeatureParts
List of feature parts.
void chopFeaturesAtRepeatDistance()
Chop layer features at the repeat distance.
void setPlacementVersion(QgsLabelingEngineSettings::PlacementEngineVersion placementVersion)
Sets the placement engine version, which dictates how the label placement problem is solved.
QgsLabelingEngineSettings::PlacementEngineVersion placementVersion() const
Returns the placement engine version, which dictates how the label placement problem is solved.
void setShowPartialLabels(bool show)
Sets whether partial labels show be allowed.
Layer * addLayer(QgsAbstractLabelProvider *provider, const QString &layerName, QgsPalLayerSettings::Placement arrangement, double defaultPriority, bool active, bool toLabel, bool displayAll=false)
add a new layer
std::unique_ptr< Problem > extractProblem(const QgsRectangle &extent, const QgsGeometry &mapBoundary)
Extracts the labeling problem for the specified map extent - only features within this extent will be...
void removeLayer(Layer *layer)
remove a layer
QList< LabelPosition * > solveProblem(Problem *prob, bool displayAll, QList< pal::LabelPosition * > *unlabeled=nullptr)
Solves the labeling problem, selecting the best candidate locations for all labels and returns a list...
bool showPartialLabels() const
Returns whether partial labels should be allowed.
Pal()
Create an new pal instance.
bool isCanceled()
Check whether the job has been canceled.
QgsRectangle boundingBox() const
Returns the point set bounding box.
Representation of a labeling problem.
QList< LabelPosition * > getSolution(bool returnInactive, QList< LabelPosition * > *unlabeled=nullptr)
Solves the labeling problem, selecting the best candidate locations for all labels and returns a list...
void chain_search()
Test with very-large scale neighborhood.
std::unique_ptr< const GEOSPreparedGeometry, GeosDeleter > prepared_unique_ptr
Scoped GEOS prepared geometry pointer.
std::unique_ptr< GEOSGeometry, GeosDeleter > unique_ptr
Scoped GEOS pointer.