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 )
644 job.context()->setFeatureFilterProvider( mFeatureFilterProvider );
679 job.imageInitialized =
true;
687 job.renderer =
nullptr;
688 job.context()->setPainter(
nullptr );
693 QElapsedTimer layerTime;
699 job.context()->setFeedback( job.renderer->feedback() );
710 if ( canUseCache || ( !painter && !deferredPainterSet ) || ( job.renderer && job.renderer->forceRasterRender() ) )
713 job.context()->setPainter( allocateImageAndPainter( ml->
id(), job.img, job.context() ) );
717 job.renderer =
nullptr;
718 layerJobs.pop_back();
727 job.elevationMap = allocateElevationMap( ml->
id() );
728 job.context()->setElevationMap( job.elevationMap );
736 if ( !cachedImage.isNull() )
738 job.previewRenderImage =
new QImage( cachedImage );
739 job.previewRenderImageInitialized =
true;
740 job.context()->setPreviewRenderPainter(
new QPainter( job.previewRenderImage ) );
741 job.context()->setPainterFlagsUsingContext( painter );
744 if ( !job.previewRenderImage )
746 job.context()->setPreviewRenderPainter( allocateImageAndPainter( ml->
id(), job.previewRenderImage, job.context() ) );
747 job.previewRenderImageInitialized =
false;
750 if ( !job.previewRenderImage )
752 delete job.context()->previewRenderPainter();
753 job.context()->setPreviewRenderPainter(
nullptr );
757 job.renderingTime = layerTime.elapsed();
765 std::vector< LayerRenderJob > secondPassJobs;
768 QHash<QString, LayerRenderJob *> layerJobMapping;
771 QMap<QString, bool> maskLayerHasEffects;
772 QMap<int, bool> labelHasEffects;
780 MaskSource(
const QString &layerId_,
const QString &labelRuleId_,
int labelMaskId_,
bool hasEffects_ ):
781 layerId( layerId_ ), labelRuleId( labelRuleId_ ), labelMaskId( labelMaskId_ ), hasEffects( hasEffects_ ) {}
786 QHash<QString, QPair<QSet<QString>, QList<MaskSource>>> maskedSymbolLayers;
793 for ( LayerRenderJob &job : firstPassJobs )
795 layerJobMapping[job.layerId] = &job;
800 for ( LayerRenderJob &job : firstPassJobs )
807 auto collectMasks = [&](
QgsMaskedLayers * masks, QString sourceLayerId, QString ruleId = QString(),
int labelMaskId = -1 )
809 bool hasEffects =
false;
810 for (
auto it = masks->begin(); it != masks->end(); ++it )
812 auto lit = maskedSymbolLayers.find( it.key() );
813 if ( lit == maskedSymbolLayers.end() )
815 maskedSymbolLayers[it.key()] = qMakePair( it.value().symbolLayerIds, QList<MaskSource>() << MaskSource( sourceLayerId, ruleId, labelMaskId, it.value().hasEffects ) );
819 if ( lit->first != it.value().symbolLayerIds )
821 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() ) );
824 lit->second.push_back( MaskSource( sourceLayerId, ruleId, labelMaskId, hasEffects ) );
826 hasEffects |= it.value().hasEffects;
828 if ( ! masks->isEmpty() && labelMaskId == -1 )
829 maskLayerHasEffects[ sourceLayerId ] = hasEffects;
834 for (
auto it = labelMasks.begin(); it != labelMasks.end(); it++ )
836 QString labelRule = it.key();
842 for (
auto mit = masks.begin(); mit != masks.end(); mit++ )
844 const QString sourceLayerId = mit.key();
846 if ( !layerJobMapping.contains( sourceLayerId ) )
849 usableMasks.insert( sourceLayerId, mit.value() );
852 if ( usableMasks.empty() )
856 QSet<QgsSymbolLayerReference> slRefs;
857 bool hasEffects =
false;
858 for (
auto mit = usableMasks.begin(); mit != usableMasks.end(); mit++ )
860 const QString sourceLayerId = mit.key();
862 if ( !layerJobMapping.contains( sourceLayerId ) )
865 for (
const QString &symbolLayerId : mit.value().symbolLayerIds )
868 hasEffects |= mit.value().hasEffects;
871 int labelMaskId = labelJob.maskIdProvider.insertLabelLayer( vl->
id(), it.key(), slRefs );
872 labelHasEffects[ labelMaskId ] = hasEffects;
875 collectMasks( &usableMasks, vl->
id(), labelRule, labelMaskId );
880 collectMasks( &symbolLayerMasks, vl->
id() );
883 if ( maskedSymbolLayers.isEmpty() )
884 return secondPassJobs;
887 for (
int maskId = 0; maskId < labelJob.maskIdProvider.size(); maskId++ )
889 QPaintDevice *maskPaintDevice =
nullptr;
890 QPainter *maskPainter =
nullptr;
891 if ( forceVector && !labelHasEffects[ maskId ] )
894 auto geomPaintDevice = std::make_unique< QgsGeometryPaintDevice >(
true );
895 geomPaintDevice->setStrokedPathSegments( 4 );
896 geomPaintDevice->setSimplificationTolerance( labelJob.context.maskSettings().simplifyTolerance() );
897 maskPaintDevice = geomPaintDevice.release();
898 maskPainter =
new QPainter( maskPaintDevice );
903 QImage *maskImage =
nullptr;
904 maskPainter = allocateImageAndPainter( QStringLiteral(
"label mask" ), maskImage, &labelJob.context );
905 maskImage->fill( 0 );
906 maskPaintDevice = maskImage;
909 labelJob.context.setMaskPainter( maskPainter, maskId );
910 labelJob.maskPainters.push_back( std::unique_ptr<QPainter>( maskPainter ) );
911 labelJob.maskPaintDevices.push_back( std::unique_ptr<QPaintDevice>( maskPaintDevice ) );
913 labelJob.context.setMaskIdProvider( &labelJob.maskIdProvider );
928 const bool canUseImage = !forceVector && !hasNonDefaultComposition;
929 if ( !labelJob.img && canUseImage )
931 labelJob.img = allocateImage( QStringLiteral(
"labels" ) );
933 else if ( !labelJob.picture && !canUseImage )
935 labelJob.picture.reset(
new QPicture() );
939 for ( LayerRenderJob &job : firstPassJobs )
941 job.maskRequiresLayerRasterization =
false;
943 auto it = maskedSymbolLayers.find( job.layerId );
944 if ( it != maskedSymbolLayers.end() )
946 const QList<MaskSource> &sourceList = it->second;
947 for (
const MaskSource &source : sourceList )
949 job.maskRequiresLayerRasterization |= source.hasEffects;
954 const bool isRasterRendering = !forceVector || job.maskRequiresLayerRasterization || ( job.renderer && job.renderer->forceRasterRender() );
955 if ( isRasterRendering && !job.img )
957 job.context()->setPainter( allocateImageAndPainter( job.layerId, job.img, job.context() ) );
959 else if ( !isRasterRendering && !job.picture )
961 PictureAndPainter pictureAndPainter = allocatePictureAndPainter( job.context() );
962 job.picture = std::move( pictureAndPainter.first );
963 if ( job.context()->painter()->hasClipping() )
966 pictureAndPainter.second->setClipping(
true );
967 pictureAndPainter.second->setClipPath( job.context()->painter()->clipPath() );
969 job.context()->setPainter( pictureAndPainter.second );
972 job.renderer = job.layer->createMapRenderer( *( job.context() ) );
976 if ( maskLayerHasEffects.contains( job.layerId ) )
978 QPaintDevice *maskPaintDevice =
nullptr;
979 QPainter *maskPainter =
nullptr;
980 if ( forceVector && !maskLayerHasEffects[ job.layerId ] )
983 auto geomPaintDevice = std::make_unique< QgsGeometryPaintDevice >( );
984 geomPaintDevice->setStrokedPathSegments( 4 );
985 geomPaintDevice->setSimplificationTolerance( job.context()->maskSettings().simplifyTolerance() );
986 maskPaintDevice = geomPaintDevice.release();
987 maskPainter =
new QPainter( maskPaintDevice );
992 QImage *maskImage =
nullptr;
993 maskPainter = allocateImageAndPainter( job.layerId, maskImage, job.context() );
994 maskImage->fill( 0 );
995 maskPaintDevice = maskImage;
998 job.context()->setMaskPainter( maskPainter );
999 job.maskPainter.reset( maskPainter );
1000 job.maskPaintDevice.reset( maskPaintDevice );
1004 for ( LayerRenderJob &job : firstPassJobs )
1008 auto it = maskedSymbolLayers.find( job.layerId );
1009 if ( it == maskedSymbolLayers.end() )
1012 QList<MaskSource> &sourceList = it->second;
1013 const QSet<QString> symbolList = it->first;
1015 secondPassJobs.emplace_back( LayerRenderJob() );
1016 LayerRenderJob &job2 = secondPassJobs.back();
1018 job2.maskRequiresLayerRasterization = job.maskRequiresLayerRasterization;
1021 for ( MaskSource &source : sourceList )
1023 if ( source.labelMaskId != -1 )
1024 job2.maskJobs.push_back( qMakePair(
nullptr, source.labelMaskId ) );
1026 job2.maskJobs.push_back( qMakePair( layerJobMapping[source.layerId], -1 ) );
1030 job2.setContext( std::make_unique< QgsRenderContext >( *job.context() ) );
1032 job2.layer = job.layer;
1033 job2.renderAboveLabels = job.renderAboveLabels;
1034 job2.layerId = job.layerId;
1037 job2.firstPassJob = &job;
1039 if ( !forceVector || job2.maskRequiresLayerRasterization )
1041 job2.context()->setPainter( allocateImageAndPainter( job.layerId, job2.img, job2.context() ) );
1045 PictureAndPainter pictureAndPainter = allocatePictureAndPainter( job2.context() );
1046 if ( job.context()->painter()->hasClipping() )
1049 pictureAndPainter.second->setClipping(
true );
1050 pictureAndPainter.second->setClipPath( job.context()->painter()->clipPath() );
1052 job2.picture = std::move( pictureAndPainter.first );
1053 job2.context()->setPainter( pictureAndPainter.second );
1056 if ( ! job2.img && ! job2.picture )
1058 secondPassJobs.pop_back();
1065 job2.renderer = mapRenderer;
1066 if ( job2.renderer )
1068 job2.context()->setFeedback( job2.renderer->feedback() );
1073 job2.context()->setDisabledSymbolLayersV2( symbolList );
1076 return secondPassJobs;
1081 QList<QPointer<QgsMapLayer> > res = _qgis_listRawToQPointer( engine->
participatingLayers() );
1085 if ( !res.contains( it ) )
1097 for ( LayerRenderJob &job : secondPassJobs )
1099 if ( job.maskRequiresLayerRasterization )
1105 for (
const QPair<LayerRenderJob *, int> &p : std::as_const( job.maskJobs ) )
1107 QPainter *maskPainter = p.first ? p.first->maskPainter.get() : labelJob.maskPainters[p.second].get();
1109 const QSet<QString> layers = job.context()->disabledSymbolLayersV2();
1112 QgsGeometry geometry( geometryDevice->geometry().clone() );
1114#if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<10
1121 for (
const QString &symbolLayerId : layers )
1123 job.context()->addSymbolLayerClipGeometry( symbolLayerId, geometry );
1128 job.context()->setDisabledSymbolLayersV2( QSet<QString>() );
1136 job.context.setPainter( painter );
1137 job.context.setLabelingEngine( labelingEngine2 );
1138 job.context.setFeedback( mLabelingEngineFeedback );
1139 if ( labelingEngine2 )
1140 job.context.labelingEngine()->prepare( job.context );
1144 job.context.setExtent( r1 );
1146 job.context.setFeatureFilterProvider( mFeatureFilterProvider );
1149 job.context.setCoordinateTransform( ct );
1160 job.complete =
true;
1163 job.context.setPainter(
nullptr );
1167 if ( canUseLabelCache && (
mCache || !painter ) )
1169 job.img = allocateImage( QStringLiteral(
"labels" ) );
1179 for ( LayerRenderJob &job : jobs )
1183 delete job.context()->painter();
1184 job.context()->setPainter(
nullptr );
1186 if (
mCache && !job.cached && job.completed && job.layer )
1188 QgsDebugMsgLevel( QStringLiteral(
"caching image for %1" ).arg( job.layerId ), 2 );
1197 if ( job.previewRenderImage )
1199 delete job.context()->previewRenderPainter();
1200 job.context()->setPreviewRenderPainter(
nullptr );
1201 delete job.previewRenderImage;
1202 job.previewRenderImage =
nullptr;
1205 if ( job.elevationMap )
1207 job.context()->setElevationMap(
nullptr );
1208 if (
mCache && !job.cached && job.completed && job.layer )
1210 QgsDebugMsgLevel( QStringLiteral(
"caching elevation map for %1" ).arg( job.layerId ), 2 );
1213 job.elevationMap->rawElevationImage(),
1216 QList< QgsMapLayer * >() << job.layer );
1219 job.elevationMap->rawElevationImage(),
1222 QList< QgsMapLayer * >() << job.layer );
1225 delete job.elevationMap;
1226 job.elevationMap =
nullptr;
1231 delete job.context()->painter();
1232 job.context()->setPainter(
nullptr );
1233 job.picture.reset(
nullptr );
1238 const QStringList
errors = job.renderer->errors();
1239 for (
const QString &message :
errors )
1240 mErrors.append( Error( job.renderer->layerId(), message ) );
1242 mRenderedItemResults->appendResults( job.renderer->takeRenderedItemDetails(), *job.context() );
1244 delete job.renderer;
1245 job.renderer =
nullptr;
1251 job.maskPainter.reset(
nullptr );
1252 job.maskPaintDevice.reset(
nullptr );
1260 for ( LayerRenderJob &job : jobs )
1264 delete job.context()->painter();
1265 job.context()->setPainter(
nullptr );
1271 if ( job.previewRenderImage )
1273 delete job.context()->previewRenderPainter();
1274 job.context()->setPreviewRenderPainter(
nullptr );
1275 delete job.previewRenderImage;
1276 job.previewRenderImage =
nullptr;
1281 delete job.context()->painter();
1282 job.context()->setPainter(
nullptr );
1287 delete job.renderer;
1288 job.renderer =
nullptr;
1302 if (
mCache && !job.cached && !job.context.renderingStopped() )
1313 job.picture.reset(
nullptr );
1314 job.maskPainters.clear();
1315 job.maskPaintDevices.clear();
1319#define DEBUG_RENDERING 0
1322 const std::vector<LayerRenderJob> &jobs,
1323 const LabelRenderJob &labelJob,
1329 image.setDotsPerMeterX(
static_cast<int>( settings.
outputDpi() * 39.37 ) );
1330 image.setDotsPerMeterY(
static_cast<int>( settings.
outputDpi() * 39.37 ) );
1334 std::unique_ptr<QgsElevationMap> mainElevationMap;
1335 if ( mapShadingRenderer.
isActive() )
1338 QPainter painter( &image );
1343 for (
const LayerRenderJob &job : jobs )
1345 if ( job.renderAboveLabels )
1352 painter.setCompositionMode( job.blendMode );
1353 painter.setOpacity( job.opacity );
1355 if ( mainElevationMap )
1358 if ( layerElevationMap.
isValid() )
1364 img.save( QString(
"/tmp/final_%1.png" ).arg( i ) );
1368 painter.drawImage( 0, 0, img );
1371 if ( mapShadingRenderer.
isActive() && mainElevationMap )
1379 if ( labelJob.img && labelJob.complete )
1381 painter.setCompositionMode( QPainter::CompositionMode_SourceOver );
1382 painter.setOpacity( 1.0 );
1383 painter.drawImage( 0, 0, *labelJob.img );
1385 else if ( labelJob.picture && labelJob.complete )
1387 painter.setCompositionMode( QPainter::CompositionMode_SourceOver );
1388 painter.setOpacity( 1.0 );
1397 painter.setCompositionMode( QPainter::CompositionMode_SourceOver );
1398 painter.setOpacity( 1.0 );
1399 painter.drawImage( 0, 0, labelCacheImage );
1403 for (
const LayerRenderJob &job : jobs )
1405 if ( !job.renderAboveLabels )
1412 painter.setCompositionMode( job.blendMode );
1413 painter.setOpacity( job.opacity );
1415 painter.drawImage( 0, 0, img );
1420 image.save(
"/tmp/final.png" );
1427 const LayerRenderJob &job,
1431 if ( job.imageCanBeComposed() )
1433 if ( job.previewRenderImage && !job.completed )
1434 return *job.previewRenderImage;
1436 Q_ASSERT( job.img );
1441 if ( cache && cache->
hasAnyCacheImage( job.layerId + QStringLiteral(
"_preview" ) ) )
1452 if ( job.imageCanBeComposed() && job.elevationMap )
1454 return *job.elevationMap;
1468 for ( LayerRenderJob &job : secondPassJobs )
1470 const bool isRasterRendering = !forceVector || job.maskRequiresLayerRasterization;
1473 if ( isRasterRendering && job.maskJobs.size() > 1 )
1475 QPainter *maskPainter =
nullptr;
1476 for ( QPair<LayerRenderJob *, int> p : job.maskJobs )
1478 QImage *maskImage =
static_cast<QImage *
>( p.first ? p.first->maskPaintDevice.get() : labelJob.maskPaintDevices[p.second].get() );
1481 maskPainter = p.first ? p.first->maskPainter.get() : labelJob.maskPainters[ p.second ].get();
1485 maskPainter->drawImage( 0, 0, *maskImage );
1490 if ( ! job.maskJobs.isEmpty() )
1493 QPair<LayerRenderJob *, int> p = *job.maskJobs.begin();
1494 if ( isRasterRendering )
1496 QImage *maskImage =
static_cast<QImage *
>( p.first ? p.first->maskPaintDevice.get() : labelJob.maskPaintDevices[p.second].get() );
1499 QPainter *painter = job.context()->painter();
1501 painter->setCompositionMode( QPainter::CompositionMode_DestinationIn );
1506 QImage maskBinAlpha = maskImage->createMaskFromColor( 0 );
1507 QVector<QRgb> mswTable;
1508 mswTable.push_back( qRgba( 0, 0, 0, 255 ) );
1509 mswTable.push_back( qRgba( 0, 0, 0, 0 ) );
1510 maskBinAlpha.setColorTable( mswTable );
1511 painter->drawImage( 0, 0, maskBinAlpha );
1515 QPainter tempPainter;
1518 QPainter *painter1 = job.firstPassJob->context()->painter();
1521 tempPainter.begin( job.firstPassJob->img );
1522 painter1 = &tempPainter;
1526 painter1->setCompositionMode( QPainter::CompositionMode_DestinationOut );
1527 painter1->drawImage( 0, 0, *maskImage );
1530 painter1->setCompositionMode( QPainter::CompositionMode_DestinationOver );
1531 painter1->drawImage( 0, 0, *job.img );
1536 job.firstPassJob->picture = std::move( job.picture );
1537 job.picture =
nullptr;
1548 QMultiMap<int, QString> elapsed;
1549 for (
const LayerRenderJob &job : jobs )
1551 for (
const LayerRenderJob &job : secondPassJobs )
1552 elapsed.insert( job.
renderingTime, job.layerId + QString(
" (second pass)" ) );
1554 elapsed.insert( labelJob.renderingTime, tr(
"Labeling" ) );
1556 QList<int> tt( elapsed.uniqueKeys() );
1557 std::sort( tt.begin(), tt.end(), std::greater<int>() );
1558 for (
int t : std::as_const( tt ) )
1560 QgsMessageLog::logMessage( tr(
"%1 ms: %2" ).arg( t ).arg( QStringList( elapsed.values( t ) ).join( QLatin1String(
", " ) ) ), tr(
"Rendering" ) );
1569 std::unique_ptr< QgsScopedRuntimeProfile > labelingProfile;
1572 labelingProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr(
"(labeling)" ), QStringLiteral(
"rendering" ) );
1579 painter->setCompositionMode( QPainter::CompositionMode_SourceOver );
1583 if ( labelingEngine2 )
1585 labelingEngine2->
run( renderContext );
1588 QgsDebugMsgLevel( QStringLiteral(
"Draw labeling took (seconds): %1" ).arg( t.elapsed() / 1000. ), 2 );
1593 Q_UNUSED( settings )
1595 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