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