Skip to content

Commit

Permalink
Ensure label cache is invalidated when a vector layer renderer
Browse files Browse the repository at this point in the history
affects the labeling and is re-drawn
  • Loading branch information
nyalldawson committed Sep 12, 2024
1 parent 39eb87a commit 84c11f5
Show file tree
Hide file tree
Showing 16 changed files with 64 additions and 6 deletions.
5 changes: 5 additions & 0 deletions python/PyQt6/core/auto_additions/qgis.py
Original file line number Diff line number Diff line change
Expand Up @@ -4809,12 +4809,17 @@
# monkey patching scoped based enum
Qgis.MapLayerRendererFlag.RenderPartialOutputs.__doc__ = "The renderer benefits from rendering temporary in-progress preview renders. These are temporary results which will be used for the layer during rendering in-progress compositions, which will differ from the final layer render. They can be used for showing overlays or other information to users which help inform them about what is actually occurring during a slow layer render, but where these overlays and additional content is not wanted in the final layer renders. Another use case is rendering unsorted results as soon as they are available, before doing a final sorted render of the entire layer contents."
Qgis.MapLayerRendererFlag.RenderPartialOutputOverPreviousCachedImage.__doc__ = "When rendering temporary in-progress preview renders, these preview renders can be drawn over any previously cached layer render we have for the same region. This can allow eg a low-resolution zoomed in version of the last map render to be used as a base painting surface to overdraw with incremental preview render outputs. If not set, an empty image will be used as the starting point for the render preview image."
Qgis.MapLayerRendererFlag.AffectsLabeling.__doc__ = "The layer rendering will interact with the map labeling \n.. versionadded:: 3.40"
Qgis.MapLayerRendererFlag.__doc__ = """Flags which control how map layer renderers behave.

.. versionadded:: 3.34

* ``RenderPartialOutputs``: The renderer benefits from rendering temporary in-progress preview renders. These are temporary results which will be used for the layer during rendering in-progress compositions, which will differ from the final layer render. They can be used for showing overlays or other information to users which help inform them about what is actually occurring during a slow layer render, but where these overlays and additional content is not wanted in the final layer renders. Another use case is rendering unsorted results as soon as they are available, before doing a final sorted render of the entire layer contents.
* ``RenderPartialOutputOverPreviousCachedImage``: When rendering temporary in-progress preview renders, these preview renders can be drawn over any previously cached layer render we have for the same region. This can allow eg a low-resolution zoomed in version of the last map render to be used as a base painting surface to overdraw with incremental preview render outputs. If not set, an empty image will be used as the starting point for the render preview image.
* ``AffectsLabeling``: The layer rendering will interact with the map labeling

.. versionadded:: 3.40


"""
# --
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,8 @@ emitted when asynchronous rendering is finished (or canceled).








Expand Down
1 change: 1 addition & 0 deletions python/PyQt6/core/auto_generated/qgis.sip.in
Original file line number Diff line number Diff line change
Expand Up @@ -1532,6 +1532,7 @@ The development version
{
RenderPartialOutputs,
RenderPartialOutputOverPreviousCachedImage,
AffectsLabeling,
};

typedef QFlags<Qgis::MapLayerRendererFlag> MapLayerRendererFlags;
Expand Down
5 changes: 5 additions & 0 deletions python/core/auto_additions/qgis.py
Original file line number Diff line number Diff line change
Expand Up @@ -4760,12 +4760,17 @@
# monkey patching scoped based enum
Qgis.MapLayerRendererFlag.RenderPartialOutputs.__doc__ = "The renderer benefits from rendering temporary in-progress preview renders. These are temporary results which will be used for the layer during rendering in-progress compositions, which will differ from the final layer render. They can be used for showing overlays or other information to users which help inform them about what is actually occurring during a slow layer render, but where these overlays and additional content is not wanted in the final layer renders. Another use case is rendering unsorted results as soon as they are available, before doing a final sorted render of the entire layer contents."
Qgis.MapLayerRendererFlag.RenderPartialOutputOverPreviousCachedImage.__doc__ = "When rendering temporary in-progress preview renders, these preview renders can be drawn over any previously cached layer render we have for the same region. This can allow eg a low-resolution zoomed in version of the last map render to be used as a base painting surface to overdraw with incremental preview render outputs. If not set, an empty image will be used as the starting point for the render preview image."
Qgis.MapLayerRendererFlag.AffectsLabeling.__doc__ = "The layer rendering will interact with the map labeling \n.. versionadded:: 3.40"
Qgis.MapLayerRendererFlag.__doc__ = """Flags which control how map layer renderers behave.

.. versionadded:: 3.34

* ``RenderPartialOutputs``: The renderer benefits from rendering temporary in-progress preview renders. These are temporary results which will be used for the layer during rendering in-progress compositions, which will differ from the final layer render. They can be used for showing overlays or other information to users which help inform them about what is actually occurring during a slow layer render, but where these overlays and additional content is not wanted in the final layer renders. Another use case is rendering unsorted results as soon as they are available, before doing a final sorted render of the entire layer contents.
* ``RenderPartialOutputOverPreviousCachedImage``: When rendering temporary in-progress preview renders, these preview renders can be drawn over any previously cached layer render we have for the same region. This can allow eg a low-resolution zoomed in version of the last map render to be used as a base painting surface to overdraw with incremental preview render outputs. If not set, an empty image will be used as the starting point for the render preview image.
* ``AffectsLabeling``: The layer rendering will interact with the map labeling

.. versionadded:: 3.40


"""
# --
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,8 @@ emitted when asynchronous rendering is finished (or canceled).








