QGIS API Documentation  3.12.1-BucureČ™ti (121cc00ff0)
qgslabelingengine.cpp
Go to the documentation of this file.
1 
2 /***************************************************************************
3  qgslabelingengine.cpp
4  --------------------------------------
5  Date : September 2015
6  Copyright : (C) 2015 by Martin Dobias
7  Email : wonder dot sk at gmail dot com
8  ***************************************************************************
9  * *
10  * This program is free software; you can redistribute it and/or modify *
11  * it under the terms of the GNU General Public License as published by *
12  * the Free Software Foundation; either version 2 of the License, or *
13  * (at your option) any later version. *
14  * *
15  ***************************************************************************/
16 
17 #include "qgslabelingengine.h"
18 
19 #include "qgslogger.h"
20 
21 #include "feature.h"
22 #include "labelposition.h"
23 #include "layer.h"
24 #include "pal.h"
25 #include "problem.h"
26 #include "qgsrendercontext.h"
27 #include "qgsmaplayer.h"
28 #include "qgssymbol.h"
31 
32 // helper function for checking for job cancellation within PAL
33 static bool _palIsCanceled( void *ctx )
34 {
35  return ( reinterpret_cast< QgsRenderContext * >( ctx ) )->renderingStopped();
36 }
37 
44 {
45  public:
46 
47  explicit QgsLabelSorter( const QgsMapSettings &mapSettings )
48  : mMapSettings( mapSettings )
49  {}
50 
52  {
53  QgsLabelFeature *lf1 = lp1->getFeaturePart()->feature();
54  QgsLabelFeature *lf2 = lp2->getFeaturePart()->feature();
55 
56  if ( !qgsDoubleNear( lf1->zIndex(), lf2->zIndex() ) )
57  return lf1->zIndex() < lf2->zIndex();
58 
59  //equal z-index, so fallback to respecting layer render order
60  QStringList layerIds = mMapSettings.layerIds();
61  int layer1Pos = layerIds.indexOf( lf1->provider()->layerId() );
62  int layer2Pos = layerIds.indexOf( lf2->provider()->layerId() );
63  if ( layer1Pos != layer2Pos && layer1Pos >= 0 && layer2Pos >= 0 )
64  return layer1Pos > layer2Pos; //higher positions are rendered first
65 
66  //same layer, so render larger labels first
67  return lf1->size().width() * lf1->size().height() > lf2->size().width() * lf2->size().height();
68  }
69 
70  private:
71 
72  const QgsMapSettings &mMapSettings;
73 };
74 
75 //
76 // QgsLabelingEngine
77 //
78 
80  : mResults( new QgsLabelingResults )
81 {}
82 
84 {
85  qDeleteAll( mProviders );
86  qDeleteAll( mSubProviders );
87 }
88 
90 {
92  if ( mResults )
93  mResults->setMapSettings( mapSettings );
94 }
95 
96 QList< QgsMapLayer * > QgsLabelingEngine::participatingLayers() const
97 {
98  QList< QgsMapLayer * > layers;
99 
100  // try to return layers sorted in the desired z order for rendering
101  QList< QgsAbstractLabelProvider * > providersByZ = mProviders;
102  std::sort( providersByZ.begin(), providersByZ.end(),
103  []( const QgsAbstractLabelProvider * a, const QgsAbstractLabelProvider * b ) -> bool
104  {
105  const QgsVectorLayerLabelProvider *providerA = dynamic_cast<const QgsVectorLayerLabelProvider *>( a );
106  const QgsVectorLayerLabelProvider *providerB = dynamic_cast<const QgsVectorLayerLabelProvider *>( b );
107 
108  if ( providerA && providerB )
109  {
110  return providerA->settings().zIndex < providerB->settings().zIndex ;
111  }
112  return false;
113  } );
114 
115  QList< QgsAbstractLabelProvider * > subProvidersByZ = mSubProviders;
116  std::sort( subProvidersByZ.begin(), subProvidersByZ.end(),
117  []( const QgsAbstractLabelProvider * a, const QgsAbstractLabelProvider * b ) -> bool
118  {
119  const QgsVectorLayerLabelProvider *providerA = dynamic_cast<const QgsVectorLayerLabelProvider *>( a );
120  const QgsVectorLayerLabelProvider *providerB = dynamic_cast<const QgsVectorLayerLabelProvider *>( b );
121 
122  if ( providerA && providerB )
123  {
124  return providerA->settings().zIndex < providerB->settings().zIndex ;
125  }
126  return false;
127  } );
128 
129  for ( QgsAbstractLabelProvider *provider : qgis::as_const( providersByZ ) )
130  {
131  if ( provider->layer() && !layers.contains( provider->layer() ) )
132  layers << provider->layer();
133  }
134  for ( QgsAbstractLabelProvider *provider : qgis::as_const( subProvidersByZ ) )
135  {
136  if ( provider->layer() && !layers.contains( provider->layer() ) )
137  layers << provider->layer();
138  }
139  return layers;
140 }
141 
143 {
144  QStringList layers;
145 
146  // try to return layers sorted in the desired z order for rendering
147  QList< QgsAbstractLabelProvider * > providersByZ = mProviders;
148  std::sort( providersByZ.begin(), providersByZ.end(),
149  []( const QgsAbstractLabelProvider * a, const QgsAbstractLabelProvider * b ) -> bool
150  {
151  const QgsVectorLayerLabelProvider *providerA = dynamic_cast<const QgsVectorLayerLabelProvider *>( a );
152  const QgsVectorLayerLabelProvider *providerB = dynamic_cast<const QgsVectorLayerLabelProvider *>( b );
153 
154  if ( providerA && providerB )
155  {
156  return providerA->settings().zIndex < providerB->settings().zIndex ;
157  }
158  return false;
159  } );
160 
161  QList< QgsAbstractLabelProvider * > subProvidersByZ = mSubProviders;
162  std::sort( subProvidersByZ.begin(), subProvidersByZ.end(),
163  []( const QgsAbstractLabelProvider * a, const QgsAbstractLabelProvider * b ) -> bool
164  {
165  const QgsVectorLayerLabelProvider *providerA = dynamic_cast<const QgsVectorLayerLabelProvider *>( a );
166  const QgsVectorLayerLabelProvider *providerB = dynamic_cast<const QgsVectorLayerLabelProvider *>( b );
167 
168  if ( providerA && providerB )
169  {
170  return providerA->settings().zIndex < providerB->settings().zIndex ;
171  }
172  return false;
173  } );
174 
175  for ( QgsAbstractLabelProvider *provider : qgis::as_const( providersByZ ) )
176  {
177  if ( !layers.contains( provider->layerId() ) )
178  layers << provider->layerId();
179  }
180  for ( QgsAbstractLabelProvider *provider : qgis::as_const( subProvidersByZ ) )
181  {
182  if ( !layers.contains( provider->layerId() ) )
183  layers << provider->layerId();
184  }
185  return layers;
186 }
187 
189 {
190  provider->setEngine( this );
191  mProviders << provider;
192 }
193 
195 {
196  int idx = mProviders.indexOf( provider );
197  if ( idx >= 0 )
198  {
199  delete mProviders.takeAt( idx );
200  }
201 }
202 
204 {
205  QgsAbstractLabelProvider::Flags flags = provider->flags();
206 
207  // create the pal layer
208  pal::Layer *l = p.addLayer( provider,
209  provider->name(),
210  provider->placement(),
211  provider->priority(),
212  true,
213  flags.testFlag( QgsAbstractLabelProvider::DrawLabels ),
214  flags.testFlag( QgsAbstractLabelProvider::DrawAllLabels ) );
215 
216  // set whether adjacent lines should be merged
218 
219  // set obstacle type
220  l->setObstacleType( provider->obstacleType() );
221 
222  // set whether location of centroid must be inside of polygons
224 
225  // set how to show upside-down labels
227  switch ( provider->upsidedownLabels() )
228  {
230  upsdnlabels = pal::Layer::Upright;
231  break;
233  upsdnlabels = pal::Layer::ShowDefined;
234  break;
236  upsdnlabels = pal::Layer::ShowAll;
237  break;
238  }
239  l->setUpsidedownLabels( upsdnlabels );
240 
241 
242  const QList<QgsLabelFeature *> features = provider->labelFeatures( context );
243 
244  for ( QgsLabelFeature *feature : features )
245  {
246  try
247  {
248  l->registerFeature( feature );
249  }
250  catch ( std::exception &e )
251  {
252  Q_UNUSED( e )
253  QgsDebugMsgLevel( QStringLiteral( "Ignoring feature %1 due PAL exception:" ).arg( feature->id() ) + QString::fromLatin1( e.what() ), 4 );
254  continue;
255  }
256  }
257 
258  // any sub-providers?
259  const auto subproviders = provider->subProviders();
260  for ( QgsAbstractLabelProvider *subProvider : subproviders )
261  {
262  mSubProviders << subProvider;
263  processProvider( subProvider, context, p );
264  }
265 }
266 
268 {
270 
271  mPal = qgis::make_unique< pal::Pal >();
272 
273  mPal->setMaximumLineCandidatesPerMapUnit( settings.maximumLineCandidatesPerCm() / context.convertToMapUnits( 10, QgsUnitTypes::RenderMillimeters ) );
274  mPal->setMaximumPolygonCandidatesPerMapUnitSquared( settings.maximumPolygonCandidatesPerCmSquared() / std::pow( context.convertToMapUnits( 10, QgsUnitTypes::RenderMillimeters ), 2 ) );
275 
276  mPal->setShowPartialLabels( settings.testFlag( QgsLabelingEngineSettings::UsePartialCandidates ) );
277  mPal->setPlacementVersion( settings.placementVersion() );
278 
279  // for each provider: get labels and register them in PAL
280  for ( QgsAbstractLabelProvider *provider : qgis::as_const( mProviders ) )
281  {
282  std::unique_ptr< QgsExpressionContextScopePopper > layerScopePopper;
283  if ( QgsMapLayer *ml = provider->layer() )
284  {
285  layerScopePopper = qgis::make_unique< QgsExpressionContextScopePopper >( context.expressionContext(), QgsExpressionContextUtils::layerScope( ml ) );
286  }
287  processProvider( provider, context, *mPal );
288  }
289 }
290 
292 {
293  Q_ASSERT( mPal.get() );
294 
295  // NOW DO THE LAYOUT (from QgsPalLabeling::drawLabeling)
297 
298  QPainter *painter = context.painter();
299 
301  QPolygonF visiblePoly = mMapSettings.visiblePolygon();
302  visiblePoly.append( visiblePoly.at( 0 ) ); //close polygon
303 
304  // get map label boundary geometry - if one hasn't been explicitly set, we use the whole of the map's visible polygon
306 
307  // label blocking regions work by "chopping away" those regions from the permissible labeling area
308  const QList< QgsLabelBlockingRegion > blockingRegions = mMapSettings.labelBlockingRegions();
309  for ( const QgsLabelBlockingRegion &region : blockingRegions )
310  {
311  mapBoundaryGeom = mapBoundaryGeom.difference( region.geometry );
312  }
313 
314  if ( settings.flags() & QgsLabelingEngineSettings::DrawCandidates )
315  {
316  // draw map boundary
317  QgsFeature f;
318  f.setGeometry( mapBoundaryGeom );
319  QgsStringMap properties;
320  properties.insert( QStringLiteral( "style" ), QStringLiteral( "no" ) );
321  properties.insert( QStringLiteral( "style_border" ), QStringLiteral( "solid" ) );
322  properties.insert( QStringLiteral( "color_border" ), QStringLiteral( "#0000ff" ) );
323  properties.insert( QStringLiteral( "width_border" ), QStringLiteral( "0.3" ) );
324  properties.insert( QStringLiteral( "joinstyle" ), QStringLiteral( "miter" ) );
325  std::unique_ptr< QgsFillSymbol > boundarySymbol( QgsFillSymbol::createSimple( properties ) );
326  boundarySymbol->startRender( context );
327  boundarySymbol->renderFeature( f, context );
328  boundarySymbol->stopRender( context );
329  }
330 
331  if ( !qgsDoubleNear( mMapSettings.rotation(), 0.0 ) )
332  {
333  //PAL features are prerotated, so extent also needs to be unrotated
335  // yes - this is rotated in the opposite direction... phew, this is confusing!
336  mapBoundaryGeom.rotate( mMapSettings.rotation(), mMapSettings.visibleExtent().center() );
337  }
338 
339  QgsRectangle extent = extentGeom.boundingBox();
340 
341  mPal->registerCancellationCallback( &_palIsCanceled, reinterpret_cast< void * >( &context ) );
342 
343  QElapsedTimer t;
344  t.start();
345 
346  // do the labeling itself
347  try
348  {
349  mProblem = mPal->extractProblem( extent, mapBoundaryGeom );
350  }
351  catch ( std::exception &e )
352  {
353  Q_UNUSED( e )
354  QgsDebugMsgLevel( "PAL EXCEPTION :-( " + QString::fromLatin1( e.what() ), 4 );
355  return;
356  }
357 
358  if ( context.renderingStopped() )
359  {
360  return; // it has been canceled
361  }
362 
363 #if 1 // XXX strk
364  // features are pre-rotated but not scaled/translated,
365  // so we only disable rotation here. Ideally, they'd be
366  // also pre-scaled/translated, as suggested here:
367  // https://github.com/qgis/QGIS/issues/20071
369  xform.setMapRotation( 0, 0, 0 );
370 #else
371  const QgsMapToPixel &xform = mMapSettings->mapToPixel();
372 #endif
373 
374  // draw rectangles with all candidates
375  // this is done before actual solution of the problem
376  // before number of candidates gets reduced
377  // TODO mCandidates.clear();
378  if ( settings.testFlag( QgsLabelingEngineSettings::DrawCandidates ) && mProblem )
379  {
380  painter->setBrush( Qt::NoBrush );
381  for ( int i = 0; i < static_cast< int >( mProblem->featureCount() ); i++ )
382  {
383  for ( int j = 0; j < mProblem->featureCandidateCount( i ); j++ )
384  {
385  pal::LabelPosition *lp = mProblem->featureCandidate( i, j );
386 
387  QgsPalLabeling::drawLabelCandidateRect( lp, painter, &xform );
388  }
389  }
390  }
391 
392  // find the solution
393  mLabels = mPal->solveProblem( mProblem.get(), settings.testFlag( QgsLabelingEngineSettings::UseAllLabels ), settings.testFlag( QgsLabelingEngineSettings::DrawUnplacedLabels ) ? &mUnlabeled : nullptr );
394 
395  // sort labels
396  std::sort( mLabels.begin(), mLabels.end(), QgsLabelSorter( mMapSettings ) );
397 
398  QgsDebugMsgLevel( QStringLiteral( "LABELING work: %1 ms ... labels# %2" ).arg( t.elapsed() ).arg( mLabels.size() ), 4 );
399 }
400 
401 void QgsLabelingEngine::drawLabels( QgsRenderContext &context, const QString &layerId )
402 {
403  QElapsedTimer t;
404  t.start();
405 
407  QPainter *painter = context.painter();
408  painter->setRenderHint( QPainter::Antialiasing );
409 
410  // prepare for rendering
411  for ( QgsAbstractLabelProvider *provider : qgis::as_const( mProviders ) )
412  {
413  if ( !layerId.isEmpty() && provider->layerId() != layerId )
414  continue;
415 
416  // provider will require the correct layer scope for expression preparation - at this stage, the existing expression context
417  // only contains generic scopes
419  provider->startRender( context );
420  }
421 
423  std::unique_ptr< QgsExpressionContextScopePopper > symbolScopePopper = qgis::make_unique< QgsExpressionContextScopePopper >( context.expressionContext(), symbolScope );
424 
425  // draw label backgrounds
426  for ( pal::LabelPosition *label : qgis::as_const( mLabels ) )
427  {
428  if ( context.renderingStopped() )
429  break;
430 
431  QgsLabelFeature *lf = label->getFeaturePart()->feature();
432  if ( !lf )
433  {
434  continue;
435  }
436 
437  if ( !layerId.isEmpty() && lf->provider()->layerId() != layerId )
438  continue;
439 
440  context.expressionContext().setFeature( lf->feature() );
441  context.expressionContext().setFields( lf->feature().fields() );
442  if ( lf->symbol() )
443  {
444  symbolScope = QgsExpressionContextUtils::updateSymbolScope( lf->symbol(), symbolScope );
445  }
446  lf->provider()->drawLabelBackground( context, label );
447  }
448 
449  // draw the labels
450  for ( pal::LabelPosition *label : qgis::as_const( mLabels ) )
451  {
452  if ( context.renderingStopped() )
453  break;
454 
455  QgsLabelFeature *lf = label->getFeaturePart()->feature();
456  if ( !lf )
457  {
458  continue;
459  }
460 
461  if ( !layerId.isEmpty() && lf->provider()->layerId() != layerId )
462  continue;
463 
464  context.expressionContext().setFeature( lf->feature() );
465  context.expressionContext().setFields( lf->feature().fields() );
466  if ( lf->symbol() )
467  {
468  symbolScope = QgsExpressionContextUtils::updateSymbolScope( lf->symbol(), symbolScope );
469  }
470  lf->provider()->drawLabel( context, label );
471  // finished with symbol -- we can't keep it around after this, it may be deleted
472  lf->setSymbol( nullptr );
473  }
474 
475  // draw unplaced labels. These are always rendered on top
477  {
478  for ( pal::LabelPosition *label : qgis::as_const( mUnlabeled ) )
479  {
480  if ( context.renderingStopped() )
481  break;
482  QgsLabelFeature *lf = label->getFeaturePart()->feature();
483  if ( !lf )
484  {
485  continue;
486  }
487 
488  if ( !layerId.isEmpty() && lf->provider()->layerId() != layerId )
489  continue;
490 
491  context.expressionContext().setFeature( lf->feature() );
492  context.expressionContext().setFields( lf->feature().fields() );
493  if ( lf->symbol() )
494  {
495  symbolScope = QgsExpressionContextUtils::updateSymbolScope( lf->symbol(), symbolScope );
496  }
497  lf->provider()->drawUnplacedLabel( context, label );
498  // finished with symbol -- we can't keep it around after this, it may be deleted
499  lf->setSymbol( nullptr );
500  }
501  }
502 
503  symbolScopePopper.reset();
504 
505  // cleanup
506  for ( QgsAbstractLabelProvider *provider : qgis::as_const( mProviders ) )
507  {
508  if ( !layerId.isEmpty() && provider->layerId() != layerId )
509  continue;
510 
511  provider->stopRender( context );
512  }
513 
514  // Reset composition mode for further drawing operations
515  painter->setCompositionMode( QPainter::CompositionMode_SourceOver );
516 
517  QgsDebugMsgLevel( QStringLiteral( "LABELING draw: %1 ms" ).arg( t.elapsed() ), 4 );
518 }
519 
521 {
522  mUnlabeled.clear();
523  mLabels.clear();
524  mProblem.reset();
525  mPal.reset();
526 }
527 
529 {
530  return mResults.release();
531 }
532 
533 
534 //
535 // QgsDefaultLabelingEngine
536 //
537 
540 {
541 
542 }
543 
545 {
546  registerLabels( context );
547  if ( context.renderingStopped() )
548  {
549  cleanup();
550  return; // it has been canceled
551  }
552 
553  solve( context );
554  if ( context.renderingStopped() )
555  {
556  cleanup();
557  return;
558  }
559 
560  drawLabels( context );
561  cleanup();
562 }
563 
564 
565 //
566 // QgsStagedRenderLabelingEngine
567 //
568 
571 {
572 
573 }
574 
576 {
577  registerLabels( context );
578  if ( context.renderingStopped() )
579  {
580  cleanup();
581  return; // it has been canceled
582  }
583 
584  solve( context );
585  if ( context.renderingStopped() )
586  {
587  cleanup();
588  return;
589  }
590 }
591 
592 
594 {
595  drawLabels( context, layerId );
596 }
597 
599 {
600  cleanup();
601 }
602 
603 
605 
607 {
608  return mLayer ? mLayer->provider() : nullptr;
609 
610 }
611 
613  : mLayerId( layer ? layer->id() : QString() )
614  , mLayer( layer )
615  , mProviderId( providerId )
616  , mFlags( DrawLabels )
617  , mPlacement( QgsPalLayerSettings::AroundPoint )
618  , mPriority( 0.5 )
619  , mUpsidedownLabels( QgsPalLayerSettings::Upright )
620 {
621 }
622 
624 {
625 
626 }
627 
629 {
630 
631 }
632 
634 {
635  const auto subproviders = subProviders();
636  for ( QgsAbstractLabelProvider *subProvider : subproviders )
637  {
638  subProvider->startRender( context );
639  }
640 }
641 
643 {
644  const auto subproviders = subProviders();
645  for ( QgsAbstractLabelProvider *subProvider : subproviders )
646  {
647  subProvider->stopRender( context );
648  }
649 }
650 
651 //
652 // QgsLabelingUtils
653 //
654 
655 QString QgsLabelingUtils::encodePredefinedPositionOrder( const QVector<QgsPalLayerSettings::PredefinedPointPosition> &positions )
656 {
657  QStringList predefinedOrderString;
658  const auto constPositions = positions;
659  for ( QgsPalLayerSettings::PredefinedPointPosition position : constPositions )
660  {
661  switch ( position )
662  {
664  predefinedOrderString << QStringLiteral( "TL" );
665  break;
667  predefinedOrderString << QStringLiteral( "TSL" );
668  break;
670  predefinedOrderString << QStringLiteral( "T" );
671  break;
673  predefinedOrderString << QStringLiteral( "TSR" );
674  break;
676  predefinedOrderString << QStringLiteral( "TR" );
677  break;
679  predefinedOrderString << QStringLiteral( "L" );
680  break;
682  predefinedOrderString << QStringLiteral( "R" );
683  break;
685  predefinedOrderString << QStringLiteral( "BL" );
686  break;
688  predefinedOrderString << QStringLiteral( "BSL" );
689  break;
691  predefinedOrderString << QStringLiteral( "B" );
692  break;
694  predefinedOrderString << QStringLiteral( "BSR" );
695  break;
697  predefinedOrderString << QStringLiteral( "BR" );
698  break;
699  }
700  }
701  return predefinedOrderString.join( ',' );
702 }
703 
704 QVector<QgsPalLayerSettings::PredefinedPointPosition> QgsLabelingUtils::decodePredefinedPositionOrder( const QString &positionString )
705 {
706  QVector<QgsPalLayerSettings::PredefinedPointPosition> result;
707  const QStringList predefinedOrderList = positionString.split( ',' );
708  result.reserve( predefinedOrderList.size() );
709  for ( const QString &position : predefinedOrderList )
710  {
711  QString cleaned = position.trimmed().toUpper();
712  if ( cleaned == QLatin1String( "TL" ) )
714  else if ( cleaned == QLatin1String( "TSL" ) )
716  else if ( cleaned == QLatin1String( "T" ) )
718  else if ( cleaned == QLatin1String( "TSR" ) )
720  else if ( cleaned == QLatin1String( "TR" ) )
722  else if ( cleaned == QLatin1String( "L" ) )
724  else if ( cleaned == QLatin1String( "R" ) )
726  else if ( cleaned == QLatin1String( "BL" ) )
728  else if ( cleaned == QLatin1String( "BSL" ) )
730  else if ( cleaned == QLatin1String( "B" ) )
732  else if ( cleaned == QLatin1String( "BSR" ) )
734  else if ( cleaned == QLatin1String( "BR" ) )
736  }
737  return result;
738 }
739 
740 QString QgsLabelingUtils::encodeLinePlacementFlags( QgsLabeling::LinePlacementFlags flags )
741 {
742  QStringList parts;
744  parts << QStringLiteral( "OL" );
746  parts << QStringLiteral( "AL" );
748  parts << QStringLiteral( "BL" );
750  parts << QStringLiteral( "LO" );
751  return parts.join( ',' );
752 }
753 
754 QgsLabeling::LinePlacementFlags QgsLabelingUtils::decodeLinePlacementFlags( const QString &string )
755 {
756  QgsLabeling::LinePlacementFlags flags = nullptr;
757  const QStringList flagList = string.split( ',' );
758  bool foundLineOrientationFlag = false;
759  for ( const QString &flag : flagList )
760  {
761  QString cleaned = flag.trimmed().toUpper();
762  if ( cleaned == QLatin1String( "OL" ) )
764  else if ( cleaned == QLatin1String( "AL" ) )
766  else if ( cleaned == QLatin1String( "BL" ) )
768  else if ( cleaned == QLatin1String( "LO" ) )
769  foundLineOrientationFlag = true;
770  }
771  if ( !foundLineOrientationFlag )
773  return flags;
774 }
775 
Label on bottom right of point.
void setSymbol(const QgsSymbol *symbol)
Sets the feature symbol associated with this label.
void processProvider(QgsAbstractLabelProvider *provider, QgsRenderContext &context, pal::Pal &p)
static QgsExpressionContextScope * updateSymbolScope(const QgsSymbol *symbol, QgsExpressionContextScope *symbolScope=nullptr)
Updates a symbol scope related to a QgsSymbol to an expression context.
QList< pal::LabelPosition * > mLabels
Layer * addLayer(QgsAbstractLabelProvider *provider, const QString &layerName, QgsPalLayerSettings::Placement arrangement, double defaultPriority, bool active, bool toLabel, bool displayAll=false)
add a new layer
Definition: pal.cpp:78
std::unique_ptr< pal::Pal > mPal
double convertToMapUnits(double size, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale()) const
Converts a size from the specified units to map units.
A rectangle specified with double values.
Definition: qgsrectangle.h:41
Base class for all map layer types.
Definition: qgsmaplayer.h:79
Label on bottom-left of point.
Label on top of point, slightly left of center.
virtual void drawLabelBackground(QgsRenderContext &context, pal::LabelPosition *label) const
Draw the background for the specified label.
void setMapRotation(double degrees, double cx, double cy)
Set map rotation in degrees (clockwise)
void addProvider(QgsAbstractLabelProvider *provider)
Add provider of label features. Takes ownership of the provider.
QList< QgsAbstractLabelProvider * > mProviders
List of providers (the are owned by the labeling engine)
void removeProvider(QgsAbstractLabelProvider *provider)
Remove provider if the provider&#39;s initialization failed. Provider instance is deleted.
QgsLabelFeature * feature()
Returns the parent feature.
Definition: feature.h:117
double rotation() const
Returns the rotation of the resulting map image, in degrees clockwise.
QgsDefaultLabelingEngine()
Construct the labeling engine with default settings.
QStringList layerIds() const
Gets list of layer IDs for map rendering The layers are stored in the reverse order of how they are r...
QgsAbstractLabelProvider * provider() const
Returns provider of this instance.
Label on top-left of point.
QgsAbstractLabelProvider(QgsMapLayer *layer, const QString &providerId=QString())
Construct the provider with default values.
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
QStringList participatingLayerIds() const
Returns a list of layer IDs for layers with providers in the engine.
static void drawLabelCandidateRect(pal::LabelPosition *lp, QPainter *painter, const QgsMapToPixel *xform, QList< QgsLabelCandidate > *candidates=nullptr)
A set of features which influence the labeling process.
Definition: layer.h:61
PredefinedPointPosition
Positions for labels when using the QgsPalLabeling::OrderedPositionsAroundPoint placement mode...
void drawLabels(QgsRenderContext &context, const QString &layerId=QString())
Draws labels to the specified render context.
static QgsFillSymbol * createSimple(const QgsStringMap &properties)
Create a fill symbol with one symbol layer: SimpleFill with specified properties. ...
Definition: qgssymbol.cpp:1310
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:315
OperationResult rotate(double rotation, const QgsPointXY &center)
Rotate this geometry around the Z axis.
const QgsSymbol * symbol()
Returns the feature symbol associated with this label.
Whether to use also label candidates that are partially outside of the map view.
QgsLabelingEngine()
Construct the labeling engine with default settings.
QList< QgsAbstractLabelProvider * > mSubProviders
bool renderingStopped() const
Returns true if the rendering operation has been stopped and any ongoing rendering should be canceled...
Main Pal labeling class.
Definition: pal.h:79
static QgsLabeling::LinePlacementFlags decodeLinePlacementFlags(const QString &string)
Decodes a string to set of line placement flags.
UpsideDownLabels
Definition: layer.h:71
Label on top-right of point.
The QgsVectorLayerLabelProvider class implements a label provider for vector layers.
void setMapSettings(const QgsMapSettings &mapSettings)
Associate map settings instance.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:122
void setUpsidedownLabels(UpsideDownLabels ud)
Sets how upside down labels will be handled within the layer.
Definition: layer.h:272
QList< pal::LabelPosition * > mUnlabeled
QgsFeature feature() const
Returns the original feature associated with this label.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:55
virtual QList< QgsLabelFeature * > labelFeatures(QgsRenderContext &context)=0
Returns list of label features (they are owned by the provider and thus deleted on its destruction) ...
QgsFields fields
Definition: qgsfeature.h:66
QMap< QString, QString > QgsStringMap
Definition: qgis.h:694
Labels can be placed directly over a line feature.
QgsRectangle visibleExtent() const
Returns the actual extent derived from requested extent that takes takes output image size into accou...
void setCentroidInside(bool forceInside)
Sets whether labels placed at the centroid of features within the layer are forced to be placed insid...
Definition: layer.h:287
Labels can be placed above a line feature. Unless MapOrientation is also specified this mode respects...
double zIndex
Z-Index of label, where labels with a higher z-index are rendered on top of labels with a lower z-ind...
void finalize()
Finalizes and cleans up the engine following the rendering of labels for the last layer to be labeled...
Whether adjacent lines (with the same label text) should be merged.
The QgsMapSettings class contains configuration for rendering of the map.
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:37
Whether to draw all labels even if there would be collisions.
static QgsGeometry fromRect(const QgsRectangle &rect)
Creates a new geometry from a QgsRectangle.
QgsGeometry labelBoundaryGeometry() const
Returns the label boundary geometry, which restricts where in the rendered map labels are permitted t...
double zIndex() const
Returns the label&#39;s z-index.
Label on left of point.
Whether to render unplaced labels as an indicator/warning for users.
void renderLabelsForLayer(QgsRenderContext &context, const QString &layerId)
Renders all the labels which belong only to the layer with matching layerId to the specified render c...
double maximumPolygonCandidatesPerCmSquared() const
Returns the maximum number of polygon label candidate positions per centimeter squared.
FeaturePart * getFeaturePart() const
Returns the feature corresponding to this labelposition.
QgsStagedRenderLabelingEngine()
Construct the labeling engine with default settings.
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
Show upside down for all labels, including dynamic ones.
double maximumLineCandidatesPerCm() const
Returns the maximum number of line label candidate positions per centimeter.
virtual void drawUnplacedLabel(QgsRenderContext &context, pal::LabelPosition *label) const
Draw an unplaced label.
bool operator()(pal::LabelPosition *lp1, pal::LabelPosition *lp2) const
const QgsPalLayerSettings & settings() const
Returns the layer&#39;s settings.
Whether location of centroid must be inside of polygons.
void setObstacleType(QgsLabelObstacleSettings::ObstacleType obstacleType)
Sets the obstacle type, which controls how features within the layer act as obstacles for labels...
Definition: layer.h:237
Upside-down labels (90 <= angle < 270) are shown upright.
QList< QgsMapLayer *> participatingLayers() const
Returns a list of layers with providers in the engine.
Label below point, slightly right of center.
Whether all features will be labelled even though overlaps occur.
Label blocking region (in map coordinates and CRS).
Single scope for storing variables and functions for use within a QgsExpressionContext.
void cleanup()
Cleans up the engine following a call to registerLabels() or solve().
QgsPalLayerSettings::Placement placement() const
What placement strategy to use for the labels.
const QgsMapToPixel & mapToPixel() const
The QgsAbstractLabelProvider class is an interface class.
Whether to draw rectangles of generated candidates (good for debugging)
void setFields(const QgsFields &fields)
Convenience function for setting a fields for the context.
QString layerId() const
Returns ID of associated layer, or empty string if no layer is associated with the provider...
QgsPalLayerSettings::UpsideDownLabels upsidedownLabels() const
How to handle labels that would be upside down.
QgsLabelObstacleSettings::ObstacleType obstacleType() const
How the feature geometries will work as obstacles.
QgsLabelSorter(const QgsMapSettings &mapSettings)
QgsExpressionContext & expressionContext()
Gets the expression context.
virtual ~QgsLabelingEngine()
Clean up everything (especially the registered providers)
bool registerFeature(QgsLabelFeature *label)
Register a feature in the layer.
Definition: layer.cpp:84
Flags flags() const
Flags associated with the provider.
static QString encodePredefinedPositionOrder(const QVector< QgsPalLayerSettings::PredefinedPointPosition > &positions)
Encodes an ordered list of predefined point label positions to a string.
The QgsLabelingEngine class provides map labeling functionality.
virtual QList< QgsAbstractLabelProvider * > subProviders()
Returns list of child providers - useful if the provider needs to put labels into more layers with di...
Contains information about the context of a rendering operation.
Signifies that the AboveLine and BelowLine flags should respect the map&#39;s orientation rather than the...
std::unique_ptr< pal::Problem > mProblem
void run(QgsRenderContext &context) override
Runs the labeling job.
QPainter * painter()
Returns the destination QPainter for the render operation.
The QgsLabelFeature class describes a feature that should be used within the labeling engine...
QString name() const
Name of the layer (for statistics, debugging etc.) - does not need to be unique.
std::unique_ptr< QgsLabelingResults > mResults
Resulting labeling layout.
Label below point, slightly left of center.
PlacementEngineVersion placementVersion() const
Returns the placement engine version, which dictates how the label placement problem is solved...
QgsMapSettings mMapSettings
Associated map settings instance.
QgsLabelingResults * takeResults()
Returns pointer to recently computed results and pass the ownership of results to the caller...
Stores global configuration for labeling engine.
Label on top of point, slightly right of center.
const QgsMapSettings & mapSettings() const
Gets associated map settings.
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
Label directly below point.
Helper class for sorting labels into correct draw order.
void setGeometry(const QgsGeometry &geometry)
Set the feature&#39;s geometry.
Definition: qgsfeature.cpp:137
double priority() const
Default priority of labels (may be overridden by individual labels)
QSizeF size(double angle=0.0) const
Size of the label (in map units)
bool testFlag(Flag f) const
Test whether a particular flag is enabled.
static QgsGeometry fromQPolygonF(const QPolygonF &polygon)
Construct geometry from a QPolygonF.
LabelPosition is a candidate feature label position.
Definition: labelposition.h:55
virtual void startRender(QgsRenderContext &context)
To be called before rendering of labels begins.
Label directly above point.
Label on right of point.
Whether the labels should be rendered.
Class that stores computed placement from labeling engine.
QPolygonF visiblePolygon() const
Returns the visible area as a polygon (may be rotated)
static QVector< QgsPalLayerSettings::PredefinedPointPosition > decodePredefinedPositionOrder(const QString &positionString)
Decodes a string to an ordered list of predefined point label positions.
QgsPointXY center() const
Returns the center point of the rectangle.
Definition: qgsrectangle.h:230
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
Show upside down when rotation is layer- or data-defined.
virtual void drawLabel(QgsRenderContext &context, pal::LabelPosition *label) const =0
Draw this label at the position determined by the labeling engine.
virtual void stopRender(QgsRenderContext &context)
To be called after rendering is complete.
void solve(QgsRenderContext &context)
Solves the label problem.
Labels can be placed below a line feature. Unless MapOrientation is also specified this mode respects...
QList< QgsLabelBlockingRegion > labelBlockingRegions() const
Returns the list of regions to avoid placing labels within.
RAII class to pop scope from an expression context on destruction.
void registerLabels(QgsRenderContext &context)
Runs the label registration step.
void setEngine(const QgsLabelingEngine *engine)
Associate provider with a labeling engine (should be only called internally from QgsLabelingEngine) ...
void run(QgsRenderContext &context) override
Runs the labeling job.
const QgsLabelingEngineSettings & labelingEngineSettings() const
Returns the global configuration of the labeling engine.
void setMergeConnectedLines(bool merge)
Sets whether connected lines should be merged before labeling.
Definition: layer.h:259
static QString encodeLinePlacementFlags(QgsLabeling::LinePlacementFlags flags)
Encodes line placement flags to a string.
QgsGeometry difference(const QgsGeometry &geometry) const
Returns a geometry representing the points making up this geometry that do not make up other...