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  completed = other.completed;
 
   70  renderingTime = other.renderingTime;
 
   71  estimatedRenderingTime = other.estimatedRenderingTime ;
 
   72  errors = other.errors;
 
   73  layerId = other.layerId;
 
   75  maskPaintDevice = std::move( other.maskPaintDevice );
 
   77  firstPassJob = other.firstPassJob;
 
   78  other.firstPassJob = 
nullptr;
 
   80  picture = std::move( other.picture );
 
   82  maskJobs = other.maskJobs;
 
   84  maskRequiresLayerRasterization = other.maskRequiresLayerRasterization;
 
   89LayerRenderJob::LayerRenderJob( LayerRenderJob &&other )
 
   90  : imageInitialized( other.imageInitialized )
 
   91  , blendMode( other.blendMode )
 
   92  , opacity( other.opacity )
 
   93  , cached( other.cached )
 
   94  , layer( other.layer )
 
   95  , completed( other.completed )
 
   96  , renderingTime( other.renderingTime )
 
   97  , estimatedRenderingTime( other.estimatedRenderingTime )
 
   98  , errors( other.errors )
 
   99  , layerId( other.layerId )
 
  100  , maskRequiresLayerRasterization( other.maskRequiresLayerRasterization )
 
  101  , maskJobs( other.maskJobs )
 
  103  mContext = std::move( other.mContext );
 
  108  renderer = other.renderer;
 
  109  other.renderer = 
nullptr;
 
  111  maskPaintDevice = std::move( other.maskPaintDevice );
 
  113  firstPassJob = other.firstPassJob;
 
  114  other.firstPassJob = 
nullptr;
 
  116  picture = std::move( other.picture );
 
  119bool LayerRenderJob::imageCanBeComposed()
 const 
  121  if ( imageInitialized )
 
  125      return renderer->isReadyToCompose();
 
  139  : mSettings( settings )
 
  185  return mLabelingEngineFeedback;
 
  190  QHash<QgsMapLayer *, int> result;
 
  193    if ( 
auto &&lKey = it.key() )
 
  194      result.insert( lKey, it.value() );
 
  214  QSet< QgsMapLayer * > labeledLayers;
 
  221    switch ( ml->type() )
 
  259    bool canUseCache = canCache && QSet< QgsMapLayer * >( labelDependentLayers.begin(), labelDependentLayers.end() ) == labeledLayers;
 
  288    static const double SPLIT_COORD = 180.0;
 
  300        QgsDebugMsgLevel( QStringLiteral( 
"\n0:%1 %2x%3\n1:%4\n2:%5 %6x%7 (w:%8 h:%9)" )
 
  303                          .arg( std::fabs( 1.0 - extent2.
width() / extent.
width() ) )
 
  304                          .arg( std::fabs( 1.0 - extent2.
height() / extent.
height() ) )
 
  326                        Qgis::TransformDirection::Reverse );
 
  330                        Qgis::TransformDirection::Reverse );
 
  338        if ( ll.
x() > ur.
x() )
 
  367        extent = 
QgsRectangle( std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), std::numeric_limits<double>::max() );
 
  376    QgsDebugMsg( QStringLiteral( 
"Transform error caught" ) );
 
  377    extent = 
QgsRectangle( std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), std::numeric_limits<double>::max() );
 
  378    r2 = 
QgsRectangle( std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), std::numeric_limits<double>::max() );
 
  385QImage *QgsMapRendererJob::allocateImage( QString layerId )
 
  392  if ( image->isNull() )
 
  401QPainter *QgsMapRendererJob::allocateImageAndPainter( QString layerId, QImage *&image, 
const QgsRenderContext *context )
 
  403  QPainter *painter = 
nullptr;
 
  404  image = allocateImage( layerId );
 
  407    painter = 
new QPainter( image );
 
  413QgsMapRendererJob::PictureAndPainter QgsMapRendererJob::allocatePictureAndPainter( 
const QgsRenderContext *context )
 
  415  std::unique_ptr<QPicture> picture = std::make_unique<QPicture>();
 
  416  QPainter *painter = 
