QGIS API Documentation 3.28.0-Firenze (ed3ad0430f)
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#include "qgslabelingresults.h"
32#include "qgsfillsymbol.h"
33
34// helper function for checking for job cancellation within PAL
35static bool _palIsCanceled( void *ctx )
36{
37 return ( reinterpret_cast< QgsRenderContext * >( ctx ) )->renderingStopped();
38}
39
46{
47 public:
48
49 explicit QgsLabelSorter( const QgsMapSettings &mapSettings )
50 : mMapSettings( mapSettings )
51 {}
52
54 {
55 QgsLabelFeature *lf1 = lp1->getFeaturePart()->feature();
56 QgsLabelFeature *lf2 = lp2->getFeaturePart()->feature();
57
58 if ( !qgsDoubleNear( lf1->zIndex(), lf2->zIndex() ) )
59 return lf1->zIndex() < lf2->zIndex();
60
61 //equal z-index, so fallback to respecting layer render order
62 QStringList layerIds = mMapSettings.layerIds();
63 int layer1Pos = layerIds.indexOf( lf1->provider()->layerId() );
64 int layer2Pos = layerIds.indexOf( lf2->provider()->layerId() );
65 if ( layer1Pos != layer2Pos && layer1Pos >= 0 && layer2Pos >= 0 )
66 return layer1Pos > layer2Pos; //higher positions are rendered first
67
68 //same layer, so render larger labels first
69 return lf1->size().width() * lf1->size().height() > lf2->size().width() * lf2->size().height();
70 }
71
72 private:
73
74 const QgsMapSettings &mMapSettings;
75};
76
77//
78// QgsLabelingEngine
79//
80
82 : mResults( new QgsLabelingResults )
83{}
84
86{
87 qDeleteAll( mProviders );
88 qDeleteAll( mSubProviders );
89}
90
92{
94 if ( mResults )
95 mResults->setMapSettings( mapSettings );
96}
97
98QList< QgsMapLayer * > QgsLabelingEngine::participatingLayers() const
99{
100 QList< QgsMapLayer * > layers;
101
102 // try to return layers sorted in the desired z order for rendering
103 QList< QgsAbstractLabelProvider * > providersByZ = mProviders;
104 std::sort( providersByZ.begin(), providersByZ.end(),
105 []( const QgsAbstractLabelProvider * a, const QgsAbstractLabelProvider * b ) -> bool
106 {
107 const QgsVectorLayerLabelProvider *providerA = dynamic_cast<const QgsVectorLayerLabelProvider *>( a );
108 const QgsVectorLayerLabelProvider *providerB = dynamic_cast<const QgsVectorLayerLabelProvider *>( b );
109
110 if ( providerA && providerB )
111 {
112 return providerA->settings().zIndex < providerB->settings().zIndex ;
113 }
114 return false;
115 } );
116
117 QList< QgsAbstractLabelProvider * > subProvidersByZ = mSubProviders;
118 std::sort( subProvidersByZ.begin(), subProvidersByZ.end(),
119 []( const QgsAbstractLabelProvider * a, const QgsAbstractLabelProvider * b ) -> bool
120 {
121 const QgsVectorLayerLabelProvider *providerA = dynamic_cast<const QgsVectorLayerLabelProvider *>( a );
122 const QgsVectorLayerLabelProvider *providerB = dynamic_cast<const QgsVectorLayerLabelProvider *>( b );
123
124 if ( providerA && providerB )
125 {
126 return providerA->settings().zIndex < providerB->settings().zIndex ;
127 }
128 return false;
129 } );
130
131 for ( QgsAbstractLabelProvider *provider : std::as_const( providersByZ ) )
132 {
133 if ( provider->layer() && !layers.contains( provider->layer() ) )
134 layers << provider->layer();
135 }
136 for ( QgsAbstractLabelProvider *provider : std::as_const( subProvidersByZ ) )
137 {
138 if ( provider->layer() && !layers.contains( provider->layer() ) )
139 layers << provider->layer();
140 }
141 return layers;
142}
143
145{
146 QStringList layers;
147
148 // try to return layers sorted in the desired z order for rendering
149 QList< QgsAbstractLabelProvider * > providersByZ = mProviders;
150 std::sort( providersByZ.begin(), providersByZ.end(),
151 []( const QgsAbstractLabelProvider * a, const QgsAbstractLabelProvider * b ) -> bool
152 {
153 const QgsVectorLayerLabelProvider *providerA = dynamic_cast<const QgsVectorLayerLabelProvider *>( a );
154 const QgsVectorLayerLabelProvider *providerB = dynamic_cast<const QgsVectorLayerLabelProvider *>( b );
155
156 if ( providerA && providerB )
157 {
158 return providerA->settings().zIndex < providerB->settings().zIndex ;
159 }
160 return false;
161 } );
162
163 QList< QgsAbstractLabelProvider * > subProvidersByZ = mSubProviders;
164 std::sort( subProvidersByZ.begin(), subProvidersByZ.end(),
165 []( const QgsAbstractLabelProvider * a, const QgsAbstractLabelProvider * b ) -> bool
166 {
167 const QgsVectorLayerLabelProvider *providerA = dynamic_cast<const QgsVectorLayerLabelProvider *>( a );
168 const QgsVectorLayerLabelProvider *providerB = dynamic_cast<const QgsVectorLayerLabelProvider *>( b );
169
170 if ( providerA && providerB )
171 {
172 return providerA->settings().zIndex < providerB->settings().zIndex ;
173 }
174 return false;
175 } );
176
177 for ( QgsAbstractLabelProvider *provider : std::as_const( providersByZ ) )
178 {
179 if ( !layers.contains( provider->layerId() ) )
180 layers << provider->layerId();
181 }
182 for ( QgsAbstractLabelProvider *provider : std::as_const( subProvidersByZ ) )
183 {
184 if ( !layers.contains( provider->layerId() ) )
185 layers << provider->layerId();
186 }
187 return layers;
188}
189
191{
192 provider->setEngine( this );
193 mProviders << provider;
194}
195
197{
198 int idx = mProviders.indexOf( provider );
199 if ( idx >= 0 )
200 {
201 delete mProviders.takeAt( idx );
202 }
203}
204
206{
207 QgsAbstractLabelProvider::Flags flags = provider->flags();
208
209 // create the pal layer
210 pal::Layer *l = p.addLayer( provider,
211 provider->name(),
212 provider->placement(),
213 provider->priority(),
214 true,
215 flags.testFlag( QgsAbstractLabelProvider::DrawLabels ) );
216
217 // set whether adjacent lines should be merged
219
220 // set obstacle type
221 l->setObstacleType( provider->obstacleType() );
222
223 // set whether location of centroid must be inside of polygons
225
226 // set how to show upside-down labels
227 l->setUpsidedownLabels( provider->upsidedownLabels() );
228
229 const QList<QgsLabelFeature *> features = provider->labelFeatures( context );
230
231 for ( QgsLabelFeature *feature : features )
232 {
233 try
234 {
235 l->registerFeature( feature );
236 }
237 catch ( std::exception &e )
238 {
239 Q_UNUSED( e )
240 QgsDebugMsgLevel( QStringLiteral( "Ignoring feature %1 due PAL exception:" ).arg( feature->id() ) + QString::fromLatin1( e.what() ), 4 );
241 continue;
242 }
243 }
244
245 // any sub-providers?
246 const auto subproviders = provider->subProviders();
247 for ( QgsAbstractLabelProvider *subProvider : subproviders )
248 {
249 mSubProviders << subProvider;
250 processProvider( subProvider, context, p );
251 }
252}
253
255{
256 QgsLabelingEngineFeedback *feedback = qobject_cast< QgsLabelingEngineFeedback * >( context.feedback() );
257
258 if ( feedback )
259 feedback->emit labelRegistrationAboutToBegin();
260
262
263 mPal = std::make_unique< pal::Pal >();
264
265 mPal->setMaximumLineCandidatesPerMapUnit( settings.maximumLineCandidatesPerCm() / context.convertToMapUnits( 10, QgsUnitTypes::RenderMillimeters ) );
266 mPal->setMaximumPolygonCandidatesPerMapUnitSquared( settings.maximumPolygonCandidatesPerCmSquared() / std::pow( context.convertToMapUnits( 10, QgsUnitTypes::RenderMillimeters ), 2 ) );
267
268 mPal->setShowPartialLabels( settings.testFlag( QgsLabelingEngineSettings::UsePartialCandidates ) );
269 mPal->setPlacementVersion( settings.placementVersion() );
270
271 // for each provider: get labels and register them in PAL
272 const double step = !mProviders.empty() ? 100.0 / mProviders.size() : 1;
273 int index = 0;
274 for ( QgsAbstractLabelProvider *provider : std::as_const( mProviders ) )
275 {
276 if ( feedback )
277 {
278 feedback->emit providerRegistrationAboutToBegin( provider );
279 feedback->setProgress( index * step );
280 }
281 index++;
282 std::unique_ptr< QgsExpressionContextScopePopper > layerScopePopper;
283 if ( provider->layerExpressionContextScope() )
284 {
285 layerScopePopper = std::make_unique< QgsExpressionContextScopePopper >( context.expressionContext(), new QgsExpressionContextScope( *provider->layerExpressionContextScope() ) );
286 }
287 processProvider( provider, context, *mPal );
288 if ( feedback )
289 feedback->emit providerRegistrationFinished( provider );
290 }
291 if ( feedback )
292 feedback->emit labelRegistrationFinished();
293}
294
296{
297 Q_ASSERT( mPal.get() );
298
299 // NOW DO THE LAYOUT (from QgsPalLabeling::drawLabeling)
301
302 QPainter *painter = context.painter();
303
306 QgsGeometry extentGeom = QgsGeometry::fromRect( r1 );
307
308 QPolygonF visiblePoly = mMapSettings.visiblePolygonWithBuffer();
309 visiblePoly.append( visiblePoly.at( 0 ) ); //close polygon
310
311 // get map label boundary geometry - if one hasn't been explicitly set, we use the whole of the map's visible polygon
313
314 // label blocking regions work by "chopping away" those regions from the permissible labeling area
315 const QList< QgsLabelBlockingRegion > blockingRegions = mMapSettings.labelBlockingRegions();
316 for ( const QgsLabelBlockingRegion &region : blockingRegions )
317 {
318 mapBoundaryGeom = mapBoundaryGeom.difference( region.geometry );
319 }
320
322 {
323 // draw map boundary
324 QgsFeature f;
325 f.setGeometry( mapBoundaryGeom );
326 QVariantMap properties;
327 properties.insert( QStringLiteral( "style" ), QStringLiteral( "no" ) );
328 properties.insert( QStringLiteral( "style_border" ), QStringLiteral( "solid" ) );
329 properties.insert( QStringLiteral( "color_border" ), QStringLiteral( "#0000ff" ) );
330 properties.insert( QStringLiteral( "width_border" ), QStringLiteral( "0.3" ) );
331 properties.insert( QStringLiteral( "joinstyle" ), QStringLiteral( "miter" ) );
332 std::unique_ptr< QgsFillSymbol > boundarySymbol( QgsFillSymbol::createSimple( properties ) );
333 boundarySymbol->startRender( context );
334 boundarySymbol->renderFeature( f, context );
335 boundarySymbol->stopRender( context );
336 }
337
338 if ( !qgsDoubleNear( mMapSettings.rotation(), 0.0 ) )
339 {
340 //PAL features are prerotated, so extent also needs to be unrotated
342 // yes - this is rotated in the opposite direction... phew, this is confusing!
344 }
345
346 QgsRectangle extent = extentGeom.boundingBox();
347
348 mPal->registerCancellationCallback( &_palIsCanceled, reinterpret_cast< void * >( &context ) );
349
350 QElapsedTimer t;
351 t.start();
352
353 // do the labeling itself
354 try
355 {
356 mProblem = mPal->extractProblem( extent, mapBoundaryGeom, context );
357 }
358 catch ( std::exception &e )
359 {
360 Q_UNUSED( e )
361 QgsDebugMsgLevel( "PAL EXCEPTION :-( " + QString::fromLatin1( e.what() ), 4 );
362 return;
363 }
364
365 if ( context.renderingStopped() )
366 {
367 return; // it has been canceled
368 }
369
370#if 1 // XXX strk
371 // features are pre-rotated but not scaled/translated,
372 // so we only disable rotation here. Ideally, they'd be
373 // also pre-scaled/translated, as suggested here:
374 // https://github.com/qgis/QGIS/issues/20071
376 xform.setMapRotation( 0, 0, 0 );
377#else
378 const QgsMapToPixel &xform = mMapSettings->mapToPixel();
379#endif
380
381 // draw rectangles with all candidates
382 // this is done before actual solution of the problem
383 // before number of candidates gets reduced
384 // TODO mCandidates.clear();
386 {
387 painter->setBrush( Qt::NoBrush );
388 for ( int i = 0; i < static_cast< int >( mProblem->featureCount() ); i++ )
389 {
390 for ( int j = 0; j < mProblem->featureCandidateCount( i ); j++ )
391 {
392 pal::LabelPosition *lp = mProblem->featureCandidate( i, j );
393
394 QgsPalLabeling::drawLabelCandidateRect( lp, painter, &xform );
395 }
396 }
397 }
398
399 // find the solution
400 mLabels = mPal->solveProblem( mProblem.get(), context,
403
404 // sort labels
405 std::sort( mLabels.begin(), mLabels.end(), QgsLabelSorter( mMapSettings ) );
406
407 QgsDebugMsgLevel( QStringLiteral( "LABELING work: %1 ms ... labels# %2" ).arg( t.elapsed() ).arg( mLabels.size() ), 4 );
408}
409
410void QgsLabelingEngine::drawLabels( QgsRenderContext &context, const QString &layerId )
411{
412 QElapsedTimer t;
413 t.start();
414
416
418 QPainter *painter = context.painter();
419
420 // prepare for rendering
421 for ( QgsAbstractLabelProvider *provider : std::as_const( mProviders ) )
422 {
423 if ( !layerId.isEmpty() && provider->layerId() != layerId )
424 continue;
425
426 // provider will require the correct layer scope for expression preparation - at this stage, the existing expression context
427 // only contains generic scopes
428 QgsExpressionContextScopePopper popper( context.expressionContext(), provider->layerExpressionContextScope() ? new QgsExpressionContextScope( *provider->layerExpressionContextScope() ) : new QgsExpressionContextScope() );
429
430 QgsScopedRenderContextReferenceScaleOverride referenceScaleOverride( context, provider->layerReferenceScale() );
431 provider->startRender( context );
432 }
433
435 std::unique_ptr< QgsExpressionContextScopePopper > symbolScopePopper = std::make_unique< QgsExpressionContextScopePopper >( context.expressionContext(), symbolScope );
436
437 // draw label backgrounds
438 for ( pal::LabelPosition *label : std::as_const( mLabels ) )
439 {
440 if ( context.renderingStopped() )
441 break;
442
443 QgsLabelFeature *lf = label->getFeaturePart()->feature();
444 if ( !lf )
445 {
446 continue;
447 }
448
449 if ( !layerId.isEmpty() && lf->provider()->layerId() != layerId )
450 continue;
451
452 context.expressionContext().setFeature( lf->feature() );
453 context.expressionContext().setFields( lf->feature().fields() );
454
455 QgsScopedRenderContextReferenceScaleOverride referenceScaleOverride( context, lf->provider()->layerReferenceScale() );
456
457 if ( lf->symbol() )
458 {
459 symbolScope = QgsExpressionContextUtils::updateSymbolScope( lf->symbol(), symbolScope );
460 }
461 lf->provider()->drawLabelBackground( context, label );
462 }
463
464 // draw the labels
465 for ( pal::LabelPosition *label : std::as_const( mLabels ) )
466 {
467 if ( context.renderingStopped() )
468 break;
469
470 QgsLabelFeature *lf = label->getFeaturePart()->feature();
471 if ( !lf )
472 {
473 continue;
474 }
475
476 if ( !layerId.isEmpty() && lf->provider()->layerId() != layerId )
477 continue;
478
479 context.expressionContext().setFeature( lf->feature() );
480 context.expressionContext().setFields( lf->feature().fields() );
481
482 QgsScopedRenderContextReferenceScaleOverride referenceScaleOverride( context, lf->provider()->layerReferenceScale() );
483 if ( lf->symbol() )
484 {
485 symbolScope = QgsExpressionContextUtils::updateSymbolScope( lf->symbol(), symbolScope );
486 }
487 lf->provider()->drawLabel( context, label );
488 // finished with symbol -- we can't keep it around after this, it may be deleted
489 lf->setSymbol( nullptr );
490 }
491
492 // draw unplaced labels. These are always rendered on top
494 {
495 for ( pal::LabelPosition *label : std::as_const( mUnlabeled ) )
496 {
497 if ( context.renderingStopped() )
498 break;
499 QgsLabelFeature *lf = label->getFeaturePart()->feature();
500 if ( !lf )
501 {
502 continue;
503 }
504
505 if ( !layerId.isEmpty() && lf->provider()->layerId() != layerId )
506 continue;
507
508 context.expressionContext().setFeature( lf->feature() );
509 context.expressionContext().setFields( lf->feature().fields() );
510
511 QgsScopedRenderContextReferenceScaleOverride referenceScaleOverride( context, lf->provider()->layerReferenceScale() );
512 if ( lf->symbol() )
513 {
514 symbolScope = QgsExpressionContextUtils::updateSymbolScope( lf->symbol(), symbolScope );
515 }
516 lf->provider()->drawUnplacedLabel( context, label );
517 // finished with symbol -- we can't keep it around after this, it may be deleted
518 lf->setSymbol( nullptr );
519 }
520 }
521
522 symbolScopePopper.reset();
523
524 // cleanup
525 for ( QgsAbstractLabelProvider *provider : std::as_const( mProviders ) )
526 {
527 if ( !layerId.isEmpty() && provider->layerId() != layerId )
528 continue;
529
530 provider->stopRender( context );
531 }
532
533 // Reset composition mode for further drawing operations
534 painter->setCompositionMode( QPainter::CompositionMode_SourceOver );
535
536 QgsDebugMsgLevel( QStringLiteral( "LABELING draw: %1 ms" ).arg( t.elapsed() ), 4 );
537}
538
540{
541 mUnlabeled.clear();
542 mLabels.clear();
543 mProblem.reset();
544 mPal.reset();
545}
546
548{
549 return mResults.release();
550}
551
552
553//
554// QgsDefaultLabelingEngine
555//
556
559{
560
561}
562
564{
565 registerLabels( context );
566 if ( context.renderingStopped() )
567 {
568 cleanup();
569 return; // it has been canceled
570 }
571
572 solve( context );
573 if ( context.renderingStopped() )
574 {
575 cleanup();
576 return;
577 }
578
579 drawLabels( context );
580 cleanup();
581}
582
583
584//
585// QgsStagedRenderLabelingEngine
586//
587
590{
591
592}
593
595{
596 registerLabels( context );
597 if ( context.renderingStopped() )
598 {
599 cleanup();
600 return; // it has been canceled
601 }
602
603 solve( context );
604 if ( context.renderingStopped() )
605 {
606 cleanup();
607 return;
608 }
609}
610
611
613{
614 drawLabels( context, layerId );
615}
616
618{
619 cleanup();
620}
621
622
624
626{
627 return mLayer ? mLayer->provider() : nullptr;
628
629}
630
632 : mLayerId( layer ? layer->id() : QString() )
633 , mLayer( layer )
634 , mProviderId( providerId )
635{
636 if ( QgsVectorLayer *vl = qobject_cast< QgsVectorLayer * >( layer ) )
637 {
638 mLayerExpressionContextScope.reset( vl->createExpressionContextScope() );
639 if ( const QgsFeatureRenderer *renderer = vl->renderer() )
640 mLayerReferenceScale = renderer->referenceScale();
641 }
642}
643
645{
646
647}
648
650{
651
652}
653
655{
656 const auto subproviders = subProviders();
657 for ( QgsAbstractLabelProvider *subProvider : subproviders )
658 {
659 subProvider->startRender( context );
660 }
661}
662
664{
665 const auto subproviders = subProviders();
666 for ( QgsAbstractLabelProvider *subProvider : subproviders )
667 {
668 subProvider->stopRender( context );
669 }
670}
671
673{
674 return mLayerExpressionContextScope.get();
675}
676
677//
678// QgsLabelingUtils
679//
680
681QString QgsLabelingUtils::encodePredefinedPositionOrder( const QVector<Qgis::LabelPredefinedPointPosition> &positions )
682{
683 QStringList predefinedOrderString;
684 const auto constPositions = positions;
685 for ( Qgis::LabelPredefinedPointPosition position : constPositions )
686 {
687 switch ( position )
688 {
690 predefinedOrderString << QStringLiteral( "TL" );
691 break;
693 predefinedOrderString << QStringLiteral( "TSL" );
694 break;
696 predefinedOrderString << QStringLiteral( "T" );
697 break;
699 predefinedOrderString << QStringLiteral( "TSR" );
700 break;
702 predefinedOrderString << QStringLiteral( "TR" );
703 break;
705 predefinedOrderString << QStringLiteral( "L" );
706 break;
708 predefinedOrderString << QStringLiteral( "R" );
709 break;
711 predefinedOrderString << QStringLiteral( "BL" );
712 break;
714 predefinedOrderString << QStringLiteral( "BSL" );
715 break;
717 predefinedOrderString << QStringLiteral( "B" );
718 break;
720 predefinedOrderString << QStringLiteral( "BSR" );
721 break;
723 predefinedOrderString << QStringLiteral( "BR" );
724 break;
725 }
726 }
727 return predefinedOrderString.join( ',' );
728}
729
730QVector<Qgis::LabelPredefinedPointPosition> QgsLabelingUtils::decodePredefinedPositionOrder( const QString &positionString )
731{
732 QVector<Qgis::LabelPredefinedPointPosition> result;
733 const QStringList predefinedOrderList = positionString.split( ',' );
734 result.reserve( predefinedOrderList.size() );
735 for ( const QString &position : predefinedOrderList )
736 {
737 QString cleaned = position.trimmed().toUpper();
738 if ( cleaned == QLatin1String( "TL" ) )
740 else if ( cleaned == QLatin1String( "TSL" ) )
742 else if ( cleaned == QLatin1String( "T" ) )
744 else if ( cleaned == QLatin1String( "TSR" ) )
746 else if ( cleaned == QLatin1String( "TR" ) )
748 else if ( cleaned == QLatin1String( "L" ) )
750 else if ( cleaned == QLatin1String( "R" ) )
752 else if ( cleaned == QLatin1String( "BL" ) )
754 else if ( cleaned == QLatin1String( "BSL" ) )
756 else if ( cleaned == QLatin1String( "B" ) )
758 else if ( cleaned == QLatin1String( "BSR" ) )
760 else if ( cleaned == QLatin1String( "BR" ) )
762 }
763 return result;
764}
765
766QString QgsLabelingUtils::encodeLinePlacementFlags( QgsLabeling::LinePlacementFlags flags )
767{
768 QStringList parts;
769 if ( flags & QgsLabeling::LinePlacementFlag::OnLine )
770 parts << QStringLiteral( "OL" );
771 if ( flags & QgsLabeling::LinePlacementFlag::AboveLine )
772 parts << QStringLiteral( "AL" );
773 if ( flags & QgsLabeling::LinePlacementFlag::BelowLine )
774 parts << QStringLiteral( "BL" );
775 if ( !( flags & QgsLabeling::LinePlacementFlag::MapOrientation ) )
776 parts << QStringLiteral( "LO" );
777 return parts.join( ',' );
778}
779
780QgsLabeling::LinePlacementFlags QgsLabelingUtils::decodeLinePlacementFlags( const QString &string )
781{
782 QgsLabeling::LinePlacementFlags flags = QgsLabeling::LinePlacementFlags();
783 const QStringList flagList = string.split( ',' );
784 bool foundLineOrientationFlag = false;
785 for ( const QString &flag : flagList )
786 {
787 QString cleaned = flag.trimmed().toUpper();
788 if ( cleaned == QLatin1String( "OL" ) )
789 flags |= QgsLabeling::LinePlacementFlag::OnLine;
790 else if ( cleaned == QLatin1String( "AL" ) )
791 flags |= QgsLabeling::LinePlacementFlag::AboveLine;
792 else if ( cleaned == QLatin1String( "BL" ) )
793 flags |= QgsLabeling::LinePlacementFlag::BelowLine;
794 else if ( cleaned == QLatin1String( "LO" ) )
795 foundLineOrientationFlag = true;
796 }
797 if ( !foundLineOrientationFlag )
798 flags |= QgsLabeling::LinePlacementFlag::MapOrientation;
799 return flags;
800}
LabelPredefinedPointPosition
Positions for labels when using the Qgis::LabelPlacement::OrderedPositionsAroundPoint placement mode.
Definition: qgis.h:583
@ MiddleLeft
Label on left of point.
@ TopRight
Label on top-right of point.
@ MiddleRight
Label on right of point.
@ TopSlightlyRight
Label on top of point, slightly right of center.
@ TopMiddle
Label directly above point.
@ BottomSlightlyLeft
Label below point, slightly left of center.
@ BottomRight
Label on bottom right of point.
@ BottomLeft
Label on bottom-left of point.
@ BottomSlightlyRight
Label below point, slightly right of center.
@ TopLeft
Label on top-left of point.
@ BottomMiddle
Label directly below point.
@ TopSlightlyLeft
Label on top of point, slightly left of center.
The QgsAbstractLabelProvider class is an interface class.
QgsExpressionContextScope * layerExpressionContextScope() const
Returns the expression context scope created from the layer associated with this provider.
virtual QList< QgsLabelFeature * > labelFeatures(QgsRenderContext &context)=0
Returns list of label features (they are owned by the provider and thus deleted on its destruction)
virtual void drawUnplacedLabel(QgsRenderContext &context, pal::LabelPosition *label) const
Draw an unplaced label.
virtual void stopRender(QgsRenderContext &context)
To be called after rendering is complete.
virtual QList< QgsAbstractLabelProvider * > subProviders()
Returns list of child providers - useful if the provider needs to put labels into more layers with di...
Qgis::LabelPlacement placement() const
What placement strategy to use for the labels.
void setEngine(const QgsLabelingEngine *engine)
Associate provider with a labeling engine (should be only called internally from QgsLabelingEngine)
virtual void drawLabel(QgsRenderContext &context, pal::LabelPosition *label) const =0
Draw this label at the position determined by the labeling engine.
double priority() const
Default priority of labels (may be overridden by individual labels)
virtual void drawLabelBackground(QgsRenderContext &context, pal::LabelPosition *label) const
Draw the background for the specified label.
QString name() const
Name of the layer (for statistics, debugging etc.) - does not need to be unique.
double layerReferenceScale() const
Returns the symbology reference scale of the layer associated with this provider.
QgsMapLayer * layer() const
Returns the associated layer, or nullptr if no layer is associated with the provider.
virtual void startRender(QgsRenderContext &context)
To be called before rendering of labels begins.
Flags flags() const
Flags associated with the provider.
QgsLabelObstacleSettings::ObstacleType obstacleType() const
How the feature geometries will work as obstacles.
@ MergeConnectedLines
Whether adjacent lines (with the same label text) should be merged.
@ DrawLabels
Whether the labels should be rendered.
@ CentroidMustBeInside
Whether location of centroid must be inside of polygons.
QString layerId() const
Returns ID of associated layer, or empty string if no layer is associated with the provider.
Qgis::UpsideDownLabelHandling upsidedownLabels() const
How to handle labels that would be upside down.
QgsAbstractLabelProvider(QgsMapLayer *layer, const QString &providerId=QString())
Construct the provider with default values.
QgsDefaultLabelingEngine()
Construct the labeling engine with default settings.
void run(QgsRenderContext &context) override
Runs the labeling job.
RAII class to pop scope from an expression context on destruction.
Single scope for storing variables and functions for use within a QgsExpressionContext.
static QgsExpressionContextScope * updateSymbolScope(const QgsSymbol *symbol, QgsExpressionContextScope *symbolScope=nullptr)
Updates a symbol scope related to a QgsSymbol to an expression context.
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
void setFields(const QgsFields &fields)
Convenience function for setting a fields for the context.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
QgsFields fields
Definition: qgsfeature.h:66
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
Definition: qgsfeature.cpp:170
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition: qgsfeedback.h:63
static QgsFillSymbol * createSimple(const QVariantMap &properties)
Create a fill symbol with one symbol layer: SimpleFill with specified properties.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:164
QgsGeometry difference(const QgsGeometry &geometry, const QgsGeometryParameters &parameters=QgsGeometryParameters()) const
Returns a geometry representing the points making up this geometry that do not make up other.
static QgsGeometry fromQPolygonF(const QPolygonF &polygon)
Construct geometry from a QPolygonF.
Q_GADGET bool isNull
Definition: qgsgeometry.h:166
static QgsGeometry fromRect(const QgsRectangle &rect) SIP_HOLDGIL
Creates a new geometry from a QgsRectangle.
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
Qgis::GeometryOperationResult rotate(double rotation, const QgsPointXY &center)
Rotate this geometry around the Z axis.
Label blocking region (in map coordinates and CRS).
The QgsLabelFeature class describes a feature that should be used within the labeling engine.
QSizeF size(double angle=0.0) const
Size of the label (in map units)
QgsAbstractLabelProvider * provider() const
Returns provider of this instance.
void setSymbol(const QgsSymbol *symbol)
Sets the feature symbol associated with this label.
pal::Layer * mLayer
Pointer to PAL layer (assigned when registered to PAL)
QgsFeature feature() const
Returns the original feature associated with this label.
double zIndex() const
Returns the label's z-index.
const QgsSymbol * symbol() const
Returns the feature symbol associated with this label.
Helper class for sorting labels into correct draw order.
QgsLabelSorter(const QgsMapSettings &mapSettings)
bool operator()(pal::LabelPosition *lp1, pal::LabelPosition *lp2) const
QgsFeedback subclass for granular reporting of labeling engine progress.
Stores global configuration for labeling engine.
bool testFlag(Flag f) const
Test whether a particular flag is enabled.
Flags flags() const
Gets flags of the labeling engine.
@ UseAllLabels
Whether to draw all labels even if there would be collisions.
@ UsePartialCandidates
Whether to use also label candidates that are partially outside of the map view.
@ CollectUnplacedLabels
Whether unplaced labels should be collected in the labeling results (regardless of whether they are b...
@ DrawUnplacedLabels
Whether to render unplaced labels as an indicator/warning for users.
@ DrawCandidates
Whether to draw rectangles of generated candidates (good for debugging)
PlacementEngineVersion placementVersion() const
Returns the placement engine version, which dictates how the label placement problem is solved.
double maximumPolygonCandidatesPerCmSquared() const
Returns the maximum number of polygon label candidate positions per centimeter squared.
double maximumLineCandidatesPerCm() const
Returns the maximum number of line label candidate positions per centimeter.
The QgsLabelingEngine class provides map labeling functionality.
std::unique_ptr< pal::Pal > mPal
std::unique_ptr< QgsLabelingResults > mResults
Resulting labeling layout.
QgsMapSettings mMapSettings
Associated map settings instance.
void solve(QgsRenderContext &context)
Solves the label problem.
QList< pal::LabelPosition * > mUnlabeled
std::unique_ptr< pal::Problem > mProblem
const QgsMapSettings & mapSettings() const
Gets associated map settings.
QList< pal::LabelPosition * > mLabels
QgsLabelingResults * takeResults()
Returns pointer to recently computed results and pass the ownership of results to the caller.
void cleanup()
Cleans up the engine following a call to registerLabels() or solve().
void setMapSettings(const QgsMapSettings &mapSettings)
Associate map settings instance.
void registerLabels(QgsRenderContext &context)
Runs the label registration step.
QList< QgsAbstractLabelProvider * > mSubProviders
void addProvider(QgsAbstractLabelProvider *provider)
Add provider of label features. Takes ownership of the provider.
void drawLabels(QgsRenderContext &context, const QString &layerId=QString())
Draws labels to the specified render context.
QStringList participatingLayerIds() const
Returns a list of layer IDs for layers with providers in the engine.
QList< QgsMapLayer * > participatingLayers() const
Returns a list of layers with providers in the engine.
void processProvider(QgsAbstractLabelProvider *provider, QgsRenderContext &context, pal::Pal &p)
QgsLabelingEngine()
Construct the labeling engine with default settings.
void removeProvider(QgsAbstractLabelProvider *provider)
Remove provider if the provider's initialization failed. Provider instance is deleted.
QList< QgsAbstractLabelProvider * > mProviders
List of providers (the are owned by the labeling engine)
virtual ~QgsLabelingEngine()
Clean up everything (especially the registered providers)
Class that stores computed placement from labeling engine.
static QString encodePredefinedPositionOrder(const QVector< Qgis::LabelPredefinedPointPosition > &positions)
Encodes an ordered list of predefined point label positions to a string.
static QString encodeLinePlacementFlags(QgsLabeling::LinePlacementFlags flags)
Encodes line placement flags to a string.
static QVector< Qgis::LabelPredefinedPointPosition > decodePredefinedPositionOrder(const QString &positionString)
Decodes a string to an ordered list of predefined point label positions.
static QgsLabeling::LinePlacementFlags decodeLinePlacementFlags(const QString &string)
Decodes a string to set of line placement flags.
Base class for all map layer types.
Definition: qgsmaplayer.h:73
The QgsMapSettings class contains configuration for rendering of the map.
const QgsLabelingEngineSettings & labelingEngineSettings() const
Returns the global configuration of the labeling engine.
QgsGeometry labelBoundaryGeometry() const
Returns the label boundary geometry, which restricts where in the rendered map labels are permitted t...
QStringList layerIds(bool expandGroupLayers=false) const
Returns the list of layer IDs which will be rendered in the map.
const QgsMapToPixel & mapToPixel() const
QList< QgsLabelBlockingRegion > labelBlockingRegions() const
Returns the list of regions to avoid placing labels within.
double extentBuffer() const
Returns the buffer in map units to use around the visible extent for rendering symbols whose correspo...
QgsRectangle visibleExtent() const
Returns the actual extent derived from requested extent that takes output image size into account.
double rotation() const
Returns the rotation of the resulting map image, in degrees clockwise.
QPolygonF visiblePolygonWithBuffer() const
Returns the visible area as a polygon (may be rotated) with extent buffer included.
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:39
void setMapRotation(double degrees, double cx, double cy)
Sets map rotation in degrees (clockwise).
static void drawLabelCandidateRect(pal::LabelPosition *lp, QPainter *painter, const QgsMapToPixel *xform, QList< QgsLabelCandidate > *candidates=nullptr)
A rectangle specified with double values.
Definition: qgsrectangle.h:42
void grow(double delta)
Grows the rectangle in place by the specified amount.
Definition: qgsrectangle.h:296
QgsPointXY center() const SIP_HOLDGIL
Returns the center point of the rectangle.
Definition: qgsrectangle.h:251
Contains information about the context of a rendering operation.
QPainter * painter()
Returns the destination QPainter for the render operation.
void setPainterFlagsUsingContext(QPainter *painter=nullptr) const
Sets relevant flags on a destination painter, using the flags and settings currently defined for the ...
QgsExpressionContext & expressionContext()
Gets the expression context.
QgsFeedback * feedback() const
Returns the feedback object that can be queried regularly during rendering to check if rendering shou...
double convertToMapUnits(double size, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale()) const
Converts a size from the specified units to map units.
bool renderingStopped() const
Returns true if the rendering operation has been stopped and any ongoing rendering should be canceled...
Scoped object for temporary override of the symbologyReferenceScale property of a QgsRenderContext.
void finalize()
Finalizes and cleans up the engine following the rendering of labels for the last layer to be labeled...
void run(QgsRenderContext &context) override
Runs the labeling job.
QgsStagedRenderLabelingEngine()
Construct the labeling engine with default settings.
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...
@ RenderMillimeters
Millimeters.
Definition: qgsunittypes.h:169
Represents a vector layer which manages a vector based data sets.
QgsLabelFeature * feature()
Returns the parent feature.
Definition: feature.h:94
LabelPosition is a candidate feature label position.
Definition: labelposition.h:56
FeaturePart * getFeaturePart() const
Returns the feature corresponding to this labelposition.
A set of features which influence the labeling process.
Definition: layer.h:63
void setUpsidedownLabels(Qgis::UpsideDownLabelHandling ud)
Sets how upside down labels will be handled within the layer.
Definition: layer.h:263
bool registerFeature(QgsLabelFeature *label)
Register a feature in the layer.
Definition: layer.cpp:79
QgsAbstractLabelProvider * provider() const
Returns pointer to the associated provider.
Definition: layer.h:157
void setObstacleType(QgsLabelObstacleSettings::ObstacleType obstacleType)
Sets the obstacle type, which controls how features within the layer act as obstacles for labels.
Definition: layer.h:228
void setMergeConnectedLines(bool merge)
Sets whether connected lines should be merged before labeling.
Definition: layer.h:250
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:278
Main Pal labeling class.
Definition: pal.h:80
Layer * addLayer(QgsAbstractLabelProvider *provider, const QString &layerName, Qgis::LabelPlacement arrangement, double defaultPriority, bool active, bool toLabel)
add a new layer
Definition: pal.cpp:80
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:2527
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39