19#include <QElapsedTimer>
21#include <QtConcurrentMap>
64LayerRenderJob &LayerRenderJob::operator=( LayerRenderJob &&other )
66 mContext = std::move( other.mContext );
71 renderer = other.renderer;
72 other.renderer =
nullptr;
74 previewRenderImage = other.previewRenderImage;
75 other.previewRenderImage =
nullptr;
77 imageInitialized = other.imageInitialized;
78 previewRenderImageInitialized = other.previewRenderImageInitialized;
80 blendMode = other.blendMode;
81 opacity = other.opacity;
82 cached = other.cached;
84 renderAboveLabels = other.renderAboveLabels;
85 completed = other.completed;
86 renderingTime = other.renderingTime;
87 estimatedRenderingTime = other.estimatedRenderingTime ;
88 errors = other.errors;
89 layerId = other.layerId;
91 maskPaintDevice = std::move( other.maskPaintDevice );
93 firstPassJob = other.firstPassJob;
94 other.firstPassJob =
nullptr;
96 picture = std::move( other.picture );
98 maskJobs = other.maskJobs;
100 maskRequiresLayerRasterization = other.maskRequiresLayerRasterization;
102 elevationMap = other.elevationMap;
103 maskPainter = std::move( other.maskPainter );
108LayerRenderJob::LayerRenderJob( LayerRenderJob &&other )
109 : imageInitialized( other.imageInitialized )
110 , previewRenderImageInitialized( other.previewRenderImageInitialized )
111 , blendMode( other.blendMode )
112 , opacity( other.opacity )
113 , cached( other.cached )
114 , renderAboveLabels( other.renderAboveLabels )
115 , layer( other.layer )
116 , completed( other.completed )
117 , renderingTime( other.renderingTime )
118 , estimatedRenderingTime( other.estimatedRenderingTime )
119 , errors( other.errors )
120 , layerId( other.layerId )
121 , maskPainter( nullptr )
122 , maskRequiresLayerRasterization( other.maskRequiresLayerRasterization )
123 , maskJobs( other.maskJobs )
125 mContext = std::move( other.mContext );
130 previewRenderImage = other.previewRenderImage;
131 other.previewRenderImage =
nullptr;
133 renderer = other.renderer;
134 other.renderer =
nullptr;
136 elevationMap = other.elevationMap;
137 other.elevationMap =
nullptr;
139 maskPaintDevice = std::move( other.maskPaintDevice );
141 firstPassJob = other.firstPassJob;
142 other.firstPassJob =
nullptr;
144 picture = std::move( other.picture );
147bool LayerRenderJob::imageCanBeComposed()
const
149 if ( imageInitialized )
153 return renderer->isReadyToCompose();
167 : mSettings( settings )
213 return mLabelingEngineFeedback;
218 QHash<QgsMapLayer *, int> result;
221 if (
auto &&lKey = it.key() )
222 result.insert( lKey, it.value() );
242 QSet< QgsMapLayer * > labeledLayers;
249 switch ( ml->type() )
297 bool canUseCache = canCache && QSet< QgsMapLayer * >( labelDependentLayers.begin(), labelDependentLayers.end() ) == labeledLayers;
326 static const double SPLIT_COORD = 180.0;
338 QgsDebugMsgLevel( QStringLiteral(
"\n0:%1 %2x%3\n1:%4\n2:%5 %6x%7 (w:%8 h:%9)" )
341 .arg( std::fabs( 1.0 - extent2.
width() / extent.
width() ) )
342 .arg( std::fabs( 1.0 - extent2.
height() / extent.
height() ) )
376 if ( ll.
x() > ur.
x() )
405 extent =
QgsRectangle( std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), std::numeric_limits<double>::max() );
415 extent =
QgsRectangle( std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), std::numeric_limits<double>::max() );
416 r2 =
QgsRectangle( std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), std::numeric_limits<double>::max() );
423QImage *QgsMapRendererJob::allocateImage( QString layerId )
430 if ( image->isNull() )
439QgsElevationMap *QgsMapRendererJob::allocateElevationMap( QString layerId )
442 if ( !elevationMap->isValid() )
447 return elevationMap.release();
450QPainter *QgsMapRendererJob::allocateImageAndPainter( QString layerId, QImage *&image,
const QgsRenderContext *context )
452 QPainter *painter =
nullptr;
453 image = allocateImage( layerId );
456 painter =
new QPainter( image );
462QgsMapRendererJob::PictureAndPainter QgsMapRendererJob::allocatePictureAndPainter(
const QgsRenderContext *context )
464 std::unique_ptr<QPicture> picture = std::make_unique<QPicture>();
465 QPainter *painter =
new QPainter( picture.get() );
467 return { std::move( picture ), painter };
472 std::vector< LayerRenderJob > layerJobs;
481 Q_UNUSED( cacheValid )
482 QgsDebugMsgLevel( QStringLiteral(
"CACHE VALID: %1" ).arg( cacheValid ), 4 );
487 while ( li.hasPrevious() )
491 QgsDebugMsgLevel( QStringLiteral(
"layer %1: minscale:%2 maxscale:%3 scaledepvis:%4 blendmode:%5 isValid:%6" )
508 QgsDebugMsgLevel( QStringLiteral(
"Layer not rendered because it is not within the defined visibility scale range" ), 3 );
514 QgsDebugMsgLevel( QStringLiteral(
"Layer not rendered because it is not visible within the map's time range" ), 3 );
520 QgsDebugMsgLevel( QStringLiteral(
"Layer not rendered because it is not visible within the map's z range" ), 3 );
529 bool haveExtentInLayerCrs =
true;
532 haveExtentInLayerCrs = reprojectToLayerExtent( ml, ct, r1, r2 );
537 mErrors.append( Error( ml->
id(), tr(
"There was a problem transforming the layer's extent. Layer skipped." ) ) );
548 if ( ( vl && vl->
isEditable() ) || requiresLabeling )
554 layerJobs.emplace_back( LayerRenderJob() );
555 LayerRenderJob &job = layerJobs.back();
557 job.layerId = ml->
id();
558 job.renderAboveLabels = ml->
customProperty( QStringLiteral(
"rendering/renderAboveLabels" ) ).toBool();
562 if ( !ml->
customProperty( QStringLiteral(
"_noset_layer_expression_context" ) ).toBool() )
564 job.context()->setPainter( painter );
565 job.context()->setLabelingEngine( labelingEngine2 );
566 job.context()->setLabelSink(
labelSink() );
567 job.context()->setCoordinateTransform( ct );
568 job.context()->setExtent( r1 );
574 if ( mFeatureFilterProvider )
575 job.context()->setFeatureFilterProvider( mFeatureFilterProvider );
608 job.imageInitialized =
true;
616 job.renderer =
nullptr;
617 job.context()->setPainter(
nullptr );
622 QElapsedTimer layerTime;
628 job.context()->setFeedback( job.renderer->feedback() );
634 if ( canUseCache || ( !painter && !deferredPainterSet ) || ( job.renderer && job.renderer->forceRasterRender() ) )
637 job.context()->setPainter( allocateImageAndPainter( ml->
id(), job.img, job.context() ) );
641 job.renderer =
nullptr;
642 layerJobs.pop_back();
651 job.elevationMap = allocateElevationMap( ml->
id() );
652 job.context()->setElevationMap( job.elevationMap );
660 if ( !cachedImage.isNull() )
662 job.previewRenderImage =
new QImage( cachedImage );
663 job.previewRenderImageInitialized =
true;
664 job.context()->setPreviewRenderPainter(
new QPainter( job.previewRenderImage ) );
665 job.context()->setPainterFlagsUsingContext( painter );
668 if ( !job.previewRenderImage )
670 job.context()->setPreviewRenderPainter( allocateImageAndPainter( ml->
id(), job.previewRenderImage, job.context() ) );
671 job.previewRenderImageInitialized =
false;
674 if ( !job.previewRenderImage )
676 delete job.context()->previewRenderPainter();
677 job.context()->setPreviewRenderPainter(
nullptr );
681 job.renderingTime = layerTime.elapsed();
689 const bool useGeometryBackend =
settingsMaskBackend->
value().compare( QLatin1String(
"geometry" ), Qt::CaseInsensitive ) == 0;
691 std::vector< LayerRenderJob > secondPassJobs;
694 QHash<QString, LayerRenderJob *> layerJobMapping;
697 QMap<QString, bool> maskLayerHasEffects;
698 QMap<int, bool> labelHasEffects;
706 MaskSource(
const QString &layerId_,
const QString &labelRuleId_,
int labelMaskId_,
bool hasEffects_ ):
707 layerId( layerId_ ), labelRuleId( labelRuleId_ ), labelMaskId( labelMaskId_ ), hasEffects( hasEffects_ ) {}
712 QHash<QString, QPair<QSet<QString>, QList<MaskSource>>> maskedSymbolLayers;
719 for ( LayerRenderJob &job : firstPassJobs )
721 layerJobMapping[job.layerId] = &job;
726 for ( LayerRenderJob &job : firstPassJobs )
733 auto collectMasks = [&](
QgsMaskedLayers * masks, QString sourceLayerId, QString ruleId = QString(),
int labelMaskId = -1 )
735 bool hasEffects =
false;
736 for (
auto it = masks->begin(); it != masks->end(); ++it )
738 auto lit = maskedSymbolLayers.find( it.key() );
739 if ( lit == maskedSymbolLayers.end() )
741 maskedSymbolLayers[it.key()] = qMakePair( it.value().symbolLayerIds, QList<MaskSource>() << MaskSource( sourceLayerId, ruleId, labelMaskId, it.value().hasEffects ) );
745 if ( lit->first != it.value().symbolLayerIds )
747 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() ) );
750 lit->second.push_back( MaskSource( sourceLayerId, ruleId, labelMaskId, hasEffects ) );
752 hasEffects |= it.value().hasEffects;
754 if ( ! masks->isEmpty() && labelMaskId == -1 )
755 maskLayerHasEffects[ sourceLayerId ] = hasEffects;
760 for (
auto it = labelMasks.begin(); it != labelMasks.end(); it++ )
762 QString labelRule = it.key();
768 for (
auto mit = masks.begin(); mit != masks.end(); mit++ )
770 const QString sourceLayerId = mit.key();
772 if ( !layerJobMapping.contains( sourceLayerId ) )
775 usableMasks.insert( sourceLayerId, mit.value() );
778 if ( usableMasks.empty() )
782 QSet<QgsSymbolLayerReference> slRefs;
783 bool hasEffects =
false;
784 for (
auto mit = usableMasks.begin(); mit != usableMasks.end(); mit++ )
786 const QString sourceLayerId = mit.key();
788 if ( !layerJobMapping.contains( sourceLayerId ) )
791 for (
const QString &symbolLayerId : mit.value().symbolLayerIds )
794 hasEffects |= mit.value().hasEffects;
797 int labelMaskId = labelJob.maskIdProvider.insertLabelLayer( vl->
id(), it.key(), slRefs );
798 labelHasEffects[ labelMaskId ] = hasEffects;
801 collectMasks( &usableMasks, vl->
id(), labelRule, labelMaskId );
806 collectMasks( &symbolLayerMasks, vl->
id() );
809 if ( maskedSymbolLayers.isEmpty() )
810 return secondPassJobs;
813 for (
int maskId = 0; maskId < labelJob.maskIdProvider.size(); maskId++ )
815 QPaintDevice *maskPaintDevice =
nullptr;
816 QPainter *maskPainter =
nullptr;
817 if ( forceVector && !labelHasEffects[ maskId ] )
820 if ( useGeometryBackend )
822 std::unique_ptr< QgsGeometryPaintDevice > geomPaintDevice = std::make_unique< QgsGeometryPaintDevice >(
true );
823 geomPaintDevice->setStrokedPathSegments( 4 );
824 geomPaintDevice->setSimplificationTolerance( labelJob.context.maskSettings().simplifyTolerance() );
825 maskPaintDevice = geomPaintDevice.release();
831 maskPainter =
new QPainter( maskPaintDevice );
836 QImage *maskImage =
nullptr;
837 maskPainter = allocateImageAndPainter( QStringLiteral(
"label mask" ), maskImage, &labelJob.context );
838 maskImage->fill( 0 );
839 maskPaintDevice = maskImage;
842 labelJob.context.setMaskPainter( maskPainter, maskId );
843 labelJob.maskPainters.push_back( std::unique_ptr<QPainter>( maskPainter ) );
844 labelJob.maskPaintDevices.push_back( std::unique_ptr<QPaintDevice>( maskPaintDevice ) );
846 labelJob.context.setMaskIdProvider( &labelJob.maskIdProvider );
857 if ( !labelJob.img && !forceVector )
859 labelJob.img = allocateImage( QStringLiteral(
"labels" ) );
861 else if ( !labelJob.picture && forceVector )
863 labelJob.picture.reset(
new QPicture() );
867 for ( LayerRenderJob &job : firstPassJobs )
869 job.maskRequiresLayerRasterization =
false;
871 auto it = maskedSymbolLayers.find( job.layerId );
872 if ( it != maskedSymbolLayers.end() )
874 const QList<MaskSource> &sourceList = it->second;
875 for (
const MaskSource &source : sourceList )
877 job.maskRequiresLayerRasterization |= source.hasEffects;
882 const bool isRasterRendering = !forceVector || job.maskRequiresLayerRasterization || ( job.renderer && job.renderer->forceRasterRender() );
883 if ( isRasterRendering && !job.img )
885 job.context()->setPainter( allocateImageAndPainter( job.layerId, job.img, job.context() ) );
887 else if ( !isRasterRendering && !job.picture )
889 PictureAndPainter pictureAndPainter = allocatePictureAndPainter( job.context() );
890 job.picture = std::move( pictureAndPainter.first );
891 job.context()->setPainter( pictureAndPainter.second );
894 job.renderer = job.layer->createMapRenderer( *( job.context() ) );
898 if ( maskLayerHasEffects.contains( job.layerId ) )
900 QPaintDevice *maskPaintDevice =
nullptr;
901 QPainter *maskPainter =
nullptr;
902 if ( forceVector && !maskLayerHasEffects[ job.layerId ] )
905 if ( useGeometryBackend )
907 std::unique_ptr< QgsGeometryPaintDevice > geomPaintDevice = std::make_unique< QgsGeometryPaintDevice >( );
908 geomPaintDevice->setStrokedPathSegments( 4 );
909 geomPaintDevice->setSimplificationTolerance( job.context()->maskSettings().simplifyTolerance() );
910 maskPaintDevice = geomPaintDevice.release();
917 maskPainter =
new QPainter( maskPaintDevice );
922 QImage *maskImage =
nullptr;
923 maskPainter = allocateImageAndPainter( job.layerId, maskImage, job.context() );
924 maskImage->fill( 0 );
925 maskPaintDevice = maskImage;
928 job.context()->setMaskPainter( maskPainter );
929 job.maskPainter.reset( maskPainter );
930 job.maskPaintDevice.reset( maskPaintDevice );
934 for ( LayerRenderJob &job : firstPassJobs )
938 auto it = maskedSymbolLayers.find( job.layerId );
939 if ( it == maskedSymbolLayers.end() )
942 QList<MaskSource> &sourceList = it->second;
943 const QSet<QString> symbolList = it->first;
945 secondPassJobs.emplace_back( LayerRenderJob() );
946 LayerRenderJob &job2 = secondPassJobs.back();
948 job2.maskRequiresLayerRasterization = job.maskRequiresLayerRasterization;
951 for ( MaskSource &source : sourceList )
953 if ( source.labelMaskId != -1 )
954 job2.maskJobs.push_back( qMakePair(
nullptr, source.labelMaskId ) );
956 job2.maskJobs.push_back( qMakePair( layerJobMapping[source.layerId], -1 ) );
960 job2.setContext( std::make_unique< QgsRenderContext >( *job.context() ) );
962 job2.layer = job.layer;
963 job2.renderAboveLabels = job.renderAboveLabels;
964 job2.layerId = job.layerId;
967 job2.firstPassJob = &job;
969 if ( !forceVector || job2.maskRequiresLayerRasterization )
971 job2.context()->setPainter( allocateImageAndPainter( job.layerId, job2.img, job2.context() ) );
975 PictureAndPainter pictureAndPainter = allocatePictureAndPainter( job2.context() );
976 job2.picture = std::move( pictureAndPainter.first );
977 job2.context()->setPainter( pictureAndPainter.second );
980 if ( ! job2.img && ! job2.picture )
982 secondPassJobs.pop_back();
989 job2.renderer = mapRenderer;
992 job2.context()->setFeedback( job2.renderer->feedback() );
997 job2.context()->setDisabledSymbolLayersV2( symbolList );
1000 return secondPassJobs;
1008 for ( LayerRenderJob &job : secondPassJobs )
1010 if ( job.maskRequiresLayerRasterization )
1016 for (
const QPair<LayerRenderJob *, int> &p : std::as_const( job.maskJobs ) )
1018 QPainter *maskPainter = p.first ? p.first->maskPainter.get() : labelJob.maskPainters[p.second].get();
1020 const QSet<QString> layers = job.context()->disabledSymbolLayersV2();
1023 QPainterPath path = maskDevice->maskPainterPath();
1024 for (
const QString &symbolLayerId : layers )
1026 job.context()->addSymbolLayerClipPath( symbolLayerId, path );
1031 QgsGeometry geometry( geometryDevice->geometry().clone() );
1033#if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<10
1040 for (
const QString &symbolLayerId : layers )
1042 job.context()->addSymbolLayerClipGeometry( symbolLayerId, geometry );
1047 job.context()->setDisabledSymbolLayersV2( QSet<QString>() );
1055 job.context.setPainter( painter );
1056 job.context.setLabelingEngine( labelingEngine2 );
1057 job.context.setFeedback( mLabelingEngineFeedback );
1061 job.context.setExtent( r1 );
1063 job.context.setFeatureFilterProvider( mFeatureFilterProvider );
1066 job.context.setCoordinateTransform( ct );
1077 job.complete =
true;
1080 job.context.setPainter(
nullptr );
1084 if ( canUseLabelCache && (
mCache || !painter ) )
1086 job.img = allocateImage( QStringLiteral(
"labels" ) );
1096 for ( LayerRenderJob &job : jobs )
1100 delete job.context()->painter();
1101 job.context()->setPainter(
nullptr );
1103 if (
mCache && !job.cached && job.completed && job.layer )
1105 QgsDebugMsgLevel( QStringLiteral(
"caching image for %1" ).arg( job.layerId ), 2 );
1114 if ( job.previewRenderImage )
1116 delete job.context()->previewRenderPainter();
1117 job.context()->setPreviewRenderPainter(
nullptr );
1118 delete job.previewRenderImage;
1119 job.previewRenderImage =
nullptr;
1122 if ( job.elevationMap )
1124 job.context()->setElevationMap(
nullptr );
1125 if (
mCache && !job.cached && job.completed && job.layer )
1127 QgsDebugMsgLevel( QStringLiteral(
"caching elevation map for %1" ).arg( job.layerId ), 2 );
1130 job.elevationMap->rawElevationImage(),
1133 QList< QgsMapLayer * >() << job.layer );
1136 job.elevationMap->rawElevationImage(),
1139 QList< QgsMapLayer * >() << job.layer );
1142 delete job.elevationMap;
1143 job.elevationMap =
nullptr;
1148 delete job.context()->painter();
1149 job.context()->setPainter(
nullptr );
1150 job.picture.reset(
nullptr );
1155 const QStringList
errors = job.renderer->errors();
1156 for (
const QString &message :
errors )
1157 mErrors.append( Error( job.renderer->layerId(), message ) );
1159 mRenderedItemResults->appendResults( job.renderer->takeRenderedItemDetails(), *job.context() );
1161 delete job.renderer;
1162 job.renderer =
nullptr;
1168 job.maskPainter.reset(
nullptr );
1169 job.maskPaintDevice.reset(
nullptr );
1177 for ( LayerRenderJob &job : jobs )
1181 delete job.context()->painter();
1182 job.context()->setPainter(
nullptr );
1188 if ( job.previewRenderImage )
1190 delete job.context()->previewRenderPainter();
1191 job.context()->setPreviewRenderPainter(
nullptr );
1192 delete job.previewRenderImage;
1193 job.previewRenderImage =
nullptr;
1198 delete job.context()->painter();
1199 job.context()->setPainter(
nullptr );
1204 delete job.renderer;
1205 job.renderer =
nullptr;
1219 if (
mCache && !job.cached && !job.context.renderingStopped() )
1230 job.picture.reset(
nullptr );
1231 job.maskPainters.clear();
1232 job.maskPaintDevices.clear();
1236#define DEBUG_RENDERING 0
1239 const std::vector<LayerRenderJob> &jobs,
1240 const LabelRenderJob &labelJob,
1246 image.setDotsPerMeterX(
static_cast<int>( settings.
outputDpi() * 39.37 ) );
1247 image.setDotsPerMeterY(
static_cast<int>( settings.
outputDpi() * 39.37 ) );
1251 std::unique_ptr<QgsElevationMap> mainElevationMap;
1252 if ( mapShadingRenderer.
isActive() )
1255 QPainter painter( &image );
1260 for (
const LayerRenderJob &job : jobs )
1262 if ( job.renderAboveLabels )
1269 painter.setCompositionMode( job.blendMode );
1270 painter.setOpacity( job.opacity );
1272 if ( mainElevationMap )
1275 if ( layerElevationMap.
isValid() )
1281 img.save( QString(
"/tmp/final_%1.png" ).arg( i ) );
1285 painter.drawImage( 0, 0, img );
1288 if ( mapShadingRenderer.
isActive() && mainElevationMap )
1296 if ( labelJob.img && labelJob.complete )
1298 painter.setCompositionMode( QPainter::CompositionMode_SourceOver );
1299 painter.setOpacity( 1.0 );
1300 painter.drawImage( 0, 0, *labelJob.img );
1308 painter.setCompositionMode( QPainter::CompositionMode_SourceOver );
1309 painter.setOpacity( 1.0 );
1310 painter.drawImage( 0, 0, labelCacheImage );
1314 for (
const LayerRenderJob &job : jobs )
1316 if ( !job.renderAboveLabels )
1323 painter.setCompositionMode( job.blendMode );
1324 painter.setOpacity( job.opacity );
1326 painter.drawImage( 0, 0, img );
1331 image.save(
"/tmp/final.png" );
1338 const LayerRenderJob &job,
1342 if ( job.imageCanBeComposed() )
1344 if ( job.previewRenderImage && !job.completed )
1345 return *job.previewRenderImage;
1347 Q_ASSERT( job.img );
1352 if ( cache && cache->
hasAnyCacheImage( job.layerId + QStringLiteral(
"_preview" ) ) )
1363 if ( job.imageCanBeComposed() && job.elevationMap )
1365 return *job.elevationMap;
1379 for ( LayerRenderJob &job : secondPassJobs )
1381 const bool isRasterRendering = !forceVector || job.maskRequiresLayerRasterization;
1384 if ( isRasterRendering && job.maskJobs.size() > 1 )
1386 QPainter *maskPainter =
nullptr;
1387 for ( QPair<LayerRenderJob *, int> p : job.maskJobs )
1389 QImage *maskImage =
static_cast<QImage *
>( p.first ? p.first->maskPaintDevice.get() : labelJob.maskPaintDevices[p.second].get() );
1392 maskPainter = p.first ? p.first->maskPainter.get() : labelJob.maskPainters[ p.second ].get();
1396 maskPainter->drawImage( 0, 0, *maskImage );
1401 if ( ! job.maskJobs.isEmpty() )
1404 QPair<LayerRenderJob *, int> p = *job.maskJobs.begin();
1405 if ( isRasterRendering )
1407 QImage *maskImage =
static_cast<QImage *
>( p.first ? p.first->maskPaintDevice.get() : labelJob.maskPaintDevices[p.second].get() );
1410 QPainter *painter = job.context()->painter();
1412 painter->setCompositionMode( QPainter::CompositionMode_DestinationIn );
1417 QImage maskBinAlpha = maskImage->createMaskFromColor( 0 );
1418 QVector<QRgb> mswTable;
1419 mswTable.push_back( qRgba( 0, 0, 0, 255 ) );
1420 mswTable.push_back( qRgba( 0, 0, 0, 0 ) );
1421 maskBinAlpha.setColorTable( mswTable );
1422 painter->drawImage( 0, 0, maskBinAlpha );
1426 QPainter tempPainter;
1429 QPainter *painter1 = job.firstPassJob->context()->painter();
1432 tempPainter.begin( job.firstPassJob->img );
1433 painter1 = &tempPainter;
1437 painter1->setCompositionMode( QPainter::CompositionMode_DestinationOut );
1438 painter1->drawImage( 0, 0, *maskImage );
1441 painter1->setCompositionMode( QPainter::CompositionMode_DestinationOver );
1442 painter1->drawImage( 0, 0, *job.img );
1447 job.firstPassJob->picture = std::move( job.picture );
1448 job.picture =
nullptr;
1459 QMultiMap<int, QString> elapsed;
1460 for (
const LayerRenderJob &job : jobs )
1462 for (
const LayerRenderJob &job : secondPassJobs )
1463 elapsed.insert( job.
renderingTime, job.layerId + QString(
" (second pass)" ) );
1465 elapsed.insert( labelJob.renderingTime, tr(
"Labeling" ) );
1467 QList<int> tt( elapsed.uniqueKeys() );
1468 std::sort( tt.begin(), tt.end(), std::greater<int>() );
1469 for (
int t : std::as_const( tt ) )
1471 QgsMessageLog::logMessage( tr(
"%1 ms: %2" ).arg( t ).arg( QStringList( elapsed.values( t ) ).join( QLatin1String(
", " ) ) ), tr(
"Rendering" ) );
1480 std::unique_ptr< QgsScopedRuntimeProfile > labelingProfile;
1483 labelingProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr(
"(labeling)" ), QStringLiteral(
"rendering" ) );
1490 painter->setCompositionMode( QPainter::CompositionMode_SourceOver );
1494 if ( labelingEngine2 )
1496 labelingEngine2->
run( renderContext );
1499 QgsDebugMsgLevel( QStringLiteral(
"Draw labeling took (seconds): %1" ).arg( t.elapsed() / 1000. ), 2 );
1504 Q_UNUSED( settings )
1506 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)
@ Linework
Combines all rings into a set of noded lines and then extracts valid polygons from that linework.
@ Structure
Structured method, first makes all rings valid and then merges shells and subtracts holes from shells...
@ 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.
A paint device which converts everything renderer to a QgsGeometry representation of the rendered sha...
A geometry is the spatial representation of a feature.
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, QgsMapLayer *layer=nullptr) const
Returns true if the layer should be visible and rendered for the specified z range.
virtual bool hasElevation() const
Returns true if the layer has an elevation or z component.
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
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).
static const QgsSettingsEntryString * settingsMaskBackend
Settings entry for mask painting backend engine.
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