new QPainter( picture.get() );
 
  418  return { std::move( picture ), painter };
 
  423  std::vector< LayerRenderJob > layerJobs;
 
  432    Q_UNUSED( cacheValid )
 
  433    QgsDebugMsgLevel( QStringLiteral( 
"CACHE VALID: %1" ).arg( cacheValid ), 4 );
 
  438  while ( li.hasPrevious() )
 
  442    QgsDebugMsgLevel( QStringLiteral( 
"layer %1:  minscale:%2  maxscale:%3  scaledepvis:%4  blendmode:%5 isValid:%6" )
 
  459      QgsDebugMsgLevel( QStringLiteral( 
"Layer not rendered because it is not within the defined visibility scale range" ), 3 );
 
  465      QgsDebugMsgLevel( QStringLiteral( 
"Layer not rendered because it is not visible within the map's time range" ), 3 );
 
  471      QgsDebugMsgLevel( QStringLiteral( 
"Layer not rendered because it is not visible within the map's z range" ), 3 );
 
  480    bool haveExtentInLayerCrs = 
true;
 
  483      haveExtentInLayerCrs = reprojectToLayerExtent( ml, ct, r1, r2 );
 
  488      mErrors.append( Error( ml->
id(), tr( 
"There was a problem transforming the layer's extent. Layer skipped." ) ) );
 
  499      if ( ( vl && vl->
isEditable() ) || requiresLabeling )
 
  505    layerJobs.emplace_back( LayerRenderJob() );
 
  506    LayerRenderJob &job = layerJobs.back();
 
  508    job.layerId = ml->
id();
 
  512    if ( !ml->
customProperty( QStringLiteral( 
"_noset_layer_expression_context" ) ).toBool() )
 
  514    job.context()->setPainter( painter );
 
  515    job.context()->setLabelingEngine( labelingEngine2 );
 
  516    job.context()->setLabelSink( 
labelSink() );
 
  517    job.context()->setCoordinateTransform( ct );
 
  518    job.context()->setExtent( r1 );
 
  519    if ( !haveExtentInLayerCrs )
 
  522    if ( mFeatureFilterProvider )
 
  523      job.context()->setFeatureFilterProvider( mFeatureFilterProvider );
 
  554      job.imageInitialized = 
true;
 
  557      job.renderer = 
nullptr;
 
  558      job.context()->setPainter( 
nullptr );
 
  563    QElapsedTimer layerTime;
 
  569      job.context()->setFeedback( job.renderer->feedback() );
 
  575    if ( 
mCache || ( !painter && !deferredPainterSet ) || ( job.renderer && job.renderer->forceRasterRender() ) )
 
  578      job.context()->setPainter( allocateImageAndPainter( ml->
id(), job.img, job.context() ) );
 
  582        job.renderer = 
nullptr;
 
  583        layerJobs.pop_back();
 
  588    job.renderingTime = layerTime.elapsed(); 
 
  596  std::vector< LayerRenderJob > secondPassJobs;
 
  599  QHash<QString, LayerRenderJob *> layerJobMapping;
 
  602  QMap<QString, bool> maskLayerHasEffects;
 
  603  QMap<int, bool> labelHasEffects;
 
  611    MaskSource( 
const QString &layerId_, 
const QString &labelRuleId_, 
int labelMaskId_, 
bool hasEffects_ ):
 
  612      layerId( layerId_ ), labelRuleId( labelRuleId_ ), labelMaskId( labelMaskId_ ), hasEffects( hasEffects_ ) {}
 
  617  QHash<QString, QPair<QSet<QgsSymbolLayerId>, QList<MaskSource>>> maskedSymbolLayers;
 
  624  for ( LayerRenderJob &job : firstPassJobs )
 
  626    layerJobMapping[job.layerId] = &job;
 
  631  for ( LayerRenderJob &job : firstPassJobs )
 
  638    auto collectMasks = [&]( 
QgsMaskedLayers * masks, QString sourceLayerId, QString ruleId = QString(), 
int labelMaskId = -1 )
 
  640      bool hasEffects = 
false;
 
  641      for ( 
auto it = masks->begin(); it != masks->end(); ++it )
 
  643        auto lit = maskedSymbolLayers.find( it.key() );
 
  644        if ( lit == maskedSymbolLayers.end() )
 
  646          maskedSymbolLayers[it.key()] = qMakePair( it.value().symbolLayerIds, QList<MaskSource>() << MaskSource( sourceLayerId, ruleId, labelMaskId, it.value().hasEffects ) );
 
  650          if ( lit->first != it.value().symbolLayerIds )
 
  652            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() ) );
 
  655          lit->second.push_back( MaskSource( sourceLayerId, ruleId, labelMaskId, hasEffects ) );
 
  657        hasEffects |= it.value().hasEffects;
 
  659      if ( ! masks->isEmpty() && labelMaskId == -1 )
 
  660        maskLayerHasEffects[ sourceLayerId ] = hasEffects;
 
  665    for ( 
auto it = labelMasks.begin(); it != labelMasks.end(); it++ )
 
  667      QString labelRule = it.key();
 
  673      for ( 
auto mit = masks.begin(); mit != masks.end(); mit++ )
 
  675        const QString sourceLayerId = mit.key();
 
  677        if ( !layerJobMapping.contains( sourceLayerId ) )
 
  680          usableMasks.insert( sourceLayerId, mit.value() );
 
  683      if ( usableMasks.empty() )
 
  687      QSet<QgsSymbolLayerReference> slRefs;
 
  688      bool hasEffects = 
