19 #include <QElapsedTimer> 
   21 #include <QtConcurrentMap> 
   53 LayerRenderJob &LayerRenderJob::operator=( LayerRenderJob &&other )
 
   55   mContext = std::move( other.mContext );
 
   60   renderer = other.renderer;
 
   61   other.renderer = 
nullptr;
 
   63   imageInitialized = other.imageInitialized;
 
   64   blendMode = other.blendMode;
 
   65   opacity = other.opacity;
 
   66   cached = other.cached;
 
   68   completed = other.completed;
 
   69   renderingTime = other.renderingTime;
 
   70   estimatedRenderingTime = other.estimatedRenderingTime ;
 
   71   errors = other.errors;
 
   72   layerId = other.layerId;
 
   74   maskImage = other.maskImage;
 
   75   other.maskImage = 
nullptr;
 
   77   firstPassJob = other.firstPassJob;
 
   78   other.firstPassJob = 
nullptr;
 
   80   maskJobs = other.maskJobs;
 
   85 LayerRenderJob::LayerRenderJob( LayerRenderJob &&other )
 
   86   : imageInitialized( other.imageInitialized )
 
   87   , blendMode( other.blendMode )
 
   88   , opacity( other.opacity )
 
   89   , cached( other.cached )
 
   90   , layer( other.layer )
 
   91   , completed( other.completed )
 
   92   , renderingTime( other.renderingTime )
 
   93   , estimatedRenderingTime( other.estimatedRenderingTime )
 
   94   , errors( other.errors )
 
   95   , layerId( other.layerId )
 
   96   , maskJobs( other.maskJobs )
 
   98   mContext = std::move( other.mContext );
 
  103   renderer = other.renderer;
 
  104   other.renderer = 
nullptr;
 
  106   maskImage = other.maskImage;
 
  107   other.maskImage = 
nullptr;
 
  109   firstPassJob = other.firstPassJob;
 
  110   other.firstPassJob = 
nullptr;
 
  113 bool LayerRenderJob::imageCanBeComposed()
 const 
  115   if ( imageInitialized )
 
  119       return renderer->isReadyToCompose();
 
  133   : mSettings( settings )
 
  178   QHash<QgsMapLayer *, int> result;
 
  181     if ( 
auto &&lKey = it.key() )
 
  182       result.insert( lKey, it.value() );
 
  202   QSet< QgsMapLayer * > labeledLayers;
 
  209     switch ( ml->type() )
 
  274     static const double SPLIT_COORD = 180.0;
 
  286         QgsDebugMsgLevel( QStringLiteral( 
"\n0:%1 %2x%3\n1:%4\n2:%5 %6x%7 (w:%8 h:%9)" )
 
  289                           .arg( std::fabs( 1.0 - extent2.
width() / extent.
width() ) )
 
  290                           .arg( std::fabs( 1.0 - extent2.
height() / extent.
height() ) )
 
  312                         Qgis::TransformDirection::Reverse );
 
  316                         Qgis::TransformDirection::Reverse );
 
  324         if ( ll.
x() > ur.
x() )
 
  353         extent = 
QgsRectangle( std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), std::numeric_limits<double>::max() );
 
  362     QgsDebugMsg( QStringLiteral( 
"Transform error caught" ) );
 
  363     extent = 
QgsRectangle( std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), std::numeric_limits<double>::max() );
 
  364     r2 = 
QgsRectangle( std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), std::numeric_limits<double>::max() );
 
  371 QImage *QgsMapRendererJob::allocateImage( QString layerId )
 
  378   if ( image->isNull() )
 
  387 QPainter *QgsMapRendererJob::allocateImageAndPainter( QString layerId, QImage *&image )
 
  389   QPainter *painter = 
nullptr;
 
  390   image = allocateImage( layerId );
 
  393     painter = 