Expand Down
1 change: 1 addition & 0 deletions python/core/auto_generated/qgis.sip.in
Original file line number Diff line number Diff line change
Expand Up @@ -1532,6 +1532,7 @@ The development version
{
RenderPartialOutputs,
RenderPartialOutputOverPreviousCachedImage,
AffectsLabeling,
};

typedef QFlags<Qgis::MapLayerRendererFlag> MapLayerRendererFlags;
Expand Down
2 changes: 1 addition & 1 deletion src/core/labeling/qgspallabeling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3974,7 +3974,7 @@ bool QgsPalLabeling::staticWillUseLayer( const QgsMapLayer *layer )
case Qgis::LayerType::Vector:
{
const QgsVectorLayer *vl = qobject_cast< const QgsVectorLayer * >( layer );
return vl->labelsEnabled() || vl->diagramsEnabled();
return vl->labelsEnabled() || vl->diagramsEnabled() || ( vl->renderer() && vl->renderer()->flags().testFlag( Qgis::FeatureRendererFlag::AffectsLabeling ) );
}

case Qgis::LayerType::VectorTile:
Expand Down
2 changes: 1 addition & 1 deletion src/core/maprenderer/qgsmaprenderercustompainterjob.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@ void QgsMapRendererCustomPainterJob::doRender()

mLabelJob.complete = true;
mLabelJob.renderingTime = labelTime.elapsed();
mLabelJob.participatingLayers = _qgis_listRawToQPointer( mLabelingEngineV2->participatingLayers() );
mLabelJob.participatingLayers = participatingLabelLayers( mLabelingEngineV2.get() );
}
}