false;
 
  689      for ( 
auto mit = usableMasks.begin(); mit != usableMasks.end(); mit++ )
 
  691        const QString sourceLayerId = mit.key();
 
  693        if ( !layerJobMapping.contains( sourceLayerId ) )
 
  696        for ( 
auto slIt = mit.value().symbolLayerIds.begin(); slIt != mit.value().symbolLayerIds.end(); slIt++ )
 
  701        hasEffects |= mit.value().hasEffects;
 
  704      int labelMaskId = labelJob.maskIdProvider.insertLabelLayer( vl->
id(), it.key(), slRefs );
 
  705      labelHasEffects[ labelMaskId ] = hasEffects;
 
  708      collectMasks( &usableMasks, vl->
id(), labelRule, labelMaskId );
 
  713    collectMasks( &symbolLayerMasks, vl->
id() );
 
  716  if ( maskedSymbolLayers.isEmpty() )
 
  717    return secondPassJobs;
 
  720  for ( 
int maskId = 0; maskId < labelJob.maskIdProvider.size(); maskId++ )
 
  722    QPaintDevice *maskPaintDevice = 
nullptr;
 
  723    QPainter *maskPainter = 
nullptr;
 
  724    if ( forceVector && !labelHasEffects[ maskId ] )
 
  728      maskPainter = 
new QPainter( maskPaintDevice );
 
  733      QImage *maskImage = 
nullptr;
 
  734      maskPainter = allocateImageAndPainter( QStringLiteral( 
"label mask" ), maskImage, &labelJob.context );
 
  735      maskImage->fill( 0 );
 
  736      maskPaintDevice = maskImage;
 
  739    labelJob.context.setMaskPainter( maskPainter, maskId );
 
  740    labelJob.maskPainters.push_back( std::unique_ptr<QPainter>( maskPainter ) );
 
  741    labelJob.maskPaintDevices.push_back( std::unique_ptr<QPaintDevice>( maskPaintDevice ) );
 
  743  labelJob.context.setMaskIdProvider( &labelJob.maskIdProvider );
 
  754  if ( !labelJob.img && !forceVector )
 
  756    labelJob.img = allocateImage( QStringLiteral( 
"labels" ) );
 
  758  else if ( !labelJob.picture && forceVector )
 
  760    labelJob.picture.reset( 
new QPicture() );
 
  764  for ( LayerRenderJob &job : firstPassJobs )
 
  766    job.maskRequiresLayerRasterization = 