new QPainter( image );
 
  395 #if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0) 
  404   std::vector< LayerRenderJob > layerJobs;
 
  413     Q_UNUSED( cacheValid )
 
  414     QgsDebugMsgLevel( QStringLiteral( 
"CACHE VALID: %1" ).arg( cacheValid ), 4 );
 
  419   while ( li.hasPrevious() )
 
  423     QgsDebugMsgLevel( QStringLiteral( 
"layer %1:  minscale:%2  maxscale:%3  scaledepvis:%4  blendmode:%5 isValid:%6" )
 
  440       QgsDebugMsgLevel( QStringLiteral( 
"Layer not rendered because it is not within the defined visibility scale range" ), 3 );
 
  446       QgsDebugMsgLevel( QStringLiteral( 
"Layer not rendered because it is not visible within the map's time range" ), 3 );
 
  452       QgsDebugMsgLevel( QStringLiteral( 
"Layer not rendered because it is not visible within the map's z range" ), 3 );
 
  461     bool haveExtentInLayerCrs = 
true;
 
  464       haveExtentInLayerCrs = reprojectToLayerExtent( ml, ct, r1, r2 );
 
  469       mErrors.append( Error( ml->
id(), tr( 
"There was a problem transforming the layer's extent. Layer skipped." ) ) );
 
  480       if ( ( vl && vl->
isEditable() ) || requiresLabeling )
 
  486     layerJobs.emplace_back( LayerRenderJob() );
 
  487     LayerRenderJob &job = layerJobs.back();
 
  489     job.layerId = ml->
id();
 
  494     job.context()->setPainter( painter );
 
  495     job.context()->setLabelingEngine( labelingEngine2 );
 
  496     job.context()->setCoordinateTransform( ct );
 
  497     job.context()->setExtent( r1 );
 
  498     if ( !haveExtentInLayerCrs )
 
  501     if ( mFeatureFilterProvider )
 
  502       job.context()->setFeatureFilterProvider( mFeatureFilterProvider );
 
  518       job.imageInitialized = 
true;
 
  521       job.renderer = 
nullptr;
 
  522       job.context()->setPainter( 
nullptr );
 
  527     QElapsedTimer layerTime;
 
  533       job.context()->setFeedback( job.renderer->feedback() );
 
  539     if ( 
mCache || ( !painter && !deferredPainterSet ) || ( job.renderer && job.renderer->forceRasterRender() ) )
 
  542       job.context()->setPainter( allocateImageAndPainter( ml->
id(), job.img ) );
 
  546         job.renderer = 
nullptr;
 
  547         layerJobs.pop_back();
 
  552     job.renderingTime = layerTime.elapsed(); 
 
  560   std::vector< LayerRenderJob > secondPassJobs;
 
  563   QHash<QString, LayerRenderJob *> layerJobMapping;
 
  566   QSet<QString> layerHasMask;
 
  573     MaskSource( 
const QString &layerId_, 
const QString &labelRuleId_, 
int labelMaskId_ ):
 
  574       layerId( layerId_ ), labelRuleId( labelRuleId_ ), labelMaskId( labelMaskId_ ) {}
 
  579   QHash<QString, QPair<QSet<QgsSymbolLayerId>, QList<MaskSource>>> maskedSymbolLayers;
 
  583   for ( LayerRenderJob &job : firstPassJobs )
 
  585     layerJobMapping[job.layerId] = &job;
 
  590   for ( LayerRenderJob &job : firstPassJobs )
 
  597     auto collectMasks = [&]( QHash<QString, QSet<QgsSymbolLayerId>> *masks, QString sourceLayerId, QString ruleId = QString(), 
int labelMaskId = -1 )
 
  599       for ( 
auto it = masks->begin(); it != masks->end(); ++it )
 
  601         auto lit = maskedSymbolLayers.find( it.key() );
 
  602         if ( lit == maskedSymbolLayers.end() )
 
  604           maskedSymbolLayers[it.key()] = qMakePair( it.value(), QList<MaskSource>() << MaskSource( sourceLayerId, ruleId, labelMaskId ) );
 
  608           if ( lit->first != it.value() )
 
  610             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() ) );
 
  613           lit->second.push_back( MaskSource( sourceLayerId, ruleId, labelMaskId ) );
 
  616       if ( ! masks->isEmpty() )
 
  617         layerHasMask.insert( sourceLayerId );
 
  622     for ( 
auto it = labelMasks.begin(); it != labelMasks.end(); it++ )
 
  624       QString labelRule = it.key();
 
  626       QHash<QString, QSet<QgsSymbolLayerId>> masks = it.value();
 
  629       QHash<QString, QSet<QgsSymbolLayerId>> usableMasks;
 
  630       for ( 
auto mit = masks.begin(); mit != masks.end(); mit++ )
 
  632         const QString sourceLayerId = mit.key();
 
  634         if ( !layerJobMapping.contains( sourceLayerId ) )
 
  637           usableMasks.insert( sourceLayerId, mit.value() );
 
  640       if ( usableMasks.empty() )
 
  644       QSet<QgsSymbolLayerReference> slRefs;
 
  645       for ( 
auto mit = usableMasks.begin(); mit != usableMasks.end(); mit++ )
 
  647         const QString sourceLayerId = mit.key();
 
  649         if ( !layerJobMapping.contains( sourceLayerId ) )
 
  652         for ( 
auto slIt = mit.value().begin(); slIt != mit.value().end(); slIt++ )
 
  658       int labelMaskId = labelJob.maskIdProvider.insertLabelLayer( vl->
id(), it.key(), slRefs );
 
  661       collectMasks( &usableMasks, vl->
id(), labelRule, labelMaskId );
 
  666     collectMasks( &symbolLayerMasks, vl->
id() );
 
  669   if ( maskedSymbolLayers.isEmpty() )
 
  670     return secondPassJobs;
 
  674   for ( LayerRenderJob &job : firstPassJobs )
 
  676     if ( job.img == 
nullptr )
 
  678       job.context()->setPainter( allocateImageAndPainter( job.layerId, job.img ) );
 
  680     if ( layerHasMask.contains( job.layerId ) )
 
  683       job.context()->setMaskPainter( allocateImageAndPainter( job.layerId, job.maskImage ) );
 
  684       job.maskImage->fill( 0 );
 
  689   if ( labelJob.img == 
nullptr )
 
  691     labelJob.img = allocateImage( QStringLiteral( 
"labels" ) );
 
  695   for ( 
int maskId = 0; maskId < labelJob.maskIdProvider.size(); maskId++ )
 
  698     labelJob.context.setMaskPainter( allocateImageAndPainter( QStringLiteral( 
"label mask" ), maskImage ), maskId );
 
  699     maskImage->fill( 0 );
 
  700     labelJob.maskImages.push_back( maskImage );
 
  702   labelJob.context.setMaskIdProvider( &labelJob.maskIdProvider );
 
  705   for ( LayerRenderJob &job : firstPassJobs )
 
  709     auto it = maskedSymbolLayers.find( ml->
id() );
 
  710     if ( it == maskedSymbolLayers.end() )
 
  713     QList<MaskSource> &sourceList = it->second;
 
  714     const QSet<QgsSymbolLayerId> &symbolList = it->first;
 
  716     secondPassJobs.emplace_back( LayerRenderJob() );
 
  717     LayerRenderJob &job2 = secondPassJobs.back();
 
  720     job2.setContext( std::make_unique< QgsRenderContext >( *job.context() ) );
 
  722     job2.layer = job.layer;
 
  723     job2.layerId = job.layerId;
 
  725     job2.firstPassJob = &job;
 
  727     QgsVectorLayer *vl1 = qobject_cast<QgsVectorLayer *>( job.layer );
 
  731     job2.context()->setMaskPainter( 
nullptr );
 
  732     job2.context()->setPainter( allocateImageAndPainter( job.layerId, job2.img ) );
 
  735       secondPassJobs.pop_back();
 
  740     for ( MaskSource &source : sourceList )
 
  742       if ( source.labelMaskId != -1 )
 
  743         job2.maskJobs.push_back( qMakePair( 
nullptr, source.labelMaskId ) );
 
  745         job2.maskJobs.push_back( qMakePair( layerJobMapping[source.layerId], -1 ) );
 
  751     job2.renderer = mapRenderer;
 
  754       job2.context()->setFeedback( job2.renderer->feedback() );
 
  762   return secondPassJobs;
 
  769   job.context.setPainter( painter );
 
  770   job.context.setLabelingEngine( labelingEngine2 );
 
  774   job.context.setExtent( r1 );
 
  776   job.context.setFeatureFilterProvider( mFeatureFilterProvider );
 
  779   job.context.setCoordinateTransform( ct );
 
  789     job.context.setPainter( 
nullptr );
 
  793     if ( canUseLabelCache && ( 
mCache || !painter ) )
 
  795       job.img = allocateImage( QStringLiteral( 
"labels" ) );
 
  805   for ( LayerRenderJob &job : jobs )
 
  809       delete job.context()->painter();
 
  810       job.context()->setPainter( 
nullptr );
 
  812       if ( 
mCache && !job.cached && job.completed && job.layer )
 
  814         QgsDebugMsgLevel( QStringLiteral( 
"caching image for %1" ).arg( job.layerId ), 2 );
 
  826       delete job.context()->maskPainter();
 
  827       job.context()->setMaskPainter( 
nullptr );
 
  828       delete job.maskImage;
 
  833       const QStringList 
