17#include "moc_qgsmaprendererjob.cpp"
20#include <QElapsedTimer>
22#include <QtConcurrentMap>
65LayerRenderJob &LayerRenderJob::operator=( LayerRenderJob &&other )
67 mContext = std::move( other.mContext );
72 renderer = other.renderer;
73 other.renderer =
nullptr;
75 previewRenderImage = other.previewRenderImage;
76 other.previewRenderImage =
nullptr;
78 imageInitialized = other.imageInitialized;
79 previewRenderImageInitialized = other.previewRenderImageInitialized;
81 blendMode = other.blendMode;
82 opacity = other.opacity;
83 cached = other.cached;
85 renderAboveLabels = other.renderAboveLabels;
86 completed = other.completed;
87 renderingTime = other.renderingTime;
88 estimatedRenderingTime = other.estimatedRenderingTime ;
89 errors = other.errors;
90 layerId = other.layerId;
92 maskPaintDevice = std::move( other.maskPaintDevice );
94 firstPassJob = other.firstPassJob;
95 other.firstPassJob =
nullptr;
97 picture = std::move( other.picture );
99 maskJobs = other.maskJobs;
101 maskRequiresLayerRasterization = other.maskRequiresLayerRasterization;
103 elevationMap = other.elevationMap;
104 maskPainter = std::move( other.maskPainter );
109LayerRenderJob::LayerRenderJob( LayerRenderJob &&other )
110 : imageInitialized( other.imageInitialized )
111 , previewRenderImageInitialized( other.previewRenderImageInitialized )
112 , blendMode( other.blendMode )
113 , opacity( other.opacity )
114 , cached( other.cached )
115 , renderAboveLabels( other.renderAboveLabels )
116 , layer( other.layer )
117 , completed( other.completed )
118 , renderingTime( other.renderingTime )
119 , estimatedRenderingTime( other.estimatedRenderingTime )
120 , errors( other.errors )
121 , layerId( other.layerId )
122 , maskPainter( nullptr )
123 , maskRequiresLayerRasterization( other.maskRequiresLayerRasterization )
124 , maskJobs( other.maskJobs )
126 mContext = std::move( other.mContext );
131 previewRenderImage = other.previewRenderImage;
132 other.previewRenderImage =
nullptr;
134 renderer = other.renderer;
135 other.renderer =
nullptr;
137 elevationMap = other.elevationMap;
138 other.elevationMap =
nullptr;
140 maskPaintDevice = std::move( other.maskPaintDevice );
142 firstPassJob = other.firstPassJob;
143 other.firstPassJob =
nullptr;
145 picture = std::move( other.picture );
148bool LayerRenderJob::imageCanBeComposed()
const
150 if ( imageInitialized )
154 return renderer->isReadyToCompose();
168 : mSettings( settings )
214 return mLabelingEngineFeedback;
219 QHash<QgsMapLayer *, int> result;
222 if (
auto &&lKey = it.key() )
223 result.insert( lKey, it.value() );
243 QSet< QgsMapLayer * > labeledLayers;
250 switch ( ml->type() )
307 bool canUseCache = canCache && QSet< QgsMapLayer * >( labelDependentLayers.begin(), labelDependentLayers.end() ) == labeledLayers;
336 static const double SPLIT_COORD = 180.0;
348 QgsDebugMsgLevel( QStringLiteral(
"\n0:%1 %2x%3\n1:%4\n2:%5 %6x%7 (w:%8 h:%9)" )
351 .arg( std::fabs( 1.0 - extent2.
width() / extent.
width() ) )
352 .arg( std::fabs( 1.0 - extent2.
height() / extent.
height() ) )
386 if ( ll.
x() > ur.
x() )
415 extent =
QgsRectangle( std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), std::numeric_limits<double>::max() );
425 extent =
QgsRectangle( std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), std::numeric_limits<double>::max() );
426 r2 =
QgsRectangle( std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), std::numeric_limits<double>::max() );
433QImage *QgsMapRendererJob::allocateImage( QString layerId )
440 if ( image->isNull() )
449QgsElevationMap *QgsMapRendererJob::allocateElevationMap( QString layerId )
452 if ( !elevationMap->isValid() )
457 return elevationMap.release();
460QPainter *QgsMapRendererJob::allocateImageAndPainter( QString layerId, QImage *&image,
const QgsRenderContext *context )
462 QPainter *painter =
nullptr;
463 image = allocateImage( layerId );
466 painter =
new QPainter( image );
472QgsMapRendererJob::PictureAndPainter QgsMapRendererJob::allocatePictureAndPainter(
const QgsRenderContext *context )
474 std::unique_ptr<QPicture> picture = std::make_unique<QPicture>();
475 QPainter *painter =
new QPainter( picture.get() );
477 return { std::move( picture ), painter };
482 std::vector< LayerRenderJob > layerJobs;
491 Q_UNUSED( cacheValid )
492 QgsDebugMsgLevel( QStringLiteral(
"CACHE VALID: %1" ).arg( cacheValid ), 4 );
497 while ( li.hasPrevious() )
501 QgsDebugMsgLevel( QStringLiteral(
"layer %1: minscale:%2 maxscale:%3 scaledepvis:%4 blendmode:%5 isValid:%6" )
518 QgsDebugMsgLevel( QStringLiteral(
"Layer not rendered because it is not within the defined visibility scale range" ), 3 );
524 QgsDebugMsgLevel( QStringLiteral(
"Layer not rendered because it is not visible within the map's time range" ), 3 );
530 QgsDebugMsgLevel( QStringLiteral(
"Layer not rendered because it is not visible within the map's z range" ), 3 );
539 bool haveExtentInLayerCrs =
true;
542 haveExtentInLayerCrs = reprojectToLayerExtent( ml, ct, r1, r2 );
547 mErrors.append( Error( ml->
id(), tr(
"There was a problem transforming the layer's extent. Layer skipped." ) ) );
558 if ( ( vl && vl->
isEditable() ) || requiresLabeling )
564 layerJobs.emplace_back( LayerRenderJob() );
565 LayerRenderJob &job = layerJobs.back();
567 job.layerId = ml->
id();
568 job.renderAboveLabels = ml->
customProperty( QStringLiteral(
"rendering/renderAboveLabels" ) ).toBool();
572 if ( !ml->
customProperty( QStringLiteral(
"_noset_layer_expression_context" ) ).toBool() )
574 job.context()->setPainter( painter );
575 job.context()->setLabelingEngine( labelingEngine2 );
576 job.context()->setLabelSink(
labelSink() );
577 job.context()->setCoordinateTransform( ct );
578 job.context()->setExtent( r1 );
584 if ( mFeatureFilterProvider )
585 job.context()->setFeatureFilterProvider( mFeatureFilterProvider );
618 job.imageInitialized =
true;
626 job.renderer =
nullptr;
627 job.context()->setPainter(
nullptr );
632 QElapsedTimer layerTime;
638 job.context()->setFeedback( job.renderer->feedback() );
649 if ( canUseCache || ( !painter && !deferredPainterSet ) || ( job.renderer && job.renderer->forceRasterRender() ) )
652 job.context()->setPainter( allocateImageAndPainter( ml->
id(), job.img, job.context() ) );
656 job.renderer =
nullptr;
657 layerJobs.pop_back();
666 job.elevationMap = allocateElevationMap( ml->
id() );
667 job.context()->setElevationMap( job.elevationMap );
675 if ( !cachedImage.isNull() )
677 job.previewRenderImage =
new QImage( cachedImage );
678 job.previewRenderImageInitialized =
true;
679 job.context()->setPreviewRenderPainter(
new QPainter( job.previewRenderImage ) );
680 job.context()->setPainterFlagsUsingContext( painter );
683 if ( !job.previewRenderImage )
685 job.context()->setPreviewRenderPainter( allocateImageAndPainter( ml->
id(), job.previewRenderImage, job.context() ) );
686 job.previewRenderImageInitialized =
false;
689 if ( !job.previewRenderImage )
691 delete job.context()->previewRenderPainter();
692 job.context()->setPreviewRenderPainter(
nullptr );
696 job.renderingTime = layerTime.elapsed();
704 std::vector< LayerRenderJob > secondPassJobs;
707 QHash<QString, LayerRenderJob *> layerJobMapping;
710 QMap<QString, bool> maskLayerHasEffects;
711 QMap<int, bool> labelHasEffects;
719 MaskSource(
const QString &layerId_,
const QString &labelRuleId_,
int labelMaskId_,
bool hasEffects_ ):
720 layerId( layerId_ ), labelRuleId( labelRuleId_ ), labelMaskId( labelMaskId_ ), hasEffects( hasEffects_ ) {}
725 QHash<QString, QPair<QSet<QString>, QList<MaskSource>>> maskedSymbolLayers;
732 for ( LayerRenderJob &job : firstPassJobs )
734 layerJobMapping[job.layerId] = &job;
739 for ( LayerRenderJob &job : firstPassJobs )
746 auto collectMasks = [&](
QgsMaskedLayers * masks, QString sourceLayerId, QString ruleId = QString(),
int labelMaskId = -1 )
748 bool hasEffects =
false;
749 for (
auto it = masks->begin(); it != masks->end(); ++it )
751 auto lit = maskedSymbolLayers.find( it.key() );
752 if ( lit == maskedSymbolLayers.end() )
754 maskedSymbolLayers[it.key()] = qMakePair( it.value().symbolLayerIds, QList<MaskSource>() << MaskSource( sourceLayerId, ruleId, labelMaskId, it.value().hasEffects ) );
758 if ( lit->first != it.value().symbolLayerIds )
760 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() ) );
763 lit->second.push_back( MaskSource( sourceLayerId, ruleId, labelMaskId, hasEffects ) );
765 hasEffects |= it.value().hasEffects;
767 if ( ! masks->isEmpty() && labelMaskId == -1 )
768 maskLayerHasEffects[ sourceLayerId ] = hasEffects;
773 for (
auto it = labelMasks.begin(); it != labelMasks.end(); it++ )
775 QString labelRule = it.key();
781 for (
auto mit = masks.begin(); mit != masks.end(); mit++ )
783 const QString sourceLayerId = mit.key();
785 if ( !layerJobMapping.contains( sourceLayerId ) )
788 usableMasks.insert( sourceLayerId, mit.value() );
791 if ( usableMasks.empty() )
795 QSet<QgsSymbolLayerReference> slRefs;
796 bool hasEffects =
false;
797 for (
auto mit = usableMasks.begin(); mit != usableMasks.end(); mit++ )
799 const QString sourceLayerId = mit.key();
801 if ( !layerJobMapping.contains( sourceLayerId ) )
804 for (
const QString &symbolLayerId : mit.value().symbolLayerIds )
807 hasEffects |= mit.value().hasEffects;
810 int labelMaskId = labelJob.maskIdProvider.insertLabelLayer( vl->
id(), it.key(), slRefs );
811 labelHasEffects[ labelMaskId ] = hasEffects;
814 collectMasks( &usableMasks, vl->
id(), labelRule, labelMaskId );
819 collectMasks( &symbolLayerMasks, vl->
id() );
822 if ( maskedSymbolLayers.isEmpty() )
823 return secondPassJobs;
826 for (
int maskId = 0; maskId < labelJob.maskIdProvider.size(); maskId++ )
828 QPaintDevice *maskPaintDevice =
nullptr;
829 QPainter *maskPainter =
nullptr;
830 if ( forceVector && !labelHasEffects[ maskId ] )
833 std::unique_ptr< QgsGeometryPaintDevice > geomPaintDevice = std::make_unique< QgsGeometryPaintDevice >(
true );
834 geomPaintDevice->setStrokedPathSegments( 4 );
835 geomPaintDevice->setSimplificationTolerance( labelJob.context.maskSettings().simplifyTolerance() );
836 maskPaintDevice = geomPaintDevice.release();
837 maskPainter =
new QPainter( maskPaintDevice );
842 QImage *maskImage =
nullptr;
843 maskPainter = allocateImageAndPainter( QStringLiteral(
"label mask" ), maskImage, &labelJob.context );
844 maskImage->fill( 0 );
845 maskPaintDevice = maskImage;
848 labelJob.context.setMaskPainter( maskPainter, maskId );
849 labelJob.maskPainters.push_back( std::unique_ptr<QPainter>( maskPainter ) );
850 labelJob.maskPaintDevices.push_back( std::unique_ptr<QPaintDevice>( maskPaintDevice ) );
852 labelJob.context.setMaskIdProvider( &labelJob.maskIdProvider );
863 if ( !labelJob.img && !forceVector )
865 labelJob.img = allocateImage( QStringLiteral(
"labels" ) );
867 else if ( !labelJob.picture && forceVector )
869 labelJob.picture.reset(
new QPicture() );
873 for ( LayerRenderJob &job : firstPassJobs )
875 job.maskRequiresLayerRasterization =
false;
877 auto it = maskedSymbolLayers.find( job.layerId );
878 if ( it != maskedSymbolLayers.end() )
880 const QList<MaskSource> &sourceList = it->second;
881 for (
const MaskSource &source : sourceList )
883 job.maskRequiresLayerRasterization |= source.hasEffects;
888 const bool isRasterRendering = !forceVector || job.maskRequiresLayerRasterization || ( job.renderer && job.renderer->forceRasterRender() );
889 if ( isRasterRendering && !job.img )
891 job.context()->setPainter( allocateImageAndPainter( job.layerId, job.img, job.context() ) );
893 else if ( !isRasterRendering && !job.picture )
895 PictureAndPainter pictureAndPainter = allocatePictureAndPainter( job.context() );
896 job.picture = std::move( pictureAndPainter.first );
897 if ( job.context()->painter()->hasClipping() )
900 pictureAndPainter.second->setClipping(
true );
901 pictureAndPainter.second->setClipPath( job.context()->painter()->clipPath() );
903 job.context()->setPainter( pictureAndPainter.second );
906 job.renderer = job.layer->createMapRenderer( *( job.context() ) );
910 if ( maskLayerHasEffects.contains( job.layerId ) )
912 QPaintDevice *maskPaintDevice =
nullptr;
913 QPainter *maskPainter =
nullptr;
914 if ( forceVector && !maskLayerHasEffects[ job.layerId ] )
917 std::unique_ptr< QgsGeometryPaintDevice > geomPaintDevice = std::make_unique< QgsGeometryPaintDevice >( );
918 geomPaintDevice->setStrokedPathSegments( 4 );
919 geomPaintDevice->setSimplificationTolerance( job.context()->maskSettings().simplifyTolerance() );
920 maskPaintDevice = geomPaintDevice.release();
921 maskPainter =
new QPainter( maskPaintDevice );
926 QImage *maskImage =
nullptr;
927 maskPainter = allocateImageAndPainter( job.layerId, maskImage, job.context() );
928 maskImage->fill( 0 );
929 maskPaintDevice = maskImage;
932 job.context()->setMaskPainter( maskPainter );
933 job.maskPainter.reset( maskPainter );
934 job.maskPaintDevice.reset( maskPaintDevice );
938 for ( LayerRenderJob &job : firstPassJobs )
942 auto it = maskedSymbolLayers.find( job.layerId );
943 if ( it == maskedSymbolLayers.end() )
946 QList<MaskSource> &sourceList = it->second;
947 const QSet<QString> symbolList = it->first;
949 secondPassJobs.emplace_back( LayerRenderJob() );
950 LayerRenderJob &job2 = secondPassJobs.back();
952 job2.maskRequiresLayerRasterization = job.maskRequiresLayerRasterization;
955 for ( MaskSource &source : sourceList )
957 if ( source.labelMaskId != -1 )
958 job2.maskJobs.push_back( qMakePair(
nullptr, source.labelMaskId ) );
960 job2.maskJobs.push_back( qMakePair( layerJobMapping[source.layerId], -1 ) );
964 job2.setContext( std::make_unique< QgsRenderContext >( *job.context() ) );
966 job2.layer = job.layer;
967 job2.renderAboveLabels = job.renderAboveLabels;
968 job2.layerId = job.layerId;
971 job2.firstPassJob = &job;
973 if ( !forceVector || job2.maskRequiresLayerRasterization )
975 job2.context()->setPainter( allocateImageAndPainter( job.layerId, job2.img, job2.context() ) );
979 PictureAndPainter pictureAndPainter = allocatePictureAndPainter( job2.context() );
980 if ( job.context()->painter()->hasClipping() )
983 pictureAndPainter.second->setClipping(
true );
984 pictureAndPainter.second->setClipPath( job.context()->painter()->clipPath() );
986 job2.picture = std::move( pictureAndPainter.first );
987 job2.context()->setPainter( pictureAndPainter.second );
990 if ( ! job2.img && ! job2.picture )
992 secondPassJobs.pop_back();
999 job2.renderer = mapRenderer;
1000 if ( job2.renderer )
1002 job2.context()->setFeedback( job2.renderer->feedback() );
1007 job2.context()->setDisabledSymbolLayersV2( symbolList );
1010 return secondPassJobs;
1015 QList<QPointer<QgsMapLayer> > res = _qgis_listRawToQPointer( engine->
participatingLayers() );
1019 if ( !res.contains( it ) )
1031 for ( LayerRenderJob &job : secondPassJobs )
1033 if ( job.maskRequiresLayerRasterization )
1039 for (
const QPair<LayerRenderJob *, int> &p : std::as_const( job.maskJobs ) )
1041 QPainter *maskPainter = p.first ? p.first->maskPainter.get() : labelJob.maskPainters[p.second].get();
1043 const QSet<QString> layers = job.context()->disabledSymbolLayersV2();
1046 QgsGeometry geometry( geometryDevice->geometry().clone() );
1048#if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<10
1055 for (
const QString &symbolLayerId : layers )
1057 job.context()->addSymbolLayerClipGeometry( symbolLayerId, geometry );
1062 job.context()->setDisabledSymbolLayersV2( QSet<QString>() );
1070 job.context.setPainter( painter );
1071 job.context.setLabelingEngine( labelingEngine2 );
1072 job.context.setFeedback( mLabelingEngineFeedback );
1073 if ( labelingEngine2 )
1074 job.context.labelingEngine()->prepare( job.context );
1078 job.context.setExtent( r1 );
1080 job.context.setFeatureFilterProvider( mFeatureFilterProvider );
1083 job.context.setCoordinateTransform( ct );
1094 job.complete =
true;
1097 job.context.setPainter(
nullptr );
1101 if ( canUseLabelCache && (
mCache || !painter ) )
1103 job.img = allocateImage( QStringLiteral(
"labels" ) );
1113 for ( LayerRenderJob &job : jobs )
1117 delete job.context()->painter();
1118 job.context()->setPainter(
nullptr );
1120 if (
mCache && !job.cached && job.completed && job.layer )
1122 QgsDebugMsgLevel( QStringLiteral(
"caching image for %1" ).arg( job.layerId ), 2 );
1131 if ( job.previewRenderImage )
1133 delete job.context()->previewRenderPainter();
1134 job.context()->setPreviewRenderPainter(
nullptr );
1135 delete job.previewRenderImage;
1136 job.previewRenderImage =
nullptr;
1139 if ( job.elevationMap )
1141 job.context()->setElevationMap(
nullptr );
1142 if (
mCache && !job.cached && job.completed && job.layer )
1144 QgsDebugMsgLevel( QStringLiteral(
"caching elevation map for %1" ).arg( job.layerId ), 2 );
1147 job.elevationMap->rawElevationImage(),
1150 QList< QgsMapLayer * >() << job.layer );
1153 job.elevationMap->rawElevationImage(),
1156 QList< QgsMapLayer * >() << job.layer );
1159 delete job.elevationMap;
1160 job.elevationMap =
nullptr;
1165 delete job.context()->painter();
1166 job.context()->setPainter(
nullptr );
1167 job.picture.reset(
nullptr );
1172 const QStringList
errors = job.renderer->errors();
1173 for (
const QString &message :
errors )
1174 mErrors.append( Error( job.renderer->layerId(), message ) );
1176 mRenderedItemResults->appendResults( job.renderer->takeRenderedItemDetails(), *job.context() );
1178 delete job.renderer;
1179 job.renderer =
nullptr;
1185 job.maskPainter.reset(
nullptr );
1186 job.maskPaintDevice.reset(
nullptr );
1194 for ( LayerRenderJob &job : jobs )
1198 delete job.context()->painter();
1199 job.context()->setPainter(
nullptr );
1205 if ( job.previewRenderImage )
1207 delete job.context()->previewRenderPainter();
1208 job.context()->setPreviewRenderPainter(
nullptr );
1209 delete job.previewRenderImage;
1210 job.previewRenderImage =
nullptr;
1215 delete job.context()->painter();
1216 job.context()->setPainter(
nullptr );
1221 delete job.renderer;
1222 job.renderer =
nullptr;
1236 if (
mCache && !job.cached && !job.context.renderingStopped() )
1247 job.picture.reset(
nullptr );
1248 job.maskPainters.clear();
1249 job.maskPaintDevices.clear();
1253#define DEBUG_RENDERING 0
1256 const std::vector<LayerRenderJob> &jobs,
1257 const LabelRenderJob &labelJob,
1263 image.setDotsPerMeterX(
static_cast<int>( settings.
outputDpi() * 39.37 ) );
1264 image.setDotsPerMeterY(
static_cast<int>( settings.
outputDpi() * 39.37 ) );
1268 std::unique_ptr<QgsElevationMap> mainElevationMap;
1269 if ( mapShadingRenderer.
isActive() )
1272 QPainter painter( &image );
1277 for (
const LayerRenderJob &job : jobs )
1279 if ( job.renderAboveLabels )
1286 painter.setCompositionMode( job.blendMode );
1287 painter.setOpacity( job.opacity );
1289 if ( mainElevationMap )
1292 if ( layerElevationMap.
isValid() )
1298 img.save( QString(
"/tmp/final_%1.png" ).arg( i ) );
1302 painter.drawImage( 0, 0, img );
1305 if ( mapShadingRenderer.
isActive() && mainElevationMap )
1313 if ( labelJob.img && labelJob.complete )
1315 painter.setCompositionMode( QPainter::CompositionMode_SourceOver );
1316 painter.setOpacity( 1.0 );
1317 painter.drawImage( 0, 0, *labelJob.img );
1325 painter.setCompositionMode( QPainter::CompositionMode_SourceOver );
1326 painter.setOpacity( 1.0 );
1327 painter.drawImage( 0, 0, labelCacheImage );
1331 for (
const LayerRenderJob &job : jobs )
1333 if ( !job.renderAboveLabels )
1340 painter.setCompositionMode( job.blendMode );
1341 painter.setOpacity( job.opacity );
1343 painter.drawImage( 0, 0, img );
1348 image.save(
"/tmp/final.png" );
1355 const LayerRenderJob &job,
1359 if ( job.imageCanBeComposed() )
1361 if ( job.previewRenderImage && !job.completed )
1362 return *job.previewRenderImage;
1364 Q_ASSERT( job.img );
1369 if ( cache && cache->
hasAnyCacheImage( job.layerId + QStringLiteral(
"_preview" ) ) )
1380 if ( job.imageCanBeComposed() && job.elevationMap )
1382 return *job.elevationMap;
1396 for ( LayerRenderJob &job : secondPassJobs )
1398 const bool isRasterRendering = !forceVector || job.maskRequiresLayerRasterization;
1401 if ( isRasterRendering && job.maskJobs.size() > 1 )
1403 QPainter *maskPainter =
nullptr;
1404 for ( QPair<LayerRenderJob *, int> p : job.maskJobs )
1406 QImage *maskImage =
static_cast<QImage *
>( p.first ? p.first->maskPaintDevice.get() : labelJob.maskPaintDevices[p.second].get() );
1409 maskPainter = p.first ? p.first->maskPainter.get() : labelJob.maskPainters[ p.second ].get();
1413 maskPainter->drawImage( 0, 0, *maskImage );
1418 if ( ! job.maskJobs.isEmpty() )
1421 QPair<LayerRenderJob *, int> p = *job.maskJobs.begin();
1422 if ( isRasterRendering )
1424 QImage *maskImage =
static_cast<QImage *
>( p.first ? p.first->maskPaintDevice.get() : labelJob.maskPaintDevices[p.second].get() );
1427 QPainter *painter = job.context()->painter();
1429 painter->setCompositionMode( QPainter::CompositionMode_DestinationIn );
1434 QImage maskBinAlpha = maskImage->createMaskFromColor( 0 );
1435 QVector<QRgb> mswTable;
1436 mswTable.push_back( qRgba( 0, 0, 0, 255 ) );
1437 mswTable.push_back( qRgba( 0, 0, 0, 0 ) );
1438 maskBinAlpha.setColorTable( mswTable );
1439 painter->drawImage( 0, 0, maskBinAlpha );
1443 QPainter tempPainter;
1446 QPainter *painter1 = job.firstPassJob->context()->painter();
1449 tempPainter.begin( job.firstPassJob->img );
1450 painter1 = &tempPainter;
1454 painter1->setCompositionMode( QPainter::CompositionMode_DestinationOut );
1455 painter1->drawImage( 0, 0, *maskImage );
1458 painter1->setCompositionMode( QPainter::CompositionMode_DestinationOver );
1459 painter1->drawImage( 0, 0, *job.img );
1464 job.firstPassJob->picture = std::move( job.picture );
1465 job.picture =
nullptr;
1476 QMultiMap<int, QString> elapsed;
1477 for (
const LayerRenderJob &job : jobs )
1479 for (
const LayerRenderJob &job : secondPassJobs )
1480 elapsed.insert( job.
renderingTime, job.layerId + QString(
" (second pass)" ) );
1482 elapsed.insert( labelJob.renderingTime, tr(
"Labeling" ) );
1484 QList<int> tt( elapsed.uniqueKeys() );
1485 std::sort( tt.begin(), tt.end(), std::greater<int>() );
1486 for (
int t : std::as_const( tt ) )
1488 QgsMessageLog::logMessage( tr(
"%1 ms: %2" ).arg( t ).arg( QStringList( elapsed.values( t ) ).join( QLatin1String(
", " ) ) ), tr(
"Rendering" ) );
1497 std::unique_ptr< QgsScopedRuntimeProfile > labelingProfile;
1500 labelingProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr(
"(labeling)" ), QStringLiteral(
"rendering" ) );
1507 painter->setCompositionMode( QPainter::CompositionMode_SourceOver );
1511 if ( labelingEngine2 )
1513 labelingEngine2->
run( renderContext );
1516 QgsDebugMsgLevel( QStringLiteral(
"Draw labeling took (seconds): %1" ).arg( t.elapsed() / 1000. ), 2 );
1521 Q_UNUSED( settings )
1523 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.
@ 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 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 ...
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.
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.
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)
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).
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.
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.
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 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