Expand Down
18 changes: 18 additions & 0 deletions src/core/maprenderer/qgsmaprendererjob.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -625,6 +625,11 @@ std::vector<LayerRenderJob> QgsMapRendererJob::prepareJobs( QPainter *painter, Q
{
job.renderer->setLayerRenderingTimeHint( job.estimatedRenderingTime );
job.context()->setFeedback( job.renderer->feedback() );

if ( job.renderer->flags().testFlag( Qgis::MapLayerRendererFlag::AffectsLabeling ) )
{
mAdditionalLabelLayers.append( ml );
}
}

// If we are drawing with an alternative blending mode then we need to render to a separate image
Expand Down Expand Up @@ -994,6 +999,19 @@ std::vector< LayerRenderJob > QgsMapRendererJob::prepareSecondPassJobs( std::vec
return secondPassJobs;
}

QList<QPointer<QgsMapLayer> > QgsMapRendererJob::participatingLabelLayers( QgsLabelingEngine *engine )
{
QList<QPointer<QgsMapLayer> > res = _qgis_listRawToQPointer( engine->participatingLayers() );

for ( auto it : std::as_const( mAdditionalLabelLayers ) )
{
if ( !res.contains( it ) )
res.append( it );
}

return res;
}

void QgsMapRendererJob::initSecondPassJobs( std::vector< LayerRenderJob > &secondPassJobs, LabelRenderJob &labelJob ) const
{
if ( !mapSettings().testFlag( Qgis::MapSettingsFlag::ForceVectorOutput ) || mapSettings().testFlag( Qgis::MapSettingsFlag::ForceRasterMasks ) )
Expand Down
14 changes: 14 additions & 0 deletions src/core/maprenderer/qgsmaprendererjob.h
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,11 @@ class CORE_EXPORT QgsMapRendererJob : public QObject SIP_ABSTRACT
*/
QHash< QString, int > mLayerRenderingTimeHints;

/**
* Additional layers participating in labeling problem
*/
QList< QPointer< QgsMapLayer > > mAdditionalLabelLayers;

/**
* TRUE if layer rendering time should be recorded.
*/
Expand Down Expand Up @@ -587,6 +592,15 @@ class CORE_EXPORT QgsMapRendererJob : public QObject SIP_ABSTRACT
*/
std::vector< LayerRenderJob > prepareSecondPassJobs( std::vector< LayerRenderJob > &firstPassJobs, LabelRenderJob &labelJob ) SIP_SKIP;

/**
* Returns a list of the layers participating in the map labeling.
*
* \note Not available in Python bindings.
*
* \since QGIS 3.40
*/
QList< QPointer< QgsMapLayer > > participatingLabelLayers( QgsLabelingEngine *engine ) SIP_SKIP;

/**
* Initialize \a secondPassJobs according to what have been rendered (mask clipping path e.g.) in first pass jobs and \a labelJob.
* \since QGIS 3.26
Expand Down
2 changes: 1 addition & 1 deletion src/core/maprenderer/qgsmaprendererparalleljob.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,7 @@ void QgsMapRendererParallelJob::renderLabelsStatic( QgsMapRendererParallelJob *s

job.renderingTime = labelTime.elapsed();
job.complete = true;
job.participatingLayers = _qgis_listRawToQPointer( self->mLabelingEngineV2->participatingLayers() );
job.participatingLayers = self->participatingLabelLayers( self->mLabelingEngineV2.get() );
if ( job.img )
{
self->mFinalImage = composeImage( self->mSettings, self->mLayerJobs, self->mLabelJob );
Expand Down
2 changes: 1 addition & 1 deletion src/core/maprenderer/qgsmaprendererstagedrenderjob.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ bool QgsMapRendererStagedRenderJob::renderCurrentPart( QPainter *painter )
mLabelJob.context.setPainter( painter );
drawLabeling( mLabelJob.context, mLabelingEngineV2.get(), painter );
mLabelJob.complete = true;
mLabelJob.participatingLayers = _qgis_listRawToQPointer( mLabelingEngineV2->participatingLayers() );
mLabelJob.participatingLayers = participatingLabelLayers( mLabelingEngineV2.get() );
mLabelJob.context.setPainter( nullptr );
}
}
Expand Down
1 change: 1 addition & 0 deletions src/core/qgis.h
Original file line number Diff line number Diff line change
Expand Up @@ -2589,6 +2589,7 @@ class CORE_EXPORT Qgis
{
RenderPartialOutputs = 1 << 0, //!< The renderer benefits from rendering temporary in-progress preview renders. These are temporary results which will be used for the layer during rendering in-progress compositions, which will differ from the final layer render. They can be used for showing overlays or other information to users which help inform them about what is actually occurring during a slow layer render, but where these overlays and additional content is not wanted in the final layer renders. Another use case is rendering unsorted results as soon as they are available, before doing a final sorted render of the entire layer contents.
RenderPartialOutputOverPreviousCachedImage = 1 << 1,//!< When rendering temporary in-progress preview renders, these preview renders can be drawn over any previously cached layer render we have for the same region. This can allow eg a low-resolution zoomed in version of the last map render to be used as a base painting surface to overdraw with incremental preview render outputs. If not set, an empty image will be used as the starting point for the render preview image.
AffectsLabeling = 1 << 2, //!< The layer rendering will interact with the map labeling \since QGIS 3.40
};
Q_ENUM( MapLayerRendererFlag )

Expand Down
8 changes: 8 additions & 0 deletions src/core/vector/qgsvectorlayerrenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,14 @@ bool QgsVectorLayerRenderer::forceRasterRender() const
return mForceRasterRender;
}

Qgis::MapLayerRendererFlags QgsVectorLayerRenderer::flags() const
{
Qgis::MapLayerRendererFlags res;
if ( mRenderer && mRenderer->flags().testFlag( Qgis::FeatureRendererFlag::AffectsLabeling ) )
res.setFlag( Qgis::MapLayerRendererFlag::AffectsLabeling );
return res;
}

bool QgsVectorLayerRenderer::render()
{
if ( mGeometryType == Qgis::GeometryType::Null || mGeometryType == Qgis::GeometryType::Unknown )
Expand Down
1 change: 1 addition & 0 deletions src/core/vector/qgsvectorlayerrenderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ class QgsVectorLayerRenderer : public QgsMapLayerRenderer
~QgsVectorLayerRenderer() override;
QgsFeedback *feedback() const override;
bool forceRasterRender() const override;
Qgis::MapLayerRendererFlags flags() const override;

/**
* Returns the feature renderer.
Expand Down
4 changes: 2 additions & 2 deletions src/gui/qgsmapcanvas.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1077,7 +1077,7 @@ void QgsMapCanvas::clearTemporalCache()
{
if ( QgsVectorLayer *vl = qobject_cast< QgsVectorLayer * >( layer ) )
{
if ( vl->labelsEnabled() || vl->diagramsEnabled() )
if ( vl->labelsEnabled() || vl->diagramsEnabled() || ( vl->renderer() && vl->renderer()->flags().testFlag( Qgis::FeatureRendererFlag::AffectsLabeling ) ) )
invalidateLabels = true;
}

Expand Down Expand Up @@ -1126,7 +1126,7 @@ void QgsMapCanvas::clearElevationCache()
{
if ( QgsVectorLayer *vl = qobject_cast< QgsVectorLayer * >( layer ) )
{
if ( vl->labelsEnabled() || vl->diagramsEnabled() )
if ( vl->labelsEnabled() || vl->diagramsEnabled() || ( vl->renderer() && vl->renderer()->flags().testFlag( Qgis::FeatureRendererFlag::AffectsLabeling ) ) )
invalidateLabels = true;
}

Expand Down

0 comments on commit 84c11f5

Please sign in to comment.