19#include <QElapsedTimer>
21#include <QtConcurrentMap>
54LayerRenderJob &LayerRenderJob::operator=( LayerRenderJob &&other )
56 mContext = std::move( other.mContext );
61 renderer = other.renderer;
62 other.renderer =
nullptr;
64 imageInitialized = other.imageInitialized;
65 blendMode = other.blendMode;
66 opacity = other.opacity;
67 cached = other.cached;
69 renderAboveLabels = other.renderAboveLabels;
70 completed = other.completed;
71 renderingTime = other.renderingTime;
72 estimatedRenderingTime = other.estimatedRenderingTime ;
73 errors = other.errors;
74 layerId = other.layerId;
76 maskPaintDevice = std::move( other.maskPaintDevice );
78 firstPassJob = other.firstPassJob;
79 other.firstPassJob =
nullptr;
81 picture = std::move( other.picture );
83 maskJobs = other.maskJobs;
85 maskRequiresLayerRasterization = other.maskRequiresLayerRasterization;
90LayerRenderJob::LayerRenderJob( LayerRenderJob &&other )
91 : imageInitialized( other.imageInitialized )
92 , blendMode( other.blendMode )
93 , opacity( other.opacity )
94 , cached( other.cached )
95 , renderAboveLabels( other.renderAboveLabels )
96 , layer( other.layer )
97 , completed( other.completed )
98 , renderingTime( other.renderingTime )
99 , estimatedRenderingTime( other.estimatedRenderingTime )
100 , errors( other.errors )
101 , layerId( other.layerId )
102 , maskRequiresLayerRasterization( other.maskRequiresLayerRasterization )
103 , maskJobs( other.maskJobs )
105 mContext = std::move( other.mContext );
110 renderer = other.renderer;
111 other.renderer =
nullptr;
113 maskPaintDevice = std::move( other.maskPaintDevice );
115 firstPassJob = other.firstPassJob;
116 other.firstPassJob =
nullptr;
118 picture = std::move( other.picture );
121bool LayerRenderJob::imageCanBeComposed()
const
123 if ( imageInitialized )
127 return renderer->isReadyToCompose();
141 : mSettings( settings )
187 return mLabelingEngineFeedback;
192 QHash<QgsMapLayer *, int> result;
195 if (
auto &&lKey = it.key() )
196 result.insert( lKey, it.value() );
216 QSet< QgsMapLayer * > labeledLayers;
223 switch ( ml->type() )
261 bool canUseCache = canCache && QSet< QgsMapLayer * >( labelDependentLayers.begin(), labelDependentLayers.end() ) == labeledLayers;
290 static const double SPLIT_COORD = 180.0;
302 QgsDebugMsgLevel( QStringLiteral(
"\n0:%1 %2x%3\n1:%4\n2:%5 %6x%7 (w:%8 h:%9)" )
305 .arg( std::fabs( 1.0 - extent2.
width() / extent.
width() ) )
306 .arg( std::fabs( 1.0 - extent2.
height() / extent.
height() ) )
340 if ( ll.
x() > ur.
x() )
369 extent =
QgsRectangle( std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), std::numeric_limits<double>::max() );
378 QgsDebugMsg( QStringLiteral(
"Transform error caught" ) );
379 extent =
QgsRectangle( std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), std::numeric_limits<double>::max() );
380 r2 =
QgsRectangle( std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), std::numeric_limits<double>::max() );
387QImage *QgsMapRendererJob::allocateImage( QString layerId )
394 if ( image->isNull() )
403QPainter *QgsMapRendererJob::allocateImageAndPainter( QString layerId, QImage *&image,
const QgsRenderContext *context )
405 QPainter *painter =
nullptr;
406 image = allocateImage( layerId );
409 painter =
new QPainter( image );
415QgsMapRendererJob::PictureAndPainter QgsMapRendererJob::allocatePictureAndPainter(
const QgsRenderContext *context )
417 std::unique_ptr<QPicture> picture = std::make_unique<QPicture>();
418 QPainter *painter =
new QPainter( picture.get() );
420 return { std::move( picture ), painter };
425 std::vector< LayerRenderJob > layerJobs;
434 Q_UNUSED( cacheValid )
435 QgsDebugMsgLevel( QStringLiteral(
"CACHE VALID: %1" ).arg( cacheValid ), 4 );
440 while ( li.hasPrevious() )
444 QgsDebugMsgLevel( QStringLiteral(
"layer %1: minscale:%2 maxscale:%3 scaledepvis:%4 blendmode:%5 isValid:%6" )
461 QgsDebugMsgLevel( QStringLiteral(
"Layer not rendered because it is not within the defined visibility scale range" ), 3 );
467 QgsDebugMsgLevel( QStringLiteral(
"Layer not rendered because it is not visible within the map's time range" ), 3 );
473 QgsDebugMsgLevel( QStringLiteral(
"Layer not rendered because it is not visible within the map's z range" ), 3 );
482 bool haveExtentInLayerCrs =
true;
485 haveExtentInLayerCrs = reprojectToLayerExtent( ml, ct, r1, r2 );
490 mErrors.append( Error( ml->
id(), tr(
"There was a problem transforming the layer's extent. Layer skipped." ) ) );
501 if ( ( vl && vl->
isEditable() ) || requiresLabeling )
507 layerJobs.emplace_back( LayerRenderJob() );
508 LayerRenderJob &job = layerJobs.back();
510 job.layerId = ml->
id();
511 job.renderAboveLabels = ml->
customProperty( QStringLiteral(
"rendering/renderAboveLabels" ) ).toBool();
515 if ( !ml->
customProperty( QStringLiteral(
"_noset_layer_expression_context" ) ).toBool() )
517 job.context()->setPainter( painter );
518 job.context()->setLabelingEngine( labelingEngine2 );
519 job.context()->setLabelSink(
labelSink() );
520 job.context()->setCoordinateTransform( ct );
521 job.context()->setExtent( r1 );
522 if ( !haveExtentInLayerCrs )
525 if ( mFeatureFilterProvider )
526 job.context()->setFeatureFilterProvider( mFeatureFilterProvider );
557 job.imageInitialized =
true;
560 job.renderer =
nullptr;
561 job.context()->setPainter(
nullptr );
566 QElapsedTimer layerTime;
572 job.context()->setFeedback( job.renderer->feedback() );
578 if (
mCache || ( !painter && !deferredPainterSet ) || ( job.renderer && job.renderer->forceRasterRender() ) )
581 job.context()->setPainter( allocateImageAndPainter( ml->
id(), job.img, job.context() ) );
585 job.renderer =
nullptr;
586 layerJobs.pop_back();
591 job.renderingTime = layerTime.elapsed();
599 std::vector< LayerRenderJob > secondPassJobs;
602 QHash<QString, LayerRenderJob *> layerJobMapping;
605 QMap<QString, bool> maskLayerHasEffects;
606 QMap<int, bool> labelHasEffects;
614 MaskSource(
const QString &layerId_,
const QString &labelRuleId_,
int labelMaskId_,
bool hasEffects_ ):
615 layerId( layerId_ ), labelRuleId( labelRuleId_ ), labelMaskId( labelMaskId_ ), hasEffects( hasEffects_ ) {}
620 QHash<QString, QPair<QSet<QgsSymbolLayerId>, QList<MaskSource>>> maskedSymbolLayers;
627 for ( LayerRenderJob &job : firstPassJobs )
629 layerJobMapping[job.layerId] = &job;
634 for ( LayerRenderJob &job : firstPassJobs )
641 auto collectMasks = [&](
QgsMaskedLayers * masks, QString sourceLayerId, QString ruleId = QString(),
int labelMaskId = -1 )
643 bool hasEffects =
false;
644 for (
auto it = masks->begin(); it != masks->end(); ++it )
646 auto lit = maskedSymbolLayers.find( it.key() );
647 if ( lit == maskedSymbolLayers.end() )
649 maskedSymbolLayers[it.key()] = qMakePair( it.value().symbolLayerIds, QList<MaskSource>() << MaskSource( sourceLayerId, ruleId, labelMaskId, it.value().hasEffects ) );
653 if ( lit->first != it.value().symbolLayerIds )
655 QgsLogger::warning( QStringLiteral(
"Layer %1 : Different sets of symbol layers are masked by different sources ! Only one (arbitrary) set will be retained !" ).arg( it.key() ) );
658 lit->second.push_back( MaskSource( sourceLayerId, ruleId, labelMaskId, hasEffects ) );
660 hasEffects |= it.value().hasEffects;
662 if ( ! masks->isEmpty() && labelMaskId == -1 )
663 maskLayerHasEffects[ sourceLayerId ] = hasEffects;
668 for (
auto it = labelMasks.begin(); it != labelMasks.end(); it++ )
670 QString labelRule = it.key();
676 for (
auto mit = masks.begin(); mit != masks.end(); mit++ )
678 const QString sourceLayerId = mit.key();
680 if ( !layerJobMapping.contains( sourceLayerId ) )
683 usableMasks.insert( sourceLayerId, mit.value() );
686 if ( usableMasks.empty() )
690 QSet<QgsSymbolLayerReference> slRefs;
691 bool hasEffects =
false;
692 for (
auto mit = usableMasks.begin(); mit != usableMasks.end(); mit++ )
694 const QString sourceLayerId = mit.key();
696 if ( !layerJobMapping.contains( sourceLayerId ) )
699 for (
auto slIt = mit.value().symbolLayerIds.begin(); slIt != mit.value().symbolLayerIds.end(); slIt++ )
704 hasEffects |= mit.value().hasEffects;
707 int labelMaskId = labelJob.maskIdProvider.insertLabelLayer( vl->
id(), it.key(), slRefs );
708 labelHasEffects[ labelMaskId ] = hasEffects;
711 collectMasks( &usableMasks, vl->
id(), labelRule, labelMaskId );
716 collectMasks( &symbolLayerMasks, vl->
id() );
719 if ( maskedSymbolLayers.isEmpty() )
720 return secondPassJobs;
723 for (
int maskId = 0; maskId < labelJob.maskIdProvider.size(); maskId++ )
725 QPaintDevice *maskPaintDevice =
nullptr;
726 QPainter *maskPainter =
nullptr;
727 if ( forceVector && !labelHasEffects[ maskId ] )
731 maskPainter =
new QPainter( maskPaintDevice );
736 QImage *maskImage =
nullptr;
737 maskPainter = allocateImageAndPainter( QStringLiteral(
"label mask" ), maskImage, &labelJob.context );
738 maskImage->fill( 0 );
739 maskPaintDevice = maskImage;
742 labelJob.context.setMaskPainter( maskPainter, maskId );
743 labelJob.maskPainters.push_back( std::unique_ptr<QPainter>( maskPainter ) );
744 labelJob.maskPaintDevices.push_back( std::unique_ptr<QPaintDevice>( maskPaintDevice ) );
746 labelJob.context.setMaskIdProvider( &labelJob.maskIdProvider );
757 if ( !labelJob.img && !forceVector )
759 labelJob.img = allocateImage( QStringLiteral(
"labels" ) );
761 else if ( !labelJob.picture && forceVector )
763 labelJob.picture.reset(
new QPicture() );
767 for ( LayerRenderJob &job : firstPassJobs )
769 job.maskRequiresLayerRasterization =
false;
771 auto it = maskedSymbolLayers.find( job.layerId );
772 if ( it != maskedSymbolLayers.end() )
774 const QList<MaskSource> &sourceList = it->second;
775 for (
const MaskSource &source : sourceList )
777 job.maskRequiresLayerRasterization |= source.hasEffects;
782 const bool isRasterRendering = !forceVector || job.maskRequiresLayerRasterization || ( job.renderer && job.renderer->forceRasterRender() );
783 if ( isRasterRendering && !job.img )
785 job.context()->setPainter( allocateImageAndPainter( job.layerId, job.img, job.context() ) );
787 else if ( !isRasterRendering && !job.picture )
789 PictureAndPainter pictureAndPainter = allocatePictureAndPainter( job.context() );
790 job.picture = std::move( pictureAndPainter.first );
791 job.context()->setPainter( pictureAndPainter.second );
794 job.renderer = job.layer->createMapRenderer( *( job.context() ) );
798 if ( maskLayerHasEffects.contains( job.layerId ) )
800 QPaintDevice *maskPaintDevice =
nullptr;
801 QPainter *maskPainter =
nullptr;
802 if ( forceVector && !maskLayerHasEffects[ job.layerId ] )
806 maskPainter =
new QPainter( maskPaintDevice );
811 QImage *maskImage =
nullptr;
812 maskPainter = allocateImageAndPainter( job.layerId, maskImage, job.context() );
813 maskImage->fill( 0 );
814 maskPaintDevice = maskImage;
817 job.context()->setMaskPainter( maskPainter );
818 job.maskPainter.reset( maskPainter );
819 job.maskPaintDevice.reset( maskPaintDevice );
823 for ( LayerRenderJob &job : firstPassJobs )
827 auto it = maskedSymbolLayers.find( job.layerId );
828 if ( it == maskedSymbolLayers.end() )
831 QList<MaskSource> &sourceList = it->second;
832 const QSet<QgsSymbolLayerId> &symbolList = it->first;
834 secondPassJobs.emplace_back( LayerRenderJob() );
835 LayerRenderJob &job2 = secondPassJobs.back();
837 job2.maskRequiresLayerRasterization = job.maskRequiresLayerRasterization;
840 for ( MaskSource &source : sourceList )
842 if ( source.labelMaskId != -1 )
843 job2.maskJobs.push_back( qMakePair(
nullptr, source.labelMaskId ) );
845 job2.maskJobs.push_back( qMakePair( layerJobMapping[source.layerId], -1 ) );
849 job2.setContext( std::make_unique< QgsRenderContext >( *job.context() ) );
851 job2.layer = job.layer;
852 job2.renderAboveLabels = job.renderAboveLabels;
853 job2.layerId = job.layerId;
856 job2.firstPassJob = &job;
858 if ( !forceVector || job2.maskRequiresLayerRasterization )
860 job2.context()->setPainter( allocateImageAndPainter( job.layerId, job2.img, job2.context() ) );
864 PictureAndPainter pictureAndPainter = allocatePictureAndPainter( job2.context() );
865 job2.picture = std::move( pictureAndPainter.first );
866 job2.context()->setPainter( pictureAndPainter.second );
869 if ( ! job2.img && ! job2.picture )
871 secondPassJobs.pop_back();
878 job2.renderer = mapRenderer;
881 job2.context()->setFeedback( job2.renderer->feedback() );
889 return secondPassJobs;
897 for ( LayerRenderJob &job : secondPassJobs )
899 if ( job.maskRequiresLayerRasterization )
905 for (
const QPair<LayerRenderJob *, int> &p : std::as_const( job.maskJobs ) )
907 QPainter *maskPainter = p.first ? p.first->maskPainter.get() : labelJob.maskPainters[p.second].get();
908 QPainterPath path =
static_cast<QgsMaskPaintDevice *
>( maskPainter->device() )->maskPainterPath();
909 for (
const QgsSymbolLayer *symbolLayer : job.context()->disabledSymbolLayers() )
911 job.context()->addSymbolLayerClipPath( symbolLayer, path );
915 job.context()->setDisabledSymbolLayers( QSet<const QgsSymbolLayer *>() );
923 job.context.setPainter( painter );
924 job.context.setLabelingEngine( labelingEngine2 );
925 job.context.setFeedback( mLabelingEngineFeedback );
929 job.context.setExtent( r1 );
931 job.context.setFeatureFilterProvider( mFeatureFilterProvider );
934 job.context.setCoordinateTransform( ct );
948 job.context.setPainter(
nullptr );
952 if ( canUseLabelCache && (
mCache || !painter ) )
954 job.img = allocateImage( QStringLiteral(
"labels" ) );
964 for ( LayerRenderJob &job : jobs )
968 delete job.context()->painter();
969 job.context()->setPainter(
nullptr );
971 if (
mCache && !job.cached && job.completed && job.layer )
973 QgsDebugMsgLevel( QStringLiteral(
"caching image for %1" ).arg( job.layerId ), 2 );
984 delete job.context()->painter();
985 job.context()->setPainter(
nullptr );
986 job.picture.reset(
nullptr );
991 const QStringList
errors = job.renderer->errors();
992 for (
const QString &message :
errors )
993 mErrors.append( Error( job.renderer->layerId(), message ) );
998 job.renderer =
nullptr;
1004 job.maskPainter.reset(
nullptr );
1005 job.maskPaintDevice.reset(
nullptr );
1013 for ( LayerRenderJob &job : jobs )
1017 delete job.context()->painter();
1018 job.context()->setPainter(
nullptr );
1026 delete job.context()->painter();
1027 job.context()->setPainter(
nullptr );
1032 delete job.renderer;
1033 job.renderer =
nullptr;
1047 if (
mCache && !job.cached && !job.context.renderingStopped() )
1058 job.picture.reset(
nullptr );
1059 job.maskPainters.clear();
1060 job.maskPaintDevices.clear();
1064#define DEBUG_RENDERING 0
1067 const std::vector<LayerRenderJob> &jobs,
1068 const LabelRenderJob &labelJob,
1074 image.setDotsPerMeterX(
static_cast<int>( settings.
outputDpi() * 39.37 ) );
1075 image.setDotsPerMeterY(
static_cast<int>( settings.
outputDpi() * 39.37 ) );
1078 QPainter painter( &image );
1083 for (
const LayerRenderJob &job : jobs )
1085 if ( job.renderAboveLabels )
1092 painter.setCompositionMode( job.blendMode );
1093 painter.setOpacity( job.opacity );
1096 img.save( QString(
"/tmp/final_%1.png" ).arg( i ) );
1100 painter.drawImage( 0, 0, img );
1106 if ( labelJob.img && labelJob.complete )
1108 painter.setCompositionMode( QPainter::CompositionMode_SourceOver );
1109 painter.setOpacity( 1.0 );
1110 painter.drawImage( 0, 0, *labelJob.img );
1118 painter.setCompositionMode( QPainter::CompositionMode_SourceOver );
1119 painter.setOpacity( 1.0 );
1120 painter.drawImage( 0, 0, labelCacheImage );
1124 for (
const LayerRenderJob &job : jobs )
1126 if ( !job.renderAboveLabels )
1133 painter.setCompositionMode( job.blendMode );
1134 painter.setOpacity( job.opacity );
1136 painter.drawImage( 0, 0, img );
1141 image.save(
"/tmp/final.png" );
1148 const LayerRenderJob &job,
1152 if ( job.imageCanBeComposed() )
1154 Q_ASSERT( job.img );
1159 if ( cache && cache->
hasAnyCacheImage( job.layerId + QStringLiteral(
"_preview" ) ) )
1171 for ( LayerRenderJob &job : secondPassJobs )
1173 const bool isRasterRendering = !forceVector || job.maskRequiresLayerRasterization;
1176 if ( isRasterRendering && job.maskJobs.size() > 1 )
1178 QPainter *maskPainter =
nullptr;
1179 for ( QPair<LayerRenderJob *, int> p : job.maskJobs )
1181 QImage *maskImage =
static_cast<QImage *
>( p.first ? p.first->maskPaintDevice.get() : labelJob.maskPaintDevices[p.second].get() );
1184 maskPainter = p.first ? p.first->maskPainter.get() : labelJob.maskPainters[ p.second ].get();
1188 maskPainter->drawImage( 0, 0, *maskImage );
1193 if ( ! job.maskJobs.isEmpty() )
1196 QPair<LayerRenderJob *, int> p = *job.maskJobs.begin();
1197 if ( isRasterRendering )
1199 QImage *maskImage =
static_cast<QImage *
>( p.first ? p.first->maskPaintDevice.get() : labelJob.maskPaintDevices[p.second].get() );
1202 QPainter *painter = job.context()->painter();
1204 painter->setCompositionMode( QPainter::CompositionMode_DestinationIn );
1209 QImage maskBinAlpha = maskImage->createMaskFromColor( 0 );
1210 QVector<QRgb> mswTable;
1211 mswTable.push_back( qRgba( 0, 0, 0, 255 ) );
1212 mswTable.push_back( qRgba( 0, 0, 0, 0 ) );
1213 maskBinAlpha.setColorTable( mswTable );
1214 painter->drawImage( 0, 0, maskBinAlpha );
1218 QPainter tempPainter;
1221 QPainter *painter1 = job.firstPassJob->context()->painter();
1224 tempPainter.begin( job.firstPassJob->img );
1225 painter1 = &tempPainter;
1229 painter1->setCompositionMode( QPainter::CompositionMode_DestinationOut );
1230 painter1->drawImage( 0, 0, *maskImage );
1233 painter1->setCompositionMode( QPainter::CompositionMode_DestinationOver );
1234 painter1->drawImage( 0, 0, *job.img );
1239 job.firstPassJob->picture = std::move( job.picture );
1240 job.picture =
nullptr;
1251 QMultiMap<int, QString> elapsed;
1252 for (
const LayerRenderJob &job : jobs )
1254 for (
const LayerRenderJob &job : secondPassJobs )
1255 elapsed.insert( job.
renderingTime, job.layerId + QString(
" (second pass)" ) );
1257 elapsed.insert( labelJob.renderingTime, tr(
"Labeling" ) );
1259 QList<int> tt( elapsed.uniqueKeys() );
1260 std::sort( tt.begin(), tt.end(), std::greater<int>() );
1261 for (
int t : std::as_const( tt ) )
1263 QgsMessageLog::logMessage( tr(
"%1 ms: %2" ).arg( t ).arg( QStringList( elapsed.values( t ) ).join( QLatin1String(
", " ) ) ), tr(
"Rendering" ) );
1276 painter->setCompositionMode( QPainter::CompositionMode_SourceOver );
1280 if ( labelingEngine2 )
1282 labelingEngine2->
run( renderContext );
1285 QgsDebugMsgLevel( QStringLiteral(
"Draw labeling took (seconds): %1" ).arg( t.elapsed() / 1000. ), 2 );
1290 Q_UNUSED( settings )
1292 drawLabeling( renderContext, labelingEngine2, painter );
@ InternalLayerOpacityHandling
The renderer internally handles the raster layer's opacity, so the default layer level opacity handli...
@ ApplyClipAfterReprojection
Feature geometry clipping to mapExtent() must be performed after the geometries are transformed using...
@ Forward
Forward transform (from source to destination)
@ Reverse
Reverse/inverse transform (from destination to source)
@ ForceVectorOutput
Vector graphics should not be cached and drawn as raster images.
@ ForceRasterMasks
Force symbol masking to be applied using a raster method. This is considerably faster when compared t...
virtual bool requiresAdvancedEffects() const =0
Returns true if drawing labels requires advanced effects like composition modes, which could prevent ...
Custom exception class for Coordinate Reference System related exceptions.
bool isInfinite() const
Returns true if the range consists of all possible values.
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
QgsFeedback subclass for granular reporting of labeling engine progress.
The QgsLabelingEngine class provides map labeling functionality.
virtual void run(QgsRenderContext &context)=0
Runs the labeling job.
static void warning(const QString &msg)
Goes to qWarning.
virtual bool isVisibleInZRange(const QgsDoubleRange &range) const
Returns true if the layer should be visible and rendered for the specified z range.
virtual void setLayerRenderingTimeHint(int time)
Sets approximate render time (in ms) for the layer to render.
Restore overridden layer style on destruction.
virtual bool isVisibleInTemporalRange(const QgsDateTimeRange &range) const
Returns true if the layer should be visible and rendered for the specified time range.
Base class for all map layer types.
bool isInScaleRange(double scale) const
Tests whether the layer should be visible at the specified scale.
Q_INVOKABLE QVariant customProperty(const QString &value, const QVariant &defaultValue=QVariant()) const
Read a custom property from layer.
QgsCoordinateReferenceSystem crs
QString id() const
Returns the layer's unique ID, which is used to access this layer from QgsProject.
QPainter::CompositionMode blendMode() const
Returns the current blending mode for a layer.
bool hasScaleBasedVisibility() const
Returns whether scale based visibility is enabled for the layer.
virtual QgsMapLayerTemporalProperties * temporalProperties()
Returns the layer's temporal properties.
virtual QgsMapLayerRenderer * createMapRenderer(QgsRenderContext &rendererContext)=0
Returns new instance of QgsMapLayerRenderer that will be used for rendering of given context.
double minimumScale() const
Returns the minimum map scale (i.e.
virtual QgsMapLayerElevationProperties * elevationProperties()
Returns the layer's elevation properties.
double maximumScale() const
Returns the maximum map scale (i.e.
This class is responsible for keeping cache of rendered images resulting from a map rendering job.
bool updateParameters(const QgsRectangle &extent, const QgsMapToPixel &mtp)
Sets extent and scale parameters.
QList< QgsMapLayer * > dependentLayers(const QString &cacheKey) const
Returns a list of map layers on which an image in the cache depends.
bool hasCacheImage(const QString &cacheKey) const
Returns true if the cache contains an image with the specified cacheKey that has the same extent and ...
QImage cacheImage(const QString &cacheKey) const
Returns the cached image for the specified cacheKey.
bool hasAnyCacheImage(const QString &cacheKey, double minimumScaleThreshold=0, double maximumScaleThreshold=0) const
Returns true if the cache contains an image with the specified cacheKey with any cache's parameters (...
void setCacheImageWithParameters(const QString &cacheKey, const QImage &image, const QgsRectangle &extent, const QgsMapToPixel &mapToPixel, const QList< QgsMapLayer * > &dependentLayers=QList< QgsMapLayer * >())
Set the cached image for a particular cacheKey, using a specific extent and mapToPixel (which may dif...
void clearCacheImage(const QString &cacheKey)
Removes an image from the cache with matching cacheKey.
QImage transformedCacheImage(const QString &cacheKey, const QgsMapToPixel &mtp) const
Returns the cached image for the specified cacheKey transformed to the particular extent and scale.
Abstract base class for map rendering implementations.
void logRenderingTime(const std::vector< LayerRenderJob > &jobs, const std::vector< LayerRenderJob > &secondPassJobs, const LabelRenderJob &labelJob)
static QImage composeImage(const QgsMapSettings &settings, const std::vector< LayerRenderJob > &jobs, const LabelRenderJob &labelJob, const QgsMapRendererCache *cache=nullptr)
void cleanupSecondPassJobs(std::vector< LayerRenderJob > &jobs)
void setCache(QgsMapRendererCache *cache)
Assign a cache to be used for reading and storing rendered images of individual layers.
QHash< QgsMapLayer *, int > perLayerRenderingTime() const
Returns the render time (in ms) per layer.
void initSecondPassJobs(std::vector< LayerRenderJob > &secondPassJobs, LabelRenderJob &labelJob) const
Initialize secondPassJobs according to what have been rendered (mask clipping path e....
static QImage layerImageToBeComposed(const QgsMapSettings &settings, const LayerRenderJob &job, const QgsMapRendererCache *cache)
QHash< QString, int > mLayerRenderingTimeHints
Approximate expected layer rendering time per layer, by layer ID.
std::unique_ptr< QgsRenderedItemResults > mRenderedItemResults
Errors errors() const
List of errors that happened during the rendering job - available when the rendering has been finishe...
static Q_DECL_DEPRECATED void drawLabeling(const QgsMapSettings &settings, QgsRenderContext &renderContext, QgsLabelingEngine *labelingEngine2, QPainter *painter)
static const QgsSettingsEntryBool settingsLogCanvasRefreshEvent
Settings entry log canvas refresh event.
static const QString LABEL_PREVIEW_CACHE_ID
QgsMapRendererCache ID string for cached label image during preview compositions only.
std::vector< LayerRenderJob > prepareJobs(QPainter *painter, QgsLabelingEngine *labelingEngine2, bool deferredPainterSet=false)
Creates a list of layer rendering jobs and prepares them for later render.
void cleanupJobs(std::vector< LayerRenderJob > &jobs)
const QgsMapSettings & mapSettings() const
Returns map settings with which this job was started.
QgsMapRendererCache * mCache
void finished()
emitted when asynchronous rendering is finished (or canceled).
QgsMapRendererJob(const QgsMapSettings &settings)
~QgsMapRendererJob() override
void start()
Start the rendering job and immediately return.
int renderingTime() const
Returns the total time it took to finish the job (in milliseconds).
QStringList mLayersRedrawnFromCache
QStringList layersRedrawnFromCache() const
Returns a list of the layer IDs for all layers which were redrawn from cached images.
QList< QgsMapRendererJob::Error > Errors
static const QString LABEL_CACHE_ID
QgsMapRendererCache ID string for cached label image.
QHash< QgsWeakMapLayerPointer, int > mPerLayerRenderingTime
Render time (in ms) per layer, by layer ID.
QgsRenderedItemResults * takeRenderedItemResults()
Takes the rendered item results from the map render job and returns them.
QgsLabelingEngineFeedback * labelingEngineFeedback()
Returns the associated labeling engine feedback object.
static void composeSecondPass(std::vector< LayerRenderJob > &secondPassJobs, LabelRenderJob &labelJob, bool forceVector=false)
Compose second pass images into first pass images.
std::vector< LayerRenderJob > prepareSecondPassJobs(std::vector< LayerRenderJob > &firstPassJobs, LabelRenderJob &labelJob)
Prepares jobs for a second pass, if selective masks exist (from labels or symbol layers).
LabelRenderJob prepareLabelingJob(QPainter *painter, QgsLabelingEngine *labelingEngine2, bool canUseLabelCache=true)
Prepares a labeling job.
void setLayerRenderingTimeHints(const QHash< QString, int > &hints)
Sets approximate render times (in ms) for map layers.
void cleanupLabelJob(LabelRenderJob &job)
Handles clean up tasks for a label job, including deletion of images and storing cached label results...
QgsLabelSink * labelSink() const
Returns the label sink associated to this rendering job.
bool prepareLabelCache() const
Prepares the cache for storing the result of labeling.
QgsMapRendererQImageJob(const QgsMapSettings &settings)
The QgsMapSettings class contains configuration for rendering of the map.
QSize deviceOutputSize() const
Returns the device output size of the map render.
QList< QgsMapLayer * > layers(bool expandGroupLayers=false) const
Returns the list of layers which will be rendered in the map.
double scale() const
Returns the calculated map scale.
QgsCoordinateTransform layerTransform(const QgsMapLayer *layer) const
Returns the coordinate transform from layer's CRS to destination CRS.
QgsDoubleRange zRange() const
Returns the range of z-values which will be visible in the map.
QColor backgroundColor() const
Returns the background color of the map.
const QgsMapToPixel & mapToPixel() const
float devicePixelRatio() const
Returns the device pixel ratio.
QSize outputSize() const
Returns the size of the resulting map image, in pixels.
QImage::Format outputImageFormat() const
format of internal QImage, default QImage::Format_ARGB32_Premultiplied
double extentBuffer() const
Returns the buffer in map units to use around the visible extent for rendering symbols whose correspo...
QgsRectangle visibleExtent() const
Returns the actual extent derived from requested extent that takes output image size into account.
double outputDpi() const
Returns the DPI (dots per inch) used for conversion between real world units (e.g.
bool testFlag(Qgis::MapSettingsFlag flag) const
Check whether a particular flag is enabled.
QMap< QString, QString > layerStyleOverrides() const
Returns the map of map layer style overrides (key: layer ID, value: style name) where a different sty...
bool hasValidSettings() const
Check whether the map settings are valid and can be used for rendering.
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination coordinate reference system for the map render.
Mask painter device that can be used to register everything painted into a QPainterPath used later as...
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
static bool staticWillUseLayer(const QgsMapLayer *layer)
Called to find out whether a specified layer is used for labeling.
A class to represent a 2D point.
QString toString(int precision=-1) const
Returns a string representation of the point (x, y) with a preset precision.
Represents a raster layer.
QgsRasterRenderer * renderer() const
Returns the raster's renderer.
virtual Qgis::RasterRendererFlags flags() const
Returns flags which dictate renderer behavior.
A rectangle specified with double values.
QString toString(int precision=16) const
Returns a string representation of form xmin,ymin : xmax,ymax Coordinates will be truncated to the sp...
double xMinimum() const
Returns the x minimum value (left side of rectangle).
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
void setXMinimum(double x)
Set the minimum x value.
double width() const
Returns the width of the rectangle.
double xMaximum() const
Returns the x maximum value (right side of rectangle).
double yMaximum() const
Returns the y maximum value (top side of rectangle).
void setXMaximum(double x)
Set the maximum x value.
void grow(double delta)
Grows the rectangle in place by the specified amount.
double height() const
Returns the height of the rectangle.
bool isFinite() const
Returns true if the rectangle has finite boundaries.
Contains information about the context of a rendering operation.
void setPainterFlagsUsingContext(QPainter *painter=nullptr) const
Sets relevant flags on a destination painter, using the flags and settings currently defined for the ...
void setPainter(QPainter *p)
Sets the destination QPainter for the render operation.
static QgsRenderContext fromMapSettings(const QgsMapSettings &mapSettings)
create initialized QgsRenderContext instance from given QgsMapSettings
Stores collated details of rendered items during a map rendering operation.
T value(const QString &dynamicKeyPart=QString()) const
Returns settings value.
Type used to refer to a specific symbol layer in a symbol of a layer.
static QSet< const QgsSymbolLayer * > toSymbolLayerPointers(QgsFeatureRenderer *renderer, const QSet< QgsSymbolLayerId > &symbolLayerIds)
Converts a set of symbol layer id to a set of pointers to actual symbol layers carried by the feature...
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...
Implementation of threaded rendering for vector layers.
QgsFeatureRenderer * featureRenderer()
Returns the feature renderer.
static QgsMaskedLayers symbolLayerMasks(const QgsVectorLayer *)
Returns all masks that may be defined on symbol layers for a given vector layer.
static QHash< QString, QgsMaskedLayers > labelMasks(const QgsVectorLayer *)
Returns masks defined in labeling options of a layer.
Represents a vector layer which manages a vector based data sets.
bool labelsEnabled() const
Returns whether the layer contains labels which are enabled and should be drawn.
const QgsAbstractVectorLayerLabeling * labeling() const
Access to const labeling configuration.
bool isEditable() const FINAL
Returns true if the provider is in editing mode.
@ PointCloudLayer
Point cloud layer. Added in QGIS 3.18.
@ MeshLayer
Mesh layer. Added in QGIS 3.2.
@ VectorLayer
Vector layer.
@ RasterLayer
Raster layer.
@ GroupLayer
Composite group layer. Added in QGIS 3.24.
@ VectorTileLayer
Vector tile layer. Added in QGIS 3.14.
@ AnnotationLayer
Contains freeform, georeferenced annotations. Added in QGIS 3.16.
@ PluginLayer
Plugin based layer.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
#define QgsDebugMsgLevel(str, level)
QHash< QString, QgsMaskedLayer > QgsMaskedLayers