QGIS API Documentation 4.3.0-Master (96c7fa699b4)
Loading...
Searching...
No Matches
qgsvectorlayerrenderer.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsvectorlayerrenderer.cpp
3 --------------------------------------
4 Date : December 2013
5 Copyright : (C) 2013 by Martin Dobias
6 Email : wonder dot sk at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
17
18#include "qgsapplication.h"
20#include "qgsexception.h"
24#include "qgslabelsink.h"
25#include "qgslogger.h"
26#include "qgsmapclippingutils.h"
27#include "qgsmessagelog.h"
28#include "qgspainteffect.h"
29#include "qgspainting.h"
30#include "qgspallabeling.h"
31#include "qgsrendercontext.h"
33#include "qgsrenderer.h"
34#include "qgsruntimeprofiler.h"
38#include "qgssymbol.h"
39#include "qgssymbollayer.h"
40#include "qgsthreadingutils.h"
41#include "qgsvectorlayer.h"
48
49#include <QPicture>
50#include <QString>
51#include <QThread>
52#include <QTimer>
53
54using namespace Qt::StringLiterals;
55
57 : QgsMapLayerRenderer( layer->id(), &context )
58 , mFeedback( std::make_unique< QgsFeedback >() )
59 , mLayer( layer )
60 , mLayerName( layer->name() )
61 , mFields( layer->fields() )
62 , mSource( std::make_unique< QgsVectorLayerFeatureSource >( layer ) )
63 , mNoSetLayerExpressionContext( layer->customProperty( u"_noset_layer_expression_context"_s ).toBool() )
64 , mEnableProfile( context.flags() & Qgis::RenderContextFlag::RecordProfile )
65{
66 QElapsedTimer timer;
67 timer.start();
68 std::unique_ptr< QgsFeatureRenderer > mainRenderer( layer->renderer() ? layer->renderer()->clone() : nullptr );
69
70 QgsVectorLayerSelectionProperties *selectionProperties = qobject_cast< QgsVectorLayerSelectionProperties * >( layer->selectionProperties() );
71 switch ( selectionProperties->selectionRenderingMode() )
72 {
74 break;
75
77 {
78 // overwrite default selection color if layer has a specific selection color set
79 const QColor layerSelectionColor = selectionProperties->selectionColor();
80 if ( layerSelectionColor.isValid() )
81 context.setSelectionColor( layerSelectionColor );
82 break;
83 }
84
86 {
87 if ( QgsSymbol *selectionSymbol = qobject_cast< QgsVectorLayerSelectionProperties * >( layer->selectionProperties() )->selectionSymbol() )
88 mSelectionSymbol.reset( selectionSymbol->clone() );
89 break;
90 }
91 }
92
93 if ( !mainRenderer )
94 return;
95
96 QList< const QgsFeatureRendererGenerator * > generators = layer->featureRendererGenerators();
97 std::sort( generators.begin(), generators.end(), []( const QgsFeatureRendererGenerator *g1, const QgsFeatureRendererGenerator *g2 ) { return g1->level() < g2->level(); } );
98
99 bool insertedMainRenderer = false;
100 double prevLevel = std::numeric_limits< double >::lowest();
101 // cppcheck-suppress danglingLifetime
102 mRenderer = mainRenderer.get();
103 for ( const QgsFeatureRendererGenerator *generator : std::as_const( generators ) )
104 {
105 if ( generator->level() >= 0 && prevLevel < 0 && !insertedMainRenderer )
106 {
107 // insert main renderer when level changes from <0 to >0
108 mRenderers.emplace_back( std::move( mainRenderer ) );
109 insertedMainRenderer = true;
110 }
111 mRenderers.emplace_back( generator->createRenderer() );
112 prevLevel = generator->level();
113 }
114 // cppcheck-suppress accessMoved
115 if ( mainRenderer )
116 {
117 // cppcheck-suppress accessMoved
118 mRenderers.emplace_back( std::move( mainRenderer ) );
119 }
120
121 mSelectedFeatureIds = layer->selectedFeatureIds();
122
123 mDrawVertexMarkers = nullptr != layer->editBuffer();
124
125 mGeometryType = layer->geometryType();
126
127 mFeatureBlendMode = layer->featureBlendMode();
128
129 if ( context.isTemporal() )
130 {
131 QgsVectorLayerTemporalContext temporalContext;
132 temporalContext.setLayer( layer );
133 mTemporalFilter = qobject_cast< const QgsVectorLayerTemporalProperties * >( layer->temporalProperties() )->createFilterString( temporalContext, context.temporalRange() );
134 QgsDebugMsgLevel( "Rendering with Temporal Filter: " + mTemporalFilter, 2 );
135 }
136
137 // if there's already a simplification method specified via the context, we respect that. Otherwise, we fall back
138 // to the layer's individual setting
140 {
141 mSimplifyMethod = renderContext()->vectorSimplifyMethod();
144 }
145 else
146 {
147 mSimplifyMethod = layer->simplifyMethod();
149 }
150
151 mVertexMarkerOnlyForSelection = QgsSettingsRegistryCore::settingsDigitizingMarkerOnlyForSelected->value();
152
153 QString markerTypeString = QgsSettingsRegistryCore::settingsDigitizingMarkerStyle->value();
154 if ( markerTypeString == "Cross"_L1 )
155 {
156 mVertexMarkerStyle = Qgis::VertexMarkerType::Cross;
157 }
158 else if ( markerTypeString == "SemiTransparentCircle"_L1 )
159 {
161 }
162 else
163 {
164 mVertexMarkerStyle = Qgis::VertexMarkerType::NoMarker;
165 }
166
168
169 // cppcheck-suppress danglingLifetime
170 QgsDebugMsgLevel( "rendering v2:\n " + mRenderer->dump(), 2 );
171
172 if ( mDrawVertexMarkers )
173 {
174 // set editing vertex markers style (main renderer only)
175 mRenderer->setVertexMarkerAppearance( mVertexMarkerStyle, mVertexMarkerSize );
176 }
177
178 for ( const std::unique_ptr< QgsFeatureRenderer > &renderer : mRenderers )
179 {
180 mAttrNames.unite( renderer->usedAttributes( context ) );
181 }
182 if ( context.hasRenderedFeatureHandlers() )
183 {
184 const QList< QgsRenderedFeatureHandlerInterface * > handlers = context.renderedFeatureHandlers();
185 for ( QgsRenderedFeatureHandlerInterface *handler : handlers )
186 mAttrNames.unite( handler->usedAttributes( layer, context ) );
187 }
188
189 //register label and diagram layer to the labeling engine
190 prepareLabeling( layer, mAttrNames );
191 prepareDiagrams( layer, mAttrNames );
192
193 mClippingRegions = QgsMapClippingUtils::collectClippingRegionsForLayer( context, layer );
194
195 if ( std::any_of( mRenderers.begin(), mRenderers.end(), []( const auto &renderer ) { return renderer->forceRasterRender(); } ) )
196 {
197 //raster rendering is forced for this layer
198 mForceRasterRender = true;
199 }
200
201 const bool allowFlattening = context.rasterizedRenderingPolicy() != Qgis::RasterizedRenderingPolicy::ForceVector;
202 if ( allowFlattening
203 && ( ( layer->blendMode() != QPainter::CompositionMode_SourceOver ) || ( layer->featureBlendMode() != QPainter::CompositionMode_SourceOver ) || ( !qgsDoubleNear( layer->opacity(), 1.0 ) ) ) )
204 {
205 //layer properties require rasterization
206 mForceRasterRender = true;
207 }
208
209 mReadyToCompose = false;
210 mPreparationTime = timer.elapsed();
211}
212
214
216{
217 mRenderTimeHint = time;
218}
219
221{
222 return mFeedback.get();
223}
224
226{
227 return mForceRasterRender;
228}
229
231{
233 if ( mRenderer && mRenderer->flags().testFlag( Qgis::FeatureRendererFlag::AffectsLabeling ) )
235 return res;
236}
237
239{
240 QgsScopedThreadName threadName( u"render:%1"_s.arg( mLayerName ) );
241
242 if ( mGeometryType == Qgis::GeometryType::Null || mGeometryType == Qgis::GeometryType::Unknown )
243 {
244 mReadyToCompose = true;
245 return true;
246 }
247
248 if ( mRenderers.empty() )
249 {
250 mReadyToCompose = true;
251 mErrors.append( QObject::tr( "No renderer for drawing." ) );
252 return false;
253 }
254
255 std::unique_ptr< QgsScopedRuntimeProfile > profile;
256 if ( mEnableProfile )
257 {
258 profile = std::make_unique< QgsScopedRuntimeProfile >( mLayerName, u"rendering"_s, layerId() );
259 if ( mPreparationTime > 0 )
260 QgsApplication::profiler()->record( QObject::tr( "Create renderer" ), mPreparationTime / 1000.0, u"rendering"_s );
261 }
262
263 // if the previous layer render was relatively quick (e.g. less than 3 seconds), the we show any previously
264 // cached version of the layer during rendering instead of the usual progressive updates
265 if ( mRenderTimeHint > 0 && mRenderTimeHint <= MAX_TIME_TO_USE_CACHED_PREVIEW_IMAGE )
266 {
267 mBlockRenderUpdates = true;
268 mElapsedTimer.start();
269 }
270
271 bool res = true;
272 int rendererIndex = 0;
273 for ( const std::unique_ptr< QgsFeatureRenderer > &renderer : mRenderers )
274 {
275 if ( mFeedback->isCanceled() || !res )
276 {
277 break;
278 }
279 res = renderInternal( renderer.get(), rendererIndex++ ) && res;
280 }
281
282 mReadyToCompose = true;
283 return res && !renderContext()->renderingStopped();
284}
285
286bool QgsVectorLayerRenderer::renderInternal( QgsFeatureRenderer *renderer, int rendererIndex )
287{
288 const bool isMainRenderer = renderer == mRenderer;
289
290 QgsRenderContext &context = *renderContext();
291 context.setSymbologyReferenceScale( renderer->referenceScale() );
292
293 if ( renderer->type() == "nullSymbol"_L1 )
294 {
295 // a little shortcut for the null symbol renderer - most of the time it is not going to render anything
296 // so we can even skip the whole loop to fetch features
297 if ( !isMainRenderer || ( !mDrawVertexMarkers && !mLabelProvider && !mDiagramProvider && mSelectedFeatureIds.isEmpty() ) )
298 return true;
299 }
300
301 std::unique_ptr< QgsScopedRuntimeProfile > preparingProfile;
302 if ( mEnableProfile )
303 {
304 QString title;
305 if ( mRenderers.size() > 1 )
306 title = QObject::tr( "Preparing render %1" ).arg( rendererIndex + 1 );
307 else
308 title = QObject::tr( "Preparing render" );
309 preparingProfile = std::make_unique< QgsScopedRuntimeProfile >( title, u"rendering"_s );
310 }
311
312 QgsScopedQPainterState painterState( context.painter() );
313
314 bool usingEffect = false;
315 if ( renderer->paintEffect() && renderer->paintEffect()->enabled() )
316 {
317 usingEffect = true;
318 renderer->paintEffect()->begin( context );
319 }
320
321 // Per feature blending mode
322 if ( context.rasterizedRenderingPolicy() != Qgis::RasterizedRenderingPolicy::ForceVector && mFeatureBlendMode != QPainter::CompositionMode_SourceOver )
323 {
324 // set the painter to the feature blend mode, so that features drawn
325 // on this layer will interact and blend with each other
326 context.painter()->setCompositionMode( mFeatureBlendMode );
327 }
328
329 renderer->startRender( context, mFields );
330
331 if ( renderer->canSkipRender() )
332 {
333 // nothing to draw for now...
334 renderer->stopRender( context );
335 return true;
336 }
337
338 QString rendererFilter = renderer->filter( mFields );
339
340 QgsRectangle requestExtent = context.extent();
341 if ( !mClippingRegions.empty() )
342 {
343 mClipFilterGeom = QgsMapClippingUtils::calculateFeatureRequestGeometry( mClippingRegions, context, mApplyClipFilter );
344 requestExtent = requestExtent.intersect( mClipFilterGeom.boundingBox() );
345
346 mClipFeatureGeom = QgsMapClippingUtils::calculateFeatureIntersectionGeometry( mClippingRegions, context, mApplyClipGeometries );
347
348 bool needsPainterClipPath = false;
349 const QPainterPath path = QgsMapClippingUtils::calculatePainterClipRegion( mClippingRegions, context, Qgis::LayerType::Vector, needsPainterClipPath );
350 if ( needsPainterClipPath )
351 context.painter()->setClipPath( path, Qt::IntersectClip );
352
353 mLabelClipFeatureGeom = QgsMapClippingUtils::calculateLabelIntersectionGeometry( mClippingRegions, context, mApplyLabelClipGeometries );
354
355 if ( mDiagramProvider )
356 mDiagramProvider->setClipFeatureGeometry( mLabelClipFeatureGeom );
357 }
358
359 renderer->modifyRequestExtent( requestExtent, context );
360
361 QgsFeatureRequest featureRequest = QgsFeatureRequest().setFilterRect( requestExtent ).setSubsetOfAttributes( mAttrNames, mFields ).setExpressionContext( context.expressionContext() );
362 if ( renderer->orderByEnabled() )
363 {
364 featureRequest.setOrderBy( renderer->orderBy() );
365 }
366
367 const QgsFeatureFilterProvider *featureFilterProvider = context.featureFilterProvider();
368 if ( featureFilterProvider )
369 {
371 if ( featureFilterProvider->isFilterThreadSafe() )
372 {
373 featureFilterProvider->filterFeatures( layerId(), featureRequest );
374 }
375 else
376 {
377 featureFilterProvider->filterFeatures( mLayer, featureRequest );
378 }
380 }
381 if ( !rendererFilter.isEmpty() && rendererFilter != "TRUE"_L1 )
382 {
383 featureRequest.combineFilterExpression( rendererFilter );
384 }
385 if ( !mTemporalFilter.isEmpty() )
386 {
387 featureRequest.combineFilterExpression( mTemporalFilter );
388 }
389
390 if ( renderer->usesEmbeddedSymbols() )
391 {
392 featureRequest.setFlags( featureRequest.flags() | Qgis::FeatureRequestFlag::EmbeddedSymbols );
393 }
394
395 // enable the simplification of the geometries (Using the current map2pixel context) before send it to renderer engine.
396 if ( mSimplifyGeometry )
397 {
398 double map2pixelTol = mSimplifyMethod.threshold();
399 bool validTransform = true;
400
401 const QgsMapToPixel &mtp = context.mapToPixel();
402 map2pixelTol *= mtp.mapUnitsPerPixel();
403 const QgsCoordinateTransform ct = context.coordinateTransform();
404
405 // resize the tolerance using the change of size of an 1-BBOX from the source CoordinateSystem to the target CoordinateSystem
406 if ( ct.isValid() && !ct.isShortCircuited() )
407 {
408 try
409 {
410 QgsCoordinateTransform toleranceTransform = ct;
411 QgsPointXY center = context.extent().center();
412 double rectSize = toleranceTransform.sourceCrs().mapUnits() == Qgis::DistanceUnit::Degrees ? 0.0008983 /* ~100/(40075014/360=111319.4833) */ : 100;
413
414 QgsRectangle sourceRect = QgsRectangle( center.x(), center.y(), center.x() + rectSize, center.y() + rectSize );
415 toleranceTransform.setBallparkTransformsAreAppropriate( true );
416 QgsRectangle targetRect = toleranceTransform.transform( sourceRect );
417
418 QgsDebugMsgLevel( u"Simplify - SourceTransformRect=%1"_s.arg( sourceRect.toString( 16 ) ), 4 );
419 QgsDebugMsgLevel( u"Simplify - TargetTransformRect=%1"_s.arg( targetRect.toString( 16 ) ), 4 );
420
421 if ( !sourceRect.isEmpty() && sourceRect.isFinite() && !targetRect.isEmpty() && targetRect.isFinite() )
422 {
423 QgsPointXY minimumSrcPoint( sourceRect.xMinimum(), sourceRect.yMinimum() );
424 QgsPointXY maximumSrcPoint( sourceRect.xMaximum(), sourceRect.yMaximum() );
425 QgsPointXY minimumDstPoint( targetRect.xMinimum(), targetRect.yMinimum() );
426 QgsPointXY maximumDstPoint( targetRect.xMaximum(), targetRect.yMaximum() );
427
428 double sourceHypothenuse = std::sqrt( minimumSrcPoint.sqrDist( maximumSrcPoint ) );
429 double targetHypothenuse = std::sqrt( minimumDstPoint.sqrDist( maximumDstPoint ) );
430
431 QgsDebugMsgLevel( u"Simplify - SourceHypothenuse=%1"_s.arg( sourceHypothenuse ), 4 );
432 QgsDebugMsgLevel( u"Simplify - TargetHypothenuse=%1"_s.arg( targetHypothenuse ), 4 );
433
434 if ( !qgsDoubleNear( targetHypothenuse, 0.0 ) )
435 map2pixelTol *= ( sourceHypothenuse / targetHypothenuse );
436 }
437 }
438 catch ( QgsCsException &cse )
439 {
440 QgsMessageLog::logMessage( QObject::tr( "Simplify transform error caught: %1" ).arg( cse.what() ), QObject::tr( "CRS" ) );
441 validTransform = false;
442 }
443 }
444
445 if ( validTransform )
446 {
447 QgsSimplifyMethod simplifyMethod;
449 simplifyMethod.setTolerance( map2pixelTol );
450 simplifyMethod.setThreshold( mSimplifyMethod.threshold() );
451 simplifyMethod.setForceLocalOptimization( mSimplifyMethod.forceLocalOptimization() );
452 featureRequest.setSimplifyMethod( simplifyMethod );
453
454 QgsVectorSimplifyMethod vectorMethod = mSimplifyMethod;
455 vectorMethod.setTolerance( map2pixelTol );
456 context.setVectorSimplifyMethod( vectorMethod );
457 }
458 else
459 {
460 QgsVectorSimplifyMethod vectorMethod;
462 context.setVectorSimplifyMethod( vectorMethod );
463 }
464 }
465 else
466 {
467 QgsVectorSimplifyMethod vectorMethod;
469 context.setVectorSimplifyMethod( vectorMethod );
470 }
471
472 featureRequest.setFeedback( mFeedback.get() );
473 // also set the interruption checker for the expression context, in case the renderer uses some complex expression
474 // which could benefit from early exit paths...
475 context.expressionContext().setFeedback( mFeedback.get() );
476
477 std::unique_ptr< QgsScopedRuntimeProfile > preparingFeatureItProfile;
478 if ( mEnableProfile )
479 {
480 preparingFeatureItProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr( "Prepare feature iteration" ), u"rendering"_s );
481 }
482
483 QgsFeatureIterator fit = mSource->getFeatures( featureRequest );
484 // Attach an interruption checker so that iterators that have potentially
485 // slow fetchFeature() implementations, such as in the WFS provider, can
486 // check it, instead of relying on just the mContext.renderingStopped() check
487 // in drawRenderer()
488
489 fit.setInterruptionChecker( mFeedback.get() );
490
491 preparingFeatureItProfile.reset();
492 preparingProfile.reset();
493
494 std::unique_ptr< QgsScopedRuntimeProfile > renderingProfile;
495 if ( mEnableProfile )
496 {
497 renderingProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr( "Rendering" ), u"rendering"_s );
498 }
499
500 if ( ( renderer->capabilities() & QgsFeatureRenderer::SymbolLevels ) && renderer->usingSymbolLevels() )
501 drawRendererLevels( renderer, fit );
502 else
503 drawRenderer( renderer, fit );
504
505 if ( !fit.isValid() )
506 {
507 mErrors.append( u"Data source invalid"_s );
508 }
509
510 if ( usingEffect )
511 {
512 renderer->paintEffect()->end( context );
513 }
514
515 context.expressionContext().setFeedback( nullptr );
516 return true;
517}
518
519static QgsGeometry combinedClipGeometry( const QgsGeometry &geom1, const QgsGeometry &geom2 )
520{
521 if ( geom1.isEmpty() )
522 return geom2;
523
524 if ( geom2.isEmpty() )
525 return geom1;
526
527 return geom1.intersection( geom2 );
528}
529
530static std::unique_ptr< QgsGeometryEngine > prepareClipGeometry( bool applyClipFilter, const QgsGeometry &clipFilterGeom, const QgsGeometry &horizonGeom )
531{
532 std::unique_ptr< QgsGeometryEngine > clipEngine;
533 if ( applyClipFilter && !horizonGeom.isEmpty() )
534 {
535 const QgsGeometry visibleRegionGeom = clipFilterGeom.intersection( horizonGeom );
536 clipEngine.reset( QgsGeometry::createGeometryEngine( visibleRegionGeom.constGet() ) );
537 clipEngine->prepareGeometry();
538 }
539 else if ( applyClipFilter && horizonGeom.isEmpty() )
540 {
541 clipEngine.reset( QgsGeometry::createGeometryEngine( clipFilterGeom.constGet() ) );
542 clipEngine->prepareGeometry();
543 }
544 else if ( !applyClipFilter && !horizonGeom.isEmpty() )
545 {
546 clipEngine.reset( QgsGeometry::createGeometryEngine( horizonGeom.constGet() ) );
547 clipEngine->prepareGeometry();
548 }
549 return clipEngine;
550}
551
552void QgsVectorLayerRenderer::drawRenderer( QgsFeatureRenderer *renderer, QgsFeatureIterator &fit )
553{
554 QElapsedTimer timer;
555 timer.start();
556 quint64 totalLabelTime = 0;
557
558 const bool isMainRenderer = renderer == mRenderer;
559
560 QgsExpressionContextScope *symbolScope = QgsExpressionContextUtils::updateSymbolScope( nullptr, new QgsExpressionContextScope() );
561 QgsRenderContext &context = *renderContext();
562 context.expressionContext().appendScope( symbolScope );
563
564 if ( mSelectionSymbol && isMainRenderer )
565 mSelectionSymbol->startRender( context, mFields );
566
567 QgsGeometry horizonGeom;
568 double lat, lon;
569 if ( context.coordinateTransform().destinationCrs().topocentricOrigin( lat, lon ) )
570 {
572 }
573
574 std::unique_ptr< QgsGeometryEngine > clipEngine = prepareClipGeometry( mApplyClipFilter, mClipFilterGeom, horizonGeom );
575
576 const QgsGeometry renderClipGeom = combinedClipGeometry( mApplyClipGeometries ? mClipFeatureGeom : QgsGeometry(), horizonGeom );
577 const QgsGeometry labelClipGeom = combinedClipGeometry( mApplyLabelClipGeometries ? mLabelClipFeatureGeom : QgsGeometry(), horizonGeom );
578
579 QgsFeature fet;
580 while ( fit.nextFeature( fet ) )
581 {
582 try
583 {
584 if ( context.renderingStopped() )
585 {
586 QgsDebugMsgLevel( u"Drawing of vector layer %1 canceled."_s.arg( layerId() ), 2 );
587 break;
588 }
589
590 if ( !fet.hasGeometry() || fet.geometry().isEmpty() )
591 continue;
592
593 if ( clipEngine && !clipEngine->intersects( fet.geometry().constGet() ) )
594 continue; // skip features outside of clipping region
595
596 if ( !renderClipGeom.isEmpty() )
597 context.setFeatureClipGeometry( renderClipGeom );
598
599 if ( !mNoSetLayerExpressionContext )
600 context.expressionContext().setFeature( fet );
601
602 const bool featureIsSelected = isMainRenderer && context.showSelection() && mSelectedFeatureIds.contains( fet.id() );
603 bool drawMarker = isMainRenderer && ( mDrawVertexMarkers && context.drawEditingInformation() && ( !mVertexMarkerOnlyForSelection || featureIsSelected ) );
604
605 // render feature
606 bool rendered = false;
608 {
609 if ( featureIsSelected && mSelectionSymbol )
610 {
611 // note: here we pass "false" for the selected argument, as we don't want to change
612 // the user's defined selection symbol colors or settings in any way
613 mSelectionSymbol->renderFeature( fet, context, -1, false, drawMarker );
614 rendered = renderer->willRenderFeature( fet, context );
615 }
616 else
617 {
618 rendered = renderer->renderFeature( fet, context, -1, featureIsSelected, drawMarker );
619 }
620 }
621 else
622 {
623 rendered = renderer->willRenderFeature( fet, context );
624 }
625
626 // labeling - register feature
627 if ( rendered )
628 {
629 // as soon as first feature is rendered, we can start showing layer updates.
630 // but if we are blocking render updates (so that a previously cached image is being shown), we wait
631 // at most e.g. 3 seconds before we start forcing progressive updates.
632 if ( !mBlockRenderUpdates || mElapsedTimer.elapsed() > MAX_TIME_TO_USE_CACHED_PREVIEW_IMAGE )
633 {
634 mReadyToCompose = true;
635 }
636
637 // new labeling engine
638 if ( isMainRenderer && context.labelingEngine() && ( mLabelProvider || mDiagramProvider ) )
639 {
640 const quint64 startLabelTime = timer.elapsed();
641 QgsLabelFeatureDetails details;
642 details.setIsSelected( featureIsSelected );
643 QgsSymbolList symbols = renderer->originalSymbolsForFeature( fet, context );
644 if ( !symbols.isEmpty() && fet.geometry().type() == Qgis::GeometryType::Point )
645 {
647 }
648
649 if ( !symbols.isEmpty() )
650 {
651 details.setSymbol( symbols.at( 0 ) );
653 }
654
655 if ( !labelClipGeom.isEmpty() )
656 context.setFeatureClipGeometry( labelClipGeom );
657
658 if ( mLabelProvider )
659 {
660 mLabelProvider->registerFeature( fet, context, details );
661 }
662 if ( mDiagramProvider )
663 {
664 mDiagramProvider->registerFeature( fet, context, details.obstacleGeometry() );
665 }
666
667 if ( !labelClipGeom.isEmpty() )
668 context.setFeatureClipGeometry( QgsGeometry() );
669
670 totalLabelTime += ( timer.elapsed() - startLabelTime );
671 }
672 }
673 }
674 catch ( const QgsCsException &cse )
675 {
676 Q_UNUSED( cse )
677 QgsDebugError( u"Failed to transform a point while drawing a feature with ID '%1'. Ignoring this feature. %2"_s.arg( fet.id() ).arg( cse.what() ) );
678 }
679 }
680
681 delete context.expressionContext().popScope();
682
683 std::unique_ptr< QgsScopedRuntimeProfile > cleanupProfile;
684 if ( mEnableProfile )
685 {
686 QgsApplication::profiler()->record( QObject::tr( "Rendering features" ), ( timer.elapsed() - totalLabelTime ) / 1000.0, u"rendering"_s );
687 if ( totalLabelTime > 0 )
688 {
689 QgsApplication::profiler()->record( QObject::tr( "Registering labels" ), totalLabelTime / 1000.0, u"rendering"_s );
690 }
691 cleanupProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr( "Finalizing" ), u"rendering"_s );
692 }
693
694 if ( mSelectionSymbol && isMainRenderer )
695 mSelectionSymbol->stopRender( context );
696
697 stopRenderer( renderer, nullptr );
698}
699
700void QgsVectorLayerRenderer::drawRendererLevels( QgsFeatureRenderer *renderer, QgsFeatureIterator &fit )
701{
702 const bool isMainRenderer = renderer == mRenderer;
703
704 // We need to figure out in which order all the features should be rendered.
705 // Ordering is based on (a) a "level" which is determined by the configured
706 // feature rendering order" and (b) the symbol level. The "level" is
707 // determined by the values of the attributes defined in the feature
708 // rendering order settings. Each time the attribute(s) have a new distinct
709 // value, a new empty QHash is added to the "features" list. This QHash is
710 // then filled by mappings from the symbol to a list of all the features
711 // that should be rendered by that symbol.
712 //
713 // If orderBy is not enabled, this list will only ever contain a single
714 // element.
715 QList<QHash< QgsSymbol *, QList<QgsFeature> >> features;
716
717 // We have at least one "level" for the features.
718 features.push_back( {} );
719
720 QSet<int> orderByAttributeIdx;
721 if ( renderer->orderByEnabled() )
722 {
723 orderByAttributeIdx = renderer->orderBy().usedAttributeIndices( mSource->fields() );
724 }
725
726 QgsRenderContext &context = *renderContext();
727
728 QgsSingleSymbolRenderer *selRenderer = nullptr;
729 if ( !mSelectedFeatureIds.isEmpty() )
730 {
731 selRenderer = new QgsSingleSymbolRenderer( QgsSymbol::defaultSymbol( mGeometryType ).release() );
732 selRenderer->symbol()->setColor( context.selectionColor() );
733 selRenderer->setVertexMarkerAppearance( mVertexMarkerStyle, mVertexMarkerSize );
734 selRenderer->startRender( context, mFields );
735 }
736
737 QgsExpressionContextScope *symbolScope = QgsExpressionContextUtils::updateSymbolScope( nullptr, new QgsExpressionContextScope() );
738 auto scopePopper = std::make_unique< QgsExpressionContextScopePopper >( context.expressionContext(), symbolScope );
739
740 std::unique_ptr< QgsScopedRuntimeProfile > fetchFeaturesProfile;
741 if ( mEnableProfile )
742 {
743 fetchFeaturesProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr( "Fetching features" ), u"rendering"_s );
744 }
745
746 QElapsedTimer timer;
747 timer.start();
748 quint64 totalLabelTime = 0;
749
750 QgsGeometry horizonGeom;
751 double lat, lon;
752 if ( context.coordinateTransform().destinationCrs().topocentricOrigin( lat, lon ) )
753 {
755 }
756
757 const QgsGeometry labelClipGeom = combinedClipGeometry( mApplyLabelClipGeometries ? mLabelClipFeatureGeom : QgsGeometry(), horizonGeom );
758 if ( !labelClipGeom.isEmpty() )
759 context.setFeatureClipGeometry( labelClipGeom );
760
761 std::unique_ptr< QgsGeometryEngine > clipEngine = prepareClipGeometry( mApplyClipFilter, mClipFilterGeom, horizonGeom );
762
763 // 1. fetch features
764 QgsFeature fet;
765 QVector<QVariant> prevValues; // previous values of ORDER BY attributes
766 while ( fit.nextFeature( fet ) )
767 {
768 if ( context.renderingStopped() )
769 {
770 qDebug( "rendering stop!" );
771 stopRenderer( renderer, selRenderer );
772 return;
773 }
774
775 if ( !fet.hasGeometry() )
776 continue;
777
778 if ( clipEngine && !clipEngine->intersects( fet.geometry().constGet() ) )
779 continue; // skip features outside of clipping region
780
781 if ( !mNoSetLayerExpressionContext )
782 context.expressionContext().setFeature( fet );
783 QgsSymbol *sym = renderer->symbolForFeature( fet, context );
784 if ( !sym )
785 {
786 continue;
787 }
788
789 if ( renderer->orderByEnabled() )
790 {
791 QVector<QVariant> currentValues;
792 for ( const int idx : std::as_const( orderByAttributeIdx ) )
793 {
794 currentValues.push_back( fet.attribute( idx ) );
795 }
796 if ( prevValues.empty() )
797 {
798 prevValues = std::move( currentValues );
799 }
800 else if ( currentValues != prevValues )
801 {
802 // Current values of ORDER BY attributes are different than previous
803 // values of these attributes. Start a new level.
804 prevValues = std::move( currentValues );
805 features.push_back( {} );
806 }
807 }
808
810 {
811 QHash<QgsSymbol *, QList<QgsFeature> > &featuresBack = features.back();
812 auto featuresBackIt = featuresBack.find( sym );
813 if ( featuresBackIt == featuresBack.end() )
814 {
815 featuresBackIt = featuresBack.insert( sym, QList<QgsFeature>() );
816 }
817 featuresBackIt->append( fet );
818 }
819
820 // new labeling engine
821 if ( isMainRenderer && context.labelingEngine() && ( mLabelProvider || mDiagramProvider ) )
822 {
823 const quint64 startLabelTime = timer.elapsed();
824
825 QgsLabelFeatureDetails details;
826 details.setIsSelected( context.showSelection() && mSelectedFeatureIds.contains( fet.id() ) );
827 QgsSymbolList symbols = renderer->originalSymbolsForFeature( fet, context );
828 if ( !symbols.isEmpty() && fet.geometry().type() == Qgis::GeometryType::Point )
829 {
831 }
832
833 if ( !symbols.isEmpty() )
834 {
835 details.setSymbol( symbols.at( 0 ) );
837 }
838
839 if ( mLabelProvider )
840 {
841 mLabelProvider->registerFeature( fet, context, details );
842 }
843 if ( mDiagramProvider )
844 {
845 mDiagramProvider->registerFeature( fet, context, details.obstacleGeometry() );
846 }
847
848 totalLabelTime += ( timer.elapsed() - startLabelTime );
849 }
850 }
851
852 fetchFeaturesProfile.reset();
853 if ( mEnableProfile )
854 {
855 if ( totalLabelTime > 0 )
856 {
857 QgsApplication::profiler()->record( QObject::tr( "Registering labels" ), totalLabelTime / 1000.0, u"rendering"_s );
858 }
859 }
860
861 if ( !labelClipGeom.isEmpty() )
862 context.setFeatureClipGeometry( QgsGeometry() );
863
864 scopePopper.reset();
865
866 if ( features.back().empty() )
867 {
868 // nothing to draw
869 stopRenderer( renderer, selRenderer );
870 return;
871 }
872
873
874 std::unique_ptr< QgsScopedRuntimeProfile > sortingProfile;
875 if ( mEnableProfile )
876 {
877 sortingProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr( "Sorting features" ), u"rendering"_s );
878 }
879 // find out the order
880 QgsSymbolLevelOrder levels;
881 QgsSymbolList symbols = renderer->symbols( context );
882 for ( int i = 0; i < symbols.count(); i++ )
883 {
884 QgsSymbol *sym = symbols[i];
885 for ( int j = 0; j < sym->symbolLayerCount(); j++ )
886 {
887 int level = sym->symbolLayer( j )->renderingPass();
888 if ( level < 0 || level >= 1000 ) // ignore invalid levels
889 continue;
890 QgsSymbolLevelItem item( sym, j );
891 while ( level >= levels.count() ) // append new empty levels
892 levels.append( QgsSymbolLevel() );
893 levels[level].append( item );
894 }
895 }
896 sortingProfile.reset();
897
898 const QgsGeometry renderClipGeom = combinedClipGeometry( mApplyClipGeometries ? mClipFeatureGeom : QgsGeometry(), horizonGeom );
899 if ( !renderClipGeom.isEmpty() )
900 context.setFeatureClipGeometry( renderClipGeom );
901
902 // 2. draw features in correct order
903 for ( const QHash< QgsSymbol *, QList<QgsFeature> > &featureLists : features )
904 {
905 for ( int l = 0; l < levels.count(); l++ )
906 {
907 const QgsSymbolLevel &level = levels[l];
908 std::unique_ptr< QgsScopedRuntimeProfile > renderingProfile;
909 if ( mEnableProfile )
910 {
911 renderingProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr( "Rendering symbol level %1" ).arg( l + 1 ), u"rendering"_s );
912 }
913
914 for ( int i = 0; i < level.count(); i++ )
915 {
916 const QgsSymbolLevelItem &item = level[i];
917 if ( !featureLists.contains( item.symbol() ) )
918 {
919 QgsDebugError( u"level item's symbol not found!"_s );
920 continue;
921 }
922 const int layer = item.layer();
923 const QList<QgsFeature> &lst = featureLists[item.symbol()];
924 for ( const QgsFeature &feature : lst )
925 {
926 if ( context.renderingStopped() )
927 {
928 stopRenderer( renderer, selRenderer );
929 return;
930 }
931
932 const bool featureIsSelected = isMainRenderer && context.showSelection() && mSelectedFeatureIds.contains( feature.id() );
933 if ( featureIsSelected && mSelectionSymbol )
934 continue; // defer rendering of selected symbols
935
936 // maybe vertex markers should be drawn only during the last pass...
937 const bool drawMarker = isMainRenderer && ( mDrawVertexMarkers && context.drawEditingInformation() && ( !mVertexMarkerOnlyForSelection || featureIsSelected ) );
938
939 if ( !mNoSetLayerExpressionContext )
940 context.expressionContext().setFeature( feature );
941
942 try
943 {
944 renderer->renderFeature( feature, context, layer, featureIsSelected, drawMarker );
945
946 // as soon as first feature is rendered, we can start showing layer updates.
947 // but if we are blocking render updates (so that a previously cached image is being shown), we wait
948 // at most e.g. 3 seconds before we start forcing progressive updates.
949 if ( !mBlockRenderUpdates || mElapsedTimer.elapsed() > MAX_TIME_TO_USE_CACHED_PREVIEW_IMAGE )
950 {
951 mReadyToCompose = true;
952 }
953 }
954 catch ( const QgsCsException &cse )
955 {
956 Q_UNUSED( cse )
957 QgsDebugError( u"Failed to transform a point while drawing a feature with ID '%1'. Ignoring this feature. %2"_s.arg( fet.id() ).arg( cse.what() ) );
958 }
959 }
960 }
961 }
962 }
963
964 if ( mSelectionSymbol && !mSelectedFeatureIds.empty() && isMainRenderer && context.showSelection() )
965 {
966 mSelectionSymbol->startRender( context, mFields );
967
968 for ( const QHash< QgsSymbol *, QList<QgsFeature> > &featureLists : features )
969 {
970 for ( auto it = featureLists.constBegin(); it != featureLists.constEnd(); ++it )
971 {
972 const QList<QgsFeature> &lst = it.value();
973 for ( const QgsFeature &feature : lst )
974 {
975 if ( context.renderingStopped() )
976 {
977 break;
978 }
979
980 const bool featureIsSelected = mSelectedFeatureIds.contains( feature.id() );
981 if ( !featureIsSelected )
982 continue;
983
984 const bool drawMarker = mDrawVertexMarkers && context.drawEditingInformation();
985 // note: here we pass "false" for the selected argument, as we don't want to change
986 // the user's defined selection symbol colors or settings in any way
987 mSelectionSymbol->renderFeature( feature, context, -1, false, drawMarker );
988 }
989 }
990 }
991
992 mSelectionSymbol->stopRender( context );
993 }
994
995 std::unique_ptr< QgsScopedRuntimeProfile > cleanupProfile;
996 if ( mEnableProfile )
997 {
998 cleanupProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr( "Finalizing" ), u"rendering"_s );
999 }
1000
1001 stopRenderer( renderer, selRenderer );
1002}
1003
1004void QgsVectorLayerRenderer::stopRenderer( QgsFeatureRenderer *renderer, QgsSingleSymbolRenderer *selRenderer )
1005{
1006 QgsRenderContext &context = *renderContext();
1007 renderer->stopRender( context );
1008 if ( selRenderer )
1009 {
1010 selRenderer->stopRender( context );
1011 delete selRenderer;
1012 }
1013}
1014
1015void QgsVectorLayerRenderer::prepareLabeling( QgsVectorLayer *layer, QSet<QString> &attributeNames )
1016{
1017 QgsRenderContext &context = *renderContext();
1018 // TODO: add attributes for geometry generator
1019 if ( QgsLabelingEngine *engine2 = context.labelingEngine() )
1020 {
1021 if ( layer->labelsEnabled() )
1022 {
1023 if ( context.labelSink() )
1024 {
1025 if ( const QgsRuleBasedLabeling *rbl = dynamic_cast<const QgsRuleBasedLabeling *>( layer->labeling() ) )
1026 {
1027 mLabelProvider = new QgsRuleBasedLabelSinkProvider( *rbl, layer, context.labelSink() );
1028 }
1029 else
1030 {
1031 QgsPalLayerSettings settings = layer->labeling()->settings();
1032 mLabelProvider = new QgsLabelSinkProvider( layer, QString(), context.labelSink(), &settings );
1033 }
1034 }
1035 else
1036 {
1037 mLabelProvider = layer->labeling()->provider( layer );
1038 }
1039 if ( mLabelProvider )
1040 {
1041 engine2->addProvider( mLabelProvider );
1042 if ( !mLabelProvider->prepare( context, attributeNames ) )
1043 {
1044 engine2->removeProvider( mLabelProvider );
1045 mLabelProvider = nullptr; // deleted by engine
1046 }
1047 }
1048 }
1049 }
1050
1051#if 0 // TODO: limit of labels, font not found
1052 QgsPalLayerSettings &palyr = mContext.labelingEngine()->layer( mLayerID );
1053
1054 // see if feature count limit is set for labeling
1055 if ( palyr.limitNumLabels && palyr.maxNumLabels > 0 )
1056 {
1057 QgsFeatureIterator fit = getFeatures( QgsFeatureRequest()
1058 .setFilterRect( mContext.extent() )
1059 .setNoAttributes() );
1060
1061 // total number of features that may be labeled
1062 QgsFeature f;
1063 int nFeatsToLabel = 0;
1064 while ( fit.nextFeature( f ) )
1065 {
1066 nFeatsToLabel++;
1067 }
1068 palyr.mFeaturesToLabel = nFeatsToLabel;
1069 }
1070
1071 // notify user about any font substitution
1072 if ( !palyr.mTextFontFound && !mLabelFontNotFoundNotified )
1073 {
1074 emit labelingFontNotFound( this, palyr.mTextFontFamily );
1075 mLabelFontNotFoundNotified = true;
1076 }
1077#endif
1078}
1079
1080void QgsVectorLayerRenderer::prepareDiagrams( QgsVectorLayer *layer, QSet<QString> &attributeNames )
1081{
1082 QgsRenderContext &context = *renderContext();
1083 if ( QgsLabelingEngine *engine2 = context.labelingEngine() )
1084 {
1085 if ( layer->diagramsEnabled() )
1086 {
1087 mDiagramProvider = new QgsVectorLayerDiagramProvider( layer );
1088 // need to be added before calling prepare() - uses map settings from engine
1089 engine2->addProvider( mDiagramProvider );
1090 if ( !mDiagramProvider->prepare( context, attributeNames ) )
1091 {
1092 engine2->removeProvider( mDiagramProvider );
1093 mDiagramProvider = nullptr; // deleted by engine
1094 }
1095 }
1096 }
1097}
Provides global constants and enumerations for use throughout the application.
Definition qgis.h:62
@ ForceVector
Always force vector-based rendering, even when the result will be visually different to a raster-base...
Definition qgis.h:2919
QFlags< MapLayerRendererFlag > MapLayerRendererFlags
Flags which control how map layer renderers behave.
Definition qgis.h:3013
QFlags< VectorRenderingSimplificationFlag > VectorRenderingSimplificationFlags
Simplification flags for vector feature rendering.
Definition qgis.h:3269
@ NoSimplification
No simplification can be applied.
Definition qgis.h:3255
@ FullSimplification
All simplification hints can be applied ( Geometry + AA-disabling ).
Definition qgis.h:3258
@ GeometrySimplification
The geometries can be simplified using the current map2pixel context state.
Definition qgis.h:3256
@ Degrees
Degrees, for planar geographic CRS distance measurements.
Definition qgis.h:5575
@ EmbeddedSymbols
Retrieve any embedded feature symbology.
Definition qgis.h:2385
@ AffectsLabeling
If present, indicates that the renderer will participate in the map labeling problem.
Definition qgis.h:911
@ Point
Points.
Definition qgis.h:400
@ Unknown
Unknown types.
Definition qgis.h:403
@ Null
No geometry.
Definition qgis.h:404
@ Vector
Vector layer.
Definition qgis.h:207
@ AffectsLabeling
The layer rendering will interact with the map labeling.
Definition qgis.h:3004
@ SkipSymbolRendering
Disable symbol rendering while still drawing labels if enabled.
Definition qgis.h:2983
@ NoMarker
No marker.
Definition qgis.h:2006
@ SemiTransparentCircle
Semi-transparent circle marker.
Definition qgis.h:2004
@ Cross
Cross marker.
Definition qgis.h:2005
@ CustomColor
Use default symbol with a custom selection color.
Definition qgis.h:1930
@ CustomSymbol
Use a custom symbol.
Definition qgis.h:1931
@ Default
Use default symbol and selection colors.
Definition qgis.h:1929
virtual QgsPalLayerSettings settings(const QString &providerId=QString()) const =0
Gets associated label settings.
virtual QgsVectorLayerLabelProvider * provider(QgsVectorLayer *layer) const
Factory for label provider implementation.
static QgsRuntimeProfiler * profiler()
Returns the application runtime profiler.
static QgsGeometry topocentricHorizonGeometry(const QgsCoordinateReferenceSystem &topocentricCrs, const QgsCoordinateReferenceSystem &outputCrs, const QgsCoordinateTransformContext &transformContext, double degreeStep=1.0)
Builds the geometry of the visible horizon (in outputCrs) when topocentricCrs is a topocentric CRS.
bool topocentricOrigin(double &latitude, double &longitude) const
Returns the topocentric origin of a topocentric compatible CRS.
QgsCoordinateReferenceSystem sourceCrs() const
Returns the source coordinate reference system, which the transform will transform coordinates from.
void setBallparkTransformsAreAppropriate(bool appropriate)
Sets whether approximate "ballpark" results are appropriate for this coordinate transform.
QgsPointXY transform(const QgsPointXY &point, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward) const
Transform the point from the source CRS to the destination CRS.
bool isShortCircuited() const
Returns true if the transform short circuits because the source and destination are equivalent.
bool isValid() const
Returns true if the coordinate transform is valid, ie both the source and destination CRS have been s...
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination coordinate reference system, which the transform will transform coordinates t...
QString what() const
static QgsExpressionContextScope * updateSymbolScope(const QgsSymbol *symbol, QgsExpressionContextScope *symbolScope=nullptr)
Updates a symbol scope related to a QgsSymbol to an expression context.
QgsExpressionContextScope * popScope()
Removes the last scope from the expression context and return it.
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
void setFeedback(QgsFeedback *feedback)
Attach a feedback object that can be queried regularly by the expression engine to check if expressio...
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
virtual Q_DECL_DEPRECATED void filterFeatures(const QgsVectorLayer *layer, QgsFeatureRequest &featureRequest) const
Add additional filters to the feature request to further restrict the features returned by the reques...
virtual Q_DECL_DEPRECATED bool isFilterThreadSafe() const
Returns true if the filterFeature function is thread safe, which will lead to reliance on layer ID in...
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
Fetch next feature and stores in f, returns true on success.
void setInterruptionChecker(QgsFeedback *interruptionChecker)
Attach an object that can be queried regularly by the iterator to check if it must stopped.
bool isValid() const
Will return if this iterator is valid.
An interface for objects which generate feature renderers for vector layers.
Abstract base class for all 2D vector feature renderers.
virtual bool canSkipRender()
Returns true if the renderer can be entirely skipped, i.e.
virtual void modifyRequestExtent(QgsRectangle &extent, QgsRenderContext &context)
Allows for a renderer to modify the extent of a feature request prior to rendering.
virtual QString filter(const QgsFields &fields=QgsFields())
If a renderer does not require all the features this method may be overridden and return an expressio...
QgsPaintEffect * paintEffect() const
Returns the current paint effect for the renderer.
virtual QgsSymbolList symbols(QgsRenderContext &context) const
Returns list of symbols used by the renderer.
virtual void stopRender(QgsRenderContext &context)
Must be called when a render cycle has finished, to allow the renderer to clean up.
QString type() const
virtual bool usesEmbeddedSymbols() const
Returns true if the renderer uses embedded symbols for features.
virtual bool renderFeature(const QgsFeature &feature, QgsRenderContext &context, int layer=-1, bool selected=false, bool drawVertexMarker=false)
Render a feature using this renderer in the given context.
double referenceScale() const
Returns the symbology reference scale.
bool usingSymbolLevels() const
virtual QgsFeatureRenderer::Capabilities capabilities()
Returns details about internals of this renderer.
virtual QgsSymbol * symbolForFeature(const QgsFeature &feature, QgsRenderContext &context) const =0
To be overridden.
@ SymbolLevels
Rendering with symbol levels (i.e. implements symbols(), symbolForFeature()).
bool orderByEnabled() const
Returns whether custom ordering will be applied before features are processed by this renderer.
virtual bool willRenderFeature(const QgsFeature &feature, QgsRenderContext &context) const
Returns whether the renderer will render a feature or not.
virtual void startRender(QgsRenderContext &context, const QgsFields &fields)
Must be called when a new render cycle is started.
void setVertexMarkerAppearance(Qgis::VertexMarkerType type, double size)
Sets type and size of editing vertex markers for subsequent rendering.
QgsFeatureRequest::OrderBy orderBy() const
Gets the order in which features shall be processed by this renderer.
virtual QgsSymbolList originalSymbolsForFeature(const QgsFeature &feature, QgsRenderContext &context) const
Equivalent of originalSymbolsForFeature() call extended to support renderers that may use more symbol...
virtual QgsFeatureRenderer * clone() const =0
Create a deep copy of this renderer.
QSet< int > CORE_EXPORT usedAttributeIndices(const QgsFields &fields) const
Returns a set of used, validated attribute indices.
QgsFeatureRequest & setFlags(Qgis::FeatureRequestFlags flags)
Sets flags that affect how features will be fetched.
QgsFeatureRequest & setSimplifyMethod(const QgsSimplifyMethod &simplifyMethod)
Set a simplification method for geometries that will be fetched.
QgsFeatureRequest & combineFilterExpression(const QString &expression)
Modifies the existing filter expression to add an additional expression filter.
Qgis::FeatureRequestFlags flags() const
Returns the flags which affect how features are fetched.
void setFeedback(QgsFeedback *feedback)
Attach a feedback object that can be queried regularly by the iterator to check if it should be cance...
QgsFeatureRequest & setOrderBy(const OrderBy &orderBy)
Set a list of order by clauses.
QgsFeatureId id
Definition qgsfeature.h:63
QgsGeometry geometry
Definition qgsfeature.h:66
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Q_INVOKABLE QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Definition qgsfeedback.h:44
A geometry is the spatial representation of a feature.
QgsGeometry intersection(const QgsGeometry &geometry, const QgsGeometryParameters &parameters=QgsGeometryParameters(), QgsFeedback *feedback=nullptr) const
Returns a geometry representing the points shared by this geometry and other.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
Qgis::GeometryType type
bool isEmpty() const
Returns true if the geometry is empty (eg a linestring with no vertices, or a collection with no geom...
static QgsGeometryEngine * createGeometryEngine(const QgsAbstractGeometry *geometry, double precision=0.0, Qgis::GeosCreationFlags flags=Qgis::GeosCreationFlag::SkipEmptyInteriorRings)
Creates and returns a new geometry engine representing the specified geometry using precision on a gr...
void setIsSelected(bool selected)
Sets whether the feature associated with the label is currently selected.
void setSymbol(const QgsSymbol *symbol)
Sets the (optional) symbol associated with the feature to label.
QgsGeometry obstacleGeometry() const
Returns the (optional) obstacle geometry for the label.
const QgsSymbol * symbol() const
Returns the (optional) symbol associated with the feature to label.
void setObstacleGeometry(const QgsGeometry &geometry)
Sets the (optional) obstacle geometry for the label.
static QPainterPath calculatePainterClipRegion(const QList< QgsMapClippingRegion > &regions, const QgsRenderContext &context, Qgis::LayerType layerType, bool &shouldClip)
Returns a QPainterPath representing the intersection of clipping regions from context which should be...
static QList< QgsMapClippingRegion > collectClippingRegionsForLayer(const QgsRenderContext &context, const QgsMapLayer *layer)
Collects the list of map clipping regions from a context which apply to a map layer.
static QgsGeometry calculateLabelIntersectionGeometry(const QList< QgsMapClippingRegion > &regions, const QgsRenderContext &context, bool &shouldClip)
Returns the geometry representing the intersection of clipping regions from context which should be u...
static QgsGeometry calculateFeatureIntersectionGeometry(const QList< QgsMapClippingRegion > &regions, const QgsRenderContext &context, bool &shouldClip)
Returns the geometry representing the intersection of clipping regions from context which should be u...
static QgsGeometry calculateFeatureRequestGeometry(const QList< QgsMapClippingRegion > &regions, const QgsRenderContext &context, bool &shouldFilter)
Returns the geometry representing the intersection of clipping regions from context.
bool mReadyToCompose
The flag must be set to false in renderer's constructor if wants to use the smarter map redraws funct...
static constexpr int MAX_TIME_TO_USE_CACHED_PREVIEW_IMAGE
Maximum time (in ms) to allow display of a previously cached preview image while rendering layers,...
QString layerId() const
Gets access to the ID of the layer rendered by this class.
QgsRenderContext * renderContext()
Returns the render context associated with the renderer.
QgsMapLayerRenderer(const QString &layerID, QgsRenderContext *context=nullptr)
Constructor for QgsMapLayerRenderer, with the associated layerID and render context.
QPainter::CompositionMode blendMode() const
Returns the current blending mode for a layer.
double opacity
Definition qgsmaplayer.h:95
double mapUnitsPerPixel() const
Returns the current map units per pixel.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE(), Qgis::StringFormat format=Qgis::StringFormat::PlainText)
Adds a message to the log instance (and creates it if necessary).
virtual void begin(QgsRenderContext &context)
Begins intercepting paint operations to a render context.
virtual void end(QgsRenderContext &context)
Ends interception of paint operations to a render context, and draws the result to the render context...
bool enabled() const
Returns whether the effect is enabled.
double y
Definition qgspointxy.h:66
double x
Definition qgspointxy.h:65
Q_INVOKABLE QString toString(int precision=16) const
Returns a string representation of form xmin,ymin : xmax,ymax Coordinates will be rounded to the spec...
double xMinimum
double yMinimum
double xMaximum
double yMaximum
QgsPointXY center
QgsRectangle intersect(const QgsRectangle &rect) const
Returns the intersection with the given rectangle.
bool isFinite() const
Returns true if the rectangle has finite boundaries.
Contains information about the context of a rendering operation.
bool hasRenderedFeatureHandlers() const
Returns true if the context has any rendered feature handlers.
QgsVectorSimplifyMethod & vectorSimplifyMethod()
Returns the simplification settings to use when rendering vector layers.
QPainter * painter()
Returns the destination QPainter for the render operation.
QgsExpressionContext & expressionContext()
Gets the expression context.
void setVectorSimplifyMethod(const QgsVectorSimplifyMethod &simplifyMethod)
Sets the simplification setting to use when rendering vector layers.
QgsCoordinateTransformContext transformContext() const
Returns the context's coordinate transform context, which stores various information regarding which ...
QgsLabelSink * labelSink() const
Returns the associated label sink, or nullptr if not set.
const QgsRectangle & extent() const
When rendering a map layer, calling this method returns the "clipping" extent for the layer (in the l...
bool testFlag(Qgis::RenderContextFlag flag) const
Check whether a particular flag is enabled.
void setFeatureClipGeometry(const QgsGeometry &geometry)
Sets a geometry to use to clip features at render time.
const QgsFeatureFilterProvider * featureFilterProvider() const
Gets the filter feature provider used for additional filtering of rendered features.
QList< QgsRenderedFeatureHandlerInterface * > renderedFeatureHandlers() const
Returns the list of rendered feature handlers to use while rendering map layers.
void setSymbologyReferenceScale(double scale)
Sets the symbology reference scale.
bool showSelection() const
Returns true if vector selections should be shown in the rendered map.
const QgsMapToPixel & mapToPixel() const
Returns the context's map to pixel transform, which transforms between map coordinates and device coo...
QColor selectionColor() const
Returns the color to use when rendering selected features.
Qgis::RasterizedRenderingPolicy rasterizedRenderingPolicy() const
Returns the policy controlling when rasterisation of content during renders is permitted.
bool drawEditingInformation() const
Returns true if edit markers should be drawn during the render operation.
bool renderingStopped() const
Returns true if the rendering operation has been stopped and any ongoing rendering should be canceled...
QgsLabelingEngine * labelingEngine() const
Gets access to new labeling engine (may be nullptr).
QgsCoordinateTransform coordinateTransform() const
Returns the current coordinate transform for the context.
void setSelectionColor(const QColor &color)
Sets the color to use when rendering selected features.
An interface for classes which provide custom handlers for features rendered as part of a map render ...
void record(const QString &name, double time, const QString &group="startup", const QString &id=QString())
Manually adds a profile event with the given name and total time (in seconds).
Scoped object for setting the current thread name.
static const QgsSettingsEntryDouble * settingsDigitizingMarkerSizeMm
Settings entry digitizing marker size mm.
static const QgsSettingsEntryBool * settingsDigitizingMarkerOnlyForSelected
Settings entry digitizing marker only for selected.
static const QgsSettingsEntryString * settingsDigitizingMarkerStyle
Settings entry digitizing marker style.
void setTolerance(double tolerance)
Sets the tolerance of simplification in map units. Represents the maximum distance in map units betwe...
void setThreshold(float threshold)
Sets the simplification threshold in pixels. Represents the maximum distance in pixels between two co...
void setForceLocalOptimization(bool localOptimization)
Sets whether the simplification executes after fetch the geometries from provider,...
void setMethodType(MethodType methodType)
Sets the simplification type.
@ OptimizeForRendering
Simplify using the map2pixel data to optimize the rendering of geometries.
A feature renderer which renders all features with the same symbol.
QgsSymbol * symbol() const
Returns the symbol which will be rendered for every feature.
void stopRender(QgsRenderContext &context) override
Must be called when a render cycle has finished, to allow the renderer to clean up.
void startRender(QgsRenderContext &context, const QgsFields &fields) override
Must be called when a new render cycle is started.
int renderingPass() const
Specifies the rendering pass in which this symbol layer should be rendered.
int layer() const
The layer of this symbol level.
QgsSymbol * symbol() const
The symbol of this symbol level.
Abstract base class for all rendered symbols.
Definition qgssymbol.h:227
QgsSymbolLayer * symbolLayer(int layer)
Returns the symbol layer at the specified index.
void setColor(const QColor &color) const
Sets the color for the symbol.
int symbolLayerCount() const
Returns the total number of symbol layers contained in the symbol.
Definition qgssymbol.h:357
static std::unique_ptr< QgsSymbol > defaultSymbol(Qgis::GeometryType geomType)
Returns a new default symbol for the specified geometry type.
const QgsDateTimeRange & temporalRange() const
Returns the datetime range for the object.
bool isTemporal() const
Returns true if the object's temporal range is enabled, and the object will be filtered when renderin...
Partial snapshot of vector layer's state (only the members necessary for access to features).
static QgsGeometry getPointObstacleGeometry(QgsFeature &fet, QgsRenderContext &context, const QgsSymbolList &symbols)
Returns the geometry for a point feature which should be used as an obstacle for labels.
Qgis::MapLayerRendererFlags flags() const override
Returns flags which control how the map layer rendering behaves.
bool forceRasterRender() const override
Returns true if the renderer must be rendered to a raster paint device (e.g.
QgsVectorLayerRenderer(QgsVectorLayer *layer, QgsRenderContext &context)
~QgsVectorLayerRenderer() override
void setLayerRenderingTimeHint(int time) override
Sets approximate render time (in ms) for the layer to render.
bool render() override
Do the rendering (based on data stored in the class).
QgsFeedback * feedback() const override
Access to feedback object of the layer renderer (may be nullptr).
Implementation of layer selection properties for vector layers.
Encapsulates the context in which a QgsVectorLayer's temporal capabilities will be applied.
void setLayer(QgsVectorLayer *layer)
Sets the associated layer.
Represents a vector layer which manages a vector based dataset.
bool labelsEnabled() const
Returns whether the layer contains labels which are enabled and should be drawn.
QgsMapLayerTemporalProperties * temporalProperties() override
Returns the layer's temporal properties.
QPainter::CompositionMode featureBlendMode() const
Returns the current blending mode for features.
bool diagramsEnabled() const
Returns whether the layer contains diagrams which are enabled and should be drawn.
Q_INVOKABLE const QgsFeatureIds & selectedFeatureIds() const
Returns a list of the selected features IDs in this layer.
const QgsAbstractVectorLayerLabeling * labeling() const
Access to const labeling configuration.
bool simplifyDrawingCanbeApplied(const QgsRenderContext &renderContext, Qgis::VectorRenderingSimplificationFlag simplifyHint) const
Returns whether the VectorLayer can apply the specified simplification hint.
QgsFeatureRenderer * renderer()
Returns the feature renderer used for rendering the features in the layer in 2D map views.
Q_INVOKABLE QgsVectorLayerEditBuffer * editBuffer()
Buffer with uncommitted editing operations. Only valid after editing has been turned on.
Q_INVOKABLE Qgis::GeometryType geometryType() const
Returns point, line or polygon.
const QgsVectorSimplifyMethod & simplifyMethod() const
Returns the simplification settings for fast rendering of features.
QList< const QgsFeatureRendererGenerator * > featureRendererGenerators() const
Returns a list of the feature renderer generators owned by the layer.
QgsMapLayerSelectionProperties * selectionProperties() override
Returns the layer's selection properties.
Qgis::VectorRenderingSimplificationFlags simplifyHints() const
Gets the simplification hints of the vector layer managed.
void setSimplifyHints(Qgis::VectorRenderingSimplificationFlags simplifyHints)
Sets the simplification hints of the vector layer managed.
void setTolerance(double tolerance)
Sets the tolerance of simplification in map units. Represents the maximum distance in map units betwe...
#define Q_NOWARN_DEPRECATED_POP
Definition qgis.h:8361
#define Q_NOWARN_DEPRECATED_PUSH
Definition qgis.h:8360
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
Definition qgis.h:7725
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:80
#define QgsDebugError(str)
Definition qgslogger.h:71
QList< QgsSymbolLevel > QgsSymbolLevelOrder
Definition qgsrenderer.h:96
QList< QgsSymbolLevelItem > QgsSymbolLevel
Definition qgsrenderer.h:92
QList< QgsSymbol * > QgsSymbolList
Definition qgsrenderer.h:51