false;
 
  768    auto it = maskedSymbolLayers.find( job.layerId );
 
  769    if ( it != maskedSymbolLayers.end() )
 
  771      const QList<MaskSource> &sourceList = it->second;
 
  772      for ( 
const MaskSource &source : sourceList )
 
  774        job.maskRequiresLayerRasterization |= source.hasEffects;
 
  779    const bool isRasterRendering = !forceVector || job.maskRequiresLayerRasterization || ( job.renderer && job.renderer->forceRasterRender() );
 
  780    if ( isRasterRendering && !job.img )
 
  782      job.context()->setPainter( allocateImageAndPainter( job.layerId, job.img, job.context() ) );
 
  784    else if ( !isRasterRendering && !job.picture )
 
  786      PictureAndPainter pictureAndPainter = allocatePictureAndPainter( job.context() );
 
  787      job.picture = std::move( pictureAndPainter.first );
 
  788      job.context()->setPainter( pictureAndPainter.second );
 
  791      job.renderer = job.layer->createMapRenderer( *( job.context() ) );
 
  795    if ( maskLayerHasEffects.contains( job.layerId ) )
 
  797      QPaintDevice *maskPaintDevice = 
nullptr;
 
  798      QPainter *maskPainter = 
nullptr;
 
  799      if ( forceVector && !maskLayerHasEffects[ job.layerId ] )
 
  803        maskPainter = 
new QPainter( maskPaintDevice );
 
  808        QImage *maskImage = 
nullptr;
 
  809        maskPainter = allocateImageAndPainter( job.layerId, maskImage, job.context() );
 
  810        maskImage->fill( 0 );
 
  811        maskPaintDevice = maskImage;
 
  814      job.context()->setMaskPainter( maskPainter );
 
  815      job.maskPainter.reset( maskPainter );
 
  816      job.maskPaintDevice.reset( maskPaintDevice );
 
  820  for ( LayerRenderJob &job : firstPassJobs )
 
  824    auto it = maskedSymbolLayers.find( job.layerId );
 
  825    if ( it == maskedSymbolLayers.end() )
 
  828    QList<MaskSource> &sourceList = it->second;
 
  829    const QSet<QgsSymbolLayerId> &symbolList = it->first;
 
  831    secondPassJobs.emplace_back( LayerRenderJob() );
 
  832    LayerRenderJob &job2 = secondPassJobs.back();
 
  834    job2.maskRequiresLayerRasterization = job.maskRequiresLayerRasterization;
 
  837    for ( MaskSource &source : sourceList )
 
  839      if ( source.labelMaskId != -1 )
 
  840        job2.maskJobs.push_back( qMakePair( 
nullptr, source.labelMaskId ) );
 
  842        job2.maskJobs.push_back( qMakePair( layerJobMapping[source.layerId], -1 ) );
 
  846    job2.setContext( std::make_unique< QgsRenderContext >( *job.context() ) );
 
  848    job2.layer = job.layer;
 
  849    job2.layerId = job.layerId;
 
  852    job2.firstPassJob = &job;
 
  854    if ( !forceVector || job2.maskRequiresLayerRasterization )
 
  856      job2.context()->setPainter( allocateImageAndPainter( job.layerId, job2.img, job2.context() ) );
 
  860      PictureAndPainter pictureAndPainter = allocatePictureAndPainter( job2.context() );
 
  861      job2.picture = std::move( pictureAndPainter.first );
 
  862      job2.context()->setPainter( pictureAndPainter.second );
 
  865    if ( ! job2.img && ! job2.picture )
 
  867      secondPassJobs.pop_back();
 
  874    job2.renderer = mapRenderer;
 
  877      job2.context()->setFeedback( job2.renderer->feedback() );
 
  885  return secondPassJobs;
 
  893  for ( LayerRenderJob &job : secondPassJobs )
 
  895    if ( job.maskRequiresLayerRasterization )
 
  901    for ( 
const QPair<LayerRenderJob *, int> &p : std::as_const( job.maskJobs ) )
 
  903      QPainter *maskPainter = p.first ? p.first->maskPainter.get() : labelJob.maskPainters[p.second].get();
 
  904      QPainterPath path = 
