QGIS API Documentation 3.41.0-Master (57ec4277f5e)
Loading...
Searching...
No Matches
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#include "moc_qgslabelingengine.cpp"
19
20#include "qgslogger.h"
21
22#include "feature.h"
23#include "labelposition.h"
24#include "layer.h"
25#include "pal.h"
26#include "problem.h"
27#include "qgsrendercontext.h"
28#include "qgsmaplayer.h"
29#include "qgssymbol.h"
32#include "qgslabelingresults.h"
33#include "qgsfillsymbol.h"
34#include "qgsruntimeprofiler.h"
36#include "qgstextlabelfeature.h"
37
38#include <QUuid>
39
40// helper function for checking for job cancellation within PAL
41static bool _palIsCanceled( void *ctx )
42{
43 return ( reinterpret_cast< QgsRenderContext * >( ctx ) )->renderingStopped();
44}
45
47
53class QgsLabelSorter
54{
55 public:
56
57 explicit QgsLabelSorter( const QStringList &layerRenderingOrderIds )
58 : mLayerRenderingOrderIds( layerRenderingOrderIds )
59 {}
60
61 bool operator()( pal::LabelPosition *lp1, pal::LabelPosition *lp2 ) const
62 {
63 QgsLabelFeature *lf1 = lp1->getFeaturePart()->feature();
64 QgsLabelFeature *lf2 = lp2->getFeaturePart()->feature();
65
66 if ( !qgsDoubleNear( lf1->zIndex(), lf2->zIndex() ) )
67 return lf1->zIndex() < lf2->zIndex();
68
69 //equal z-index, so fallback to respecting layer render order
70 int layer1Pos = mLayerRenderingOrderIds.indexOf( lf1->provider()->layerId() );
71 int layer2Pos = mLayerRenderingOrderIds.indexOf( lf2->provider()->layerId() );
72 if ( layer1Pos != layer2Pos && layer1Pos >= 0 && layer2Pos >= 0 )
73 return layer1Pos > layer2Pos; //higher positions are rendered first
74
75 //same layer, so render larger labels first
76 return lf1->size().width() * lf1->size().height() > lf2->size().width() * lf2->size().height();
77 }
78
79 private:
80
81 const QStringList mLayerRenderingOrderIds;
82};
83
85
86//
87// QgsLabelingEngine
88//
89
93
95{
96 qDeleteAll( mProviders );
97 qDeleteAll( mSubProviders );
98}
99
101{
103 mLayerRenderingOrderIds = mMapSettings.layerIds();
104 if ( mResults )
105 mResults->setMapSettings( mapSettings );
106}
107
109{
110 const QList<const QgsAbstractLabelingEngineRule *> rules = mMapSettings.labelingEngineSettings().rules();
111 bool res = true;
112 for ( const QgsAbstractLabelingEngineRule *rule : rules )
113 {
114 if ( !rule->active() || !rule->isAvailable() )
115 continue;
116
117 std::unique_ptr< QgsAbstractLabelingEngineRule > ruleClone( rule->clone() );
118 res = ruleClone->prepare( context ) && res;
119 mEngineRules.emplace_back( std::move( ruleClone ) );
120 }
121 return res;
122}
123
124QList< QgsMapLayer * > QgsLabelingEngine::participatingLayers() const
125{
126 QList< QgsMapLayer * > layers;
127
128 // try to return layers sorted in the desired z order for rendering
129 QList< QgsAbstractLabelProvider * > providersByZ = mProviders;
130 std::sort( providersByZ.begin(), providersByZ.end(),
131 []( const QgsAbstractLabelProvider * a, const QgsAbstractLabelProvider * b ) -> bool
132 {
133 const QgsVectorLayerLabelProvider *providerA = dynamic_cast<const QgsVectorLayerLabelProvider *>( a );
134 const QgsVectorLayerLabelProvider *providerB = dynamic_cast<const QgsVectorLayerLabelProvider *>( b );
135
136 if ( providerA && providerB )
137 {
138 return providerA->settings().zIndex < providerB->settings().zIndex ;
139 }
140 return false;
141 } );
142
143 QList< QgsAbstractLabelProvider * > subProvidersByZ = mSubProviders;
144 std::sort( subProvidersByZ.begin(), subProvidersByZ.end(),
145 []( const QgsAbstractLabelProvider * a, const QgsAbstractLabelProvider * b ) -> bool
146 {
147 const QgsVectorLayerLabelProvider *providerA = dynamic_cast<const QgsVectorLayerLabelProvider *>( a );
148 const QgsVectorLayerLabelProvider *providerB = dynamic_cast<const QgsVectorLayerLabelProvider *>( b );
149
150 if ( providerA && providerB )
151 {
152 return providerA->settings().zIndex < providerB->settings().zIndex ;
153 }
154 return false;
155 } );
156
157 for ( QgsAbstractLabelProvider *provider : std::as_const( providersByZ ) )
158 {
159 if ( provider->layer() && !layers.contains( provider->layer() ) )
160 layers << provider->layer();
161 }
162 for ( QgsAbstractLabelProvider *provider : std::as_const( subProvidersByZ ) )
163 {
164 if ( provider->layer() && !layers.contains( provider->layer() ) )
165 layers << provider->layer();
166 }
167 return layers;
168}
169
171{
172 QStringList layers;
173
174 // try to return layers sorted in the desired z order for rendering
175 QList< QgsAbstractLabelProvider * > providersByZ = mProviders;
176 std::sort( providersByZ.begin(), providersByZ.end(),
177 []( const QgsAbstractLabelProvider * a, const QgsAbstractLabelProvider * b ) -> bool
178 {
179 const QgsVectorLayerLabelProvider *providerA = dynamic_cast<const QgsVectorLayerLabelProvider *>( a );
180 const QgsVectorLayerLabelProvider *providerB = dynamic_cast<const QgsVectorLayerLabelProvider *>( b );
181
182 if ( providerA && providerB )
183 {
184 return providerA->settings().zIndex < providerB->settings().zIndex ;
185 }
186 return false;
187 } );
188
189 QList< QgsAbstractLabelProvider * > subProvidersByZ = mSubProviders;
190 std::sort( subProvidersByZ.begin(), subProvidersByZ.end(),
191 []( const QgsAbstractLabelProvider * a, const QgsAbstractLabelProvider * b ) -> bool
192 {
193 const QgsVectorLayerLabelProvider *providerA = dynamic_cast<const QgsVectorLayerLabelProvider *>( a );
194 const QgsVectorLayerLabelProvider *providerB = dynamic_cast<const QgsVectorLayerLabelProvider *>( b );
195
196 if ( providerA && providerB )
197 {
198 return providerA->settings().zIndex < providerB->settings().zIndex ;
199 }
200 return false;
201 } );
202
203 for ( QgsAbstractLabelProvider *provider : std::as_const( providersByZ ) )
204 {
205 if ( !layers.contains( provider->layerId() ) )
206 layers << provider->layerId();
207 }
208 for ( QgsAbstractLabelProvider *provider : std::as_const( subProvidersByZ ) )
209 {
210 if ( !layers.contains( provider->layerId() ) )
211 layers << provider->layerId();
212 }
213 return layers;
214}
215
217{
218 provider->setEngine( this );
219 mProviders << provider;
220 const QString id = QUuid::createUuid().toString( QUuid::WithoutBraces );
221 mProvidersById.insert( id, provider );
222 return id;
223}
224
226{
227 return mProvidersById.value( id );
228}
229
231{
232 int idx = mProviders.indexOf( provider );
233 if ( idx >= 0 )
234 {
235 mProvidersById.remove( mProvidersById.key( provider ) );
236 delete mProviders.takeAt( idx );
237 }
238}
239
241{
242 QgsAbstractLabelProvider::Flags flags = provider->flags();
243
244 // create the pal layer
245 pal::Layer *l = p.addLayer( provider,
246 provider->name(),
247 provider->placement(),
248 provider->priority(),
249 true,
250 flags.testFlag( QgsAbstractLabelProvider::DrawLabels ) );
251
252 // set whether adjacent lines should be merged
254
255 // set obstacle type
256 l->setObstacleType( provider->obstacleType() );
257
258 // set whether location of centroid must be inside of polygons
260
261 // set how to show upside-down labels
262 l->setUpsidedownLabels( provider->upsidedownLabels() );
263
264 const QList<QgsLabelFeature *> features = provider->labelFeatures( context );
265
266 for ( QgsLabelFeature *feature : features )
267 {
268 try
269 {
270 l->registerFeature( feature );
271 }
272 catch ( std::exception &e )
273 {
274 Q_UNUSED( e )
275 QgsDebugMsgLevel( QStringLiteral( "Ignoring feature %1 due PAL exception:" ).arg( feature->id() ) + QString::fromLatin1( e.what() ), 4 );
276 continue;
277 }
278 }
279
280 // any sub-providers?
281 const auto subproviders = provider->subProviders();
282 for ( QgsAbstractLabelProvider *subProvider : subproviders )
283 {
284 mSubProviders << subProvider;
285 processProvider( subProvider, context, p );
286 }
287}
288
290{
291 std::unique_ptr< QgsScopedRuntimeProfile > registeringProfile;
293 {
294 registeringProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr( "Registering labels" ), QStringLiteral( "rendering" ) );
295 }
296
297 QgsLabelingEngineFeedback *feedback = qobject_cast< QgsLabelingEngineFeedback * >( context.feedback() );
298
299 if ( feedback )
300 feedback->emit labelRegistrationAboutToBegin();
301
303
304 mPal = std::make_unique< pal::Pal >();
305
306 mPal->setMaximumLineCandidatesPerMapUnit( settings.maximumLineCandidatesPerCm() / context.convertToMapUnits( 10, Qgis::RenderUnit::Millimeters ) );
307 mPal->setMaximumPolygonCandidatesPerMapUnitSquared( settings.maximumPolygonCandidatesPerCmSquared() / std::pow( context.convertToMapUnits( 10, Qgis::RenderUnit::Millimeters ), 2 ) );
308
309 mPal->setShowPartialLabels( settings.testFlag( Qgis::LabelingFlag::UsePartialCandidates ) );
310 mPal->setPlacementVersion( settings.placementVersion() );
311
312 QList< QgsAbstractLabelingEngineRule * > rules;
313 rules.reserve( static_cast< int >( mEngineRules.size() ) );
314 for ( auto &it : mEngineRules )
315 {
316 rules.append( it.get() );
317 }
318 mPal->setRules( rules );
319
320 // for each provider: get labels and register them in PAL
321 const double step = !mProviders.empty() ? 100.0 / mProviders.size() : 1;
322 int index = 0;
323 for ( QgsAbstractLabelProvider *provider : std::as_const( mProviders ) )
324 {
325 if ( feedback )
326 {
327 feedback->emit providerRegistrationAboutToBegin( provider );
328 feedback->setProgress( index * step );
329 }
330 index++;
331 std::unique_ptr< QgsExpressionContextScopePopper > layerScopePopper;
332 if ( provider->layerExpressionContextScope() )
333 {
334 layerScopePopper = std::make_unique< QgsExpressionContextScopePopper >( context.expressionContext(), new QgsExpressionContextScope( *provider->layerExpressionContextScope() ) );
335 }
336 processProvider( provider, context, *mPal );
337 if ( feedback )
338 feedback->emit providerRegistrationFinished( provider );
339 }
340 if ( feedback )
341 feedback->emit labelRegistrationFinished();
342}
343
345{
346 Q_ASSERT( mPal.get() );
347
348 // NOW DO THE LAYOUT (from QgsPalLabeling::drawLabeling)
350
351 QPainter *painter = context.painter();
352
355 QgsGeometry extentGeom = QgsGeometry::fromRect( r1 );
356
357 QPolygonF visiblePoly = mMapSettings.visiblePolygonWithBuffer();
358 visiblePoly.append( visiblePoly.at( 0 ) ); //close polygon
359
360 // get map label boundary geometry - if one hasn't been explicitly set, we use the whole of the map's visible polygon
362
363 // label blocking regions work by "chopping away" those regions from the permissible labeling area
364 const QList< QgsLabelBlockingRegion > blockingRegions = mMapSettings.labelBlockingRegions();
365 for ( const QgsLabelBlockingRegion &region : blockingRegions )
366 {
367 mapBoundaryGeom = mapBoundaryGeom.difference( region.geometry );
368 }
369
370 if ( settings.flags() & Qgis::LabelingFlag::DrawCandidates )
371 {
372 // draw map boundary
373 QgsFeature f;
374 f.setGeometry( mapBoundaryGeom );
375 QVariantMap properties;
376 properties.insert( QStringLiteral( "style" ), QStringLiteral( "no" ) );
377 properties.insert( QStringLiteral( "style_border" ), QStringLiteral( "solid" ) );
378 properties.insert( QStringLiteral( "color_border" ), QStringLiteral( "#0000ff" ) );
379 properties.insert( QStringLiteral( "width_border" ), QStringLiteral( "0.3" ) );
380 properties.insert( QStringLiteral( "joinstyle" ), QStringLiteral( "miter" ) );
381 std::unique_ptr< QgsFillSymbol > boundarySymbol( QgsFillSymbol::createSimple( properties ) );
382 boundarySymbol->startRender( context );
383 boundarySymbol->renderFeature( f, context );
384 boundarySymbol->stopRender( context );
385 }
386
387 if ( !qgsDoubleNear( mMapSettings.rotation(), 0.0 ) )
388 {
389 //PAL features are prerotated, so extent also needs to be unrotated
391 // yes - this is rotated in the opposite direction... phew, this is confusing!
393 }
394
395 QgsRectangle extent = extentGeom.boundingBox();
396
397 mPal->registerCancellationCallback( &_palIsCanceled, reinterpret_cast< void * >( &context ) );
398
399 QElapsedTimer t;
400 t.start();
401
402 // do the labeling itself
403 try
404 {
405 mProblem = mPal->extractProblem( extent, mapBoundaryGeom, context );
406 }
407 catch ( std::exception &e )
408 {
409 Q_UNUSED( e )
410 QgsDebugMsgLevel( "PAL EXCEPTION :-( " + QString::fromLatin1( e.what() ), 4 );
411 return;
412 }
413
414 if ( context.renderingStopped() )
415 {
416 return; // it has been canceled
417 }
418
419#if 1 // XXX strk
420 // features are pre-rotated but not scaled/translated,
421 // so we only disable rotation here. Ideally, they'd be
422 // also pre-scaled/translated, as suggested here:
423 // https://github.com/qgis/QGIS/issues/20071
425 xform.setMapRotation( 0, 0, 0 );
426#else
427 const QgsMapToPixel &xform = mMapSettings->mapToPixel();
428#endif
429
430 // draw rectangles with all candidates
431 // this is done before actual solution of the problem
432 // before number of candidates gets reduced
433 // TODO mCandidates.clear();
435 {
436 painter->setBrush( Qt::NoBrush );
437 for ( int i = 0; i < static_cast< int >( mProblem->featureCount() ); i++ )
438 {
439 for ( int j = 0; j < mProblem->featureCandidateCount( i ); j++ )
440 {
441 pal::LabelPosition *lp = mProblem->featureCandidate( i, j );
442
443 drawLabelCandidateRect( lp, context, &xform );
444 }
445 }
446 }
447
448 // find the solution
449 mLabels = mPal->solveProblem( mProblem.get(), context,
453
454 // sort labels
455 std::sort( mLabels.begin(), mLabels.end(), QgsLabelSorter( mLayerRenderingOrderIds ) );
456
457 QgsDebugMsgLevel( QStringLiteral( "LABELING work: %1 ms ... labels# %2" ).arg( t.elapsed() ).arg( mLabels.size() ), 4 );
458}
459
460void QgsLabelingEngine::drawLabels( QgsRenderContext &context, const QString &layerId )
461{
462 QElapsedTimer t;
463 t.start();
464
465 std::unique_ptr< QgsScopedRuntimeProfile > drawingProfile;
467 {
468 drawingProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr( "Rendering labels" ), QStringLiteral( "rendering" ) );
469 }
470
472
474 QPainter *painter = context.painter();
475
476 // prepare for rendering
477 for ( QgsAbstractLabelProvider *provider : std::as_const( mProviders ) )
478 {
479 if ( !layerId.isEmpty() && provider->layerId() != layerId )
480 continue;
481
482 // provider will require the correct layer scope for expression preparation - at this stage, the existing expression context
483 // only contains generic scopes
484 QgsExpressionContextScopePopper popper( context.expressionContext(), provider->layerExpressionContextScope() ? new QgsExpressionContextScope( *provider->layerExpressionContextScope() ) : new QgsExpressionContextScope() );
485
486 QgsScopedRenderContextReferenceScaleOverride referenceScaleOverride( context, provider->layerReferenceScale() );
487 provider->startRender( context );
488 }
489
491 std::unique_ptr< QgsExpressionContextScopePopper > symbolScopePopper = std::make_unique< QgsExpressionContextScopePopper >( context.expressionContext(), symbolScope );
492
493 // draw label backgrounds
494 for ( pal::LabelPosition *label : std::as_const( mLabels ) )
495 {
496 if ( context.renderingStopped() )
497 break;
498
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
513 if ( lf->symbol() )
514 {
515 symbolScope = QgsExpressionContextUtils::updateSymbolScope( lf->symbol(), symbolScope );
516 }
517 lf->provider()->drawLabelBackground( context, label );
518 }
519
521 {
522 // features are pre-rotated but not scaled/translated,
523 // so we only disable rotation here. Ideally, they'd be
524 // also pre-scaled/translated, as suggested here:
525 // https://github.com/qgis/QGIS/issues/20071
526 QgsMapToPixel xform = context.mapToPixel();
527 xform.setMapRotation( 0, 0, 0 );
528
529 std::function<void( pal::LabelPosition * )> drawLabelRect;
530 drawLabelRect = [&xform, painter, &drawLabelRect]( pal::LabelPosition * label )
531 {
532 QPointF outPt = xform.transform( label->getX(), label->getY() ).toQPointF();
533
534 QgsPointXY outPt2 = xform.transform( label->getX() + label->getWidth(), label->getY() + label->getHeight() );
535 QRectF rect( 0, 0, outPt2.x() - outPt.x(), outPt2.y() - outPt.y() );
536 painter->save();
537 painter->setRenderHint( QPainter::Antialiasing, false );
538 painter->translate( QPointF( outPt.x(), outPt.y() ) );
539 painter->rotate( -label->getAlpha() * 180 / M_PI );
540
541 if ( label->conflictsWithObstacle() )
542 {
543 painter->setBrush( QColor( 255, 0, 0, 100 ) );
544 painter->setPen( QColor( 255, 0, 0, 150 ) );
545 }
546 else
547 {
548 painter->setBrush( QColor( 0, 255, 0, 100 ) );
549 painter->setPen( QColor( 0, 255, 0, 150 ) );
550 }
551
552 painter->drawRect( rect );
553 painter->restore();
554
555 if ( pal::LabelPosition *nextPart = label->nextPart() )
556 drawLabelRect( nextPart );
557 };
558
559 for ( pal::LabelPosition *label : std::as_const( mLabels ) )
560 {
561 drawLabelRect( label );
562 }
563
565 {
566 for ( pal::LabelPosition *label : std::as_const( mUnlabeled ) )
567 {
568 drawLabelRect( label );
569 }
570 }
571 }
572 else
573 {
575 {
576 // features are pre-rotated but not scaled/translated,
577 // so we only disable rotation here. Ideally, they'd be
578 // also pre-scaled/translated, as suggested here:
579 // https://github.com/qgis/QGIS/issues/20071
580 QgsMapToPixel xform = context.mapToPixel();
581 xform.setMapRotation( 0, 0, 0 );
582
583 std::function<void( pal::LabelPosition * )> drawLabelMetricsRecursive;
584 drawLabelMetricsRecursive = [&xform, &context, &drawLabelMetricsRecursive]( pal::LabelPosition * label )
585 {
586 QPointF outPt = xform.transform( label->getX(), label->getY() ).toQPointF();
587 QgsLabelingEngine::drawLabelMetrics( label, xform, context, outPt );
588 if ( pal::LabelPosition *nextPart = label->nextPart() )
589 drawLabelMetricsRecursive( nextPart );
590 };
591
592 for ( pal::LabelPosition *label : std::as_const( mLabels ) )
593 {
594 drawLabelMetricsRecursive( label );
595 }
596 }
597
598 // draw the labels
599 for ( pal::LabelPosition *label : std::as_const( mLabels ) )
600 {
601 if ( context.renderingStopped() )
602 break;
603
604 QgsLabelFeature *lf = label->getFeaturePart()->feature();
605 if ( !lf )
606 {
607 continue;
608 }
609
610 if ( !layerId.isEmpty() && lf->provider()->layerId() != layerId )
611 continue;
612
613 context.expressionContext().setFeature( lf->feature() );
614 context.expressionContext().setFields( lf->feature().fields() );
615
616 QgsScopedRenderContextReferenceScaleOverride referenceScaleOverride( context, lf->provider()->layerReferenceScale() );
617 if ( lf->symbol() )
618 {
619 symbolScope = QgsExpressionContextUtils::updateSymbolScope( lf->symbol(), symbolScope );
620 }
621 lf->provider()->drawLabel( context, label );
622 // finished with symbol -- we can't keep it around after this, it may be deleted
623 lf->setSymbol( nullptr );
624 }
625
626 // draw unplaced labels. These are always rendered on top
628 {
629 for ( pal::LabelPosition *label : std::as_const( mUnlabeled ) )
630 {
631 if ( context.renderingStopped() )
632 break;
633 QgsLabelFeature *lf = label->getFeaturePart()->feature();
634 if ( !lf )
635 {
636 continue;
637 }
638
639 if ( !layerId.isEmpty() && lf->provider()->layerId() != layerId )
640 continue;
641
642 context.expressionContext().setFeature( lf->feature() );
643 context.expressionContext().setFields( lf->feature().fields() );
644
645 QgsScopedRenderContextReferenceScaleOverride referenceScaleOverride( context, lf->provider()->layerReferenceScale() );
646 if ( lf->symbol() )
647 {
648 symbolScope = QgsExpressionContextUtils::updateSymbolScope( lf->symbol(), symbolScope );
649 }
650 lf->provider()->drawUnplacedLabel( context, label );
651 // finished with symbol -- we can't keep it around after this, it may be deleted
652 lf->setSymbol( nullptr );
653 }
654 }
655 }
656
657 symbolScopePopper.reset();
658
659 // cleanup
660 for ( QgsAbstractLabelProvider *provider : std::as_const( mProviders ) )
661 {
662 if ( !layerId.isEmpty() && provider->layerId() != layerId )
663 continue;
664
665 provider->stopRender( context );
666 }
667
668 // Reset composition mode for further drawing operations
669 painter->setCompositionMode( QPainter::CompositionMode_SourceOver );
670
671 QgsDebugMsgLevel( QStringLiteral( "LABELING draw: %1 ms" ).arg( t.elapsed() ), 4 );
672}
673
675{
676 mUnlabeled.clear();
677 mLabels.clear();
678 mProblem.reset();
679 mPal.reset();
680}
681
686
687void QgsLabelingEngine::drawLabelCandidateRect( pal::LabelPosition *lp, QgsRenderContext &context, const QgsMapToPixel *xform, QList<QgsLabelCandidate> *candidates )
688{
689 QPainter *painter = context.painter();
690 if ( !painter )
691 return;
692
693 QgsPointXY outPt = xform->transform( lp->getX(), lp->getY() );
694
695 painter->save();
696
697 QgsPointXY outPt2 = xform->transform( lp->getX() + lp->getWidth(), lp->getY() + lp->getHeight() );
698 QRectF rect( 0, 0, outPt2.x() - outPt.x(), outPt2.y() - outPt.y() );
699 painter->translate( QPointF( outPt.x(), outPt.y() ) );
700 painter->rotate( -lp->getAlpha() * 180 / M_PI );
701
702 if ( lp->conflictsWithObstacle() )
703 {
704 painter->setPen( QColor( 255, 0, 0, 64 ) );
705 }
706 else
707 {
708 painter->setPen( QColor( 0, 0, 0, 64 ) );
709 }
710 painter->drawRect( rect );
711 painter->restore();
712
713 // save the rect
714 rect.moveTo( outPt.x(), outPt.y() );
715 if ( candidates )
716 candidates->append( QgsLabelCandidate( rect, lp->cost() * 1000 ) );
717
718 // show all parts of the multipart label
719 if ( lp->nextPart() )
720 drawLabelCandidateRect( lp->nextPart(), context, xform, candidates );
721}
722
723void QgsLabelingEngine::drawLabelMetrics( pal::LabelPosition *label, const QgsMapToPixel &xform, QgsRenderContext &context, const QPointF &renderPoint )
724{
725 QPainter *painter = context.painter();
726 if ( !painter )
727 return;
728
729 QgsPointXY outPt2 = xform.transform( label->getX() + label->getWidth(), label->getY() + label->getHeight() );
730 QRectF rect( 0, 0, outPt2.x() - renderPoint.x(), outPt2.y() - renderPoint.y() );
731 painter->save();
732 painter->setRenderHint( QPainter::Antialiasing, false );
733 painter->translate( QPointF( renderPoint.x(), renderPoint.y() ) );
734 painter->rotate( -label->getAlpha() * 180 / M_PI );
735
736 painter->setBrush( Qt::NoBrush );
737 painter->setPen( QColor( 255, 0, 0, 220 ) );
738
739 painter->drawRect( rect );
740
741 painter->setPen( QColor( 0, 0, 0, 60 ) );
742 const QgsMargins &margins = label->getFeaturePart()->feature()->visualMargin();
743 if ( margins.top() > 0 )
744 {
745 const double topMargin = margins.top() / context.mapToPixel().mapUnitsPerPixel();
746 painter->drawLine( QPointF( rect.left(), rect.top() - topMargin ), QPointF( rect.right(), rect.top() - topMargin ) );
747 }
748 if ( margins.bottom() > 0 )
749 {
750 const double bottomMargin = margins.top() / context.mapToPixel().mapUnitsPerPixel();
751 painter->drawLine( QPointF( rect.left(), rect.bottom() + bottomMargin ), QPointF( rect.right(), rect.bottom() + bottomMargin ) );
752 }
753
754 const QRectF outerBounds = label->getFeaturePart()->feature()->outerBounds();
755 if ( !outerBounds.isNull() )
756 {
757 const QRectF mapOuterBounds = QRectF( label->getX() + outerBounds.left(),
758 label->getY() + outerBounds.top(),
759 outerBounds.width(), outerBounds.height() );
760
761 QgsPointXY outerBoundsPt1 = xform.transform( mapOuterBounds.left(), mapOuterBounds.top() );
762 QgsPointXY outerBoundsPt2 = xform.transform( mapOuterBounds.right(), mapOuterBounds.bottom() );
763
764 const QRectF outerBoundsPixel( outerBoundsPt1.x() - renderPoint.x(),
765 outerBoundsPt1.y() - renderPoint.y(),
766 outerBoundsPt2.x() - outerBoundsPt1.x(),
767 outerBoundsPt2.y() - outerBoundsPt1.y() );
768
769 QPen pen( QColor( 255, 0, 255, 140 ) );
770 pen.setCosmetic( true );
771 pen.setWidth( 1 );
772 painter->setPen( pen );
773 painter->drawRect( outerBoundsPixel );
774 }
775
776 if ( QgsTextLabelFeature *textFeature = dynamic_cast< QgsTextLabelFeature * >( label->getFeaturePart()->feature() ) )
777 {
778 const QgsTextDocumentMetrics &metrics = textFeature->documentMetrics();
779 const QgsTextDocument &document = textFeature->document();
780 const int blockCount = document.size();
781
782 double prevBlockBaseline = rect.bottom() - rect.top();
783 const double verticalAlignOffset = -metrics.blockVerticalMargin( document.size() - 1 );
784
785 // draw block baselines
786 for ( int blockIndex = 0; blockIndex < blockCount; ++blockIndex )
787 {
788 const double blockBaseLine = metrics.baselineOffset( blockIndex, Qgis::TextLayoutMode::Labeling );
789
790 const QgsTextBlock &block = document.at( blockIndex );
791 const int fragmentCount = block.size();
792 double left = metrics.blockLeftMargin( blockIndex );
793 for ( int fragmentIndex = 0; fragmentIndex < fragmentCount; ++fragmentIndex )
794 {
795 const double fragmentVerticalOffset = metrics.fragmentVerticalOffset( blockIndex, fragmentIndex, Qgis::TextLayoutMode::Labeling );
796 const double right = left + metrics.fragmentHorizontalAdvance( blockIndex, fragmentIndex, Qgis::TextLayoutMode::Labeling );
797
798 if ( fragmentIndex > 0 )
799 {
800 QPen pen( QColor( 0, 0, 255, 220 ) );
801 pen.setStyle( Qt::PenStyle::DashLine );
802
803 painter->setPen( pen );
804
805 painter->drawLine( QPointF( rect.left() + left, rect.top() + blockBaseLine + fragmentVerticalOffset + verticalAlignOffset ),
806 QPointF( rect.left() + left, rect.top() + prevBlockBaseline + verticalAlignOffset ) );
807
808 }
809
810 painter->setPen( QColor( 0, 0, 255, 220 ) );
811 painter->drawLine( QPointF( rect.left() + left, rect.top() + blockBaseLine + fragmentVerticalOffset + verticalAlignOffset ),
812 QPointF( rect.left() + right, rect.top() + blockBaseLine + fragmentVerticalOffset + verticalAlignOffset ) );
813 left = right;
814 }
815 prevBlockBaseline = blockBaseLine;
816 }
817 }
818
819 painter->restore();
820}
821
822
823//
824// QgsDefaultLabelingEngine
825//
826
832
834{
835 registerLabels( context );
836 if ( context.renderingStopped() )
837 {
838 cleanup();
839 return; // it has been canceled
840 }
841
842 solve( context );
843 if ( context.renderingStopped() )
844 {
845 cleanup();
846 return;
847 }
848
849 drawLabels( context );
850 cleanup();
851}
852
853
854//
855// QgsStagedRenderLabelingEngine
856//
857
863
865{
866 registerLabels( context );
867 if ( context.renderingStopped() )
868 {
869 cleanup();
870 return; // it has been canceled
871 }
872
873 solve( context );
874 if ( context.renderingStopped() )
875 {
876 cleanup();
877 return;
878 }
879}
880
881
883{
884 drawLabels( context, layerId );
885}
886
891
892
894
896{
897 return mLayer ? mLayer->provider() : nullptr;
898
899}
900
902 : mLayerId( layer ? layer->id() : QString() )
903 , mLayer( layer )
904 , mProviderId( providerId )
905{
906 if ( QgsVectorLayer *vl = qobject_cast< QgsVectorLayer * >( layer ) )
907 {
908 mLayerExpressionContextScope.reset( vl->createExpressionContextScope() );
909 if ( const QgsFeatureRenderer *renderer = vl->renderer() )
910 mLayerReferenceScale = renderer->referenceScale();
911 }
912}
913
918
923
925{
926 const auto subproviders = subProviders();
927 for ( QgsAbstractLabelProvider *subProvider : subproviders )
928 {
929 subProvider->startRender( context );
930 }
931}
932
934{
935 const auto subproviders = subProviders();
936 for ( QgsAbstractLabelProvider *subProvider : subproviders )
937 {
938 subProvider->stopRender( context );
939 }
940}
941
943{
944 return mLayerExpressionContextScope.get();
945}
946
947//
948// QgsLabelingUtils
949//
950
951QString QgsLabelingUtils::encodePredefinedPositionOrder( const QVector<Qgis::LabelPredefinedPointPosition> &positions )
952{
953 QStringList predefinedOrderString;
954 const auto constPositions = positions;
955 for ( Qgis::LabelPredefinedPointPosition position : constPositions )
956 {
957 switch ( position )
958 {
960 predefinedOrderString << QStringLiteral( "TL" );
961 break;
963 predefinedOrderString << QStringLiteral( "TSL" );
964 break;
966 predefinedOrderString << QStringLiteral( "T" );
967 break;
969 predefinedOrderString << QStringLiteral( "TSR" );
970 break;
972 predefinedOrderString << QStringLiteral( "TR" );
973 break;
975 predefinedOrderString << QStringLiteral( "L" );
976 break;
978 predefinedOrderString << QStringLiteral( "R" );
979 break;
981 predefinedOrderString << QStringLiteral( "BL" );
982 break;
984 predefinedOrderString << QStringLiteral( "BSL" );
985 break;
987 predefinedOrderString << QStringLiteral( "B" );
988 break;
990 predefinedOrderString << QStringLiteral( "BSR" );
991 break;
993 predefinedOrderString << QStringLiteral( "BR" );
994 break;
996 predefinedOrderString << QStringLiteral( "O" );
997 break;
998 }
999 }
1000 return predefinedOrderString.join( ',' );
1001}
1002
1003QVector<Qgis::LabelPredefinedPointPosition> QgsLabelingUtils::decodePredefinedPositionOrder( const QString &positionString )
1004{
1005 QVector<Qgis::LabelPredefinedPointPosition> result;
1006 const QStringList predefinedOrderList = positionString.split( ',' );
1007 result.reserve( predefinedOrderList.size() );
1008 for ( const QString &position : predefinedOrderList )
1009 {
1010 QString cleaned = position.trimmed().toUpper();
1011 if ( cleaned == QLatin1String( "TL" ) )
1013 else if ( cleaned == QLatin1String( "TSL" ) )
1015 else if ( cleaned == QLatin1String( "T" ) )
1017 else if ( cleaned == QLatin1String( "TSR" ) )
1019 else if ( cleaned == QLatin1String( "TR" ) )
1021 else if ( cleaned == QLatin1String( "L" ) )
1023 else if ( cleaned == QLatin1String( "R" ) )
1025 else if ( cleaned == QLatin1String( "BL" ) )
1027 else if ( cleaned == QLatin1String( "BSL" ) )
1029 else if ( cleaned == QLatin1String( "B" ) )
1031 else if ( cleaned == QLatin1String( "BSR" ) )
1033 else if ( cleaned == QLatin1String( "BR" ) )
1035 else if ( cleaned == QLatin1String( "O" ) )
1037 }
1038 return result;
1039}
1040
1042{
1043 QStringList parts;
1045 parts << QStringLiteral( "OL" );
1047 parts << QStringLiteral( "AL" );
1049 parts << QStringLiteral( "BL" );
1051 parts << QStringLiteral( "LO" );
1052 return parts.join( ',' );
1053}
1054
1056{
1058 const QStringList flagList = string.split( ',' );
1059 bool foundLineOrientationFlag = false;
1060 for ( const QString &flag : flagList )
1061 {
1062 QString cleaned = flag.trimmed().toUpper();
1063 if ( cleaned == QLatin1String( "OL" ) )
1065 else if ( cleaned == QLatin1String( "AL" ) )
1067 else if ( cleaned == QLatin1String( "BL" ) )
1069 else if ( cleaned == QLatin1String( "LO" ) )
1070 foundLineOrientationFlag = true;
1071 }
1072 if ( !foundLineOrientationFlag )
1074 return flags;
1075}
@ BelowLine
Labels can be placed below a line feature. Unless MapOrientation is also specified this mode respects...
@ MapOrientation
Signifies that the AboveLine and BelowLine flags should respect the map's orientation rather than the...
@ OnLine
Labels can be placed directly over a line feature.
@ AboveLine
Labels can be placed above a line feature. Unless MapOrientation is also specified this mode respects...
QFlags< LabelLinePlacementFlag > LabelLinePlacementFlags
Line placement flags, which control how candidates are generated for a linear feature.
Definition qgis.h:1221
@ Labeling
Labeling-specific layout mode.
@ DrawCandidates
Whether to draw rectangles of generated candidates (good for debugging)
@ CollectUnplacedLabels
Whether unplaced labels should be collected in the labeling results (regardless of whether they are b...
@ DrawLabelMetrics
Whether to render label metric guides (for debugging)
@ DrawUnplacedLabels
Whether to render unplaced labels as an indicator/warning for users.
@ UseAllLabels
Whether to draw all labels even if there would be collisions.
@ DrawLabelRectOnly
Whether to only draw the label rect and not the actual label text (used for unit tests)
@ UsePartialCandidates
Whether to use also label candidates that are partially outside of the map view.
@ Millimeters
Millimeters.
@ RecordProfile
Enable run-time profiling while rendering.
LabelPredefinedPointPosition
Positions for labels when using the Qgis::LabelPlacement::OrderedPositionsAroundPoint placement mode.
Definition qgis.h:1146
@ OverPoint
Label directly centered over point.
@ 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.
Abstract base class for labeling engine rules.
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.
Abstract base class for all 2D vector feature renderers.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition qgsfeature.h:58
QgsFields fields
Definition qgsfeature.h:68
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition qgsfeedback.h:61
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.
static QgsGeometry fromRect(const QgsRectangle &rect)
Creates a new geometry from a QgsRectangle.
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.
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).
Represents a label candidate.
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 QgsMargins & visualMargin() const
Returns the visual margin for the label feature.
QRectF outerBounds() const
Returns the extreme outer bounds of the label feature, including any surrounding content like borders...
const QgsSymbol * symbol() const
Returns the feature symbol associated with this label.
QgsFeedback subclass for granular reporting of labeling engine progress.
Stores global configuration for labeling engine.
Qgis::LabelPlacementEngineVersion placementVersion() const
Returns the placement engine version, which dictates how the label placement problem is solved.
bool testFlag(Qgis::LabelingFlag f) const
Test whether a particular flag is enabled.
Qgis::LabelingFlags flags() const
Gets flags of the labeling engine.
QList< QgsAbstractLabelingEngineRule * > rules()
Returns a list of labeling engine rules which must be satisfied while placing labels.
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
const QgsLabelingEngineSettings & engineSettings() const
Gets associated labeling engine settings.
std::unique_ptr< QgsLabelingResults > mResults
Resulting labeling layout.
QgsMapSettings mMapSettings
Associated map settings instance.
bool prepare(QgsRenderContext &context)
Prepares the engine for rendering in the specified context.
void solve(QgsRenderContext &context)
Solves the label problem.
QList< pal::LabelPosition * > mUnlabeled
std::vector< std::unique_ptr< QgsAbstractLabelingEngineRule > > mEngineRules
std::unique_ptr< pal::Problem > mProblem
QString addProvider(QgsAbstractLabelProvider *provider)
Adds a provider of label features.
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
List of labeling engine rules (owned by the labeling engine)
static void drawLabelCandidateRect(pal::LabelPosition *lp, QgsRenderContext &context, const QgsMapToPixel *xform, QList< QgsLabelCandidate > *candidates=nullptr)
Draws label candidate rectangles.
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)
QgsAbstractLabelProvider * providerById(const QString &id)
Returns the provider with matching id, where id corresponds to the value returned by the addProvider(...
QgsLabelingEngine()
Construct the labeling engine with default settings.
QHash< QString, QgsAbstractLabelProvider * > mProvidersById
void removeProvider(QgsAbstractLabelProvider *provider)
Remove provider if the provider's initialization failed. Provider instance is deleted.
static void drawLabelMetrics(pal::LabelPosition *label, const QgsMapToPixel &xform, QgsRenderContext &context, const QPointF &renderPoint)
Draws label metrics.
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 QVector< Qgis::LabelPredefinedPointPosition > decodePredefinedPositionOrder(const QString &positionString)
Decodes a string to an ordered list of predefined point label positions.
static Qgis::LabelLinePlacementFlags decodeLinePlacementFlags(const QString &string)
Decodes a string to set of line placement flags.
static QString encodeLinePlacementFlags(Qgis::LabelLinePlacementFlags flags)
Encodes line placement flags to a string.
Base class for all map layer types.
Definition qgsmaplayer.h:76
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.
void setMapRotation(double degrees, double cx, double cy)
Sets map rotation in degrees (clockwise).
double mapUnitsPerPixel() const
Returns the current map units per pixel.
QgsPointXY transform(const QgsPointXY &p) const
Transforms a point p from map (world) coordinates to device coordinates.
The QgsMargins class defines the four margins of a rectangle.
Definition qgsmargins.h:37
double top() const
Returns the top margin.
Definition qgsmargins.h:77
double bottom() const
Returns the bottom margin.
Definition qgsmargins.h:89
A class to represent a 2D point.
Definition qgspointxy.h:60
double y
Definition qgspointxy.h:64
double x
Definition qgspointxy.h:63
A rectangle specified with double values.
void grow(double delta)
Grows the rectangle in place by the specified amount.
QgsPointXY center
Contains information about the context of a rendering operation.
double convertToMapUnits(double size, Qgis::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale()) const
Converts a size from the specified units to map units.
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.
const QgsMapToPixel & mapToPixel() const
Returns the context's map to pixel transform, which transforms between map coordinates and device coo...
QgsFeedback * feedback() const
Returns the feedback object that can be queried regularly during rendering to check if rendering shou...
bool renderingStopped() const
Returns true if the rendering operation has been stopped and any ongoing rendering should be canceled...
Qgis::RenderContextFlags flags() const
Returns combination of flags used for rendering.
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...
Represents a block of text consisting of one or more QgsTextFragment objects.
int size() const
Returns the number of fragments in the block.
Contains pre-calculated metrics of a QgsTextDocument.
double fragmentVerticalOffset(int blockIndex, int fragmentIndex, Qgis::TextLayoutMode mode) const
Returns the vertical offset from a text block's baseline which should be applied to the fragment at t...
double baselineOffset(int blockIndex, Qgis::TextLayoutMode mode) const
Returns the offset from the top of the document to the text baseline for the given block index.
double blockLeftMargin(int blockIndex) const
Returns the margin for the left side of the specified block index.
double fragmentHorizontalAdvance(int blockIndex, int fragmentIndex, Qgis::TextLayoutMode mode) const
Returns the horizontal advance of the fragment at the specified block and fragment index.
double blockVerticalMargin(int blockIndex) const
Returns the vertical margin for the specified block index.
Represents a document consisting of one or more QgsTextBlock objects.
const QgsTextBlock & at(int index) const
Returns the block at the specified index.
int size() const
Returns the number of blocks in the document.
Class that adds extra information to QgsLabelFeature for text labels.
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.
double getAlpha() const
Returns the angle to rotate text (in radians).
double getHeight() const
double cost() const
Returns the candidate label position's geographical cost.
bool conflictsWithObstacle() const
Returns whether the position is marked as conflicting with an obstacle feature.
double getWidth() const
FeaturePart * getFeaturePart() const
Returns the feature corresponding to this labelposition.
double getX(int i=0) const
Returns the down-left x coordinate.
double getY(int i=0) const
Returns the down-left y coordinate.
LabelPosition * nextPart() const
Returns the next part of this label position (i.e.
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:83
Layer * addLayer(QgsAbstractLabelProvider *provider, const QString &layerName, Qgis::LabelPlacement arrangement, double defaultPriority, bool active, bool toLabel)
add a new layer
Definition pal.cpp:87
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition qgis.h:6066
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:39