Skip to content

Commit

Permalink
Ensure temporal and elevation filters work correctly in conjunction
Browse files Browse the repository at this point in the history
Fixes #56938
  • Loading branch information
nyalldawson committed Mar 25, 2024
1 parent 5bc06fe commit 94bef54
Show file tree
Hide file tree
Showing 14 changed files with 800 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,13 @@ Returns the band corresponding to the specified ``range``.
This is only considered when :py:func:`~QgsRasterLayerTemporalProperties.mode` is :py:class:`Qgis`.RasterTemporalMode.FixedRangePerBand.
For other modes it will always return -1.

.. versionadded:: 3.38
%End

QList< int > filteredBandsForTemporalRange( QgsRasterLayer *layer, const QgsDateTimeRange &range ) const;
%Docstring
Returns a filtered list of bands which match the specified ``range``.

.. versionadded:: 3.38
%End

Expand Down
53 changes: 53 additions & 0 deletions python/PyQt6/core/auto_generated/raster/qgsrasterlayerutils.sip.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/raster/qgsrasterlayerutils.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/





class QgsRasterLayerUtils
{
%Docstring(signature="appended")
Contains utility functions for working with raster layers.

.. versionadded:: 3.38
%End

%TypeHeaderCode
#include "qgsrasterlayerutils.h"
%End
public:

static int renderedBandForElevationAndTemporalRange(
QgsRasterLayer *layer,
const QgsDateTimeRange &temporalRange,
const QgsDoubleRange &elevationRange,
bool &matched /Out/ );
%Docstring
Given a raster ``layer``, returns the band which should be used for
rendering the layer for a specified temporal and elevation range,
respecting any elevation and temporal settings which affect the rendered band.

:param layer: Target raster layer
:param temporalRange: temporal range for rendering
:param elevationRange: elevation range for rendering

:return: - Matched band, or -1 if the layer does not have any elevation
- matched: will be set to ``True`` if a band matching the temporal and elevation range was found
or temporal settings which affect the rendered band.
%End

};