errors = job.renderer->errors();
 
  834       for ( 
const QString &message : 
errors )
 
  835         mErrors.append( Error( job.renderer->layerId(), message ) );
 
  840       job.renderer = 
nullptr;
 
  852   for ( LayerRenderJob &job : jobs )
 
  856       delete job.context()->painter();
 
  857       job.context()->setPainter( 
nullptr );
 
  866       job.renderer = 
nullptr;
 
  880     if ( 
mCache && !job.cached && !job.context.renderingStopped() )
 
  891   for ( 
int maskId = 0; maskId < job.maskImages.size(); maskId++ )
 
  893     delete job.context.maskPainter( maskId );
 
  894     job.context.setMaskPainter( 
nullptr, maskId );
 
  895     delete job.maskImages[maskId];
 
  900 #define DEBUG_RENDERING 0 
  903                                         const std::vector<LayerRenderJob> &jobs,
 
  904                                         const LabelRenderJob &labelJob,
 
  910   image.setDotsPerMeterX( 
static_cast<int>( settings.
outputDpi() * 39.37 ) );
 
  911   image.setDotsPerMeterY( 
static_cast<int>( settings.
outputDpi() * 39.37 ) );
 
  914   QPainter painter( &image );
 
  919   for ( 
const LayerRenderJob &job : jobs )
 
  921     if ( job.layer && job.layer->customProperty( QStringLiteral( 
"rendering/renderAboveLabels" ) ).toBool() )
 
  928     painter.setCompositionMode( job.blendMode );
 
  929     painter.setOpacity( job.opacity );
 
  932     img.save( QString( 
"/tmp/final_%1.png" ).arg( i ) );
 
  936     painter.drawImage( 0, 0, img );
 
  942   if ( labelJob.img && labelJob.complete )
 
  944     painter.setCompositionMode( QPainter::CompositionMode_SourceOver );
 
  945     painter.setOpacity( 1.0 );
 
  946     painter.drawImage( 0, 0, *labelJob.img );
 
  954     painter.setCompositionMode( QPainter::CompositionMode_SourceOver );
 
  955     painter.setOpacity( 1.0 );
 
  956     painter.drawImage( 0, 0, labelCacheImage );
 
  960   for ( 
const LayerRenderJob &job : jobs )
 
  962     if ( !job.layer || !job.layer->customProperty( QStringLiteral( 
"rendering/renderAboveLabels" ) ).toBool() )
 
  969     painter.setCompositionMode( job.blendMode );
 
  970     painter.setOpacity( job.opacity );
 
  972     painter.drawImage( 0, 0, img );
 
  977   image.save( 
"/tmp/final.png" );
 
  984   const LayerRenderJob &job,
 
  988   if ( job.imageCanBeComposed() )
 
  995     if ( cache && cache->
hasAnyCacheImage( job.layerId + QStringLiteral( 
"_preview" ) ) )
 
 1010   for ( LayerRenderJob &job : secondPassJobs )
 
 1014     job.img->save( QString( 
"/tmp/second_%1.png" ).arg( i ) );
 
 1019     if ( job.maskJobs.size() > 1 )
 
 1021       QPainter *maskPainter = 
