LayerRenderJobs QgsMapRendererJob::prepareJobs( QPainter* painter, QgsPalLabeling* labelingEngine ) { LayerRenderJobs layerJobs; // render all layers in the stack, starting at the base QListIterator<QString> li( mSettings.layers() ); li.toBack(); if ( mCache ) { bool cacheValid = mCache->init( mSettings.visibleExtent(), mSettings.scale() ); QgsDebugMsg( QString( "CACHE VALID: %1" ).arg( cacheValid ) ); Q_UNUSED( cacheValid ); } mGeometryCaches.clear(); while ( li.hasPrevious() ) { QString layerId = li.previous(); QgsDebugMsg( "Rendering at layer item " + layerId ); QgsMapLayer *ml = QgsMapLayerRegistry::instance()->mapLayer( layerId ); if ( !ml ) { mErrors.append( Error( layerId, "Layer not found in registry." ) ); continue; } QgsDebugMsg( QString( "layer %1: minscale:%2 maxscale:%3 scaledepvis:%4 extent:%5 blendmode:%6" ) .arg( ml->name() ) .arg( ml->minimumScale() ) .arg( ml->maximumScale() ) .arg( ml->hasScaleBasedVisibility() ) .arg( ml->extent().toString() ) .arg( ml->blendMode() ) ); if ( ml->hasScaleBasedVisibility() && ( mSettings.scale() < ml->minimumScale() || mSettings.scale() > ml->maximumScale() ) ) //|| mOverview ) { QgsDebugMsg( "Layer not rendered because it is not within the defined visibility scale range" ); continue; } QgsRectangle r1 = mSettings.visibleExtent(), r2; const QgsCoordinateTransform* ct = 0; if ( mSettings.hasCrsTransformEnabled() ) { ct = mSettings.layerTransfrom( ml ); if ( ct ) { reprojectToLayerExtent( ct, ml->crs().geographicFlag(), r1, r2 ); } QgsDebugMsg( "extent: " + r1.toString() ); if ( !r1.isFinite() || !r2.isFinite() ) { mErrors.append( Error( layerId, "There was a problem transforming layer's' extent. Layer skipped." ) ); continue; } } // Force render of layers that are being edited // or if there's a labeling engine that needs the layer to register features if ( mCache && ml->type() == QgsMapLayer::VectorLayer ) { QgsVectorLayer* vl = qobject_cast<QgsVectorLayer *>( ml ); if ( vl->isEditable() || ( labelingEngine && labelingEngine->willUseLayer( vl ) ) ) mCache->clearCacheImage( ml->id() ); } layerJobs.append( LayerRenderJob() ); LayerRenderJob& job = layerJobs.last(); job.cached = false; job.img = 0; job.blendMode = ml->blendMode(); job.layerId = ml->id(); job.context = QgsRenderContext::fromMapSettings( mSettings ); job.context.setPainter( painter ); job.context.setLabelingEngine( labelingEngine ); job.context.setCoordinateTransform( ct ); job.context.setExtent( r1 ); // if we can use the cache, let's do it and avoid rendering! if ( mCache && !mCache->cacheImage( ml->id() ).isNull() ) { job.cached = true; job.img = new QImage( mCache->cacheImage( ml->id() ) ); job.renderer = 0; job.context.setPainter( 0 ); continue; } // If we are drawing with an alternative blending mode then we need to render to a separate image // before compositing this on the map. This effectively flattens the layer and prevents // blending occuring between objects on the layer if ( mCache || !painter || needTemporaryImage( ml ) ) { // Flattened image for drawing when a blending mode is set QImage * mypFlattenedImage = 0; mypFlattenedImage = new QImage( mSettings.outputSize().width(), mSettings.outputSize().height(), mSettings.outputImageFormat() ); if ( mypFlattenedImage->isNull() ) { mErrors.append( Error( layerId, "Insufficient memory for image " + QString::number( mSettings.outputSize().width() ) + "x" + QString::number( mSettings.outputSize().height() ) ) ); delete mypFlattenedImage; layerJobs.removeLast(); continue; } mypFlattenedImage->fill( 0 ); job.img = mypFlattenedImage; QPainter* mypPainter = new QPainter( job.img ); mypPainter->setRenderHint( QPainter::Antialiasing, mSettings.testFlag( QgsMapSettings::Antialiasing ) ); job.context.setPainter( mypPainter ); } job.renderer = ml->createMapRenderer( job.context ); if ( mRequestedGeomCacheForLayers.contains( ml->id() ) ) { if ( QgsVectorLayerRenderer* vlr = dynamic_cast<QgsVectorLayerRenderer*>( job.renderer ) ) { vlr->setGeometryCachePointer( &mGeometryCaches[ ml->id()] ); } } } // while (li.hasPrevious()) return layerJobs; }
LayerRenderJobs QgsMapRendererJob::prepareJobs( QPainter *painter, QgsLabelingEngine *labelingEngine2 ) { LayerRenderJobs layerJobs; // render all layers in the stack, starting at the base QListIterator<QgsMapLayer *> li( mSettings.layers() ); li.toBack(); if ( mCache ) { bool cacheValid = mCache->init( mSettings.visibleExtent(), mSettings.scale() ); Q_UNUSED( cacheValid ); QgsDebugMsgLevel( QString( "CACHE VALID: %1" ).arg( cacheValid ), 4 ); } bool requiresLabelRedraw = !( mCache && mCache->hasCacheImage( LABEL_CACHE_ID ) ); while ( li.hasPrevious() ) { QgsMapLayer *ml = li.previous(); QgsDebugMsgLevel( QString( "layer %1: minscale:%2 maxscale:%3 scaledepvis:%4 blendmode:%5" ) .arg( ml->name() ) .arg( ml->minimumScale() ) .arg( ml->maximumScale() ) .arg( ml->hasScaleBasedVisibility() ) .arg( ml->blendMode() ) , 3 ); if ( !ml->isInScaleRange( mSettings.scale() ) ) //|| mOverview ) { QgsDebugMsgLevel( "Layer not rendered because it is not within the defined visibility scale range", 3 ); continue; } QgsRectangle r1 = mSettings.visibleExtent(), r2; QgsCoordinateTransform ct; ct = mSettings.layerTransform( ml ); if ( ct.isValid() ) { reprojectToLayerExtent( ml, ct, r1, r2 ); } QgsDebugMsgLevel( "extent: " + r1.toString(), 3 ); if ( !r1.isFinite() || !r2.isFinite() ) { mErrors.append( Error( ml->id(), tr( "There was a problem transforming the layer's extent. Layer skipped." ) ) ); continue; } // Force render of layers that are being edited // or if there's a labeling engine that needs the layer to register features if ( mCache && ml->type() == QgsMapLayer::VectorLayer ) { QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( ml ); bool requiresLabeling = false; requiresLabeling = ( labelingEngine2 && QgsPalLabeling::staticWillUseLayer( vl ) ) && requiresLabelRedraw; if ( vl->isEditable() || requiresLabeling ) { mCache->clearCacheImage( ml->id() ); } } layerJobs.append( LayerRenderJob() ); LayerRenderJob &job = layerJobs.last(); job.cached = false; job.img = nullptr; job.layer = ml; job.renderingTime = -1; job.context = QgsRenderContext::fromMapSettings( mSettings ); job.context.expressionContext().appendScope( QgsExpressionContextUtils::layerScope( ml ) ); job.context.setPainter( painter ); job.context.setLabelingEngine( labelingEngine2 ); job.context.setCoordinateTransform( ct ); job.context.setExtent( r1 ); if ( mFeatureFilterProvider ) job.context.setFeatureFilterProvider( mFeatureFilterProvider ); QgsMapLayerStyleOverride styleOverride( ml ); if ( mSettings.layerStyleOverrides().contains( ml->id() ) ) styleOverride.setOverrideStyle( mSettings.layerStyleOverrides().value( ml->id() ) ); job.blendMode = ml->blendMode(); job.opacity = 1.0; if ( QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( ml ) ) { job.opacity = vl->opacity(); } // if we can use the cache, let's do it and avoid rendering! if ( mCache && mCache->hasCacheImage( ml->id() ) ) { job.cached = true; job.imageInitialized = true; job.img = new QImage( mCache->cacheImage( ml->id() ) ); job.renderer = nullptr; job.context.setPainter( nullptr ); continue; } // If we are drawing with an alternative blending mode then we need to render to a separate image // before compositing this on the map. This effectively flattens the layer and prevents // blending occurring between objects on the layer if ( mCache || !painter || needTemporaryImage( ml ) ) { // Flattened image for drawing when a blending mode is set QImage *mypFlattenedImage = nullptr; mypFlattenedImage = new QImage( mSettings.outputSize().width(), mSettings.outputSize().height(), mSettings.outputImageFormat() ); if ( mypFlattenedImage->isNull() ) { mErrors.append( Error( ml->id(), tr( "Insufficient memory for image %1x%2" ).arg( mSettings.outputSize().width() ).arg( mSettings.outputSize().height() ) ) ); delete mypFlattenedImage; layerJobs.removeLast(); continue; } job.img = mypFlattenedImage; QPainter *mypPainter = new QPainter( job.img ); mypPainter->setRenderHint( QPainter::Antialiasing, mSettings.testFlag( QgsMapSettings::Antialiasing ) ); job.context.setPainter( mypPainter ); } QTime layerTime; layerTime.start(); job.renderer = ml->createMapRenderer( job.context ); job.renderingTime = layerTime.elapsed(); // include job preparation time in layer rendering time } // while (li.hasPrevious()) return layerJobs; }