19#include <QElapsedTimer>
21#include <QtConcurrentMap>
55LayerRenderJob &LayerRenderJob::operator=( LayerRenderJob &&other )
57 mContext = std::move( other.mContext );
62 renderer = other.renderer;
63 other.renderer =
nullptr;
65 imageInitialized = other.imageInitialized;
66 blendMode = other.blendMode;
67 opacity = other.opacity;
68 cached = other.cached;
70 renderAboveLabels = other.renderAboveLabels;
71 completed = other.completed;
72 renderingTime = other.renderingTime;
73 estimatedRenderingTime = other.estimatedRenderingTime ;
74 errors = other.errors;
75 layerId = other.layerId;
77 maskPaintDevice = std::move( other.maskPaintDevice );
79 firstPassJob = other.firstPassJob;
80 other.firstPassJob =
nullptr;
82 picture = std::move( other.picture );
84 maskJobs = other.maskJobs;
86 maskRequiresLayerRasterization = other.maskRequiresLayerRasterization;
91LayerRenderJob::LayerRenderJob( LayerRenderJob &&other )
92 : imageInitialized( other.imageInitialized )
93 , blendMode( other.blendMode )
94 , opacity( other.opacity )
95 , cached( other.cached )
96 , renderAboveLabels( other.renderAboveLabels )
97 , layer( other.layer )
98 , completed( other.completed )
99 , renderingTime( other.renderingTime )
100 , estimatedRenderingTime( other.estimatedRenderingTime )
101 , errors( other.errors )
102 , layerId( other.layerId )
103 , maskRequiresLayerRasterization( other.maskRequiresLayerRasterization )
104 , maskJobs( other.maskJobs )
106 mContext = std::move( other.mContext );
111 renderer = other.renderer;
112 other.renderer =
nullptr;
114 maskPaintDevice = std::move( other.maskPaintDevice );
116 firstPassJob = other.firstPassJob;
117 other.firstPassJob =
nullptr;
119 picture = std::move( other.picture );
122bool LayerRenderJob::imageCanBeComposed()
const
124 if ( imageInitialized )
128 return renderer->isReadyToCompose();
142 : mSettings( settings )
188 return mLabelingEngineFeedback;
193 QHash<QgsMapLayer *, int> result;
196 if (
auto &&lKey = it.key() )
197 result.insert( lKey, it.value() );
217 QSet< QgsMapLayer * > labeledLayers;
224 switch ( ml->type() )
262 bool canUseCache = canCache && QSet< QgsMapLayer * >( labelDependentLayers.begin(), labelDependentLayers.end() ) == labeledLayers;
291 static const double SPLIT_COORD = 180.0;
303 QgsDebugMsgLevel( QStringLiteral(
"\n0:%1 %2x%3\n1:%4\n2:%5 %6x%7 (w:%8 h:%9)" )
306 .arg( std::fabs( 1.0 - extent2.
width() / extent.
width() ) )
307 .arg( std::fabs( 1.0 - extent2.
height() / extent.
height() ) )
329 Qgis::TransformDirection::Reverse );
333 Qgis::TransformDirection::Reverse );
341 if ( ll.
x() > ur.
x() )
370 extent =
QgsRectangle( std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), std::numeric_limits<double>::max() );
379 QgsDebugMsg( QStringLiteral(
"Transform error caught" ) );
380 extent =
QgsRectangle( std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), std::numeric_limits<double>::max() );
381 r2 =
QgsRectangle( std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), std::numeric_limits<double>::max() );
388QImage *QgsMapRendererJob::allocateImage( QString layerId )
395 if ( image->isNull() )
404QPainter *QgsMapRendererJob::allocateImageAndPainter( QString layerId, QImage *&image,
const QgsRenderContext *context )
406 QPainter *painter =
nullptr;
407 image = allocateImage( layerId );
410 painter =
new QPainter( image );
416QgsMapRendererJob::PictureAndPainter QgsMapRendererJob::allocatePictureAndPainter(
const QgsRenderContext *context )
418 std::unique_ptr<QPicture> picture = std::make_unique<QPicture>();
419 QPainter *painter =
new QPainter( picture.get() );
421 return { std::move( picture ), painter };
426 std::vector< LayerRenderJob > layerJobs;
435 Q_UNUSED( cacheValid )
436 QgsDebugMsgLevel( QStringLiteral(
"CACHE VALID: %1" ).arg( cacheValid ), 4 );
441 while ( li.hasPrevious() )
445 QgsDebugMsgLevel( QStringLiteral(
"layer %1: minscale:%2 maxscale:%3 scaledepvis:%4 blendmode:%5 isValid:%6" )
462 QgsDebugMsgLevel( QStringLiteral(
"Layer not rendered because it is not within the defined visibility scale range" ), 3 );
468 QgsDebugMsgLevel( QStringLiteral(
"Layer not rendered because it is not visible within the map's time range" ), 3 );
474 QgsDebugMsgLevel( QStringLiteral(
"Layer not rendered because it is not visible within the map's z range" ), 3 );
483 bool haveExtentInLayerCrs =
true;
486 haveExtentInLayerCrs = reprojectToLayerExtent( ml, ct, r1, r2 );
491 mErrors.append( Error( ml->
id(), tr(
"There was a problem transforming the layer's extent. Layer skipped." ) ) );
502 if ( ( vl && vl->
isEditable() ) || requiresLabeling )
508 layerJobs.emplace_back( LayerRenderJob() );
509 LayerRenderJob &job = layerJobs.back();
511 job.layerId = ml->
id();
512 job.renderAboveLabels = ml->
customProperty( QStringLiteral(
"rendering/renderAboveLabels" ) ).toBool();
516 if ( !ml->
customProperty( QStringLiteral(
"_noset_layer_expression_context" ) ).toBool() )
518 job.context()->setPainter( painter );
519 job.context()->setLabelingEngine( labelingEngine2 );
520 job.context()->setLabelSink(
labelSink() );
521 job.context()->setCoordinateTransform( ct );
522 job.context()->setExtent( r1 );
523 if ( !haveExtentInLayerCrs )
526 if ( mFeatureFilterProvider )
527 job.context()->setFeatureFilterProvider( mFeatureFilterProvider );
558 job.imageInitialized =
true;
561 job.renderer =
nullptr;
562 job.context()->setPainter(
nullptr );
567 QElapsedTimer layerTime;
573 job.context()->setFeedback( job.renderer->feedback() );
579 if (
mCache || ( !painter && !deferredPainterSet ) || ( job.renderer && job.renderer->forceRasterRender() ) )
582 job.context()->setPainter( allocateImageAndPainter( ml->
id(), job.img, job.context() ) );
586 job.renderer =
nullptr;
587 layerJobs.pop_back();
592 job.renderingTime = layerTime.elapsed();
600 std::vector< LayerRenderJob > secondPassJobs;
603 QHash<QString, LayerRenderJob *> layerJobMapping;
606 QMap<QString, bool> maskLayerHasEffects;
607 QMap<int, bool> labelHasEffects;
615 MaskSource(
const QString &layerId_,
const QString &labelRuleId_,
int labelMaskId_,
bool hasEffects_ ):
616 layerId( layerId_ ), labelRuleId( labelRuleId_ ), labelMaskId( labelMaskId_ ), hasEffects( hasEffects_ ) {}
621 QHash<QString, QPair<QSet<QgsSymbolLayerId>, QList<MaskSource>>> maskedSymbolLayers;
628 for ( LayerRenderJob &job : firstPassJobs )
630 layerJobMapping[job.layerId] = &job;
635 for ( LayerRenderJob &job : firstPassJobs )
642 auto collectMasks = [&](
QgsMaskedLayers * masks, QString sourceLayerId, QString ruleId = QString(),
int labelMaskId = -1 )
644 bool hasEffects =
false;
645 for (
auto it = masks->begin(); it != masks->end(); ++it )
647 auto lit = maskedSymbolLayers.find( it.key() );
648 if ( lit == maskedSymbolLayers.end() )
650 maskedSymbolLayers[it.key()] = qMakePair( it.value().symbolLayerIds, QList<MaskSource>() << MaskSource( sourceLayerId, ruleId, labelMaskId, it.value().hasEffects ) );
654 if ( lit->first != it.value().symbolLayerIds )
656 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() ) );
659 lit->second.push_back( MaskSource( sourceLayerId, ruleId, labelMaskId, hasEffects ) );
661 hasEffects |= it.value().hasEffects;
663 if ( ! masks->isEmpty() && labelMaskId == -1 )
664 maskLayerHasEffects[ sourceLayerId ] = hasEffects;
669 for (
auto it = labelMasks.begin(); it != labelMasks.end(); it++ )
671 QString labelRule = it.key();
677 for (
auto mit = masks.begin(); mit != masks.end(); mit++ )
679 const QString sourceLayerId = mit.key();
681 if ( !layerJobMapping.contains( sourceLayerId ) )
684 usableMasks.insert( sourceLayerId, mit.value() );
687 if ( usableMasks.empty() )
691 QSet<QgsSymbolLayerReference> slRefs;
692 bool hasEffects =
false;
693 for (
auto mit = usableMasks.begin(); mit != usableMasks.end(); mit++ )
695 const QString sourceLayerId = mit.key();
697 if ( !layerJobMapping.contains( sourceLayerId ) )
700 for (
auto slIt = mit.value().symbolLayerIds.begin(); slIt != mit.value().symbolLayerIds.end(); slIt++ )
705 hasEffects |= mit.value().hasEffects;
708 int labelMaskId = labelJob.maskIdProvider.insertLabelLayer( vl->
id(), it.key(), slRefs );
709 labelHasEffects[ labelMaskId ] = hasEffects;
712 collectMasks( &usableMasks, vl->
id(), labelRule, labelMaskId );
717 collectMasks( &symbolLayerMasks, vl->
id() );
720 if ( maskedSymbolLayers.isEmpty() )
721 return secondPassJobs;
724 for (
int maskId = 0; maskId < labelJob.maskIdProvider.size(); maskId++ )
726 QPaintDevice *maskPaintDevice =
nullptr;
727 QPainter *maskPainter =
nullptr;
728 if ( forceVector && !labelHasEffects[ maskId ] )
732 maskPainter =
new QPainter( maskPaintDevice );
737 QImage *maskImage =
nullptr;
738 maskPainter = allocateImageAndPainter( QStringLiteral(
"label mask" ), maskImage, &labelJob.context );
739 maskImage->fill( 0 );
740 maskPaintDevice = maskImage;
743 labelJob.context.setMaskPainter( maskPainter, maskId );
744 labelJob.maskPainters.push_back( std::unique_ptr<QPainter>( maskPainter ) );
745 labelJob.maskPaintDevices.push_back( std::unique_ptr<QPaintDevice>( maskPaintDevice ) );
747 labelJob.context.setMaskIdProvider( &labelJob.maskIdProvider );
758 if ( !labelJob.img && !forceVector )
760 labelJob.img = allocateImage( QStringLiteral(
"labels" ) );
762 else if ( !labelJob.picture && forceVector )
764 labelJob.picture.reset(
new QPicture() );
768 for ( LayerRenderJob &job : firstPassJobs )
770 job.maskRequiresLayerRasterization =
false;
772 auto it = maskedSymbolLayers.find( job.layerId );
773 if ( it != maskedSymbolLayers.end() )
775 const QList<MaskSource> &sourceList = it->second;
776 for (
const MaskSource &source : sourceList )
778 job.maskRequiresLayerRasterization |= source.hasEffects;
783 const bool isRasterRendering = !forceVector || job.maskRequiresLayerRasterization || ( job.renderer && job.renderer->forceRasterRender() );
784 if ( isRasterRendering && !job.img )
786 job.context()->setPainter( allocateImageAndPainter( job.layerId, job.img, job.context() ) );
788 else if ( !isRasterRendering && !job.picture )
790 PictureAndPainter pictureAndPainter = allocatePictureAndPainter( job.context() );
791 job.picture = std::move( pictureAndPainter.first );
792 job.context()->setPainter( pictureAndPainter.second );
795 job.renderer = job.layer->createMapRenderer( *( job.context() ) );
799 if ( maskLayerHasEffects.contains( job.layerId ) )
801 QPaintDevice *maskPaintDevice =
nullptr;
802 QPainter *maskPainter =
nullptr;
803 if ( forceVector && !maskLayerHasEffects[ job.layerId ] )
807 maskPainter =
new QPainter( maskPaintDevice );
812 QImage *maskImage =
nullptr;
813 maskPainter = allocateImageAndPainter( job.layerId, maskImage, job.context() );
814 maskImage->fill( 0 );
815 maskPaintDevice = maskImage;
818 job.context()->setMaskPainter( maskPainter );
819 job.maskPainter.reset( maskPainter );
820 job.maskPaintDevice.reset( maskPaintDevice );
824 for ( LayerRenderJob &job : firstPassJobs )
828 auto it = maskedSymbolLayers.find( job.layerId );
829 if ( it == maskedSymbolLayers.end() )
832 QList<MaskSource> &sourceList = it->second;
833 const QSet<QgsSymbolLayerId> &symbolList = it->first;
835 secondPassJobs.emplace_back( LayerRenderJob() );
836 LayerRenderJob &job2 = secondPassJobs.back();
838 job2.maskRequiresLayerRasterization = job.maskRequiresLayerRasterization;
841 for ( MaskSource &source : sourceList )
843 if ( source.labelMaskId != -1 )
844 job2.maskJobs.push_back( qMakePair(
nullptr, source.labelMaskId ) );
846 job2.maskJobs.push_back( qMakePair( layerJobMapping[source.layerId], -1 ) );
850 job2.setContext( std::make_unique< QgsRenderContext >( *job.context() ) );
852 job2.layer = job.layer;
853 job2.renderAboveLabels = job.renderAboveLabels;
854 job2.layerId = job.layerId;
857 job2.firstPassJob = &job;
859 if ( !forceVector || job2.maskRequiresLayerRasterization )
861 job2.context()->setPainter( allocateImageAndPainter( job.layerId, job2.img, job2.context() ) );
865 PictureAndPainter pictureAndPainter = allocatePictureAndPainter( job2.context() );
866 job2.picture = std::move( pictureAndPainter.first );
867 job2.context()->setPainter( pictureAndPainter.second );
870 if ( ! job2.img && ! job2.picture )
872 secondPassJobs.pop_back();
879 job2.renderer = mapRenderer;
882 job2.context()->setFeedback( job2.renderer->feedback() );
890 return secondPassJobs;
898 for ( LayerRenderJob &job : secondPassJobs )
900 if ( job.maskRequiresLayerRasterization )
906 for (
const QPair<LayerRenderJob *, int> &p : std::as_const( job.maskJobs ) )
908 QPainter *maskPainter = p.first ? p.first->maskPainter.get() : labelJob.maskPainters[p.second].get();
909 QPainterPath path =
static_cast<QgsMaskPaintDevice *
>( maskPainter->device() )->maskPainterPath();
910 for (
const QgsSymbolLayer *symbolLayer : job.context()->disabledSymbolLayers() )
912 job.context()->addSymbolLayerClipPath( symbolLayer, path );
916 job.context()->setDisabledSymbolLayers( QSet<const QgsSymbolLayer *>() );
924 job.context.setPainter( painter );
925 job.context.setLabelingEngine( labelingEngine2 );
926 job.context.setFeedback( mLabelingEngineFeedback );
930 job.context.setExtent( r1 );
932 job.context.setFeatureFilterProvider( mFeatureFilterProvider );
935 job.context.setCoordinateTransform( ct );
949 job.context.setPainter(
nullptr );
953 if ( canUseLabelCache && (
mCache || !painter ) )
955 job.img = allocateImage( QStringLiteral(
"labels" ) );
965 for ( LayerRenderJob &job : jobs )
969 delete job.context()->painter();
970 job.context()->setPainter(
nullptr );
972 if (
mCache && !job.cached && job.completed && job.layer )
974 QgsDebugMsgLevel( QStringLiteral(
"caching image for %1" ).arg( job.layerId ), 2 );
985 delete job.context()->painter();
986 job.context()->setPainter(
nullptr );
987 job.picture.reset(
nullptr );
992 const QStringList
errors = job.renderer->errors();
993 for (
const QString &message :
errors )
994 mErrors.append( Error( job.renderer->layerId(), message ) );
999 job.renderer =
nullptr;
1005 job.maskPainter.reset(
nullptr );
1006 job.maskPaintDevice.reset(
nullptr );
1014 for ( LayerRenderJob &job : jobs )
1018 delete job.context()->painter();
1019 job.context()->setPainter(
nullptr );
1027 delete job.context()->painter();
1028 job.context()->setPainter(
nullptr );
1033 delete job.renderer;
1034 job.renderer =
nullptr;
1048 if (
mCache && !job.cached && !job.context.renderingStopped() )
1059 job.picture.reset(
nullptr );
1060 job.maskPainters.clear();
1061 job.maskPaintDevices.clear();
1065#define DEBUG_RENDERING 0
1068 const std::vector<LayerRenderJob> &jobs,
1069 const LabelRenderJob &labelJob,
1075 image.setDotsPerMeterX(
static_cast<int>( settings.
outputDpi() * 39.37 ) );
1076 image.setDotsPerMeterY(
static_cast<int>( settings.
outputDpi() * 39.37 ) );
1079 QPainter painter( &image );
1084 for (
const LayerRenderJob &job : jobs )
1086 if ( job.renderAboveLabels )
1093 painter.setCompositionMode( job.blendMode );
1094 painter.setOpacity( job.opacity );
1097 img.save( QString(
"/tmp/final_%1.png" ).arg( i ) );
1101 painter.drawImage( 0, 0, img );
1107 if ( labelJob.img && labelJob.complete )
1109 painter.setCompositionMode( QPainter::CompositionMode_SourceOver );
1110 painter.setOpacity( 1.0 );
1111 painter.drawImage( 0, 0, *labelJob.img );
1119 painter.setCompositionMode( QPainter::CompositionMode_SourceOver );
1120 painter.setOpacity( 1.0 );
1121 painter.drawImage( 0, 0, labelCacheImage );
1125 for (
const LayerRenderJob &job : jobs )
1127 if ( !job.renderAboveLabels )
1134 painter.setCompositionMode( job.blendMode );
1135 painter.setOpacity( job.opacity );
1137 painter.drawImage( 0, 0, img );
1142 image.save(
"/tmp/final.png" );
1149 const LayerRenderJob &job,
1153 if ( job.imageCanBeComposed() )
1155 Q_ASSERT( job.img );
1160 if ( cache && cache->
hasAnyCacheImage( job.layerId + QStringLiteral(
"_preview" ) ) )
1172 for ( LayerRenderJob &job : secondPassJobs )
1174 const bool isRasterRendering = !forceVector || job.maskRequiresLayerRasterization;
1177 if ( isRasterRendering && job.maskJobs.size() > 1 )
1179 QPainter *maskPainter =
nullptr;
1180 for ( QPair<LayerRenderJob *, int> p : job.maskJobs )
1182 QImage *maskImage =
static_cast<QImage *
>( p.first ? p.first->maskPaintDevice.get() : labelJob.maskPaintDevices[p.second].get() );
1185 maskPainter = p.first ? p.first->maskPainter.get() : labelJob.maskPainters[ p.second ].get();
1189 maskPainter->drawImage( 0, 0, *maskImage );
1194 if ( ! job.maskJobs.isEmpty() )
1197 QPair<LayerRenderJob *, int> p = *job.maskJobs.begin();
1198 if ( isRasterRendering )
1200 QImage *maskImage =
static_cast<QImage *
>( p.first ? p.first->maskPaintDevice.get() : labelJob.maskPaintDevices[p.second].get() );
1203 QPainter *painter = job.context()->painter();
1205 painter->setCompositionMode( QPainter::CompositionMode_DestinationIn );
1210 QImage maskBinAlpha = maskImage->createMaskFromColor( 0 );
1211 QVector<QRgb> mswTable;
1212 mswTable.push_back( qRgba( 0, 0, 0, 255 ) );
1213 mswTable.push_back( qRgba( 0, 0, 0, 0 ) );
1214 maskBinAlpha.setColorTable( mswTable );
1215 painter->drawImage( 0, 0, maskBinAlpha );
1219 QPainter tempPainter;
1222 QPainter *painter1 = job.firstPassJob->context()->painter();
1225 tempPainter.begin( job.firstPassJob->img );
1226 painter1 = &tempPainter;
1230 painter1->setCompositionMode( QPainter::CompositionMode_DestinationOut );
1231 painter1->drawImage( 0, 0, *maskImage );
1234 painter1->setCompositionMode( QPainter::CompositionMode_DestinationOver );
1235 painter1->drawImage( 0, 0, *job.img );
1240 job.firstPassJob->picture = std::move( job.picture );
1241 job.picture =
nullptr;
1252 QMultiMap<int, QString> elapsed;
1253 for (
const LayerRenderJob &job : jobs )
1254 elapsed.insert( job.renderingTime, job.layerId );
1255 for (
const LayerRenderJob &job : secondPassJobs )
1256 elapsed.insert( job.renderingTime, job.layerId + QString(
" (second pass)" ) );
1258 elapsed.insert( labelJob.renderingTime, tr(
"Labeling" ) );
1260 QList<int> tt( elapsed.uniqueKeys() );
1261 std::sort( tt.begin(), tt.end(), std::greater<int>() );
1262 for (
int t : std::as_const( tt ) )
1264 QgsMessageLog::logMessage( tr(
"%1 ms: %2" ).arg( t ).arg( QStringList( elapsed.values( t ) ).join( QLatin1String(
", " ) ) ), tr(
"Rendering" ) );
1277 painter->setCompositionMode( QPainter::CompositionMode_SourceOver );
1281 if ( labelingEngine2 )
1283 labelingEngine2->
run( renderContext );
1286 QgsDebugMsgLevel( QStringLiteral(
"Draw labeling took (seconds): %1" ).arg( t.elapsed() / 1000. ), 2 );
1291 Q_UNUSED( settings )
1293 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...
@ 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.
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 yMaximum() const SIP_HOLDGIL
Returns the y maximum value (top side of rectangle).
double xMaximum() const SIP_HOLDGIL
Returns the x maximum value (right side of rectangle).
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
void setXMaximum(double x) SIP_HOLDGIL
Set the maximum x value.
void setXMinimum(double x) SIP_HOLDGIL
Set the minimum x value.
double height() const SIP_HOLDGIL
Returns the height of the rectangle.
void grow(double delta)
Grows the rectangle in place by the specified amount.
double width() const SIP_HOLDGIL
Returns the width 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