nullptr;
 
 1022       for ( QPair<LayerRenderJob *, int> p : job.maskJobs )
 
 1024         QImage *maskImage = p.first ? p.first->maskImage : labelJob.maskImages[p.second];
 
 1026         maskImage->save( QString( 
"/tmp/mask_%1_%2.png" ).arg( i ).arg( mask++ ) );
 
 1028         if ( ! maskPainter )
 
 1030           maskPainter = p.first ? p.first->context()->maskPainter() : labelJob.context.maskPainter( p.second );
 
 1034           maskPainter->drawImage( 0, 0, *maskImage );
 
 1039     if ( ! job.maskJobs.isEmpty() )
 
 1042       QPair<LayerRenderJob *, int> p = *job.maskJobs.begin();
 
 1043       QImage *maskImage = p.first ? p.first->maskImage : labelJob.maskImages[p.second];
 
 1045       maskImage->save( QString( 
"/tmp/mask_%1.png" ).arg( i ) );
 
 1049       QPainter *painter = job.context()->painter();
 
 1050       painter->setCompositionMode( QPainter::CompositionMode_DestinationIn );
 
 1055       QImage maskBinAlpha = maskImage->createMaskFromColor( 0 );
 
 1056       QVector<QRgb> mswTable;
 
 1057       mswTable.push_back( qRgba( 0, 0, 0, 255 ) );
 
 1058       mswTable.push_back( qRgba( 0, 0, 0, 0 ) );
 
 1059       maskBinAlpha.setColorTable( mswTable );
 
 1060       painter->drawImage( 0, 0, maskBinAlpha );
 
 1062       job.img->save( QString( 
"/tmp/second_%1_a.png" ).arg( i ) );
 
 1067         QPainter tempPainter;
 
 1070         QPainter *painter1 = job.firstPassJob->context()->painter();
 
 1073           tempPainter.begin( job.firstPassJob->img );
 
 1074           painter1 = &tempPainter;
 
 1077         job.firstPassJob->img->save( QString( 
"/tmp/second_%1_first_pass_1.png" ).arg( i ) );
 
 1080         painter1->setCompositionMode( QPainter::CompositionMode_DestinationOut );
 
 1081         painter1->drawImage( 0, 0, *maskImage );
 
 1084         job.firstPassJob->img->save( QString( 
"/tmp/second_%1_first_pass_2.png" ).arg( i ) );
 
 1087         painter1->setCompositionMode( QPainter::CompositionMode_DestinationOver );
 
 1088         painter1->drawImage( 0, 0, *job.img );
 
 1090         job.img->save( QString( 
"/tmp/second_%1_b.png" ).arg( i ) );
 
 1091         if ( job.firstPassJob )
 
 1092           job.firstPassJob->img->save( QString( 
"/tmp/second_%1_first_pass_3.png" ).arg( i ) );
 
 1099 void QgsMapRendererJob::logRenderingTime( 
const std::vector< LayerRenderJob > &jobs, 
const std::vector< LayerRenderJob > &secondPassJobs, 
const LabelRenderJob &labelJob )
 
 1104   QMultiMap<int, QString> elapsed;
 
 1105   for ( 
const LayerRenderJob &job : jobs )
 
 1106     elapsed.insert( job.renderingTime, job.layerId );
 
 1107   for ( 
const LayerRenderJob &job : secondPassJobs )
 
 1108     elapsed.insert( job.renderingTime, job.layerId + QString( 
" (second pass)" ) );
 
 1110   elapsed.insert( labelJob.renderingTime, tr( 
"Labeling" ) );
 
 1112   QList<int> tt( elapsed.uniqueKeys() );
 
 1113   std::sort( tt.begin(), tt.end(), std::greater<int>() );
 
 1114   for ( 
int t : std::as_const( tt ) )
 
 1116     QgsMessageLog::logMessage( tr( 
"%1 ms: %2" ).arg( t ).arg( QStringList( elapsed.values( t ) ).join( QLatin1String( 
", " ) ) ), tr( 
"Rendering" ) );
 
 1129   painter->setCompositionMode( QPainter::CompositionMode_SourceOver );
 
 1133   if ( labelingEngine2 )
 
 1135     labelingEngine2->
