19#include <QElapsedTimer>
21#include <QtConcurrentMap>
59LayerRenderJob &LayerRenderJob::operator=( LayerRenderJob &&other )
61 mContext = std::move( other.mContext );
66 renderer = other.renderer;
67 other.renderer =
nullptr;
69 previewRenderImage = other.previewRenderImage;
70 other.previewRenderImage =
nullptr;
72 imageInitialized = other.imageInitialized;
73 previewRenderImageInitialized = other.previewRenderImageInitialized;
75 blendMode = other.blendMode;
76 opacity = other.opacity;
77 cached = other.cached;
79 renderAboveLabels = other.renderAboveLabels;
80 completed = other.completed;
81 renderingTime = other.renderingTime;
82 estimatedRenderingTime = other.estimatedRenderingTime ;
83 errors = other.errors;
84 layerId = other.layerId;
86 maskPaintDevice = std::move( other.maskPaintDevice );
88 firstPassJob = other.firstPassJob;
89 other.firstPassJob =
nullptr;
91 picture = std::move( other.picture );
93 maskJobs = other.maskJobs;
95 maskRequiresLayerRasterization = other.maskRequiresLayerRasterization;
97 elevationMap = other.elevationMap;
98 maskPainter = std::move( other.maskPainter );
103LayerRenderJob::LayerRenderJob( LayerRenderJob &&other )
104 : imageInitialized( other.imageInitialized )
105 , previewRenderImageInitialized( other.previewRenderImageInitialized )
106 , blendMode( other.blendMode )
107 , opacity( other.opacity )
108 , cached( other.cached )
109 , renderAboveLabels( other.renderAboveLabels )
110 , layer( other.layer )
111 , completed( other.completed )
112 , renderingTime( other.renderingTime )
113 , estimatedRenderingTime( other.estimatedRenderingTime )
114 , errors( other.errors )
115 , layerId( other.layerId )
116 , maskPainter( nullptr )
117 , maskRequiresLayerRasterization( other.maskRequiresLayerRasterization )
118 , maskJobs( other.maskJobs )
120 mContext = std::move( other.mContext );
125 previewRenderImage = other.previewRenderImage;
126 other.previewRenderImage =
nullptr;
128 renderer = other.renderer;
129 other.renderer =
nullptr;
131 elevationMap = other.elevationMap;
132 other.elevationMap =
nullptr;
134 maskPaintDevice = std::move( other.maskPaintDevice );
136 firstPassJob = other.firstPassJob;
137 other.firstPassJob =
nullptr;
139 picture = std::move( other.picture );
142bool LayerRenderJob::imageCanBeComposed()
const
144 if ( imageInitialized )
148 return renderer->isReadyToCompose();
162 : mSettings( settings )
208 return mLabelingEngineFeedback;
213 QHash<QgsMapLayer *, int> result;
216 if (
auto &&lKey = it.key() )
217 result.insert( lKey, it.value() );
237 QSet< QgsMapLayer * > labeledLayers;
244 switch ( ml->type() )
283 bool canUseCache = canCache && QSet< QgsMapLayer * >( labelDependentLayers.begin(), labelDependentLayers.end() ) == labeledLayers;
312 static const double SPLIT_COORD = 180.0;
324 QgsDebugMsgLevel( QStringLiteral(
"\n0:%1 %2x%3\n1:%4\n2:%5 %6x%7 (w:%8 h:%9)" )
327 .arg( std::fabs( 1.0 - extent2.
width() / extent.
width() ) )
328 .arg( std::fabs( 1.0 - extent2.
height() / extent.
height() ) )
362 if ( ll.
x() > ur.
x() )
391 extent =
QgsRectangle( std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), std::numeric_limits<double>::max() );
401 extent =
QgsRectangle( std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), std::numeric_limits<double>::max() );
402 r2 =
QgsRectangle( std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), std::numeric_limits<double>::max() );
409QImage *QgsMapRendererJob::allocateImage( QString layerId )
416 if ( image->isNull() )
425QgsElevationMap *QgsMapRendererJob::allocateElevationMap( QString layerId )
428 if ( !elevationMap->isValid() )
433 return elevationMap.release();
436QPainter *QgsMapRendererJob::allocateImageAndPainter( QString layerId, QImage *&image,
const QgsRenderContext *context )
438 QPainter *painter =
nullptr;
439 image = allocateImage( layerId );
442 painter =
new QPainter( image );
448QgsMapRendererJob::PictureAndPainter QgsMapRendererJob::allocatePictureAndPainter(
const QgsRenderContext *context )
450 std::unique_ptr<QPicture> picture = std::make_unique<QPicture>();
451 QPainter *painter =
new QPainter( picture.get() );
453 return { std::move( picture ), painter };
458 std::vector< LayerRenderJob > layerJobs;
467 Q_UNUSED( cacheValid )
468 QgsDebugMsgLevel( QStringLiteral(
"CACHE VALID: %1" ).arg( cacheValid ), 4 );
473 while ( li.hasPrevious() )
477 QgsDebugMsgLevel( QStringLiteral(
"layer %1: minscale:%2 maxscale:%3 scaledepvis:%4 blendmode:%5 isValid:%6" )
494 QgsDebugMsgLevel( QStringLiteral(
"Layer not rendered because it is not within the defined visibility scale range" ), 3 );
500 QgsDebugMsgLevel( QStringLiteral(
"Layer not rendered because it is not visible within the map's time range" ), 3 );
506 QgsDebugMsgLevel( QStringLiteral(
"Layer not rendered because it is not visible within the map's z range" ), 3 );
515 bool haveExtentInLayerCrs =
true;
518 haveExtentInLayerCrs = reprojectToLayerExtent( ml, ct, r1, r2 );
523 mErrors.append( Error( ml->
id(), tr(
"There was a problem transforming the layer's extent. Layer skipped." ) ) );
534 if ( ( vl && vl->
isEditable() ) || requiresLabeling )
540 layerJobs.emplace_back( LayerRenderJob() );
541 LayerRenderJob &job = layerJobs.back();
543 job.layerId = ml->
id();
544 job.renderAboveLabels = ml->
customProperty( QStringLiteral(
"rendering/renderAboveLabels" ) ).toBool();
548 if ( !ml->
customProperty( QStringLiteral(
"_noset_layer_expression_context" ) ).toBool() )
550 job.context()->setPainter( painter );
551 job.context()->setLabelingEngine( labelingEngine2 );
552 job.context()->setLabelSink(
labelSink() );
553 job.context()->setCoordinateTransform( ct );
554 job.context()->setExtent( r1 );
560 if ( mFeatureFilterProvider )
561 job.context()->setFeatureFilterProvider( mFeatureFilterProvider );
594 job.imageInitialized =
true;
602 job.renderer =
nullptr;
603 job.context()->setPainter(
nullptr );
608 QElapsedTimer layerTime;
614 job.context()->setFeedback( job.renderer->feedback() );
620 if (
mCache || ( !painter && !deferredPainterSet ) || ( job.renderer && job.renderer->forceRasterRender() ) )
623 job.context()->setPainter( allocateImageAndPainter( ml->
id(), job.img, job.context() ) );
627 job.renderer =
nullptr;
628 layerJobs.pop_back();
637 job.elevationMap = allocateElevationMap( ml->
id() );
638 job.context()->setElevationMap( job.elevationMap );
646 if ( !cachedImage.isNull() )
648 job.previewRenderImage =
new QImage( cachedImage );
649 job.previewRenderImageInitialized =
true;
650 job.context()->setPreviewRenderPainter(
new QPainter( job.previewRenderImage ) );
651 job.context()->setPainterFlagsUsingContext( painter );
654 if ( !job.previewRenderImage )
656 job.context()->setPreviewRenderPainter( allocateImageAndPainter( ml->
id(), job.previewRenderImage, job.context() ) );
657 job.previewRenderImageInitialized =
false;
660 if ( !job.previewRenderImage )
662 delete job.context()->previewRenderPainter();
663 job.context()->setPreviewRenderPainter(
nullptr );
667 job.renderingTime = layerTime.elapsed();
675 std::vector< LayerRenderJob > secondPassJobs;
678 QHash<QString, LayerRenderJob *> layerJobMapping;
681 QMap<QString, bool> maskLayerHasEffects;
682 QMap<int, bool> labelHasEffects;
690 MaskSource(
const QString &layerId_,
const QString &labelRuleId_,
int labelMaskId_,
bool hasEffects_ ):
691 layerId( layerId_ ), labelRuleId( labelRuleId_ ), labelMaskId( labelMaskId_ ), hasEffects( hasEffects_ ) {}
696 QHash<QString, QPair<QSet<QString>, QList<MaskSource>>> maskedSymbolLayers;
703 for ( LayerRenderJob &job : firstPassJobs )
705 layerJobMapping[job.layerId] = &job;
710 for ( LayerRenderJob &job : firstPassJobs )
717 auto collectMasks = [&](
QgsMaskedLayers * masks, QString sourceLayerId, QString ruleId = QString(),
int labelMaskId = -1 )
719 bool hasEffects =
false;
720 for (
auto it = masks->begin(); it != masks->end(); ++it )
722 auto lit = maskedSymbolLayers.find( it.key() );
723 if ( lit == maskedSymbolLayers.end() )
725 maskedSymbolLayers[it.key()] = qMakePair( it.value().symbolLayerIds, QList<MaskSource>() << MaskSource( sourceLayerId, ruleId, labelMaskId, it.value().hasEffects ) );
729 if ( lit->first != it.value().symbolLayerIds )
731 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() ) );
734 lit->second.push_back( MaskSource( sourceLayerId, ruleId, labelMaskId, hasEffects ) );
736 hasEffects |= it.value().hasEffects;
738 if ( ! masks->isEmpty() && labelMaskId == -1 )
739 maskLayerHasEffects[ sourceLayerId ] = hasEffects;
744 for (
auto it = labelMasks.begin(); it != labelMasks.end(); it++ )
746 QString labelRule = it.key();
752 for (
auto mit = masks.begin(); mit != masks.end(); mit++ )
754 const QString sourceLayerId = mit.key();
756 if ( !layerJobMapping.contains( sourceLayerId ) )
759 usableMasks.insert( sourceLayerId, mit.value() );
762 if ( usableMasks.empty() )
766 QSet<QgsSymbolLayerReference> slRefs;
767 bool hasEffects =
false;
768 for (
auto mit = usableMasks.begin(); mit != usableMasks.end(); mit++ )
770 const QString sourceLayerId = mit.key();
772 if ( !layerJobMapping.contains( sourceLayerId ) )
775 for (
const QString &symbolLayerId : mit.value().symbolLayerIds )
778 hasEffects |= mit.value().hasEffects;
781 int labelMaskId = labelJob.maskIdProvider.insertLabelLayer( vl->
id(), it.key(), slRefs );
782 labelHasEffects[ labelMaskId ] = hasEffects;
785 collectMasks( &usableMasks, vl->
id(), labelRule, labelMaskId );
790 collectMasks( &symbolLayerMasks, vl->
id() );
793 if ( maskedSymbolLayers.isEmpty() )
794 return secondPassJobs;
797 for (
int maskId = 0; maskId < labelJob.maskIdProvider.size(); maskId++ )
799 QPaintDevice *maskPaintDevice =
nullptr;
800 QPainter *maskPainter =
nullptr;
801 if ( forceVector && !labelHasEffects[ maskId ] )
805 maskPainter =
new QPainter( maskPaintDevice );
810 QImage *maskImage =
nullptr;
811 maskPainter = allocateImageAndPainter( QStringLiteral(
"label mask" ), maskImage, &labelJob.context );
812 maskImage->fill( 0 );
813 maskPaintDevice = maskImage;
816 labelJob.context.setMaskPainter( maskPainter, maskId );
817 labelJob.maskPainters.push_back( std::unique_ptr<QPainter>( maskPainter ) );
818 labelJob.maskPaintDevices.push_back( std::unique_ptr<QPaintDevice>( maskPaintDevice ) );
820 labelJob.context.setMaskIdProvider( &labelJob.maskIdProvider );
831 if ( !labelJob.img && !forceVector )
833 labelJob.img = allocateImage( QStringLiteral(
"labels" ) );
835 else if ( !labelJob.picture && forceVector )
837 labelJob.picture.reset(
new QPicture() );
841 for ( LayerRenderJob &job : firstPassJobs )
843 job.maskRequiresLayerRasterization =
false;
845 auto it = maskedSymbolLayers.find( job.layerId );
846 if ( it != maskedSymbolLayers.end() )
848 const QList<MaskSource> &sourceList = it->second;
849 for (
const MaskSource &source : sourceList )
851 job.maskRequiresLayerRasterization |= source.hasEffects;
856 const bool isRasterRendering = !forceVector || job.maskRequiresLayerRasterization || ( job.renderer && job.renderer->forceRasterRender() );
857 if ( isRasterRendering && !job.img )
859 job.context()->setPainter( allocateImageAndPainter( job.layerId, job.img, job.context() ) );
861 else if ( !isRasterRendering && !job.picture )
863 PictureAndPainter pictureAndPainter = allocatePictureAndPainter( job.context() );
864 job.picture = std::move( pictureAndPainter.first );
865 job.context()->setPainter( pictureAndPainter.second );
868 job.renderer = job.layer->createMapRenderer( *( job.context() ) );
872 if ( maskLayerHasEffects.contains( job.layerId ) )
874 QPaintDevice *maskPaintDevice =
nullptr;
875 QPainter *maskPainter =
nullptr;
876 if ( forceVector && !maskLayerHasEffects[ job.layerId ] )
880 maskPainter =
new QPainter( maskPaintDevice );
885 QImage *maskImage =
nullptr;
886 maskPainter = allocateImageAndPainter( job.layerId, maskImage, job.context() );
887 maskImage->fill( 0 );
888 maskPaintDevice = maskImage;
891 job.context()->setMaskPainter( maskPainter );
892 job.maskPainter.reset( maskPainter );
893 job.maskPaintDevice.reset( maskPaintDevice );
897 for ( LayerRenderJob &job : firstPassJobs )
901 auto it = maskedSymbolLayers.find( job.layerId );
902 if ( it == maskedSymbolLayers.end() )
905 QList<MaskSource> &sourceList = it->second;
906 const QSet<QString> symbolList = it->first;
908 secondPassJobs.emplace_back( LayerRenderJob() );
909 LayerRenderJob &job2 = secondPassJobs.back();
911 job2.maskRequiresLayerRasterization = job.maskRequiresLayerRasterization;
914 for ( MaskSource &source : sourceList )
916 if ( source.labelMaskId != -1 )
917 job2.maskJobs.push_back( qMakePair(
nullptr, source.labelMaskId ) );
919 job2.maskJobs.push_back( qMakePair( layerJobMapping[source.layerId], -1 ) );
923 job2.setContext( std::make_unique< QgsRenderContext >( *job.context() ) );
925 job2.layer = job.layer;
926 job2.renderAboveLabels = job.renderAboveLabels;
927 job2.layerId = job.layerId;
930 job2.firstPassJob = &job;
932 if ( !forceVector || job2.maskRequiresLayerRasterization )
934 job2.context()->setPainter( allocateImageAndPainter( job.layerId, job2.img, job2.context() ) );
938 PictureAndPainter pictureAndPainter = allocatePictureAndPainter( job2.context() );
939 job2.picture = std::move( pictureAndPainter.first );
940 job2.context()->setPainter( pictureAndPainter.second );
943 if ( ! job2.img && ! job2.picture )
945 secondPassJobs.pop_back();
952 job2.renderer = mapRenderer;
955 job2.context()->setFeedback( job2.renderer->feedback() );
960 job2.context()->setDisabledSymbolLayersV2( symbolList );
963 return secondPassJobs;
971 for ( LayerRenderJob &job : secondPassJobs )
973 if ( job.maskRequiresLayerRasterization )
979 for (
const QPair<LayerRenderJob *, int> &p : std::as_const( job.maskJobs ) )
981 QPainter *maskPainter = p.first ? p.first->maskPainter.get() : labelJob.maskPainters[p.second].get();
982 QPainterPath path =
static_cast<QgsMaskPaintDevice *
>( maskPainter->device() )->maskPainterPath();
983 for (
const QString &symbolLayerId : job.context()->disabledSymbolLayersV2() )
985 job.context()->addSymbolLayerClipPath( symbolLayerId, path );
989 job.context()->setDisabledSymbolLayersV2( QSet<QString>() );
997 job.context.setPainter( painter );
998 job.context.setLabelingEngine( labelingEngine2 );
999 job.context.setFeedback( mLabelingEngineFeedback );
1003 job.context.setExtent( r1 );
1005 job.context.setFeatureFilterProvider( mFeatureFilterProvider );
1008 job.context.setCoordinateTransform( ct );
1019 job.complete =
true;
1022 job.context.setPainter(
nullptr );
1026 if ( canUseLabelCache && (
mCache || !painter ) )
1028 job.img = allocateImage( QStringLiteral(
"labels" ) );
1038 for ( LayerRenderJob &job : jobs )
1042 delete job.context()->painter();
1043 job.context()->setPainter(
nullptr );
1045 if (
mCache && !job.cached && job.completed && job.layer )
1047 QgsDebugMsgLevel( QStringLiteral(
"caching image for %1" ).arg( job.layerId ), 2 );
1056 if ( job.previewRenderImage )
1058 delete job.context()->previewRenderPainter();
1059 job.context()->setPreviewRenderPainter(
nullptr );
1060 delete job.previewRenderImage;
1061 job.previewRenderImage =
nullptr;
1064 if ( job.elevationMap )
1066 job.context()->setElevationMap(
nullptr );
1067 if (
mCache && !job.cached && job.completed && job.layer )
1069 QgsDebugMsgLevel( QStringLiteral(
"caching elevation map for %1" ).arg( job.layerId ), 2 );
1072 job.elevationMap->rawElevationImage(),
1075 QList< QgsMapLayer * >() << job.layer );
1078 job.elevationMap->rawElevationImage(),
1081 QList< QgsMapLayer * >() << job.layer );
1084 delete job.elevationMap;
1085 job.elevationMap =
nullptr;
1090 delete job.context()->painter();
1091 job.context()->setPainter(
nullptr );
1092 job.picture.reset(
nullptr );
1097 const QStringList
errors = job.renderer->errors();
1098 for (
const QString &message :
errors )
1099 mErrors.append( Error( job.renderer->layerId(), message ) );
1101 mRenderedItemResults->appendResults( job.renderer->takeRenderedItemDetails(), *job.context() );
1103 delete job.renderer;
1104 job.renderer =
nullptr;
1110 job.maskPainter.reset(
nullptr );
1111 job.maskPaintDevice.reset(
nullptr );
1119 for ( LayerRenderJob &job : jobs )
1123 delete job.context()->painter();
1124 job.context()->setPainter(
nullptr );
1130 if ( job.previewRenderImage )
1132 delete job.context()->previewRenderPainter();
1133 job.context()->setPreviewRenderPainter(
nullptr );
1134 delete job.previewRenderImage;
1135 job.previewRenderImage =
nullptr;
1140 delete job.context()->painter();
1141 job.context()->setPainter(
nullptr );
1146 delete job.renderer;
1147 job.renderer =
nullptr;
1161 if (
mCache && !job.cached && !job.context.renderingStopped() )
1172 job.picture.reset(
nullptr );
1173 job.maskPainters.clear();
1174 job.maskPaintDevices.clear();
1178#define DEBUG_RENDERING 0
1181 const std::vector<LayerRenderJob> &jobs,
1182 const LabelRenderJob &labelJob,
1188 image.setDotsPerMeterX(
static_cast<int>( settings.
outputDpi() * 39.37 ) );
1189 image.setDotsPerMeterY(
static_cast<int>( settings.
outputDpi() * 39.37 ) );
1193 std::unique_ptr<QgsElevationMap> mainElevationMap;
1194 if ( mapShadingRenderer.
isActive() )
1197 QPainter painter( &image );
1202 for (
const LayerRenderJob &job : jobs )
1204 if ( job.renderAboveLabels )
1211 painter.setCompositionMode( job.blendMode );
1212 painter.setOpacity( job.opacity );
1214 if ( mainElevationMap )
1217 if ( layerElevationMap.
isValid() )
1223 img.save( QString(
"/tmp/final_%1.png" ).arg( i ) );
1227 painter.drawImage( 0, 0, img );
1230 if ( mapShadingRenderer.
isActive() && mainElevationMap )
1238 if ( labelJob.img && labelJob.complete )
1240 painter.setCompositionMode( QPainter::CompositionMode_SourceOver );
1241 painter.setOpacity( 1.0 );
1242 painter.drawImage( 0, 0, *labelJob.img );
1250 painter.setCompositionMode( QPainter::CompositionMode_SourceOver );
1251 painter.setOpacity( 1.0 );
1252 painter.drawImage( 0, 0, labelCacheImage );
1256 for (
const LayerRenderJob &job : jobs )
1258 if ( !job.renderAboveLabels )
1265 painter.setCompositionMode( job.blendMode );
1266 painter.setOpacity( job.opacity );
1268 painter.drawImage( 0, 0, img );
1273 image.save(
"/tmp/final.png" );
1280 const LayerRenderJob &job,
1284 if ( job.imageCanBeComposed() )
1286 if ( job.previewRenderImage && !job.completed )
1287 return *job.previewRenderImage;
1289 Q_ASSERT( job.img );
1294 if ( cache && cache->
hasAnyCacheImage( job.layerId + QStringLiteral(
"_preview" ) ) )
1305 if ( job.imageCanBeComposed() && job.elevationMap )
1307 return *job.elevationMap;
1321 for ( LayerRenderJob &job : secondPassJobs )
1323 const bool isRasterRendering = !forceVector || job.maskRequiresLayerRasterization;
1326 if ( isRasterRendering && job.maskJobs.size() > 1 )
1328 QPainter *maskPainter =
nullptr;
1329 for ( QPair<LayerRenderJob *, int> p : job.maskJobs )
1331 QImage *maskImage =
static_cast<QImage *
>( p.first ? p.first->maskPaintDevice.get() : labelJob.maskPaintDevices[p.second].get() );
1334 maskPainter = p.first ? p.first->maskPainter.get() : labelJob.maskPainters[ p.second ].get();
1338 maskPainter->drawImage( 0, 0, *maskImage );
1343 if ( ! job.maskJobs.isEmpty() )
1346 QPair<LayerRenderJob *, int> p = *job.maskJobs.begin();
1347 if ( isRasterRendering )
1349 QImage *maskImage =
static_cast<QImage *
>( p.first ? p.first->maskPaintDevice.get() : labelJob.maskPaintDevices[p.second].get() );
1352 QPainter *painter = job.context()->painter();
1354 painter->setCompositionMode( QPainter::CompositionMode_DestinationIn );
1359 QImage maskBinAlpha = maskImage->createMaskFromColor( 0 );
1360 QVector<QRgb> mswTable;
1361 mswTable.push_back( qRgba( 0, 0, 0, 255 ) );
1362 mswTable.push_back( qRgba( 0, 0, 0, 0 ) );
1363 maskBinAlpha.setColorTable( mswTable );
1364 painter->drawImage( 0, 0, maskBinAlpha );
1368 QPainter tempPainter;
1371 QPainter *painter1 = job.firstPassJob->context()->painter();
1374 tempPainter.begin( job.firstPassJob->img );
1375 painter1 = &tempPainter;
1379 painter1->setCompositionMode( QPainter::CompositionMode_DestinationOut );
1380 painter1->drawImage( 0, 0, *maskImage );
1383 painter1->setCompositionMode( QPainter::CompositionMode_DestinationOver );
1384 painter1->drawImage( 0, 0, *job.img );
1389 job.firstPassJob->picture = std::move( job.picture );
1390 job.picture =
nullptr;
1401 QMultiMap<int, QString> elapsed;
1402 for (
const LayerRenderJob &job : jobs )
1404 for (
const LayerRenderJob &job : secondPassJobs )
1405 elapsed.insert( job.
renderingTime, job.layerId + QString(
" (second pass)" ) );
1407 elapsed.insert( labelJob.renderingTime, tr(
"Labeling" ) );
1409 QList<int> tt( elapsed.uniqueKeys() );
1410 std::sort( tt.begin(), tt.end(), std::greater<int>() );
1411 for (
int t : std::as_const( tt ) )
1413 QgsMessageLog::logMessage( tr(
"%1 ms: %2" ).arg( t ).arg( QStringList( elapsed.values( t ) ).join( QLatin1String(
", " ) ) ), tr(
"Rendering" ) );
1422 std::unique_ptr< QgsScopedRuntimeProfile > labelingProfile;
1425 labelingProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr(
"(labeling)" ), QStringLiteral(
"rendering" ) );
1432 painter->setCompositionMode( QPainter::CompositionMode_SourceOver );
1436 if ( labelingEngine2 )
1438 labelingEngine2->
run( renderContext );
1441 QgsDebugMsgLevel( QStringLiteral(
"Draw labeling took (seconds): %1" ).arg( t.elapsed() / 1000. ), 2 );
1446 Q_UNUSED( settings )
1448 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 ...
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...
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