19#include <QElapsedTimer>
21#include <QtConcurrentMap>
61LayerRenderJob &LayerRenderJob::operator=( LayerRenderJob &&other )
63 mContext = std::move( other.mContext );
68 renderer = other.renderer;
69 other.renderer =
nullptr;
71 previewRenderImage = other.previewRenderImage;
72 other.previewRenderImage =
nullptr;
74 imageInitialized = other.imageInitialized;
75 previewRenderImageInitialized = other.previewRenderImageInitialized;
77 blendMode = other.blendMode;
78 opacity = other.opacity;
79 cached = other.cached;
81 renderAboveLabels = other.renderAboveLabels;
82 completed = other.completed;
83 renderingTime = other.renderingTime;
84 estimatedRenderingTime = other.estimatedRenderingTime ;
85 errors = other.errors;
86 layerId = other.layerId;
88 maskPaintDevice = std::move( other.maskPaintDevice );
90 firstPassJob = other.firstPassJob;
91 other.firstPassJob =
nullptr;
93 picture = std::move( other.picture );
95 maskJobs = other.maskJobs;
97 maskRequiresLayerRasterization = other.maskRequiresLayerRasterization;
99 elevationMap = other.elevationMap;
100 maskPainter = std::move( other.maskPainter );
105LayerRenderJob::LayerRenderJob( LayerRenderJob &&other )
106 : imageInitialized( other.imageInitialized )
107 , previewRenderImageInitialized( other.previewRenderImageInitialized )
108 , blendMode( other.blendMode )
109 , opacity( other.opacity )
110 , cached( other.cached )
111 , renderAboveLabels( other.renderAboveLabels )
112 , layer( other.layer )
113 , completed( other.completed )
114 , renderingTime( other.renderingTime )
115 , estimatedRenderingTime( other.estimatedRenderingTime )
116 , errors( other.errors )
117 , layerId( other.layerId )
118 , maskPainter( nullptr )
119 , maskRequiresLayerRasterization( other.maskRequiresLayerRasterization )
120 , maskJobs( other.maskJobs )
122 mContext = std::move( other.mContext );
127 previewRenderImage = other.previewRenderImage;
128 other.previewRenderImage =
nullptr;
130 renderer = other.renderer;
131 other.renderer =
nullptr;
133 elevationMap = other.elevationMap;
134 other.elevationMap =
nullptr;
136 maskPaintDevice = std::move( other.maskPaintDevice );
138 firstPassJob = other.firstPassJob;
139 other.firstPassJob =
nullptr;
141 picture = std::move( other.picture );
144bool LayerRenderJob::imageCanBeComposed()
const
146 if ( imageInitialized )
150 return renderer->isReadyToCompose();
164 : mSettings( settings )
210 return mLabelingEngineFeedback;
215 QHash<QgsMapLayer *, int> result;
218 if (
auto &&lKey = it.key() )
219 result.insert( lKey, it.value() );
239 QSet< QgsMapLayer * > labeledLayers;
246 switch ( ml->type() )
294 bool canUseCache = canCache && QSet< QgsMapLayer * >( labelDependentLayers.begin(), labelDependentLayers.end() ) == labeledLayers;
323 static const double SPLIT_COORD = 180.0;
335 QgsDebugMsgLevel( QStringLiteral(
"\n0:%1 %2x%3\n1:%4\n2:%5 %6x%7 (w:%8 h:%9)" )
338 .arg( std::fabs( 1.0 - extent2.
width() / extent.
width() ) )
339 .arg( std::fabs( 1.0 - extent2.
height() / extent.
height() ) )
373 if ( ll.
x() > ur.
x() )
402 extent =
QgsRectangle( std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), std::numeric_limits<double>::max() );
412 extent =
QgsRectangle( std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), std::numeric_limits<double>::max() );
413 r2 =
QgsRectangle( std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), std::numeric_limits<double>::max() );
420QImage *QgsMapRendererJob::allocateImage( QString layerId )
427 if ( image->isNull() )
436QgsElevationMap *QgsMapRendererJob::allocateElevationMap( QString layerId )
439 if ( !elevationMap->isValid() )
444 return elevationMap.release();
447QPainter *QgsMapRendererJob::allocateImageAndPainter( QString layerId, QImage *&image,
const QgsRenderContext *context )
449 QPainter *painter =
nullptr;
450 image = allocateImage( layerId );
453 painter =
new QPainter( image );
459QgsMapRendererJob::PictureAndPainter QgsMapRendererJob::allocatePictureAndPainter(
const QgsRenderContext *context )
461 std::unique_ptr<QPicture> picture = std::make_unique<QPicture>();
462 QPainter *painter =
new QPainter( picture.get() );
464 return { std::move( picture ), painter };
469 std::vector< LayerRenderJob > layerJobs;
478 Q_UNUSED( cacheValid )
479 QgsDebugMsgLevel( QStringLiteral(
"CACHE VALID: %1" ).arg( cacheValid ), 4 );
484 while ( li.hasPrevious() )
488 QgsDebugMsgLevel( QStringLiteral(
"layer %1: minscale:%2 maxscale:%3 scaledepvis:%4 blendmode:%5 isValid:%6" )
505 QgsDebugMsgLevel( QStringLiteral(
"Layer not rendered because it is not within the defined visibility scale range" ), 3 );
511 QgsDebugMsgLevel( QStringLiteral(
"Layer not rendered because it is not visible within the map's time range" ), 3 );
517 QgsDebugMsgLevel( QStringLiteral(
"Layer not rendered because it is not visible within the map's z range" ), 3 );
526 bool haveExtentInLayerCrs =
true;
529 haveExtentInLayerCrs = reprojectToLayerExtent( ml, ct, r1, r2 );
534 mErrors.append( Error( ml->
id(), tr(
"There was a problem transforming the layer's extent. Layer skipped." ) ) );
545 if ( ( vl && vl->
isEditable() ) || requiresLabeling )
551 layerJobs.emplace_back( LayerRenderJob() );
552 LayerRenderJob &job = layerJobs.back();
554 job.layerId = ml->
id();
555 job.renderAboveLabels = ml->
customProperty( QStringLiteral(
"rendering/renderAboveLabels" ) ).toBool();
559 if ( !ml->
customProperty( QStringLiteral(
"_noset_layer_expression_context" ) ).toBool() )
561 job.context()->setPainter( painter );
562 job.context()->setLabelingEngine( labelingEngine2 );
563 job.context()->setLabelSink(
labelSink() );
564 job.context()->setCoordinateTransform( ct );
565 job.context()->setExtent( r1 );
571 if ( mFeatureFilterProvider )
572 job.context()->setFeatureFilterProvider( mFeatureFilterProvider );
605 job.imageInitialized =
true;
613 job.renderer =
nullptr;
614 job.context()->setPainter(
nullptr );
619 QElapsedTimer layerTime;
625 job.context()->setFeedback( job.renderer->feedback() );
631 if (
mCache || ( !painter && !deferredPainterSet ) || ( job.renderer && job.renderer->forceRasterRender() ) )
634 job.context()->setPainter( allocateImageAndPainter( ml->
id(), job.img, job.context() ) );
638 job.renderer =
nullptr;
639 layerJobs.pop_back();
648 job.elevationMap = allocateElevationMap( ml->
id() );
649 job.context()->setElevationMap( job.elevationMap );
657 if ( !cachedImage.isNull() )
659 job.previewRenderImage =
new QImage( cachedImage );
660 job.previewRenderImageInitialized =
true;
661 job.context()->setPreviewRenderPainter(
new QPainter( job.previewRenderImage ) );
662 job.context()->setPainterFlagsUsingContext( painter );
665 if ( !job.previewRenderImage )
667 job.context()->setPreviewRenderPainter( allocateImageAndPainter( ml->
id(), job.previewRenderImage, job.context() ) );
668 job.previewRenderImageInitialized =
false;
671 if ( !job.previewRenderImage )
673 delete job.context()->previewRenderPainter();
674 job.context()->setPreviewRenderPainter(
nullptr );
678 job.renderingTime = layerTime.elapsed();
686 std::vector< LayerRenderJob > secondPassJobs;
689 QHash<QString, LayerRenderJob *> layerJobMapping;
692 QMap<QString, bool> maskLayerHasEffects;
693 QMap<int, bool> labelHasEffects;
701 MaskSource(
const QString &layerId_,
const QString &labelRuleId_,
int labelMaskId_,
bool hasEffects_ ):
702 layerId( layerId_ ), labelRuleId( labelRuleId_ ), labelMaskId( labelMaskId_ ), hasEffects( hasEffects_ ) {}
707 QHash<QString, QPair<QSet<QString>, QList<MaskSource>>> maskedSymbolLayers;
714 for ( LayerRenderJob &job : firstPassJobs )
716 layerJobMapping[job.layerId] = &job;
721 for ( LayerRenderJob &job : firstPassJobs )
728 auto collectMasks = [&](
QgsMaskedLayers * masks, QString sourceLayerId, QString ruleId = QString(),
int labelMaskId = -1 )
730 bool hasEffects =
false;
731 for (
auto it = masks->begin(); it != masks->end(); ++it )
733 auto lit = maskedSymbolLayers.find( it.key() );
734 if ( lit == maskedSymbolLayers.end() )
736 maskedSymbolLayers[it.key()] = qMakePair( it.value().symbolLayerIds, QList<MaskSource>() << MaskSource( sourceLayerId, ruleId, labelMaskId, it.value().hasEffects ) );
740 if ( lit->first != it.value().symbolLayerIds )
742 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() ) );
745 lit->second.push_back( MaskSource( sourceLayerId, ruleId, labelMaskId, hasEffects ) );
747 hasEffects |= it.value().hasEffects;
749 if ( ! masks->isEmpty() && labelMaskId == -1 )
750 maskLayerHasEffects[ sourceLayerId ] = hasEffects;
755 for (
auto it = labelMasks.begin(); it != labelMasks.end(); it++ )
757 QString labelRule = it.key();
763 for (
auto mit = masks.begin(); mit != masks.end(); mit++ )
765 const QString sourceLayerId = mit.key();
767 if ( !layerJobMapping.contains( sourceLayerId ) )
770 usableMasks.insert( sourceLayerId, mit.value() );
773 if ( usableMasks.empty() )
777 QSet<QgsSymbolLayerReference> slRefs;
778 bool hasEffects =
false;
779 for (
auto mit = usableMasks.begin(); mit != usableMasks.end(); mit++ )
781 const QString sourceLayerId = mit.key();
783 if ( !layerJobMapping.contains( sourceLayerId ) )
786 for (
const QString &symbolLayerId : mit.value().symbolLayerIds )
789 hasEffects |= mit.value().hasEffects;
792 int labelMaskId = labelJob.maskIdProvider.insertLabelLayer( vl->
id(), it.key(), slRefs );
793 labelHasEffects[ labelMaskId ] = hasEffects;
796 collectMasks( &usableMasks, vl->
id(), labelRule, labelMaskId );
801 collectMasks( &symbolLayerMasks, vl->
id() );
804 if ( maskedSymbolLayers.isEmpty() )
805 return secondPassJobs;
808 for (
int maskId = 0; maskId < labelJob.maskIdProvider.size(); maskId++ )
810 QPaintDevice *maskPaintDevice =
nullptr;
811 QPainter *maskPainter =
nullptr;
812 if ( forceVector && !labelHasEffects[ maskId ] )
816 maskPainter =
new QPainter( maskPaintDevice );
821 QImage *maskImage =
nullptr;
822 maskPainter = allocateImageAndPainter( QStringLiteral(
"label mask" ), maskImage, &labelJob.context );
823 maskImage->fill( 0 );
824 maskPaintDevice = maskImage;
827 labelJob.context.setMaskPainter( maskPainter, maskId );
828 labelJob.maskPainters.push_back( std::unique_ptr<QPainter>( maskPainter ) );
829 labelJob.maskPaintDevices.push_back( std::unique_ptr<QPaintDevice>( maskPaintDevice ) );
831 labelJob.context.setMaskIdProvider( &labelJob.maskIdProvider );
842 if ( !labelJob.img && !forceVector )
844 labelJob.img = allocateImage( QStringLiteral(
"labels" ) );
846 else if ( !labelJob.picture && forceVector )
848 labelJob.picture.reset(
new QPicture() );
852 for ( LayerRenderJob &job : firstPassJobs )
854 job.maskRequiresLayerRasterization =
false;
856 auto it = maskedSymbolLayers.find( job.layerId );
857 if ( it != maskedSymbolLayers.end() )
859 const QList<MaskSource> &sourceList = it->second;
860 for (
const MaskSource &source : sourceList )
862 job.maskRequiresLayerRasterization |= source.hasEffects;
867 const bool isRasterRendering = !forceVector || job.maskRequiresLayerRasterization || ( job.renderer && job.renderer->forceRasterRender() );
868 if ( isRasterRendering && !job.img )
870 job.context()->setPainter( allocateImageAndPainter( job.layerId, job.img, job.context() ) );
872 else if ( !isRasterRendering && !job.picture )
874 PictureAndPainter pictureAndPainter = allocatePictureAndPainter( job.context() );
875 job.picture = std::move( pictureAndPainter.first );
876 job.context()->setPainter( pictureAndPainter.second );
879 job.renderer = job.layer->createMapRenderer( *( job.context() ) );
883 if ( maskLayerHasEffects.contains( job.layerId ) )
885 QPaintDevice *maskPaintDevice =
nullptr;
886 QPainter *maskPainter =
nullptr;
887 if ( forceVector && !maskLayerHasEffects[ job.layerId ] )
891 maskPainter =
new QPainter( maskPaintDevice );
896 QImage *maskImage =
nullptr;
897 maskPainter = allocateImageAndPainter( job.layerId, maskImage, job.context() );
898 maskImage->fill( 0 );
899 maskPaintDevice = maskImage;
902 job.context()->setMaskPainter( maskPainter );
903 job.maskPainter.reset( maskPainter );
904 job.maskPaintDevice.reset( maskPaintDevice );
908 for ( LayerRenderJob &job : firstPassJobs )
912 auto it = maskedSymbolLayers.find( job.layerId );
913 if ( it == maskedSymbolLayers.end() )
916 QList<MaskSource> &sourceList = it->second;
917 const QSet<QString> symbolList = it->first;
919 secondPassJobs.emplace_back( LayerRenderJob() );
920 LayerRenderJob &job2 = secondPassJobs.back();
922 job2.maskRequiresLayerRasterization = job.maskRequiresLayerRasterization;
925 for ( MaskSource &source : sourceList )
927 if ( source.labelMaskId != -1 )
928 job2.maskJobs.push_back( qMakePair(
nullptr, source.labelMaskId ) );
930 job2.maskJobs.push_back( qMakePair( layerJobMapping[source.layerId], -1 ) );
934 job2.setContext( std::make_unique< QgsRenderContext >( *job.context() ) );
936 job2.layer = job.layer;
937 job2.renderAboveLabels = job.renderAboveLabels;
938 job2.layerId = job.layerId;
941 job2.firstPassJob = &job;
943 if ( !forceVector || job2.maskRequiresLayerRasterization )
945 job2.context()->setPainter( allocateImageAndPainter( job.layerId, job2.img, job2.context() ) );
949 PictureAndPainter pictureAndPainter = allocatePictureAndPainter( job2.context() );
950 job2.picture = std::move( pictureAndPainter.first );
951 job2.context()->setPainter( pictureAndPainter.second );
954 if ( ! job2.img && ! job2.picture )
956 secondPassJobs.pop_back();
963 job2.renderer = mapRenderer;
966 job2.context()->setFeedback( job2.renderer->feedback() );
971 job2.context()->setDisabledSymbolLayersV2( symbolList );
974 return secondPassJobs;
982 for ( LayerRenderJob &job : secondPassJobs )
984 if ( job.maskRequiresLayerRasterization )
990 for (
const QPair<LayerRenderJob *, int> &p : std::as_const( job.maskJobs ) )
992 QPainter *maskPainter = p.first ? p.first->maskPainter.get() : labelJob.maskPainters[p.second].get();
993 QPainterPath path =
static_cast<QgsMaskPaintDevice *
>( maskPainter->device() )->maskPainterPath();
994 for (
const QString &symbolLayerId : job.context()->disabledSymbolLayersV2() )
996 job.context()->addSymbolLayerClipPath( symbolLayerId, path );
1000 job.context()->setDisabledSymbolLayersV2( QSet<QString>() );
1008 job.context.setPainter( painter );
1009 job.context.setLabelingEngine( labelingEngine2 );
1010 job.context.setFeedback( mLabelingEngineFeedback );
1014 job.context.setExtent( r1 );
1016 job.context.setFeatureFilterProvider( mFeatureFilterProvider );
1019 job.context.setCoordinateTransform( ct );
1030 job.complete =
true;
1033 job.context.setPainter(
nullptr );
1037 if ( canUseLabelCache && (
mCache || !painter ) )
1039 job.img = allocateImage( QStringLiteral(
"labels" ) );
1049 for ( LayerRenderJob &job : jobs )
1053 delete job.context()->painter();
1054 job.context()->setPainter(
nullptr );
1056 if (
mCache && !job.cached && job.completed && job.layer )
1058 QgsDebugMsgLevel( QStringLiteral(
"caching image for %1" ).arg( job.layerId ), 2 );
1067 if ( job.previewRenderImage )
1069 delete job.context()->previewRenderPainter();
1070 job.context()->setPreviewRenderPainter(
nullptr );
1071 delete job.previewRenderImage;
1072 job.previewRenderImage =
nullptr;
1075 if ( job.elevationMap )
1077 job.context()->setElevationMap(
nullptr );
1078 if (
mCache && !job.cached && job.completed && job.layer )
1080 QgsDebugMsgLevel( QStringLiteral(
"caching elevation map for %1" ).arg( job.layerId ), 2 );
1083 job.elevationMap->rawElevationImage(),
1086 QList< QgsMapLayer * >() << job.layer );
1089 job.elevationMap->rawElevationImage(),
1092 QList< QgsMapLayer * >() << job.layer );
1095 delete job.elevationMap;
1096 job.elevationMap =
nullptr;
1101 delete job.context()->painter();
1102 job.context()->setPainter(
nullptr );
1103 job.picture.reset(
nullptr );
1108 const QStringList
errors = job.renderer->errors();
1109 for (
const QString &message :
errors )
1110 mErrors.append( Error( job.renderer->layerId(), message ) );
1112 mRenderedItemResults->appendResults( job.renderer->takeRenderedItemDetails(), *job.context() );
1114 delete job.renderer;
1115 job.renderer =
nullptr;
1121 job.maskPainter.reset(
nullptr );
1122 job.maskPaintDevice.reset(
nullptr );
1130 for ( LayerRenderJob &job : jobs )
1134 delete job.context()->painter();
1135 job.context()->setPainter(
nullptr );
1141 if ( job.previewRenderImage )
1143 delete job.context()->previewRenderPainter();
1144 job.context()->setPreviewRenderPainter(
nullptr );
1145 delete job.previewRenderImage;
1146 job.previewRenderImage =
nullptr;
1151 delete job.context()->painter();
1152 job.context()->setPainter(
nullptr );
1157 delete job.renderer;
1158 job.renderer =
nullptr;
1172 if (
mCache && !job.cached && !job.context.renderingStopped() )
1183 job.picture.reset(
nullptr );
1184 job.maskPainters.clear();
1185 job.maskPaintDevices.clear();
1189#define DEBUG_RENDERING 0
1192 const std::vector<LayerRenderJob> &jobs,
1193 const LabelRenderJob &labelJob,
1199 image.setDotsPerMeterX(
static_cast<int>( settings.
outputDpi() * 39.37 ) );
1200 image.setDotsPerMeterY(
static_cast<int>( settings.
outputDpi() * 39.37 ) );
1204 std::unique_ptr<QgsElevationMap> mainElevationMap;
1205 if ( mapShadingRenderer.
isActive() )
1208 QPainter painter( &image );
1213 for (
const LayerRenderJob &job : jobs )
1215 if ( job.renderAboveLabels )
1222 painter.setCompositionMode( job.blendMode );
1223 painter.setOpacity( job.opacity );
1225 if ( mainElevationMap )
1228 if ( layerElevationMap.
isValid() )
1234 img.save( QString(
"/tmp/final_%1.png" ).arg( i ) );
1238 painter.drawImage( 0, 0, img );
1241 if ( mapShadingRenderer.
isActive() && mainElevationMap )
1249 if ( labelJob.img && labelJob.complete )
1251 painter.setCompositionMode( QPainter::CompositionMode_SourceOver );
1252 painter.setOpacity( 1.0 );
1253 painter.drawImage( 0, 0, *labelJob.img );
1261 painter.setCompositionMode( QPainter::CompositionMode_SourceOver );
1262 painter.setOpacity( 1.0 );
1263 painter.drawImage( 0, 0, labelCacheImage );
1267 for (
const LayerRenderJob &job : jobs )
1269 if ( !job.renderAboveLabels )
1276 painter.setCompositionMode( job.blendMode );
1277 painter.setOpacity( job.opacity );
1279 painter.drawImage( 0, 0, img );
1284 image.save(
"/tmp/final.png" );
1291 const LayerRenderJob &job,
1295 if ( job.imageCanBeComposed() )
1297 if ( job.previewRenderImage && !job.completed )
1298 return *job.previewRenderImage;
1300 Q_ASSERT( job.img );
1305 if ( cache && cache->
hasAnyCacheImage( job.layerId + QStringLiteral(
"_preview" ) ) )
1316 if ( job.imageCanBeComposed() && job.elevationMap )
1318 return *job.elevationMap;
1332 for ( LayerRenderJob &job : secondPassJobs )
1334 const bool isRasterRendering = !forceVector || job.maskRequiresLayerRasterization;
1337 if ( isRasterRendering && job.maskJobs.size() > 1 )
1339 QPainter *maskPainter =
nullptr;
1340 for ( QPair<LayerRenderJob *, int> p : job.maskJobs )
1342 QImage *maskImage =
static_cast<QImage *
>( p.first ? p.first->maskPaintDevice.get() : labelJob.maskPaintDevices[p.second].get() );
1345 maskPainter = p.first ? p.first->maskPainter.get() : labelJob.maskPainters[ p.second ].get();
1349 maskPainter->drawImage( 0, 0, *maskImage );
1354 if ( ! job.maskJobs.isEmpty() )
1357 QPair<LayerRenderJob *, int> p = *job.maskJobs.begin();
1358 if ( isRasterRendering )
1360 QImage *maskImage =
static_cast<QImage *
>( p.first ? p.first->maskPaintDevice.get() : labelJob.maskPaintDevices[p.second].get() );
1363 QPainter *painter = job.context()->painter();
1365 painter->setCompositionMode( QPainter::CompositionMode_DestinationIn );
1370 QImage maskBinAlpha = maskImage->createMaskFromColor( 0 );
1371 QVector<QRgb> mswTable;
1372 mswTable.push_back( qRgba( 0, 0, 0, 255 ) );
1373 mswTable.push_back( qRgba( 0, 0, 0, 0 ) );
1374 maskBinAlpha.setColorTable( mswTable );
1375 painter->drawImage( 0, 0, maskBinAlpha );
1379 QPainter tempPainter;
1382 QPainter *painter1 = job.firstPassJob->context()->painter();
1385 tempPainter.begin( job.firstPassJob->img );
1386 painter1 = &tempPainter;
1390 painter1->setCompositionMode( QPainter::CompositionMode_DestinationOut );
1391 painter1->drawImage( 0, 0, *maskImage );
1394 painter1->setCompositionMode( QPainter::CompositionMode_DestinationOver );
1395 painter1->drawImage( 0, 0, *job.img );
1400 job.firstPassJob->picture = std::move( job.picture );
1401 job.picture =
nullptr;
1412 QMultiMap<int, QString> elapsed;
1413 for (
const LayerRenderJob &job : jobs )
1415 for (
const LayerRenderJob &job : secondPassJobs )
1416 elapsed.insert( job.
renderingTime, job.layerId + QString(
" (second pass)" ) );
1418 elapsed.insert( labelJob.renderingTime, tr(
"Labeling" ) );
1420 QList<int> tt( elapsed.uniqueKeys() );
1421 std::sort( tt.begin(), tt.end(), std::greater<int>() );
1422 for (
int t : std::as_const( tt ) )
1424 QgsMessageLog::logMessage( tr(
"%1 ms: %2" ).arg( t ).arg( QStringList( elapsed.values( t ) ).join( QLatin1String(
", " ) ) ), tr(
"Rendering" ) );
1433 std::unique_ptr< QgsScopedRuntimeProfile > labelingProfile;
1436 labelingProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr(
"(labeling)" ), QStringLiteral(
"rendering" ) );
1443 painter->setCompositionMode( QPainter::CompositionMode_SourceOver );
1447 if ( labelingEngine2 )
1449 labelingEngine2->
run( renderContext );
1452 QgsDebugMsgLevel( QStringLiteral(
"Draw labeling took (seconds): %1" ).arg( t.elapsed() / 1000. ), 2 );
1457 Q_UNUSED( settings )
1459 drawLabeling( renderContext, labelingEngine2, painter );
@ InternalLayerOpacityHandling
The renderer internally handles the raster layer's opacity, so the default layer level opacity handli...
@ Group
Composite group layer. Added in QGIS 3.24.
@ Plugin
Plugin based layer.
@ TiledScene
Tiled scene layer. Added in QGIS 3.34.
@ Annotation
Contains freeform, georeferenced annotations. Added in QGIS 3.16.
@ VectorTile
Vector tile layer. Added in QGIS 3.14.
@ Mesh
Mesh layer. Added in QGIS 3.2.
@ PointCloud
Point cloud layer. Added in QGIS 3.18.
@ RenderPartialOutputOverPreviousCachedImage
When rendering temporary in-progress preview renders, these preview renders can be drawn over any pre...
@ RenderPartialOutputs
The renderer benefits from rendering temporary in-progress preview renders. These are temporary resul...
@ ApplyClipAfterReprojection
Feature geometry clipping to mapExtent() must be performed after the geometries are transformed using...
@ RecordProfile
Enable run-time profiling while rendering (since QGIS 3.34)
@ Forward
Forward transform (from source to destination)
@ Reverse
Reverse/inverse transform (from destination to source)
@ ForceVectorOutput
Vector graphics should not be cached and drawn as raster images.
@ RenderPartialOutput
Whether to make extra effort to update map image with partially rendered layers (better for interacti...
@ 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 ...
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.
Stores digital elevation model in a raster image which may get updated as a part of map layer renderi...
bool isValid() const
Returns whether the elevation map is valid.
This class can render elevation shading on an image with different methods (eye dome lighting,...
Qgis::ElevationMapCombineMethod combinedElevationMethod() const
Returns the method used when conbining different elevation sources.
bool isActive() const
Returns whether this shading renderer is active.
void renderShading(const QgsElevationMap &elevation, QImage &image, const QgsRenderContext &context) const
Render shading on image condidering the elevation map elevation and the renderer context context If e...
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 hasElevation() const
Returns true if the layer has an elevation or z component.
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 QgsElevationMap layerElevationToBeComposed(const QgsMapSettings &settings, const LayerRenderJob &job, const QgsMapRendererCache *cache)
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 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).
static const QgsSettingsEntryBool * settingsLogCanvasRefreshEvent
Settings entry log canvas refresh event.
QgsMapRendererJob(const QgsMapSettings &settings)
~QgsMapRendererJob() override
void start()
Start the rendering job and immediately return.
int renderingTime() const
Returns the total time it took to finish the job (in milliseconds).
QStringList mLayersRedrawnFromCache
QStringList layersRedrawnFromCache() const
Returns a list of the layer IDs for all layers which were redrawn from cached images.
QList< QgsMapRendererJob::Error > Errors
static const QString LABEL_CACHE_ID
QgsMapRendererCache ID string for cached label image.
static const QString ELEVATION_MAP_CACHE_PREFIX
QgsMapRendererCache prefix string for cached elevation map 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...
Qgis::MapSettingsFlags flags() const
Returns combination of flags used for rendering.
QgsRectangle visibleExtent() const
Returns the actual extent derived from requested extent that takes output image size into account.
const QgsElevationShadingRenderer & elevationShadingRenderer() const
Returns the shading renderer used to render shading on the entire 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.
Mask painter device that can be used to register everything painted into a QPainterPath used later as...
Represents a mesh layer supporting display of data on structured or unstructured meshes.
const QgsAbstractMeshLayerLabeling * labeling() const
Access to const labeling configuration.
bool labelsEnabled() const
Returns whether the layer contains labels which are enabled and should be drawn.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
static bool staticWillUseLayer(const QgsMapLayer *layer)
Called to find out whether a specified layer is used for labeling.
A class to represent a 2D point.
QString toString(int precision=-1) const
Returns a string representation of the point (x, y) with a preset precision.
Represents a raster layer.
QgsRasterRenderer * renderer() const
Returns the raster's renderer.
virtual Qgis::RasterRendererFlags flags() const
Returns flags which dictate renderer behavior.
A rectangle specified with double values.
QString toString(int precision=16) const
Returns a string representation of form xmin,ymin : xmax,ymax Coordinates will be truncated to the sp...
double xMinimum() const
Returns the x minimum value (left side of rectangle).
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
void setXMinimum(double x)
Set the minimum x value.
double width() const
Returns the width of the rectangle.
double xMaximum() const
Returns the x maximum value (right side of rectangle).
double yMaximum() const
Returns the y maximum value (top side of rectangle).
void setXMaximum(double x)
Set the maximum x value.
void grow(double delta)
Grows the rectangle in place by the specified amount.
double height() const
Returns the height of the rectangle.
bool isFinite() const
Returns true if the rectangle has finite boundaries.
Contains information about the context of a rendering operation.
void setPainterFlagsUsingContext(QPainter *painter=nullptr) const
Sets relevant flags on a destination painter, using the flags and settings currently defined for the ...
void setPainter(QPainter *p)
Sets the destination QPainter for the render operation.
static QgsRenderContext fromMapSettings(const QgsMapSettings &mapSettings)
create initialized QgsRenderContext instance from given QgsMapSettings
Qgis::RenderContextFlags flags() const
Returns combination of flags used for rendering.
Stores collated details of rendered items during a map rendering operation.
T value(const QString &dynamicKeyPart=QString()) const
Returns settings value.
A boolean settings entry.
static QgsSettingsTreeNode * sTreeMap
Type used to refer to a specific symbol layer in a symbol of a layer.
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.
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.
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)
#define QgsDebugError(str)
QHash< QString, QgsMaskedLayer > QgsMaskedLayers
masked layers where key is the layer id