static_cast<QgsMaskPaintDevice *
>( maskPainter->device() )->maskPainterPath();
 
  905      for ( 
const QgsSymbolLayer *symbolLayer : job.context()->disabledSymbolLayers() )
 
  907        job.context()->addSymbolLayerClipPath( symbolLayer, path );
 
  911    job.context()->setDisabledSymbolLayers( QSet<const QgsSymbolLayer *>() );
 
  919  job.context.setPainter( painter );
 
  920  job.context.setLabelingEngine( labelingEngine2 );
 
  921  job.context.setFeedback( mLabelingEngineFeedback );
 
  925  job.context.setExtent( r1 );
 
  927  job.context.setFeatureFilterProvider( mFeatureFilterProvider );
 
  930  job.context.setCoordinateTransform( ct );
 
  944    job.context.setPainter( 
nullptr );
 
  948    if ( canUseLabelCache && ( 
mCache || !painter ) )
 
  950      job.img = allocateImage( QStringLiteral( 
"labels" ) );
 
  960  for ( LayerRenderJob &job : jobs )
 
  964      delete job.context()->painter();
 
  965      job.context()->setPainter( 
nullptr );
 
  967      if ( 
mCache && !job.cached && job.completed && job.layer )
 
  969        QgsDebugMsgLevel( QStringLiteral( 
"caching image for %1" ).arg( job.layerId ), 2 );
 
  980      delete job.context()->painter();
 
  981      job.context()->setPainter( 
nullptr );
 
  982      job.picture.reset( 
nullptr );
 
  987      const QStringList 
errors = job.renderer->errors();
 
  988      for ( 
const QString &message : 
errors )
 
  989        mErrors.append( Error( job.renderer->layerId(), message ) );
 
  994      job.renderer = 
nullptr;
 
 1000    job.maskPainter.reset( 
nullptr );
 
 1001    job.maskPaintDevice.reset( 
nullptr );
 
 1009  for ( LayerRenderJob &job : jobs )
 
 1013      delete job.context()->painter();
 
 1014      job.context()->setPainter( 
nullptr );
 
 1022      delete job.context()->painter();
 
 1023      job.context()->setPainter( 
nullptr );
 
 1028      delete job.renderer;
 
 1029      job.renderer = 
nullptr;
 
 1043    if ( 
mCache && !job.cached && !job.context.renderingStopped() )
 
 1054  job.picture.reset( 
nullptr );
 
 1055  job.maskPainters.clear();
 
 1056  job.maskPaintDevices.clear();
 
 1060#define DEBUG_RENDERING 0 
 1063                                        const std::vector<LayerRenderJob> &jobs,
 
 1064                                        const LabelRenderJob &labelJob,
 
 1070  image.setDotsPerMeterX( 
static_cast<int>( settings.
outputDpi() * 39.37 ) );
 
 1071  image.setDotsPerMeterY( 
static_cast<int>( settings.
outputDpi() * 39.37 ) );
 
 1074  QPainter painter( &image );
 
 1079  for ( 
const LayerRenderJob &job : jobs )
 
 1081    if ( job.layer && job.layer->customProperty( QStringLiteral( 
"rendering/renderAboveLabels" ) ).toBool() )
 
 1088    painter.setCompositionMode( job.blendMode );
 
 1089    painter.setOpacity( job.opacity );
 
 1092    img.save( QString( 
"/tmp/final_%1.png" ).arg( i ) );
 
 1096    painter.drawImage( 0, 0, img );
 
 1102  if ( labelJob.img && labelJob.complete )
 
 1104    painter.setCompositionMode( QPainter::CompositionMode_SourceOver );
 
 1105    painter.setOpacity( 1.0 );
 
 1106    painter.drawImage( 0, 0, *labelJob.img );
 
 1114    painter.setCompositionMode( QPainter::CompositionMode_SourceOver );
 
 1115    painter.setOpacity( 1.0 );
 
 1116    painter.drawImage( 0, 0, labelCacheImage );
 
 1120  for ( 
const LayerRenderJob &job : jobs )
 
 1122    if ( !job.layer || !job.layer->customProperty( QStringLiteral( 
"rendering/renderAboveLabels" ) ).toBool() )
 
 1129    painter.setCompositionMode( job.blendMode );
 
 1130    painter.setOpacity( job.opacity );
 
 1132    painter.drawImage( 0, 0, img );
 
 1137  image.save( 
"/tmp/final.png" );
 
 1144  const LayerRenderJob &job,
 
 1148  if ( job.imageCanBeComposed() )
 
 1150    Q_ASSERT( job.img );
 
 1155    if ( cache && cache->
hasAnyCacheImage( job.layerId + QStringLiteral( 
"_preview" ) ) )
 
 1167  for ( LayerRenderJob &job : secondPassJobs )
 
 1169    const bool isRasterRendering = !forceVector || job.maskRequiresLayerRasterization;
 
 1172    if ( isRasterRendering && job.maskJobs.size() > 1 )
 
 1174      QPainter *maskPainter = 