/************************************************************************
* This file has been generated automatically from *
* *
* src/core/raster/qgsrasterlayerutils.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
1 change: 1 addition & 0 deletions python/PyQt6/core/core_auto.sip
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,7 @@
%Include auto_generated/raster/qgsrasterlayer.sip
%Include auto_generated/raster/qgsrasterlayerelevationproperties.sip
%Include auto_generated/raster/qgsrasterlayertemporalproperties.sip
%Include auto_generated/raster/qgsrasterlayerutils.sip
%Include auto_generated/raster/qgsrasterminmaxorigin.sip
%Include auto_generated/raster/qgsrasternuller.sip
%Include auto_generated/raster/qgsrasterpipe.sip
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,13 @@ Returns the band corresponding to the specified ``range``.
This is only considered when :py:func:`~QgsRasterLayerTemporalProperties.mode` is :py:class:`Qgis`.RasterTemporalMode.FixedRangePerBand.
For other modes it will always return -1.

.. versionadded:: 3.38
%End

QList< int > filteredBandsForTemporalRange( QgsRasterLayer *layer, const QgsDateTimeRange &range ) const;
%Docstring
Returns a filtered list of bands which match the specified ``range``.

.. versionadded:: 3.38
%End

Expand Down
53 changes: 53 additions & 0 deletions python/core/auto_generated/raster/qgsrasterlayerutils.sip.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/raster/qgsrasterlayerutils.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/





class QgsRasterLayerUtils
{
%Docstring(signature="appended")
Contains utility functions for working with raster layers.

.. versionadded:: 3.38
%End

%TypeHeaderCode
#include "qgsrasterlayerutils.h"
%End
public:

static int renderedBandForElevationAndTemporalRange(
QgsRasterLayer *layer,
const QgsDateTimeRange &temporalRange,
const QgsDoubleRange &elevationRange,
bool &matched /Out/ );
%Docstring
Given a raster ``layer``, returns the band which should be used for
rendering the layer for a specified temporal and elevation range,
respecting any elevation and temporal settings which affect the rendered band.

:param layer: Target raster layer
:param temporalRange: temporal range for rendering
:param elevationRange: elevation range for rendering

:return: - Matched band, or -1 if the layer does not have any elevation
- matched: will be set to ``True`` if a band matching the temporal and elevation range was found
or temporal settings which affect the rendered band.
%End

};

/************************************************************************
* This file has been generated automatically from *
* *
* src/core/raster/qgsrasterlayerutils.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
1 change: 1 addition & 0 deletions python/core/core_auto.sip
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,7 @@
%Include auto_generated/raster/qgsrasterlayer.sip
%Include auto_generated/raster/qgsrasterlayerelevationproperties.sip
%Include auto_generated/raster/qgsrasterlayertemporalproperties.sip
%Include auto_generated/raster/qgsrasterlayerutils.sip
%Include auto_generated/raster/qgsrasterminmaxorigin.sip
%Include auto_generated/raster/qgsrasternuller.sip
%Include auto_generated/raster/qgsrasterpipe.sip
Expand Down
2 changes: 2 additions & 0 deletions src/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -759,6 +759,7 @@ set(QGIS_CORE_SRCS
raster/qgsrasterlayerprofilegenerator.cpp
raster/qgsrasterlayerrenderer.cpp
raster/qgsrasterlayertemporalproperties.cpp
raster/qgsrasterlayerutils.cpp
raster/qgsrasterminmaxorigin.cpp
raster/qgsrasternuller.cpp
raster/qgsrasterpipe.cpp
Expand Down Expand Up @@ -1861,6 +1862,7 @@ set(QGIS_CORE_HDRS
raster/qgsrasterlayerprofilegenerator.h
raster/qgsrasterlayerrenderer.h
raster/qgsrasterlayertemporalproperties.h
raster/qgsrasterlayerutils.h
raster/qgsrasterminmaxorigin.h
raster/qgsrasternuller.h
raster/qgsrasterpipe.h
Expand Down
53 changes: 26 additions & 27 deletions src/core/raster/qgsrasterlayerrenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include "qgsruntimeprofiler.h"
#include "qgsapplication.h"
#include "qgsrastertransparency.h"
#include "qgsrasterlayerutils.h"

#include <QElapsedTimer>
#include <QPointer>
Expand Down Expand Up @@ -272,26 +273,33 @@ QgsRasterLayerRenderer::QgsRasterLayerRenderer( QgsRasterLayer *layer, QgsRender
mPipe->evaluateDataDefinedProperties( rendererContext.expressionContext() );

const QgsRasterLayerTemporalProperties *temporalProperties = qobject_cast< const QgsRasterLayerTemporalProperties * >( layer->temporalProperties() );
const QgsRasterLayerElevationProperties *elevationProperties = qobject_cast<QgsRasterLayerElevationProperties *>( layer->elevationProperties() );

if ( ( temporalProperties->isActive() && renderContext()->isTemporal() )
|| ( elevationProperties->hasElevation() && !renderContext()->zRange().isInfinite() ) )
{
// temporal and/or elevation band filtering may be applicable
bool matched = false;
const int matchedBand = QgsRasterLayerUtils::renderedBandForElevationAndTemporalRange(
layer,
rendererContext.temporalRange(),
rendererContext.zRange(),
matched
);
if ( matched && matchedBand > 0 )
{
mPipe->renderer()->setInputBand( matchedBand );
}
}

if ( temporalProperties->isActive() && renderContext()->isTemporal() )
{
switch ( temporalProperties->mode() )
{
case Qgis::RasterTemporalMode::FixedTemporalRange:
case Qgis::RasterTemporalMode::RedrawLayerOnly:
break;

case Qgis::RasterTemporalMode::FixedRangePerBand:
{
const int matchingBand = temporalProperties->bandForTemporalRange( layer, rendererContext.temporalRange() );

// this is guaranteed, as we won't ever be creating a renderer if this condition is not met, but let's be ultra safe!
if ( matchingBand > 0 )
{
mPipe->renderer()->setInputBand( matchingBand );
}

break;
}

case Qgis::RasterTemporalMode::TemporalRangeFromDataProvider:
// in this mode we need to pass on the desired render temporal range to the data provider
Expand All @@ -311,17 +319,16 @@ QgsRasterLayerRenderer::QgsRasterLayerRenderer( QgsRasterLayer *layer, QgsRender

mClippingRegions = QgsMapClippingUtils::collectClippingRegionsForLayer( *renderContext(), layer );

if ( layer->elevationProperties() && layer->elevationProperties()->hasElevation() )
if ( elevationProperties && elevationProperties->hasElevation() )
{
QgsRasterLayerElevationProperties *elevProp = qobject_cast<QgsRasterLayerElevationProperties *>( layer->elevationProperties() );
mDrawElevationMap = true;
mElevationScale = elevProp->zScale();
mElevationOffset = elevProp->zOffset();
mElevationBand = elevProp->bandNumber();
mElevationScale = elevationProperties->zScale();
mElevationOffset = elevationProperties->zOffset();
mElevationBand = elevationProperties->bandNumber();

if ( !rendererContext.zRange().isInfinite() )
{
switch ( elevProp->mode() )
switch ( elevationProperties->mode() )
{
case Qgis::RasterElevationMode::FixedElevationRange:
// don't need to handle anything here -- the layer renderer will never be created if the
Expand All @@ -330,16 +337,8 @@ QgsRasterLayerRenderer::QgsRasterLayerRenderer( QgsRasterLayer *layer, QgsRender

case Qgis::RasterElevationMode::FixedRangePerBand:
case Qgis::RasterElevationMode::DynamicRangePerBand:
{
const int matchingBand = elevProp->bandForElevationRange( layer, rendererContext.zRange() );

// this is guaranteed, as we won't ever be creating a renderer if this condition is not met, but let's be ultra safe!
if ( matchingBand > 0 )
{
mPipe->renderer()->setInputBand( matchingBand );
}
// temporal/elevation band based filtering was already handled earlier in this method
break;
}

case Qgis::RasterElevationMode::RepresentsElevationSurface:
{
Expand Down
35 changes: 35 additions & 0 deletions src/core/raster/qgsrasterlayertemporalproperties.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,41 @@ int QgsRasterLayerTemporalProperties::bandForTemporalRange( QgsRasterLayer *, co
BUILTIN_UNREACHABLE
}

QList<int> QgsRasterLayerTemporalProperties::filteredBandsForTemporalRange( QgsRasterLayer *layer, const QgsDateTimeRange &range ) const
{
switch ( mMode )
{
case Qgis::RasterTemporalMode::FixedTemporalRange:
case Qgis::RasterTemporalMode::TemporalRangeFromDataProvider:
case Qgis::RasterTemporalMode::RedrawLayerOnly:
{
const int bandCount = layer->bandCount();
QList< int > res;
res.reserve( bandCount );
for ( int i = 1; i <= bandCount; ++i )
res.append( i );
return res;
}

case Qgis::RasterTemporalMode::FixedRangePerBand:
{
QList<int> res;
res.reserve( mRangePerBand.size() );
// find the latest-most band which matches the map range
QgsDateTimeRange currentMatchingRange;
for ( auto it = mRangePerBand.constBegin(); it != mRangePerBand.constEnd(); ++it )
{
if ( it.value().overlaps( range ) )
{
res.append( it.key() );
}
}
return res;
}
}
BUILTIN_UNREACHABLE
}

bool QgsRasterLayerTemporalProperties::readXml( const QDomElement &element, const QgsReadWriteContext &context )
{
Q_UNUSED( context )
Expand Down
7 changes: 7 additions & 0 deletions src/core/raster/qgsrasterlayertemporalproperties.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,13 @@ class CORE_EXPORT QgsRasterLayerTemporalProperties : public QgsMapLayerTemporalP
*/
int bandForTemporalRange( QgsRasterLayer *layer, const QgsDateTimeRange &range ) const;

/**
* Returns a filtered list of bands which match the specified \a range.
*
* \since QGIS 3.38
*/
QList< int > filteredBandsForTemporalRange( QgsRasterLayer *layer, const QgsDateTimeRange &range ) const;

QDomElement writeXml( QDomElement &element, QDomDocument &doc, const QgsReadWriteContext &context ) override;

bool readXml( const QDomElement &element, const QgsReadWriteContext &context ) override;
Expand Down
Loading

0 comments on commit 94bef54

Please sign in to comment.