run( renderContext );
 
 1138   QgsDebugMsgLevel( QStringLiteral( 
"Draw labeling took (seconds): %1" ).arg( t.elapsed() / 1000. ), 2 );
 
 1143   Q_UNUSED( settings )
 
 1145   drawLabeling( renderContext, labelingEngine2, painter );
 
@ ApplyClipAfterReprojection
Feature geometry clipping to mapExtent() must be performed after the geometries are transformed using...
@ LosslessImageRendering
Render images losslessly whenever possible, instead of the default lossy jpeg rendering used for some...
@ Antialiasing
Enable anti-aliasing for map rendering.
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.
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.
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.
virtual QgsMapLayerRenderer * createMapRenderer(QgsRenderContext &rendererContext)=0
Returns new instance of QgsMapLayerRenderer that will be used for rendering of given context.
bool hasScaleBasedVisibility() const
Returns whether scale based visibility is enabled for the layer.
double minimumScale() const
Returns the minimum map scale (i.e.
virtual QgsMapLayerElevationProperties * elevationProperties()
Returns the layer's elevation properties.
virtual QgsMapLayerTemporalProperties * temporalProperties()
Returns the layer's temporal 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 void composeSecondPass(std::vector< LayerRenderJob > &secondPassJobs, LabelRenderJob &labelJob)
Compose second pass images into first pass images.
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.
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.
const QgsMapSettings & mapSettings() const
Returns map settings with which this job was started.
void cleanupJobs(std::vector< LayerRenderJob > &jobs)
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.
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...
QgsRenderedItemResults * takeRenderedItemResults()
Takes the rendered item results from the map render job and returns them.
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.
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.
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...
const QgsMapToPixel & mapToPixel() const
QgsRectangle visibleExtent() const
Returns the actual extent derived from requested extent that takes output image size into account.
QList< QgsMapLayer * > layers() const
Returns the list of layers which will be rendered in the map.
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.
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.
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 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.
bool value(const QString &dynamicKeyPart=QString(), bool useDefaultValueOverride=false, bool defaultValueOverride=false) 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 QHash< QString, QHash< QString, QSet< QgsSymbolLayerId > > > labelMasks(const QgsVectorLayer *)
Returns masks defined in labeling options of a layer.
static QHash< QString, QSet< QgsSymbolLayerId > > symbolLayerMasks(const QgsVectorLayer *)
Returns all masks that may be defined on symbol layers for a given vector 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.
QgsMapLayerRenderer * createMapRenderer(QgsRenderContext &rendererContext) FINAL
Returns new instance of QgsMapLayerRenderer that will be used for rendering of given context.
bool isEditable() const FINAL
Returns true if the provider is in editing mode.
const QgsAbstractVectorLayerLabeling * labeling() const
Access to const labeling configuration.
@ PointCloudLayer
Added in 3.18.
@ VectorTileLayer
Added in 3.14.
@ AnnotationLayer
Contains freeform, georeferenced annotations. Added in QGIS 3.16.
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)