nullptr;
 
 1175      for ( QPair<LayerRenderJob *, int> p : job.maskJobs )
 
 1177        QImage *maskImage = 
static_cast<QImage *
>( p.first ? p.first->maskPaintDevice.get() : labelJob.maskPaintDevices[p.second].get() );
 
 1180          maskPainter = p.first ? p.first->maskPainter.get() : labelJob.maskPainters[ p.second ].get();
 
 1184          maskPainter->drawImage( 0, 0, *maskImage );
 
 1189    if ( ! job.maskJobs.isEmpty() )
 
 1192      QPair<LayerRenderJob *, int> p = *job.maskJobs.begin();
 
 1193      if ( isRasterRendering )
 
 1195        QImage *maskImage = 
static_cast<QImage *
>( p.first ? p.first->maskPaintDevice.get() : labelJob.maskPaintDevices[p.second].get() );
 
 1198        QPainter *painter = job.context()->painter();
 
 1200        painter->setCompositionMode( QPainter::CompositionMode_DestinationIn );
 
 1205        QImage maskBinAlpha = maskImage->createMaskFromColor( 0 );
 
 1206        QVector<QRgb> mswTable;
 
 1207        mswTable.push_back( qRgba( 0, 0, 0, 255 ) );
 
 1208        mswTable.push_back( qRgba( 0, 0, 0, 0 ) );
 
 1209        maskBinAlpha.setColorTable( mswTable );
 
 1210        painter->drawImage( 0, 0, maskBinAlpha );
 
 1214          QPainter tempPainter;
 
 1217          QPainter *painter1 = job.firstPassJob->context()->painter();
 
 1220            tempPainter.begin( job.firstPassJob->img );
 
 1221            painter1 = &tempPainter;
 
 1225          painter1->setCompositionMode( QPainter::CompositionMode_DestinationOut );
 
 1226          painter1->drawImage( 0, 0, *maskImage );
 
 1229          painter1->setCompositionMode( QPainter::CompositionMode_DestinationOver );
 
 1230          painter1->drawImage( 0, 0, *job.img );
 
 1235        job.firstPassJob->picture = std::move( job.picture );
 
 1236        job.picture = 
nullptr;
 
 1247  QMultiMap<int, QString> elapsed;
 
 1248  for ( 
const LayerRenderJob &job : jobs )
 
 1249    elapsed.insert( job.renderingTime, job.layerId );
 
 1250  for ( 
const LayerRenderJob &job : secondPassJobs )
 
 1251    elapsed.insert( job.renderingTime, job.layerId + QString( 
" (second pass)" ) );
 
 1253  elapsed.insert( labelJob.renderingTime, tr( 
"Labeling" ) );
 
 1255  QList<int> tt( elapsed.uniqueKeys() );
 
 1256  std::sort( tt.begin(), tt.end(), std::greater<int>() );
 
 1257  for ( 
int t : std::as_const( tt ) )
 
 1259    QgsMessageLog::logMessage( tr( 
"%1 ms: %2" ).arg( t ).arg( QStringList( elapsed.values( t ) ).join( QLatin1String( 
", " ) ) ), tr( 
"Rendering" ) );
 
 1272  painter->setCompositionMode( QPainter::CompositionMode_SourceOver );
 
 1276  if ( labelingEngine2 )
 
 1278    labelingEngine2->
run( renderContext );
 
 1281  QgsDebugMsgLevel( QStringLiteral( 
"Draw labeling took (seconds): %1" ).arg( t.elapsed() / 1000. ), 2 );
 
 1286  Q_UNUSED( settings )
 
 1288  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