QGIS API Documentation 4.3.0-Master (0de80482b60)
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 "qgspallabeling.h"
30#include "qgsrendercontext.h"
32#include "qgsrenderer.h"
33#include "qgsruntimeprofiler.h"
37#include "qgssymbol.h"
38#include "qgssymbollayer.h"
39#include "qgsthreadingutils.h"
40#include "qgsvectorlayer.h"
47
48#include <QPicture>
49#include <QString>
50#include <QThread>
51#include <QTimer>
52
53using namespace Qt::StringLiterals;
54
56 : QgsMapLayerRenderer( layer->id(), &context )
57 , mFeedback( std::make_unique< QgsFeedback >() )
58 , mLayer( layer )
59 , mLayerName( layer->name() )
60 , mFields( layer->fields() )
61 , mSource( std::make_unique< QgsVectorLayerFeatureSource >( layer ) )
62 , mNoSetLayerExpressionContext( layer->customProperty( u"_noset_layer_expression_context"_s ).toBool() )
63 , mEnableProfile( context.flags() & Qgis::RenderContextFlag::RecordProfile )
64{
65 QElapsedTimer timer;
66 timer.start();
67 std::unique_ptr< QgsFeatureRenderer > mainRenderer( layer->renderer() ? layer->renderer()->clone() : nullptr );
68
69 QgsVectorLayerSelectionProperties *selectionProperties = qobject_cast< QgsVectorLayerSelectionProperties * >( layer->selectionProperties() );
70 switch ( selectionProperties->selectionRenderingMode() )
71 {
73 break;
74
76 {
77 // overwrite default selection color if layer has a specific selection color set
78 const QColor layerSelectionColor = selectionProperties->selectionColor();
79 if ( layerSelectionColor.isValid() )
80 context.setSelectionColor( layerSelectionColor );
81 break;
82 }
83
85 {
86 if ( QgsSymbol *selectionSymbol = qobject_cast< QgsVectorLayerSelectionProperties * >( layer->selectionProperties() )->selectionSymbol() )
87 mSelectionSymbol.reset( selectionSymbol->clone() );
88 break;
89 }
90 }
91
92 if ( !mainRenderer )
93 return;
94
95 QList< const QgsFeatureRendererGenerator * > generators = layer->featureRendererGenerators();
96 std::sort( generators.begin(), generators.end(), []( const QgsFeatureRendererGenerator *g1, const QgsFeatureRendererGenerator *g2 ) { return g1->level() < g2->level(); } );
97
98 bool insertedMainRenderer = false;
99 double prevLevel = std::numeric_limits< double >::lowest();
100 // cppcheck-suppress danglingLifetime
101 mRenderer = mainRenderer.get();
102 for ( const QgsFeatureRendererGenerator *generator : std::as_const( generators ) )
103 {
104 if ( generator->level() >= 0 && prevLevel < 0 && !insertedMainRenderer )
105 {
106 // insert main renderer when level changes from <0 to >0
107 mRenderers.emplace_back( std::move( mainRenderer ) );
108 insertedMainRenderer = true;
109 }
110 mRenderers.emplace_back( generator->createRenderer() );
111 prevLevel = generator->level();
112 }
113 // cppcheck-suppress accessMoved
114 if ( mainRenderer )
115 {
116 // cppcheck-suppress accessMoved
117 mRenderers.emplace_back( std::move( mainRenderer ) );
118 }
119
120 mSelectedFeatureIds = layer->selectedFeatureIds();
121
122 mDrawVertexMarkers = nullptr != layer->editBuffer();
123
124 mGeometryType = layer->geometryType();
125
126 mFeatureBlendMode = layer->featureBlendMode();
127
128 if ( context.isTemporal() )
129 {
130 QgsVectorLayerTemporalContext temporalContext;
131 temporalContext.setLayer( layer );
132 mTemporalFilter = qobject_cast< const QgsVectorLayerTemporalProperties * >( layer->temporalProperties() )->createFilterString( temporalContext, context.temporalRange() );
133 QgsDebugMsgLevel( "Rendering with Temporal Filter: " + mTemporalFilter, 2 );
134 }
135
136 // if there's already a simplification method specified via the context, we respect that. Otherwise, we fall back
137 // to the layer's individual setting
139 {
140 mSimplifyMethod = renderContext()->vectorSimplifyMethod();
143 }
144 else
145 {
146 mSimplifyMethod = layer->simplifyMethod();
148 }
149
150 mVertexMarkerOnlyForSelection = QgsSettingsRegistryCore::settingsDigitizingMarkerOnlyForSelected->value();
151
152 QString markerTypeString = QgsSettingsRegistryCore::settingsDigitizingMarkerStyle->value();
153 if ( markerTypeString == "Cross"_L1 )
154 {
155 mVertexMarkerStyle = Qgis::VertexMarkerType::Cross;
156 }
157 else if ( markerTypeString == "SemiTransparentCircle"_L1 )
158 {
160 }
161 else
162 {
163 mVertexMarkerStyle = Qgis::VertexMarkerType::NoMarker;
164 }
165
167
168 // cppcheck-suppress danglingLifetime
169 QgsDebugMsgLevel( "rendering v2:\n " + mRenderer->dump(), 2 );
170
171 if ( mDrawVertexMarkers )
172 {
173 // set editing vertex markers style (main renderer only)
174 mRenderer->setVertexMarkerAppearance( mVertexMarkerStyle, mVertexMarkerSize );
175 }
176
177 for ( const std::unique_ptr< QgsFeatureRenderer > &renderer : mRenderers )
178 {
179 mAttrNames.unite( renderer->usedAttributes( context ) );
180 }
181 if ( context.hasRenderedFeatureHandlers() )
182 {
183 const QList< QgsRenderedFeatureHandlerInterface * > handlers = context.renderedFeatureHandlers();
184 for ( QgsRenderedFeatureHandlerInterface *handler : handlers )
185 mAttrNames.unite( handler->usedAttributes( layer, context ) );
186 }
187
188 //register label and diagram layer to the labeling engine
189 prepareLabeling( layer, mAttrNames );
190 prepareDiagrams( layer, mAttrNames );
191
192 mClippingRegions = QgsMapClippingUtils::collectClippingRegionsForLayer( context, layer );
193
194 if ( std::any_of( mRenderers.begin(), mRenderers.end(), []( const auto &renderer ) { return renderer->forceRasterRender(); } ) )
195 {
196 //raster rendering is forced for this layer
197 mForceRasterRender = true;
198 }
199
200 const bool allowFlattening = context.rasterizedRenderingPolicy() != Qgis::RasterizedRenderingPolicy::ForceVector;
201 if ( allowFlattening
202 && ( ( layer->blendMode() != QPainter::CompositionMode_SourceOver ) || ( layer->featureBlendMode() != QPainter::CompositionMode_SourceOver ) || ( !qgsDoubleNear( layer->opacity(), 1.0 ) ) ) )
203 {
204 //layer properties require rasterization
205 mForceRasterRender = true;
206 }
207
208 mReadyToCompose = false;
209 mPreparationTime = timer.elapsed();
210}
211
213
215{
216 mRenderTimeHint = time;
217}
218
220{
221 return mFeedback.get();
222}
223
225{
226 return mForceRasterRender;
227}
228
230{
232 if ( mRenderer && mRenderer->flags().testFlag( Qgis::FeatureRendererFlag::AffectsLabeling ) )
234 return res;
235}
236
238{
239 QgsScopedThreadName threadName( u"render:%1"_s.arg( mLayerName ) );
240
241 if ( mGeometryType == Qgis::GeometryType::Null || mGeometryType == Qgis::GeometryType::Unknown )
242 {
243 mReadyToCompose = true;
244 return true;
245 }
246
247 if ( mRenderers.empty() )
248 {
249 mReadyToCompose = true;
250 mErrors.append( QObject::tr( "No renderer for drawing." ) );
251 return false;
252 }
253
254 std::unique_ptr< QgsScopedRuntimeProfile > profile;
255 if ( mEnableProfile )
256 {
257 profile = std::make_unique< QgsScopedRuntimeProfile >( mLayerName, u"rendering"_s, layerId() );
258 if ( mPreparationTime > 0 )
259 QgsApplication::profiler()->record( QObject::tr( "Create renderer" ), mPreparationTime / 1000.0, u"rendering"_s );
260 }
261
262 // if the previous layer render was relatively quick (e.g. less than 3 seconds), the we show any previously
263 // cached version of the layer during rendering instead of the usual progressive updates
264 if ( mRenderTimeHint > 0 && mRenderTimeHint <= MAX_TIME_TO_USE_CACHED_PREVIEW_IMAGE )
265 {
266 mBlockRenderUpdates = true;
267 mElapsedTimer.start();
268 }
269
270 bool res = true;
271 int rendererIndex = 0;
272 for ( const std::unique_ptr< QgsFeatureRenderer > &renderer : mRenderers )
273 {
274 if ( mFeedback->isCanceled() || !res )
275 {
276 break;
277 }
278 res = renderInternal( renderer.get(), rendererIndex++ ) && res;
279 }
280
281 mReadyToCompose = true;
282 return res && !renderContext()->renderingStopped();
283}
284
285bool QgsVectorLayerRenderer::renderInternal( QgsFeatureRenderer *renderer, int rendererIndex )
286{
287 const bool isMainRenderer = renderer == mRenderer;
288
289 QgsRenderContext &context = *renderContext();
290 context.setSymbologyReferenceScale( renderer->referenceScale() );
291
292 if ( renderer->type() == "nullSymbol"_L1 )
293 {
294 // a little shortcut for the null symbol renderer - most of the time it is not going to render anything
295 // so we can even skip the whole loop to fetch features
296 if ( !isMainRenderer || ( !mDrawVertexMarkers && !mLabelProvider && !mDiagramProvider && mSelectedFeatureIds.isEmpty() ) )
297 return true;
298 }
299
300 std::unique_ptr< QgsScopedRuntimeProfile > preparingProfile;
301 if ( mEnableProfile )
302 {
303 QString title;
304 if ( mRenderers.size() > 1 )
305 title = QObject::tr( "Preparing render %1" ).arg( rendererIndex + 1 );
306 else
307 title = QObject::tr( "Preparing render" );
308 preparingProfile = std::make_unique< QgsScopedRuntimeProfile >( title, u"rendering"_s );
309 }
310
311 QgsScopedQPainterState painterState( context.painter() );
312
313 bool usingEffect = false;
314 if ( renderer->paintEffect() && renderer->paintEffect()->enabled() )
315 {
316 usingEffect = true;
317 renderer->paintEffect()->begin( context );
318 }
319
320 // Per feature blending mode
321 if ( context.rasterizedRenderingPolicy() != Qgis::RasterizedRenderingPolicy::ForceVector && mFeatureBlendMode != QPainter::CompositionMode_SourceOver )
322 {
323 // set the painter to the feature blend mode, so that features drawn
324 // on this layer will interact and blend with each other
325 context.painter()->setCompositionMode( mFeatureBlendMode );
326 }
327
328 renderer->startRender( context, mFields );
329
330 if ( renderer->canSkipRender() )
331 {
332 // nothing to draw for now...
333 renderer->stopRender( context );
334 return true;
335 }
336
337 QString rendererFilter = renderer->filter( mFields );
338
339 QgsRectangle requestExtent = context.extent();
340 if ( !mClippingRegions.empty() )
341 {
342 mClipFilterGeom = QgsMapClippingUtils::calculateFeatureRequestGeometry( mClippingRegions, context, mApplyClipFilter );
343 requestExtent = requestExtent.intersect( mClipFilterGeom.boundingBox() );
344
345 mClipFeatureGeom = QgsMapClippingUtils::calculateFeatureIntersectionGeometry( mClippingRegions, context, mApplyClipGeometries );
346
347 bool needsPainterClipPath = false;
348 const QPainterPath path = QgsMapClippingUtils::calculatePainterClipRegion( mClippingRegions, context, Qgis::LayerType::Vector, needsPainterClipPath );
349 if ( needsPainterClipPath )
350 context.painter()->setClipPath( path, Qt::IntersectClip );
351
352 mLabelClipFeatureGeom = QgsMapClippingUtils::calculateLabelIntersectionGeometry( mClippingRegions, context, mApplyLabelClipGeometries );
353
354 if ( mDiagramProvider )
355 mDiagramProvider->setClipFeatureGeometry( mLabelClipFeatureGeom );
356 }
357
358 renderer->modifyRequestExtent( requestExtent, context );
359
360 QgsFeatureRequest featureRequest = QgsFeatureRequest().setFilterRect( requestExtent ).setSubsetOfAttributes( mAttrNames, mFields ).setExpressionContext( context.expressionContext() );
361 if ( renderer->orderByEnabled() )
362 {
363 featureRequest.setOrderBy( renderer->orderBy() );
364 }
365
366 const QgsFeatureFilterProvider *featureFilterProvider = context.featureFilterProvider();
367 if ( featureFilterProvider )
368 {
370 if ( featureFilterProvider->isFilterThreadSafe() )
371 {
372 featureFilterProvider->filterFeatures( layerId(), featureRequest );
373 }
374 else
375 {
376 featureFilterProvider->filterFeatures( mLayer, featureRequest );
377 }
379 }
380 if ( !rendererFilter.isEmpty() && rendererFilter != "TRUE"_L1 )
381 {
382 featureRequest.combineFilterExpression( rendererFilter );
383 }
384 if ( !mTemporalFilter.isEmpty() )
385 {
386 featureRequest.combineFilterExpression( mTemporalFilter );
387 }
388
389 if ( renderer->usesEmbeddedSymbols() )
390 {
391 featureRequest.setFlags( featureRequest.flags() | Qgis::FeatureRequestFlag::EmbeddedSymbols );
392 }
393
394 // enable the simplification of the geometries (Using the current map2pixel context) before send it to renderer engine.
395 if ( mSimplifyGeometry )
396 {
397 double map2pixelTol = mSimplifyMethod.threshold();
398 bool validTransform = true;
399
400 const QgsMapToPixel &mtp = context.mapToPixel();
401 map2pixelTol *= mtp.mapUnitsPerPixel();
402 const QgsCoordinateTransform ct = context.coordinateTransform();
403
404 // resize the tolerance using the change of size of an 1-BBOX from the source CoordinateSystem to the target CoordinateSystem
405 if ( ct.isValid() && !ct.isShortCircuited() )
406 {
407 try
408 {
409 QgsCoordinateTransform toleranceTransform = ct;
410 QgsPointXY center = context.extent().center();
411 double rectSize = toleranceTransform.sourceCrs().mapUnits() == Qgis::DistanceUnit::Degrees ? 0.0008983 /* ~100/(40075014/360=111319.4833) */ : 100;
412
413 QgsRectangle sourceRect = QgsRectangle( center.x(), center.y(), center.x() + rectSize, center.y() + rectSize );
414 toleranceTransform.setBallparkTransformsAreAppropriate( true );
415 QgsRectangle targetRect = toleranceTransform.transform( sourceRect );
416
417 QgsDebugMsgLevel( u"Simplify - SourceTransformRect=%1"_s.arg( sourceRect.toString( 16 ) ), 4 );
418 QgsDebugMsgLevel( u"Simplify - TargetTransformRect=%1"_s.arg( targetRect.toString( 16 ) ), 4 );
419
420 if ( !sourceRect.isEmpty() && sourceRect.isFinite() && !targetRect.isEmpty() && targetRect.isFinite() )
421 {
422 QgsPointXY minimumSrcPoint( sourceRect.xMinimum(), sourceRect.yMinimum() );
423 QgsPointXY maximumSrcPoint( sourceRect.xMaximum(), sourceRect.yMaximum() );
424 QgsPointXY minimumDstPoint( targetRect.xMinimum(), targetRect.yMinimum() );
425 QgsPointXY maximumDstPoint( targetRect.xMaximum(), targetRect.yMaximum() );
426
427 double sourceHypothenuse = std::sqrt( minimumSrcPoint.sqrDist( maximumSrcPoint ) );
428 double targetHypothenuse = std::sqrt( minimumDstPoint.sqrDist( maximumDstPoint ) );
429
430 QgsDebugMsgLevel( u"Simplify - SourceHypothenuse=%1"_s.arg( sourceHypothenuse ), 4 );
431 QgsDebugMsgLevel( u"Simplify - TargetHypothenuse=%1"_s.arg( targetHypothenuse ), 4 );
432
433 if ( !qgsDoubleNear( targetHypothenuse, 0.0 ) )
434 map2pixelTol *= ( sourceHypothenuse / targetHypothenuse );
435 }
436 }
437 catch ( QgsCsException &cse )
438 {
439 QgsMessageLog::logMessage( QObject::tr( "Simplify transform error caught: %1" ).arg( cse.what() ), QObject::tr( "CRS" ) );
440 validTransform = false;
441 }
442 }
443
444 if ( validTransform )
445 {
446 QgsSimplifyMethod simplifyMethod;
448 simplifyMethod.setTolerance( map2pixelTol );
449 simplifyMethod.setThreshold( mSimplifyMethod.threshold() );
450 simplifyMethod.setForceLocalOptimization( mSimplifyMethod.forceLocalOptimization() );
451 featureRequest.setSimplifyMethod( simplifyMethod );
452
453 QgsVectorSimplifyMethod vectorMethod = mSimplifyMethod;
454 vectorMethod.setTolerance( map2pixelTol );
455 context.setVectorSimplifyMethod( vectorMethod );
456 }
457 else
458 {
459 QgsVectorSimplifyMethod vectorMethod;
461 context.setVectorSimplifyMethod( vectorMethod );
462 }
463 }
464 else
465 {
466 QgsVectorSimplifyMethod vectorMethod;
468 context.setVectorSimplifyMethod( vectorMethod );
469 }
470
471 featureRequest.setFeedback( mFeedback.get() );
472 // also set the interruption checker for the expression context, in case the renderer uses some complex expression
473 // which could benefit from early exit paths...
474 context.expressionContext().setFeedback( mFeedback.get() );
475
476 std::unique_ptr< QgsScopedRuntimeProfile > preparingFeatureItProfile;
477 if ( mEnableProfile )
478 {
479 preparingFeatureItProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr( "Prepare feature iteration" ), u"rendering"_s );
480 }
481
482 QgsFeatureIterator fit = mSource->getFeatures( featureRequest );
483 // Attach an interruption checker so that iterators that have potentially
484 // slow fetchFeature() implementations, such as in the WFS provider, can
485 // check it, instead of relying on just the mContext.renderingStopped() check
486 // in drawRenderer()
487
488 fit.setInterruptionChecker( mFeedback.get() );
489
490 preparingFeatureItProfile.reset();
491 preparingProfile.reset();
492
493 std::unique_ptr< QgsScopedRuntimeProfile > renderingProfile;
494 if ( mEnableProfile )
495 {
496 renderingProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr( "Rendering" ), u"rendering"_s );
497 }
498
499 if ( ( renderer->capabilities() & QgsFeatureRenderer::SymbolLevels ) && renderer->usingSymbolLevels() )
500 drawRendererLevels( renderer, fit );
501 else
502 drawRenderer( renderer, fit );
503
504 if ( !fit.isValid() )
505 {
506 mErrors.append( u"Data source invalid"_s );
507 }
508
509 if ( usingEffect )
510 {
511 renderer->paintEffect()->end( context );
512 }
513
514 context.expressionContext().setFeedback( nullptr );
515 return true;
516}
517
518static QgsGeometry combinedClipGeometry( const QgsGeometry &geom1, const QgsGeometry &geom2 )
519{
520 if ( geom1.isEmpty() )
521 return geom2;
522
523 if ( geom2.isEmpty() )
524 return geom1;
525
526 return geom1.intersection( geom2 );
527}
528
529static std::unique_ptr< QgsGeometryEngine > prepareClipGeometry( bool applyClipFilter, const QgsGeometry &clipFilterGeom, const QgsGeometry &horizonGeom )
530{
531 std::unique_ptr< QgsGeometryEngine > clipEngine;
532 if ( applyClipFilter && !horizonGeom.isEmpty() )
533 {
534 const QgsGeometry visibleRegionGeom = clipFilterGeom.intersection( horizonGeom );
535 clipEngine.reset( QgsGeometry::createGeometryEngine( visibleRegionGeom.constGet() ) );
536 clipEngine->prepareGeometry();
537 }
538 else if ( applyClipFilter && horizonGeom.isEmpty() )
539 {
540 clipEngine.reset( QgsGeometry::createGeometryEngine( clipFilterGeom.constGet() ) );
541 clipEngine->prepareGeometry();
542 }
543 else if ( !applyClipFilter && !horizonGeom.isEmpty() )
544 {
545 clipEngine.reset( QgsGeometry::createGeometryEngine( horizonGeom.constGet() ) );
546 clipEngine->prepareGeometry();
547 }
548 return clipEngine;
549}
550
551void QgsVectorLayerRenderer::drawRenderer( QgsFeatureRenderer *renderer, QgsFeatureIterator &fit )
552{
553 QElapsedTimer timer;
554 timer.start();
555 quint64 totalLabelTime = 0;
556
557 const bool isMainRenderer = renderer == mRenderer;
558
559 QgsExpressionContextScope *symbolScope = QgsExpressionContextUtils::updateSymbolScope( nullptr, new QgsExpressionContextScope() );
560 QgsRenderContext &context = *renderContext();
561 context.expressionContext().appendScope( symbolScope );
562
563 if ( mSelectionSymbol && isMainRenderer )
564 mSelectionSymbol->startRender( context, mFields );
565
566 QgsGeometry horizonGeom;
567 double lat, lon;
568 if ( context.coordinateTransform().destinationCrs().topocentricOrigin( lat, lon ) )
569 {
571 }
572
573 std::unique_ptr< QgsGeometryEngine > clipEngine = prepareClipGeometry( mApplyClipFilter, mClipFilterGeom, horizonGeom );
574
575 const QgsGeometry renderClipGeom = combinedClipGeometry( mApplyClipGeometries ? mClipFeatureGeom : QgsGeometry(), horizonGeom );
576 const QgsGeometry labelClipGeom = combinedClipGeometry( mApplyLabelClipGeometries ? mLabelClipFeatureGeom : QgsGeometry(), horizonGeom );
577
578 QgsFeature fet;
579 while ( fit.nextFeature( fet ) )
580 {
581 try
582 {
583 if ( context.renderingStopped() )
584 {
585 QgsDebugMsgLevel( u"Drawing of vector layer %1 canceled."_s.arg( layerId() ), 2 );
586 break;
587 }
588
589 if ( !fet.hasGeometry() || fet.geometry().isEmpty() )
590 continue;
591
592 if ( clipEngine && !clipEngine->intersects( fet.geometry().constGet() ) )
593 continue; // skip features outside of clipping region
594
595 if ( !renderClipGeom.isEmpty() )
596 context.setFeatureClipGeometry( renderClipGeom );
597
598 if ( !mNoSetLayerExpressionContext )
599 context.expressionContext().setFeature( fet );
600
601 const bool featureIsSelected = isMainRenderer && context.showSelection() && mSelectedFeatureIds.contains( fet.id() );
602 bool drawMarker = isMainRenderer && ( mDrawVertexMarkers && context.drawEditingInformation() && ( !mVertexMarkerOnlyForSelection || featureIsSelected ) );
603
604 // render feature
605 bool rendered = false;
607 {
608 if ( featureIsSelected && mSelectionSymbol )
609 {
610 // note: here we pass "false" for the selected argument, as we don't want to change
611 // the user's defined selection symbol colors or settings in any way
612 mSelectionSymbol->renderFeature( fet, context, -1, false, drawMarker );
613 rendered = renderer->willRenderFeature( fet, context );
614 }
615 else
616 {
617 rendered = renderer->renderFeature( fet, context, -1, featureIsSelected, drawMarker );
618 }
619 }
620 else
621 {
622 rendered = renderer->willRenderFeature( fet, context );
623 }
624
625 // labeling - register feature
626 if ( rendered )
627 {
628 // as soon as first feature is rendered, we can start showing layer updates.
629 // but if we are blocking render updates (so that a previously cached image is being shown), we wait
630 // at most e.g. 3 seconds before we start forcing progressive updates.
631 if ( !mBlockRenderUpdates || mElapsedTimer.elapsed() > MAX_TIME_TO_USE_CACHED_PREVIEW_IMAGE )
632 {
633 mReadyToCompose = true;
634 }
635
636 // new labeling engine
637 if ( isMainRenderer && context.labelingEngine() && ( mLabelProvider || mDiagramProvider ) )
638 {
639 const quint64 startLabelTime = timer.elapsed();
640 QgsGeometry obstacleGeometry;
641 QgsSymbolList symbols = renderer->originalSymbolsForFeature( fet, context );
642 QgsSymbol *symbol = nullptr;
643 if ( !symbols.isEmpty() && fet.geometry().type() == Qgis::GeometryType::Point )
644 {
645 obstacleGeometry = QgsVectorLayerLabelProvider::getPointObstacleGeometry( fet, context, symbols );
646 }
647
648 if ( !symbols.isEmpty() )
649 {
650 symbol = symbols.at( 0 );
652 }
653
654 if ( !labelClipGeom.isEmpty() )
655 context.setFeatureClipGeometry( labelClipGeom );
656
657 if ( mLabelProvider )
658 {
659 mLabelProvider->registerFeature( fet, context, obstacleGeometry, symbol );
660 }
661 if ( mDiagramProvider )
662 {
663 mDiagramProvider->registerFeature( fet, context, obstacleGeometry );
664 }
665
666 if ( !labelClipGeom.isEmpty() )
667 context.setFeatureClipGeometry( QgsGeometry() );
668
669 totalLabelTime += ( timer.elapsed() - startLabelTime );
670 }
671 }
672 }
673 catch ( const QgsCsException &cse )
674 {
675 Q_UNUSED( cse )
676 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() ) );
677 }
678 }
679
680 delete context.expressionContext().popScope();
681
682 std::unique_ptr< QgsScopedRuntimeProfile > cleanupProfile;
683 if ( mEnableProfile )
684 {
685 QgsApplication::profiler()->record( QObject::tr( "Rendering features" ), ( timer.elapsed() - totalLabelTime ) / 1000.0, u"rendering"_s );
686 if ( totalLabelTime > 0 )
687 {
688 QgsApplication::profiler()->record( QObject::tr( "Registering labels" ), totalLabelTime / 1000.0, u"rendering"_s );
689 }
690 cleanupProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr( "Finalizing" ), u"rendering"_s );
691 }
692
693 if ( mSelectionSymbol && isMainRenderer )
694 mSelectionSymbol->stopRender( context );
695
696 stopRenderer( renderer, nullptr );
697}
698
699void QgsVectorLayerRenderer::drawRendererLevels( QgsFeatureRenderer *renderer, QgsFeatureIterator &fit )
700{
701 const bool isMainRenderer = renderer == mRenderer;
702
703 // We need to figure out in which order all the features should be rendered.
704 // Ordering is based on (a) a "level" which is determined by the configured
705 // feature rendering order" and (b) the symbol level. The "level" is
706 // determined by the values of the attributes defined in the feature
707 // rendering order settings. Each time the attribute(s) have a new distinct
708 // value, a new empty QHash is added to the "features" list. This QHash is
709 // then filled by mappings from the symbol to a list of all the features
710 // that should be rendered by that symbol.
711 //
712 // If orderBy is not enabled, this list will only ever contain a single
713 // element.
714 QList<QHash< QgsSymbol *, QList<QgsFeature> >> features;
715
716 // We have at least one "level" for the features.
717 features.push_back( {} );
718
719 QSet<int> orderByAttributeIdx;
720 if ( renderer->orderByEnabled() )
721 {
722 orderByAttributeIdx = renderer->orderBy().usedAttributeIndices( mSource->fields() );
723 }
724
725 QgsRenderContext &context = *renderContext();
726
727 QgsSingleSymbolRenderer *selRenderer = nullptr;
728 if ( !mSelectedFeatureIds.isEmpty() )
729 {
730 selRenderer = new QgsSingleSymbolRenderer( QgsSymbol::defaultSymbol( mGeometryType ).release() );
731 selRenderer->symbol()->setColor( context.selectionColor() );
732 selRenderer->setVertexMarkerAppearance( mVertexMarkerStyle, mVertexMarkerSize );
733 selRenderer->startRender( context, mFields );
734 }
735
736 QgsExpressionContextScope *symbolScope = QgsExpressionContextUtils::updateSymbolScope( nullptr, new QgsExpressionContextScope() );
737 auto scopePopper = std::make_unique< QgsExpressionContextScopePopper >( context.expressionContext(), symbolScope );
738
739 std::unique_ptr< QgsScopedRuntimeProfile > fetchFeaturesProfile;
740 if ( mEnableProfile )
741 {
742 fetchFeaturesProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr( "Fetching features" ), u"rendering"_s );
743 }
744
745 QElapsedTimer timer;
746 timer.start();
747 quint64 totalLabelTime = 0;
748
749 QgsGeometry horizonGeom;
750 double lat, lon;
751 if ( context.coordinateTransform().destinationCrs().topocentricOrigin( lat, lon ) )
752 {
754 }
755
756 const QgsGeometry labelClipGeom = combinedClipGeometry( mApplyLabelClipGeometries ? mLabelClipFeatureGeom : QgsGeometry(), horizonGeom );
757 if ( !labelClipGeom.isEmpty() )
758 context.setFeatureClipGeometry( labelClipGeom );
759
760 std::unique_ptr< QgsGeometryEngine > clipEngine = prepareClipGeometry( mApplyClipFilter, mClipFilterGeom, horizonGeom );
761
762 // 1. fetch features
763 QgsFeature fet;
764 QVector<QVariant> prevValues; // previous values of ORDER BY attributes
765 while ( fit.nextFeature( fet ) )
766 {
767 if ( context.renderingStopped() )
768 {
769 qDebug( "rendering stop!" );
770 stopRenderer( renderer, selRenderer );
771 return;
772 }
773
774 if ( !fet.hasGeometry() )
775 continue;
776
777 if ( clipEngine && !clipEngine->intersects( fet.geometry().constGet() ) )
778 continue; // skip features outside of clipping region
779
780 if ( !mNoSetLayerExpressionContext )
781 context.expressionContext().setFeature( fet );
782 QgsSymbol *sym = renderer->symbolForFeature( fet, context );
783 if ( !sym )
784 {
785 continue;
786 }
787
788 if ( renderer->orderByEnabled() )
789 {
790 QVector<QVariant> currentValues;
791 for ( const int idx : std::as_const( orderByAttributeIdx ) )
792 {
793 currentValues.push_back( fet.attribute( idx ) );
794 }
795 if ( prevValues.empty() )
796 {
797 prevValues = std::move( currentValues );
798 }
799 else if ( currentValues != prevValues )
800 {
801 // Current values of ORDER BY attributes are different than previous
802 // values of these attributes. Start a new level.
803 prevValues = std::move( currentValues );
804 features.push_back( {} );
805 }
806 }
807
809 {
810 QHash<QgsSymbol *, QList<QgsFeature> > &featuresBack = features.back();
811 auto featuresBackIt = featuresBack.find( sym );
812 if ( featuresBackIt == featuresBack.end() )
813 {
814 featuresBackIt = featuresBack.insert( sym, QList<QgsFeature>() );
815 }
816 featuresBackIt->append( fet );
817 }
818
819 // new labeling engine
820 if ( isMainRenderer && context.labelingEngine() && ( mLabelProvider || mDiagramProvider ) )
821 {
822 const quint64 startLabelTime = timer.elapsed();
823
824 QgsGeometry obstacleGeometry;
825 QgsSymbolList symbols = renderer->originalSymbolsForFeature( fet, context );
826 QgsSymbol *symbol = nullptr;
827 if ( !symbols.isEmpty() && fet.geometry().type() == Qgis::GeometryType::Point )
828 {
829 obstacleGeometry = QgsVectorLayerLabelProvider::getPointObstacleGeometry( fet, context, symbols );
830 }
831
832 if ( !symbols.isEmpty() )
833 {
834 symbol = symbols.at( 0 );
836 }
837
838 if ( mLabelProvider )
839 {
840 mLabelProvider->registerFeature( fet, context, obstacleGeometry, symbol );
841 }
842 if ( mDiagramProvider )
843 {
844 mDiagramProvider->registerFeature( fet, context, obstacleGeometry );
845 }
846
847 totalLabelTime += ( timer.elapsed() - startLabelTime );
848 }
849 }
850
851 fetchFeaturesProfile.reset();
852 if ( mEnableProfile )
853 {
854 if ( totalLabelTime > 0 )
855 {
856 QgsApplication::profiler()->record( QObject::tr( "Registering labels" ), totalLabelTime / 1000.0, u"rendering"_s );
857 }
858 }
859
860 if ( !labelClipGeom.isEmpty() )
861 context.setFeatureClipGeometry( QgsGeometry() );
862
863 scopePopper.reset();
864
865 if ( features.back().empty() )
866 {
867 // nothing to draw
868 stopRenderer( renderer, selRenderer );
869 return;
870 }
871
872
873 std::unique_ptr< QgsScopedRuntimeProfile > sortingProfile;
874 if ( mEnableProfile )
875 {
876 sortingProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr( "Sorting features" ), u"rendering"_s );
877 }
878 // find out the order
879 QgsSymbolLevelOrder levels;
880 QgsSymbolList symbols = renderer->symbols( context );
881 for ( int i = 0; i < symbols.count(); i++ )
882 {
883 QgsSymbol *sym = symbols[i];
884 for ( int j = 0; j < sym->symbolLayerCount(); j++ )
885 {
886 int level = sym->symbolLayer( j )->renderingPass();
887 if ( level < 0 || level >= 1000 ) // ignore invalid levels
888 continue;
889 QgsSymbolLevelItem item( sym, j );
890 while ( level >= levels.count() ) // append new empty levels
891 levels.append( QgsSymbolLevel() );
892 levels[level].append( item );
893 }
894 }
895 sortingProfile.reset();
896
897 const QgsGeometry renderClipGeom = combinedClipGeometry( mApplyClipGeometries ? mClipFeatureGeom : QgsGeometry(), horizonGeom );
898 if ( !renderClipGeom.isEmpty() )
899 context.setFeatureClipGeometry( renderClipGeom );
900
901 // 2. draw features in correct order
902 for ( const QHash< QgsSymbol *, QList<QgsFeature> > &featureLists : features )
903 {
904 for ( int l = 0; l < levels.count(); l++ )
905 {
906 const QgsSymbolLevel &level = levels[l];
907 std::unique_ptr< QgsScopedRuntimeProfile > renderingProfile;
908 if ( mEnableProfile )
909 {
910 renderingProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr( "Rendering symbol level %1" ).arg( l + 1 ), u"rendering"_s );
911 }
912
913 for ( int i = 0; i < level.count(); i++ )
914 {
915 const QgsSymbolLevelItem &item = level[i];
916 if ( !featureLists.contains( item.symbol() ) )
917 {
918 QgsDebugError( u"level item's symbol not found!"_s );
919 continue;
920 }
921 const int layer = item.layer();
922 const QList<QgsFeature> &lst = featureLists[item.symbol()];
923 for ( const QgsFeature &feature : lst )
924 {
925 if ( context.renderingStopped() )
926 {
927 stopRenderer( renderer, selRenderer );
928 return;
929 }
930
931 const bool featureIsSelected = isMainRenderer && context.showSelection() && mSelectedFeatureIds.contains( feature.id() );
932 if ( featureIsSelected && mSelectionSymbol )
933 continue; // defer rendering of selected symbols
934
935 // maybe vertex markers should be drawn only during the last pass...
936 const bool drawMarker = isMainRenderer && ( mDrawVertexMarkers && context.drawEditingInformation() && ( !mVertexMarkerOnlyForSelection || featureIsSelected ) );
937
938 if ( !mNoSetLayerExpressionContext )
939 context.expressionContext().setFeature( feature );
940
941 try
942 {
943 renderer->renderFeature( feature, context, layer, featureIsSelected, drawMarker );
944
945 // as soon as first feature is rendered, we can start showing layer updates.
946 // but if we are blocking render updates (so that a previously cached image is being shown), we wait
947 // at most e.g. 3 seconds before we start forcing progressive updates.
948 if ( !mBlockRenderUpdates || mElapsedTimer.elapsed() > MAX_TIME_TO_USE_CACHED_PREVIEW_IMAGE )
949 {
950 mReadyToCompose = true;
951 }
952 }
953 catch ( const QgsCsException &cse )
954 {
955 Q_UNUSED( cse )
956 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() ) );
957 }
958 }
959 }
960 }
961 }
962
963 if ( mSelectionSymbol && !mSelectedFeatureIds.empty() && isMainRenderer && context.showSelection() )
964 {
965 mSelectionSymbol->startRender( context, mFields );
966
967 for ( const QHash< QgsSymbol *, QList<QgsFeature> > &featureLists : features )
968 {
969 for ( auto it = featureLists.constBegin(); it != featureLists.constEnd(); ++it )
970 {
971 const QList<QgsFeature> &lst = it.value();
972 for ( const QgsFeature &feature : lst )
973 {
974 if ( context.renderingStopped() )
975 {
976 break;
977 }
978
979 const bool featureIsSelected = mSelectedFeatureIds.contains( feature.id() );
980 if ( !featureIsSelected )
981 continue;
982
983 const bool drawMarker = mDrawVertexMarkers && context.drawEditingInformation();
984 // note: here we pass "false" for the selected argument, as we don't want to change
985 // the user's defined selection symbol colors or settings in any way
986 mSelectionSymbol->renderFeature( feature, context, -1, false, drawMarker );
987 }
988 }
989 }
990
991 mSelectionSymbol->stopRender( context );
992 }
993
994 std::unique_ptr< QgsScopedRuntimeProfile > cleanupProfile;
995 if ( mEnableProfile )
996 {
997 cleanupProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr( "Finalizing" ), u"rendering"_s );
998 }
999
1000 stopRenderer( renderer, selRenderer );
1001}
1002
1003void QgsVectorLayerRenderer::stopRenderer( QgsFeatureRenderer *renderer, QgsSingleSymbolRenderer *selRenderer )
1004{
1005 QgsRenderContext &context = *renderContext();
1006 renderer->stopRender( context );
1007 if ( selRenderer )
1008 {
1009 selRenderer->stopRender( context );
1010 delete selRenderer;
1011 }
1012}
1013
1014void QgsVectorLayerRenderer::prepareLabeling( QgsVectorLayer *layer, QSet<QString> &attributeNames )
1015{
1016 QgsRenderContext &context = *renderContext();
1017 // TODO: add attributes for geometry generator
1018 if ( QgsLabelingEngine *engine2 = context.labelingEngine() )
1019 {
1020 if ( layer->labelsEnabled() )
1021 {
1022 if ( context.labelSink() )
1023 {
1024 if ( const QgsRuleBasedLabeling *rbl = dynamic_cast<const QgsRuleBasedLabeling *>( layer->labeling() ) )
1025 {
1026 mLabelProvider = new QgsRuleBasedLabelSinkProvider( *rbl, layer, context.labelSink() );
1027 }
1028 else
1029 {
1030 QgsPalLayerSettings settings = layer->labeling()->settings();
1031 mLabelProvider = new QgsLabelSinkProvider( layer, QString(), context.labelSink(), &settings );
1032 }
1033 }
1034 else
1035 {
1036 mLabelProvider = layer->labeling()->provider( layer );
1037 }
1038 if ( mLabelProvider )
1039 {
1040 engine2->addProvider( mLabelProvider );
1041 if ( !mLabelProvider->prepare( context, attributeNames ) )
1042 {
1043 engine2->removeProvider( mLabelProvider );
1044 mLabelProvider = nullptr; // deleted by engine
1045 }
1046 }
1047 }
1048 }
1049
1050#if 0 // TODO: limit of labels, font not found
1051 QgsPalLayerSettings &palyr = mContext.labelingEngine()->layer( mLayerID );
1052
1053 // see if feature count limit is set for labeling
1054 if ( palyr.limitNumLabels && palyr.maxNumLabels > 0 )
1055 {
1056 QgsFeatureIterator fit = getFeatures( QgsFeatureRequest()
1057 .setFilterRect( mContext.extent() )
1058 .setNoAttributes() );
1059
1060 // total number of features that may be labeled
1061 QgsFeature f;
1062 int nFeatsToLabel = 0;
1063 while ( fit.nextFeature( f ) )
1064 {
1065 nFeatsToLabel++;
1066 }
1067 palyr.mFeaturesToLabel = nFeatsToLabel;
1068 }
1069
1070 // notify user about any font substitution
1071 if ( !palyr.mTextFontFound && !mLabelFontNotFoundNotified )
1072 {
1073 emit labelingFontNotFound( this, palyr.mTextFontFamily );
1074 mLabelFontNotFoundNotified = true;
1075 }
1076#endif
1077}
1078
1079void QgsVectorLayerRenderer::prepareDiagrams( QgsVectorLayer *layer, QSet<QString> &attributeNames )
1080{
1081 QgsRenderContext &context = *renderContext();
1082 if ( QgsLabelingEngine *engine2 = context.labelingEngine() )
1083 {
1084 if ( layer->diagramsEnabled() )
1085 {
1086 mDiagramProvider = new QgsVectorLayerDiagramProvider( layer );
1087 // need to be added before calling prepare() - uses map settings from engine
1088 engine2->addProvider( mDiagramProvider );
1089 if ( !mDiagramProvider->prepare( context, attributeNames ) )
1090 {
1091 engine2->removeProvider( mDiagramProvider );
1092 mDiagramProvider = nullptr; // deleted by engine
1093 }
1094 }
1095 }
1096}
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:2899
QFlags< MapLayerRendererFlag > MapLayerRendererFlags
Flags which control how map layer renderers behave.
Definition qgis.h:2991
QFlags< VectorRenderingSimplificationFlag > VectorRenderingSimplificationFlags
Simplification flags for vector feature rendering.
Definition qgis.h:3247
@ NoSimplification
No simplification can be applied.
Definition qgis.h:3233
@ FullSimplification
All simplification hints can be applied ( Geometry + AA-disabling ).
Definition qgis.h:3236
@ GeometrySimplification
The geometries can be simplified using the current map2pixel context state.
Definition qgis.h:3234
@ Degrees
Degrees, for planar geographic CRS distance measurements.
Definition qgis.h:5519
@ EmbeddedSymbols
Retrieve any embedded feature symbology.
Definition qgis.h:2365
@ AffectsLabeling
If present, indicates that the renderer will participate in the map labeling problem.
Definition qgis.h:891
@ Point
Points.
Definition qgis.h:380
@ Unknown
Unknown types.
Definition qgis.h:383
@ Null
No geometry.
Definition qgis.h:384
@ Vector
Vector layer.
Definition qgis.h:207
@ AffectsLabeling
The layer rendering will interact with the map labeling.
Definition qgis.h:2982
@ SkipSymbolRendering
Disable symbol rendering while still drawing labels if enabled.
Definition qgis.h:2962
@ NoMarker
No marker.
Definition qgis.h:1986
@ SemiTransparentCircle
Semi-transparent circle marker.
Definition qgis.h:1984
@ Cross
Cross marker.
Definition qgis.h:1985
@ CustomColor
Use default symbol with a custom selection color.
Definition qgis.h:1910
@ CustomSymbol
Use a custom symbol.
Definition qgis.h:1911
@ Default
Use default symbol and selection colors.
Definition qgis.h:1909
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...
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:8193
#define Q_NOWARN_DEPRECATED_PUSH
Definition qgis.h:8192
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
Definition qgis.h:7557
#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