17#include "moc_qgsmaprendererjob.cpp"
20#include <QElapsedTimer>
22#include <QtConcurrentMap>
66LayerRenderJob &LayerRenderJob::operator=( LayerRenderJob &&other )
68 mContext = std::move( other.mContext );
73 renderer = other.renderer;
74 other.renderer =
nullptr;
76 previewRenderImage = other.previewRenderImage;
77 other.previewRenderImage =
nullptr;
79 imageInitialized = other.imageInitialized;
80 previewRenderImageInitialized = other.previewRenderImageInitialized;
82 blendMode = other.blendMode;
83 opacity = other.opacity;
84 cached = other.cached;
86 renderAboveLabels = other.renderAboveLabels;
87 completed = other.completed;
88 renderingTime = other.renderingTime;
89 estimatedRenderingTime = other.estimatedRenderingTime ;
90 errors = other.errors;
91 layerId = other.layerId;
93 maskPaintDevice = std::move( other.maskPaintDevice );
95 firstPassJob = other.firstPassJob;
96 other.firstPassJob =
nullptr;
98 picture = std::move( other.picture );
100 maskJobs = other.maskJobs;
102 maskRequiresLayerRasterization = other.maskRequiresLayerRasterization;
104 elevationMap = other.elevationMap;
105 maskPainter = std::move( other.maskPainter );
110LayerRenderJob::LayerRenderJob( LayerRenderJob &&other )
111 : imageInitialized( other.imageInitialized )
112 , previewRenderImageInitialized( other.previewRenderImageInitialized )
113 , blendMode( other.blendMode )
114 , opacity( other.opacity )
115 , cached( other.cached )
116 , renderAboveLabels( other.renderAboveLabels )
117 , layer( other.layer )
118 , completed( other.completed )
119 , renderingTime( other.renderingTime )
120 , estimatedRenderingTime( other.estimatedRenderingTime )
121 , errors( other.errors )
122 , layerId( other.layerId )
123 , maskPainter( nullptr )
124 , maskRequiresLayerRasterization( other.maskRequiresLayerRasterization )
125 , maskJobs( other.maskJobs )
127 mContext = std::move( other.mContext );
132 previewRenderImage = other.previewRenderImage;
133 other.previewRenderImage =
nullptr;
135 renderer = other.renderer;
136 other.renderer =
nullptr;
138 elevationMap = other.elevationMap;
139 other.elevationMap =
nullptr;
141 maskPaintDevice = std::move( other.maskPaintDevice );
143 firstPassJob = other.firstPassJob;
144 other.firstPassJob =
nullptr;
146 picture = std::move( other.picture );
149bool LayerRenderJob::imageCanBeComposed()
const
151 if ( imageInitialized )
155 return renderer->isReadyToCompose();
169 : mSettings( settings )
215 return mLabelingEngineFeedback;
220 QHash<QgsMapLayer *, int> result;
223 if (
auto &&lKey = it.key() )
224 result.insert( lKey, it.value() );
244 QSet< QgsMapLayer * > labeledLayers;
251 switch ( ml->type() )
308 bool canUseCache = canCache && QSet< QgsMapLayer * >( labelDependentLayers.begin(), labelDependentLayers.end() ) == labeledLayers;
326 switch ( ml->type() )
394 static const double SPLIT_COORD = 180.0;
406 QgsDebugMsgLevel( QStringLiteral(
"\n0:%1 %2x%3\n1:%4\n2:%5 %6x%7 (w:%8 h:%9)" )
409 .arg( std::fabs( 1.0 - extent2.
width() / extent.
width() ) )
410 .arg( std::fabs( 1.0 - extent2.
height() / extent.
height() ) )
444 if ( ll.
x() > ur.
x() )
473 extent =
QgsRectangle( std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), std::numeric_limits<double>::max() );
483 extent =
QgsRectangle( std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), std::numeric_limits<double>::max() );
484 r2 =
QgsRectangle( std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), std::numeric_limits<double>::max() );
491QImage *QgsMapRendererJob::allocateImage( QString layerId )
498 if ( image->isNull() )
507QgsElevationMap *QgsMapRendererJob::allocateElevationMap( QString layerId )
510 if ( !elevationMap->isValid() )
515 return elevationMap.release();
518QPainter *QgsMapRendererJob::allocateImageAndPainter( QString layerId, QImage *&image,
const QgsRenderContext *context )
520 QPainter *painter =
nullptr;
521 image = allocateImage( layerId );
524 painter =
new QPainter( image );
530QgsMapRendererJob::PictureAndPainter QgsMapRendererJob::allocatePictureAndPainter(
const QgsRenderContext *context )
532 auto picture = std::make_unique<QPicture>();
533 QPainter *painter =
new QPainter( picture.get() );
535 return { std::move( picture ), painter };
540 std::vector< LayerRenderJob > layerJobs;
549 Q_UNUSED( cacheValid )
550 QgsDebugMsgLevel( QStringLiteral(
"CACHE VALID: %1" ).arg( cacheValid ), 4 );
555 while ( li.hasPrevious() )
559 QgsDebugMsgLevel( QStringLiteral(
"layer %1: minscale:%2 maxscale:%3 scaledepvis:%4 blendmode:%5 isValid:%6" )
576 QgsDebugMsgLevel( QStringLiteral(
"Layer not rendered because it is not within the defined visibility scale range" ), 3 );
582 QgsDebugMsgLevel( QStringLiteral(
"Layer not rendered because it is not visible within the map's time range" ), 3 );
588 QgsDebugMsgLevel( QStringLiteral(
"Layer not rendered because it is not visible within the map's z range" ), 3 );
597 bool haveExtentInLayerCrs =
true;
600 haveExtentInLayerCrs = reprojectToLayerExtent( ml, ct, r1, r2 );
605 mErrors.append( Error( ml->
id(), tr(
"There was a problem transforming the layer's extent. Layer skipped." ) ) );
616 if ( ( vl && vl->
isEditable() ) || requiresLabeling )
622 layerJobs.emplace_back( LayerRenderJob() );
623 LayerRenderJob &job = layerJobs.back();
625 job.layerId = ml->
id();
626 job.renderAboveLabels = ml->
customProperty( QStringLiteral(
"rendering/renderAboveLabels" ) ).toBool();
630 if ( !ml->
customProperty( QStringLiteral(
"_noset_layer_expression_context" ) ).toBool() )
632 job.context()->setPainter( painter );
633 job.context()->setLabelingEngine( labelingEngine2 );
634 job.context()->setLabelSink(
labelSink() );
635 job.context()->setCoordinateTransform( ct );
636 job.context()->setExtent( r1 );
642 if ( mFeatureFilterProvider )
643 job.context()->setFeatureFilterProvider( mFeatureFilterProvider );
677 job.imageInitialized =
true;
685 job.renderer =
nullptr;
686 job.context()->setPainter(
nullptr );
691 QElapsedTimer layerTime;
697 job.context()->setFeedback( job.renderer->feedback() );
708 if ( canUseCache || ( !painter && !deferredPainterSet ) || ( job.renderer && job.renderer->forceRasterRender() ) )
711 job.context()->setPainter( allocateImageAndPainter( ml->
id(), job.img, job.context() ) );
715 job.renderer =
nullptr;
716 layerJobs.pop_back();
725 job.elevationMap = allocateElevationMap( ml->
id() );
726 job.context()->setElevationMap( job.elevationMap );
734 if ( !cachedImage.isNull() )
736 job.previewRenderImage =
new QImage( cachedImage );
737 job.previewRenderImageInitialized =
true;
738 job.context()->setPreviewRenderPainter(
new QPainter( job.previewRenderImage ) );
739 job.context()->setPainterFlagsUsingContext( painter );
742 if ( !job.previewRenderImage )
744 job.context()->setPreviewRenderPainter( allocateImageAndPainter( ml->
id(), job.previewRenderImage, job.context() ) );
745 job.previewRenderImageInitialized =
false;
748 if ( !job.previewRenderImage )
750 delete job.context()->previewRenderPainter();
751 job.context()->setPreviewRenderPainter(
nullptr );
755 job.renderingTime = layerTime.elapsed();
763 std::vector< LayerRenderJob > secondPassJobs;
766 QHash<QString, LayerRenderJob *> layerJobMapping;
769 QMap<QString, bool> maskLayerHasEffects;
770 QMap<int, bool> labelHasEffects;
778 MaskSource(
const QString &layerId_,
const QString &labelRuleId_,
int labelMaskId_,
bool hasEffects_ ):
779 layerId( layerId_ ), labelRuleId( labelRuleId_ ), labelMaskId( labelMaskId_ ), hasEffects( hasEffects_ ) {}
784 QHash<QString, QPair<QSet<QString>, QList<MaskSource>>> maskedSymbolLayers;
791 for ( LayerRenderJob &job : firstPassJobs )
793 layerJobMapping[job.layerId] = &job;
798 for ( LayerRenderJob &job : firstPassJobs )
805 auto collectMasks = [&](
QgsMaskedLayers * masks, QString sourceLayerId, QString ruleId = QString(),
int labelMaskId = -1 )
807 bool hasEffects =
false;
808 for (
auto it = masks->begin(); it != masks->end(); ++it )
810 auto lit = maskedSymbolLayers.find( it.key() );
811 if ( lit == maskedSymbolLayers.end() )
813 maskedSymbolLayers[it.key()] = qMakePair( it.value().symbolLayerIds, QList<MaskSource>() << MaskSource( sourceLayerId, ruleId, labelMaskId, it.value().hasEffects ) );
817 if ( lit->first != it.value().symbolLayerIds )
819 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() ) );
822 lit->second.push_back( MaskSource( sourceLayerId, ruleId, labelMaskId, hasEffects ) );
824 hasEffects |= it.value().hasEffects;
826 if ( ! masks->isEmpty() && labelMaskId == -1 )
827 maskLayerHasEffects[ sourceLayerId ] = hasEffects;
832 for (
auto it = labelMasks.begin(); it != labelMasks.end(); it++ )
834 QString labelRule = it.key();
840 for (
auto mit = masks.begin(); mit != masks.end(); mit++ )
842 const QString sourceLayerId = mit.key();
844 if ( !layerJobMapping.contains( sourceLayerId ) )
847 usableMasks.insert( sourceLayerId, mit.value() );
850 if ( usableMasks.empty() )
854 QSet<QgsSymbolLayerReference> slRefs;
855 bool hasEffects =
false;
856 for (
auto mit = usableMasks.begin(); mit != usableMasks.end(); mit++ )
858 const QString sourceLayerId = mit.key();
860 if ( !layerJobMapping.contains( sourceLayerId ) )
863 for (
const QString &symbolLayerId : mit.value().symbolLayerIds )
866 hasEffects |= mit.value().hasEffects;
869 int labelMaskId = labelJob.maskIdProvider.insertLabelLayer( vl->
id(), it.key(), slRefs );
870 labelHasEffects[ labelMaskId ] = hasEffects;
873 collectMasks( &usableMasks, vl->
id(), labelRule, labelMaskId );
878 collectMasks( &symbolLayerMasks, vl->
id() );
881 if ( maskedSymbolLayers.isEmpty() )
882 return secondPassJobs;
885 for (
int maskId = 0; maskId < labelJob.maskIdProvider.size(); maskId++ )
887 QPaintDevice *maskPaintDevice =
nullptr;
888 QPainter *maskPainter =
nullptr;
889 if ( forceVector && !labelHasEffects[ maskId ] )
892 auto geomPaintDevice = std::make_unique< QgsGeometryPaintDevice >(
true );
893 geomPaintDevice->setStrokedPathSegments( 4 );
894 geomPaintDevice->setSimplificationTolerance( labelJob.context.maskSettings().simplifyTolerance() );
895 maskPaintDevice = geomPaintDevice.release();
896 maskPainter =
new QPainter( maskPaintDevice );
901 QImage *maskImage =
nullptr;
902 maskPainter = allocateImageAndPainter( QStringLiteral(
"label mask" ), maskImage, &labelJob.context );
903 maskImage->fill( 0 );
904 maskPaintDevice = maskImage;
907 labelJob.context.setMaskPainter( maskPainter, maskId );
908 labelJob.maskPainters.push_back( std::unique_ptr<QPainter>( maskPainter ) );
909 labelJob.maskPaintDevices.push_back( std::unique_ptr<QPaintDevice>( maskPaintDevice ) );
911 labelJob.context.setMaskIdProvider( &labelJob.maskIdProvider );
926 const bool canUseImage = !forceVector && !hasNonDefaultComposition;
927 if ( !labelJob.img && canUseImage )
929 labelJob.img = allocateImage( QStringLiteral(
"labels" ) );
931 else if ( !labelJob.picture && !canUseImage )
933 labelJob.picture.reset(
new QPicture() );
937 for ( LayerRenderJob &job : firstPassJobs )
939 job.maskRequiresLayerRasterization =
false;
941 auto it = maskedSymbolLayers.find( job.layerId );
942 if ( it != maskedSymbolLayers.end() )
944 const QList<MaskSource> &sourceList = it->second;
945 for (
const MaskSource &source : sourceList )
947 job.maskRequiresLayerRasterization |= source.hasEffects;
952 const bool isRasterRendering = !forceVector || job.maskRequiresLayerRasterization || ( job.renderer && job.renderer->forceRasterRender() );
953 if ( isRasterRendering && !job.img )
955 job.context()->setPainter( allocateImageAndPainter( job.layerId, job.img, job.context() ) );
957 else if ( !isRasterRendering && !job.picture )
959 PictureAndPainter pictureAndPainter = allocatePictureAndPainter( job.context() );
960 job.picture = std::move( pictureAndPainter.first );
961 if ( job.context()->painter()->hasClipping() )
964 pictureAndPainter.second->setClipping(
true );
965 pictureAndPainter.second->setClipPath( job.context()->painter()->clipPath() );
967 job.context()->setPainter( pictureAndPainter.second );
970 job.renderer = job.layer->createMapRenderer( *( job.context() ) );
974 if ( maskLayerHasEffects.contains( job.layerId ) )
976 QPaintDevice *maskPaintDevice =
nullptr;
977 QPainter *maskPainter =
nullptr;
978 if ( forceVector && !maskLayerHasEffects[ job.layerId ] )
981 auto geomPaintDevice = std::make_unique< QgsGeometryPaintDevice >( );
982 geomPaintDevice->setStrokedPathSegments( 4 );
983 geomPaintDevice->setSimplificationTolerance( job.context()->maskSettings().simplifyTolerance() );
984 maskPaintDevice = geomPaintDevice.release();
985 maskPainter =
new QPainter( maskPaintDevice );
990 QImage *maskImage =
nullptr;
991 maskPainter = allocateImageAndPainter( job.layerId, maskImage, job.context() );
992 maskImage->fill( 0 );
993 maskPaintDevice = maskImage;
996 job.context()->setMaskPainter( maskPainter );
997 job.maskPainter.reset( maskPainter );
998 job.maskPaintDevice.reset( maskPaintDevice );
1002 for ( LayerRenderJob &job : firstPassJobs )
1006 auto it = maskedSymbolLayers.find( job.layerId );
1007 if ( it == maskedSymbolLayers.end() )
1010 QList<MaskSource> &sourceList = it->second;
1011 const QSet<QString> symbolList = it->first;
1013 secondPassJobs.emplace_back( LayerRenderJob() );
1014 LayerRenderJob &job2 = secondPassJobs.back();
1016 job2.maskRequiresLayerRasterization = job.maskRequiresLayerRasterization;
1019 for ( MaskSource &source : sourceList )
1021 if ( source.labelMaskId != -1 )
1022 job2.maskJobs.push_back( qMakePair(
nullptr, source.labelMaskId ) );
1024 job2.maskJobs.push_back( qMakePair( layerJobMapping[source.layerId], -1 ) );
1028 job2.setContext( std::make_unique< QgsRenderContext >( *job.context() ) );
1030 job2.layer = job.layer;
1031 job2.renderAboveLabels = job.renderAboveLabels;
1032 job2.layerId = job.layerId;
1035 job2.firstPassJob = &job;
1037 if ( !forceVector || job2.maskRequiresLayerRasterization )
1039 job2.context()->setPainter( allocateImageAndPainter( job.layerId, job2.img, job2.context() ) );
1043 PictureAndPainter pictureAndPainter = allocatePictureAndPainter( job2.context() );
1044 if ( job.context()->painter()->hasClipping() )
1047 pictureAndPainter.second->setClipping(
true );
1048 pictureAndPainter.second->setClipPath( job.context()->painter()->clipPath() );
1050 job2.picture = std::move( pictureAndPainter.first );
1051 job2.context()->setPainter( pictureAndPainter.second );
1054 if ( ! job2.img && ! job2.picture )
1056 secondPassJobs.pop_back();
1063 job2.renderer = mapRenderer;
1064 if ( job2.renderer )
1066 job2.context()->setFeedback( job2.renderer->feedback() );
1071 job2.context()->setDisabledSymbolLayersV2( symbolList );
1074 return secondPassJobs;
1079 QList<QPointer<QgsMapLayer> > res = _qgis_listRawToQPointer( engine->
participatingLayers() );
1083 if ( !res.contains( it ) )
1095 for ( LayerRenderJob &job : secondPassJobs )
1097 if ( job.maskRequiresLayerRasterization )
1103 for (
const QPair<LayerRenderJob *, int> &p : std::as_const( job.maskJobs ) )
1105 QPainter *maskPainter = p.first ? p.first->maskPainter.get() : labelJob.maskPainters[p.second].get();
1107 const QSet<QString> layers = job.context()->disabledSymbolLayersV2();
1110 QgsGeometry geometry( geometryDevice->geometry().clone() );
1112#if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<10
1119 for (
const QString &symbolLayerId : layers )
1121 job.context()->addSymbolLayerClipGeometry( symbolLayerId, geometry );
1126 job.context()->setDisabledSymbolLayersV2( QSet<QString>() );
1134 job.context.setPainter( painter );
1135 job.context.setLabelingEngine( labelingEngine2 );
1136 job.context.setFeedback( mLabelingEngineFeedback );
1137 if ( labelingEngine2 )
1138 job.context.labelingEngine()->prepare( job.context );
1142 job.context.setExtent( r1 );
1144 job.context.setFeatureFilterProvider( mFeatureFilterProvider );
1147 job.context.setCoordinateTransform( ct );
1158 job.complete =
true;
1161 job.context.setPainter(
nullptr );
1165 if ( canUseLabelCache && (
mCache || !painter ) )
1167 job.img = allocateImage( QStringLiteral(
"labels" ) );
1177 for ( LayerRenderJob &job : jobs )
1181 delete job.context()->painter();
1182 job.context()->setPainter(
nullptr );
1184 if (
mCache && !job.cached && job.completed && job.layer )
1186 QgsDebugMsgLevel( QStringLiteral(
"caching image for %1" ).arg( job.layerId ), 2 );
1195 if ( job.previewRenderImage )
1197 delete job.context()->previewRenderPainter();
1198 job.context()->setPreviewRenderPainter(
nullptr );
1199 delete job.previewRenderImage;
1200 job.previewRenderImage =
nullptr;
1203 if ( job.elevationMap )
1205 job.context()->setElevationMap(
nullptr );
1206 if (
mCache && !job.cached && job.completed && job.layer )
1208 QgsDebugMsgLevel( QStringLiteral(
"caching elevation map for %1" ).arg( job.layerId ), 2 );
1211 job.elevationMap->rawElevationImage(),
1214 QList< QgsMapLayer * >() << job.layer );
1217 job.elevationMap->rawElevationImage(),
1220 QList< QgsMapLayer * >() << job.layer );
1223 delete job.elevationMap;
1224 job.elevationMap =
nullptr;
1229 delete job.context()->painter();
1230 job.context()->setPainter(
nullptr );
1231 job.picture.reset(
nullptr );
1236 const QStringList
errors = job.renderer->errors();
1237 for (
const QString &message :
errors )
1238 mErrors.append( Error( job.renderer->layerId(), message ) );
1240 mRenderedItemResults->appendResults( job.renderer->takeRenderedItemDetails(), *job.context() );
1242 delete job.renderer;
1243 job.renderer =
nullptr;
1249 job.maskPainter.reset(
nullptr );
1250 job.maskPaintDevice.reset(
nullptr );
1258 for ( LayerRenderJob &job : jobs )
1262 delete job.context()->painter();
1263 job.context()->setPainter(
nullptr );
1269 if ( job.previewRenderImage )
1271 delete job.context()->previewRenderPainter();
1272 job.context()->setPreviewRenderPainter(
nullptr );
1273 delete job.previewRenderImage;
1274 job.previewRenderImage =
nullptr;
1279 delete job.context()->painter();
1280 job.context()->setPainter(
nullptr );
1285 delete job.renderer;
1286 job.renderer =
nullptr;
1300 if (
mCache && !job.cached && !job.context.renderingStopped() )
1311 job.picture.reset(
nullptr );
1312 job.maskPainters.clear();
1313 job.maskPaintDevices.clear();
1317#define DEBUG_RENDERING 0
1320 const std::vector<LayerRenderJob> &jobs,
1321 const LabelRenderJob &labelJob,
1327 image.setDotsPerMeterX(
static_cast<int>( settings.
outputDpi() * 39.37 ) );
1328 image.setDotsPerMeterY(
static_cast<int>( settings.
outputDpi() * 39.37 ) );
1332 std::unique_ptr<QgsElevationMap> mainElevationMap;
1333 if ( mapShadingRenderer.
isActive() )
1336 QPainter painter( &image );
1341 for (
const LayerRenderJob &job : jobs )
1343 if ( job.renderAboveLabels )
1350 painter.setCompositionMode( job.blendMode );
1351 painter.setOpacity( job.opacity );
1353 if ( mainElevationMap )
1356 if ( layerElevationMap.
isValid() )
1362 img.save( QString(
"/tmp/final_%1.png" ).arg( i ) );
1366 painter.drawImage( 0, 0, img );
1369 if ( mapShadingRenderer.
isActive() && mainElevationMap )
1377 if ( labelJob.img && labelJob.complete )
1379 painter.setCompositionMode( QPainter::CompositionMode_SourceOver );
1380 painter.setOpacity( 1.0 );
1381 painter.drawImage( 0, 0, *labelJob.img );
1383 else if ( labelJob.picture && labelJob.complete )
1385 painter.setCompositionMode( QPainter::CompositionMode_SourceOver );
1386 painter.setOpacity( 1.0 );
1395 painter.setCompositionMode( QPainter::CompositionMode_SourceOver );
1396 painter.setOpacity( 1.0 );
1397 painter.drawImage( 0, 0, labelCacheImage );
1401 for (
const LayerRenderJob &job : jobs )
1403 if ( !job.renderAboveLabels )
1410 painter.setCompositionMode( job.blendMode );
1411 painter.setOpacity( job.opacity );
1413 painter.drawImage( 0, 0, img );
1418 image.save(
"/tmp/final.png" );
1425 const LayerRenderJob &job,
1429 if ( job.imageCanBeComposed() )
1431 if ( job.previewRenderImage && !job.completed )
1432 return *job.previewRenderImage;
1434 Q_ASSERT( job.img );
1439 if ( cache && cache->
hasAnyCacheImage( job.layerId + QStringLiteral(
"_preview" ) ) )
1450 if ( job.imageCanBeComposed() && job.elevationMap )
1452 return *job.elevationMap;
1466 for ( LayerRenderJob &job : secondPassJobs )
1468 const bool isRasterRendering = !forceVector || job.maskRequiresLayerRasterization;
1471 if ( isRasterRendering && job.maskJobs.size() > 1 )
1473 QPainter *maskPainter =
nullptr;
1474 for ( QPair<LayerRenderJob *, int> p : job.maskJobs )
1476 QImage *maskImage =
static_cast<QImage *
>( p.first ? p.first->maskPaintDevice.get() : labelJob.maskPaintDevices[p.second].get() );
1479 maskPainter = p.first ? p.first->maskPainter.get() : labelJob.maskPainters[ p.second ].get();
1483 maskPainter->drawImage( 0, 0, *maskImage );
1488 if ( ! job.maskJobs.isEmpty() )
1491 QPair<LayerRenderJob *, int> p = *job.maskJobs.begin();
1492 if ( isRasterRendering )
1494 QImage *maskImage =
static_cast<QImage *
>( p.first ? p.first->maskPaintDevice.get() : labelJob.maskPaintDevices[p.second].get() );
1497 QPainter *painter = job.context()->painter();
1499 painter->setCompositionMode( QPainter::CompositionMode_DestinationIn );
1504 QImage maskBinAlpha = maskImage->createMaskFromColor( 0 );
1505 QVector<QRgb> mswTable;
1506 mswTable.push_back( qRgba( 0, 0, 0, 255 ) );
1507 mswTable.push_back( qRgba( 0, 0, 0, 0 ) );
1508 maskBinAlpha.setColorTable( mswTable );
1509 painter->drawImage( 0, 0, maskBinAlpha );
1513 QPainter tempPainter;
1516 QPainter *painter1 = job.firstPassJob->context()->painter();
1519 tempPainter.begin( job.firstPassJob->img );
1520 painter1 = &tempPainter;
1524 painter1->setCompositionMode( QPainter::CompositionMode_DestinationOut );
1525 painter1->drawImage( 0, 0, *maskImage );
1528 painter1->setCompositionMode( QPainter::CompositionMode_DestinationOver );
1529 painter1->drawImage( 0, 0, *job.img );
1534 job.firstPassJob->picture = std::move( job.picture );
1535 job.picture =
nullptr;
1546 QMultiMap<int, QString> elapsed;
1547 for (
const LayerRenderJob &job : jobs )
1549 for (
const LayerRenderJob &job : secondPassJobs )
1550 elapsed.insert( job.
renderingTime, job.layerId + QString(
" (second pass)" ) );
1552 elapsed.insert( labelJob.renderingTime, tr(
"Labeling" ) );
1554 QList<int> tt( elapsed.uniqueKeys() );
1555 std::sort( tt.begin(), tt.end(), std::greater<int>() );
1556 for (
int t : std::as_const( tt ) )
1558 QgsMessageLog::logMessage( tr(
"%1 ms: %2" ).arg( t ).arg( QStringList( elapsed.values( t ) ).join( QLatin1String(
", " ) ) ), tr(
"Rendering" ) );
1567 std::unique_ptr< QgsScopedRuntimeProfile > labelingProfile;
1570 labelingProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr(
"(labeling)" ), QStringLiteral(
"rendering" ) );
1577 painter->setCompositionMode( QPainter::CompositionMode_SourceOver );
1581 if ( labelingEngine2 )
1583 labelingEngine2->
run( renderContext );
1586 QgsDebugMsgLevel( QStringLiteral(
"Draw labeling took (seconds): %1" ).arg( t.elapsed() / 1000. ), 2 );
1591 Q_UNUSED( settings )
1593 drawLabeling( renderContext, labelingEngine2, painter );
@ Default
Allow raster-based rendering in situations where it is required for correct rendering or where it wil...
@ 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.
@ AffectsLabeling
The layer rendering will interact with the map labeling.
@ 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.
@ 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 hasNonDefaultCompositionMode() const =0
Returns true the labeling requires a non-default composition mode.
virtual bool requiresAdvancedEffects() const =0
Returns true if drawing labels requires advanced effects like composition modes, which could prevent ...
virtual bool hasNonDefaultCompositionMode() const =0
Returns true the labeling requires a non-default composition mode.
virtual bool requiresAdvancedEffects() const =0
Returns true if drawing labels requires advanced effects like composition modes, which could prevent ...
virtual bool hasNonDefaultCompositionMode() const =0
Returns true the labeling requires a non-default composition mode.
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 a digital elevation model in a raster image which may get updated as a part of the map layer r...
bool isValid() const
Returns whether the elevation map is valid.
Renders elevation shading on an image with different methods (eye dome lighting, hillshading,...
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.
Provides map labeling functionality.
virtual void run(QgsRenderContext &context)=0
Runs the labeling job.
QList< QgsMapLayer * > participatingLayers() const
Returns a list of layers with providers in the engine.
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.
Responsible for keeping a 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)
QList< QPointer< QgsMapLayer > > participatingLabelLayers(QgsLabelingEngine *engine)
Returns a list of the layers participating in the map labeling.
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.
QList< QPointer< QgsMapLayer > > mAdditionalLabelLayers
Additional layers participating in labeling problem.
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).
bool labelingHasNonDefaultCompositionModes() const
Returns true if any component of the map labeling requires non-default composition modes.
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)
Contains configuration for rendering maps.
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.
Qgis::RasterizedRenderingPolicy rasterizedRenderingPolicy() const
Returns the policy controlling when rasterisation of content during renders is permitted.
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination coordinate reference system for the map render.
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, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE())
Adds a message to the log instance (and creates it if necessary).
static void drawPicture(QPainter *painter, const QPointF &point, const QPicture &picture)
Draws a picture onto a painter, correctly applying workarounds to avoid issues with incorrect scaling...
static bool staticWillUseLayer(const QgsMapLayer *layer)
Called to find out whether a specified layer is used for labeling.
QString toString(int precision=-1) const
Returns a string representation of the point (x, y) with a preset precision.
Represents a raster layer.
const QgsAbstractRasterLayerLabeling * labeling() const
Access to const labeling configuration.
bool labelsEnabled() const
Returns whether the layer contains labels which are enabled and should be drawn.
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.
Q_INVOKABLE QString toString(int precision=16) const
Returns a string representation of form xmin,ymin : xmax,ymax Coordinates will be truncated to the sp...
void setXMinimum(double x)
Set the minimum x value.
void setXMaximum(double x)
Set the maximum x value.
void grow(double delta)
Grows the rectangle in place by the specified amount.
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 dataset.
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