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++ )
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 )
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 )
217 prob->positionsWithNoCandidates()->emplace_back( std::move( unplacedPosition ) );
230 obstacles.
insert( obstaclePart, obstaclePart->boundingBox() );
231 allObstacleParts.emplace_back( obstaclePart );
240 if ( features.size() - previousFeatureCount > 0 || obstacleCount > previousObstacleCount )
242 layersWithFeaturesInBBox << layer->
name();
244 previousFeatureCount = features.size();
245 previousObstacleCount = obstacleCount;
252 prob->mLayerCount = layersWithFeaturesInBBox.size();
253 prob->labelledLayersName = layersWithFeaturesInBBox;
255 prob->mFeatureCount = features.size();
256 prob->mTotalCandidates = 0;
257 prob->mFeatNbLp.resize( prob->mFeatureCount );
258 prob->mFeatStartId.resize( prob->mFeatureCount );
259 prob->mInactiveCost.resize( prob->mFeatureCount );
261 if ( !features.empty() )
264 for (
FeaturePart *obstaclePart : allObstacleParts )
269 allCandidatesFirstRound.
intersects( obstaclePart->boundingBox(), [obstaclePart,
this](
const LabelPosition * candidatePosition ) ->
bool 276 if ( ( !obstaclePart->getHoleOf() && candidatePosition->getFeaturePart()->hasSameLabelFeatureAs( obstaclePart ) )
277 || ( obstaclePart->getHoleOf() && !candidatePosition->getFeaturePart()->hasSameLabelFeatureAs( dynamic_cast< FeaturePart * >( obstaclePart->getHoleOf() ) ) ) )
294 for ( std::size_t i = 0; i < prob->mFeatureCount; i++ )
296 std::unique_ptr< Feats > feat = std::move( features.front() );
297 features.pop_front();
299 prob->mFeatStartId[i] = idlp;
300 prob->mInactiveCost[i] = std::pow( 2, 10 - 10 * feat->priority );
302 std::size_t maxCandidates = 0;
303 switch ( feat->feature->getGeosType() )
307 maxCandidates = feat->feature->maximumPointCandidates();
310 case GEOS_LINESTRING:
311 maxCandidates = feat->feature->maximumLineCandidates();
315 maxCandidates = feat->feature->maximumPolygonCandidates();
322 switch ( mPlacementVersion )
333 feat->candidates.erase( std::remove_if( feat->candidates.begin() + 1, feat->candidates.end(), [ & ]( std::unique_ptr< LabelPosition > &candidate )
335 if ( candidate->hasHardObstacleConflict() )
340 } ), feat->candidates.end() );
342 if ( feat->candidates.size() == 1 && feat->candidates[ 0 ]->hasHardObstacleConflict() )
346 prob->positionsWithNoCandidates()->emplace_back( std::move( feat->candidates.front() ) );
347 feat->candidates.clear();
352 if ( feat->candidates.empty() )
362 if ( maxCandidates > 0 && feat->candidates.size() > maxCandidates )
364 feat->candidates.resize( maxCandidates );
371 prob->mFeatNbLp[i] =
static_cast< int >( feat->candidates.size() );
372 prob->mTotalCandidates +=
static_cast< int >( feat->candidates.size() );
375 for ( std::unique_ptr< LabelPosition > &candidate : feat->candidates )
377 candidate->insertIntoIndex( prob->allCandidatesIndex() );
378 candidate->setProblemIds( static_cast< int >( i ), idlp++ );
380 features.emplace_back( std::move( feat ) );
387 while ( !features.empty() )
392 std::unique_ptr< Feats > feat = std::move( features.front() );
393 features.pop_front();
395 for ( std::unique_ptr< LabelPosition > &candidate : feat->candidates )
397 std::unique_ptr< LabelPosition > lp = std::move( candidate );
399 lp->resetNumOverlaps();
407 lp->getBoundingBox( amin, amax );
408 prob->allCandidatesIndex().intersects(
QgsRectangle( amin[0], amin[1], amax[0], amax[1] ), [&lp](
const LabelPosition * lp2 )->
bool 410 if ( lp->isInConflict( lp2 ) )
412 lp->incrementNumOverlaps();
419 nbOverlaps += lp->getNumOverlaps();
421 prob->addCandidatePosition( std::move( lp ) );
428 prob->mAllNblp = prob->mTotalCandidates;
429 prob->mNbOverlap = nbOverlaps;
437 fnIsCanceled = fnCanceled;
438 fnIsCanceledContext = context;
443 return extract( extent, mapBoundary );
449 return QList<LabelPosition *>();
459 return QList<LabelPosition *>();
465 void Pal::setMinIt(
int min_it )
471 void Pal::setMaxIt(
int max_it )
477 void Pal::setPopmusicR(
int r )
483 void Pal::setEjChainDeg(
int degree )
485 this->mEjChainDeg = degree;
488 void Pal::setTenure(
int tenure )
490 this->mTenure = tenure;
493 void Pal::setCandListSize(
double fact )
495 this->mCandListSize = fact;
500 this->mShowPartialLabels = show;
505 return mPlacementVersion;
525 return mShowPartialLabels;
static void addObstacleCostPenalty(pal::LabelPosition *lp, pal::FeaturePart *obstacle, Pal *pal)
Increase candidate's cost according to its collision with passed feature.
Layer * addLayer(QgsAbstractLabelProvider *provider, const QString &layerName, QgsPalLayerSettings::Placement arrangement, double defaultPriority, bool active, bool toLabel, bool displayAll=false)
add a new layer
QList< FeaturePart * > mObstacleParts
List of obstacle parts.
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.
A rectangle specified with double values.
bool mergeConnectedLines() const
Returns whether connected lines will be merged before labeling.
bool showPartialLabels() const
Returns whether partial labels should be allowed.
This class is a composition of two QSettings instances:
Version 1, matches placement from QGIS <= 3.10.1.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
std::unique_ptr< const GEOSPreparedGeometry, GeosDeleter > prepared_unique_ptr
Scoped GEOS prepared geometry pointer.
void registerCancellationCallback(FnIsCanceled fnCanceled, void *context)
Register a function that returns whether this job has been canceled - PAL calls it during the computa...
A set of features which influence the labeling process.
void chopFeaturesAtRepeatDistance()
Chop layer features at the repeat distance *.
A geometry is the spatial representation of a feature.
void setPlacementVersion(QgsLabelingEngineSettings::PlacementEngineVersion placementVersion)
Sets the placement engine version, which dictates how the label placement problem is solved...
A rtree spatial index for use in the pal labeling engine.
static GEOSContextHandle_t getGEOSHandler()
void removeLayer(Layer *layer)
remove a 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...
bool intersects(const QgsRectangle &bounds, const std::function< bool(T *data)> &callback) const
Performs an intersection check against the index, for data intersecting the specified bounds...
QgsRectangle buffered(double width) const
Gets rectangle enlarged by buffer.
Version 2 (default for new projects since QGIS 3.12)
void chain_search()
Test with very-large scale neighborhood.
bool(* FnIsCanceled)(void *ctx)
void joinConnectedFeatures()
Join connected features with the same label text.
double width() const
Returns the width of the rectangle.
QgsLabelingEngineSettings::PlacementEngineVersion placementVersion() const
Returns the placement engine version, which dictates how the label placement problem is solved...
bool isCanceled()
Check whether the job has been canceled.
std::unique_ptr< GEOSGeometry, GeosDeleter > unique_ptr
Scoped GEOS pointer.
Main class to handle feature.
The QgsAbstractLabelProvider class is an interface class.
Pal()
Create an new pal instance.
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Placement
Placement modes which determine how label candidates are generated for a feature. ...
QgsRectangle boundingBox() const
Returns the point set bounding box.
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...
QLinkedList< FeaturePart * > mFeatureParts
List of feature parts.
FeaturePart * getSelfObstacle(int i)
Gets hole (inner ring) - considered as obstacle.
QString name() const
Returns the layer's name.
bool active() const
Returns whether the layer is currently active.
LabelPosition is a candidate feature label position.
double xMinimum() const
Returns the x minimum value (left side of rectangle).
Representation of a labeling problem.
double yMaximum() const
Returns the y maximum value (top side of rectangle).
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...
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 insert(T *data, const QgsRectangle &bounds)
Inserts new data into the spatial index, with the specified bounds.
PlacementEngineVersion
Placement engine version.
static void finalizeCandidatesCosts(Feats *feat, double bbx[4], double bby[4])
Sort candidates by costs, skip the worse ones, evaluate polygon candidates.
Thrown when trying to access an empty data set.
double height() const
Returns the height of the rectangle.
void setShowPartialLabels(bool show)
Sets whether partial labels show be allowed.