From feabbe722ed9084b16ee9ba107d5d27bf615f1be Mon Sep 17 00:00:00 2001 From: Mathieu Pellerin Date: Sat, 6 Apr 2024 10:41:37 +0700 Subject: [PATCH] Address review --- .../qgsrasterlayertemporalproperties.sip.in | 62 +++--------------- .../qgsrasterlayertemporalproperties.sip.in | 62 +++--------------- src/core/raster/qgsrasterlayerrenderer.cpp | 8 ++- .../qgsrasterlayertemporalproperties.cpp | 44 +++++-------- .../raster/qgsrasterlayertemporalproperties.h | 53 ++++----------- src/core/raster/qgsrasterlayerutils.cpp | 2 +- ...qgsrasterlayertemporalpropertieswidget.cpp | 17 +++-- .../src/python/test_qgsrasterlayerrenderer.py | 52 +++++++++++++++ .../test_qgsrasterlayertemporalproperties.py | 34 ++++++---- ...cted_represents_temporal_values_filter.png | Bin 0 -> 471523 bytes ...d_represents_temporal_values_no_filter.png | Bin 0 -> 471523 bytes 11 files changed, 138 insertions(+), 196 deletions(-) create mode 100644 tests/testdata/control_images/rasterlayerrenderer/expected_represents_temporal_values_filter/expected_represents_temporal_values_filter.png create mode 100644 tests/testdata/control_images/rasterlayerrenderer/expected_represents_temporal_values_no_filter/expected_represents_temporal_values_no_filter.png diff --git a/python/PyQt6/core/auto_generated/raster/qgsrasterlayertemporalproperties.sip.in b/python/PyQt6/core/auto_generated/raster/qgsrasterlayertemporalproperties.sip.in index 65e50c481bb..606ace7eefd 100644 --- a/python/PyQt6/core/auto_generated/raster/qgsrasterlayertemporalproperties.sip.in +++ b/python/PyQt6/core/auto_generated/raster/qgsrasterlayertemporalproperties.sip.in @@ -142,28 +142,28 @@ Returns a filtered list of bands which match the specified ``range``. .. versionadded:: 3.38 %End - int temporalRepresentationBandNumber() const; + int bandNumber() const; %Docstring -Returns the band number from which the temporal values should be taken. +Returns the band number from which temporal values should be taken. .. note:: This is only considered when :py:func:`~QgsRasterLayerTemporalProperties.mode` is :py:class:`Qgis`.RasterTemporalMode.RepresentsTemporalValues. -.. seealso:: :py:func:`setTemporalRepresentationBandNumber` +.. seealso:: :py:func:`setBandNumber` .. versionadded:: 3.38 %End - void setTemporalRepresentationBandNumber( int number ); + void setBandNumber( int number ); %Docstring -Sets the band number from which the temporal values should be taken. +Sets the band number from which temporal values should be taken. .. note:: This is only considered when :py:func:`~QgsRasterLayerTemporalProperties.mode` is :py:class:`Qgis`.RasterTemporalMode.RepresentsTemporalValues. -.. seealso:: :py:func:`temporalRepresentationBandNumber` +.. seealso:: :py:func:`bandNumber` .. versionadded:: 3.38 %End @@ -196,9 +196,9 @@ from the layer. .. versionadded:: 3.38 %End - double temporalRepresentationScale() const; + QgsInterval temporalRepresentationScale() const; %Docstring -Returns the scale, which is a duration factor which should be applied to individual pixel +Returns the scale, which is an interval factor which should be applied to individual pixel values from the layer. .. note:: @@ -207,16 +207,12 @@ values from the layer. .. seealso:: :py:func:`setTemporalRepresentationScale` -.. seealso:: :py:func:`temporalRepresentationScaleUnit` - -.. seealso:: :py:func:`setTemporalRepresentationScaleUnit` - .. versionadded:: 3.38 %End - void setTemporalRepresentationScale( double scale ); + void setTemporalRepresentationScale( QgsInterval scale ); %Docstring -Sets the scale, which is a duration factor which should be applied to individual pixel +Sets the scale, which is an interval factor which should be applied to individual pixel values from the layer. .. note:: @@ -225,44 +221,6 @@ values from the layer. .. seealso:: :py:func:`temporalRepresentationScale` -.. seealso:: :py:func:`temporalRepresentationScaleUnit` - -.. seealso:: :py:func:`setTemporalRepresentationScaleUnit` - -.. versionadded:: 3.38 -%End - - Qgis::TemporalUnit temporalRepresentationScaleUnit() const; -%Docstring -Returns the scale's temporal unit type. - -.. note:: - - This is only considered when :py:func:`~QgsRasterLayerTemporalProperties.mode` is :py:class:`Qgis`.RasterTemporalMode.RepresentsTemporalValues. - -.. seealso:: :py:func:`setTemporalRepresentationScaleUnit` - -.. seealso:: :py:func:`temporalRepresentationScale` - -.. seealso:: :py:func:`setTemporalRepresentationScale` - -.. versionadded:: 3.38 -%End - - void setTemporalRepresentationScaleUnit( Qgis::TemporalUnit unit ); -%Docstring -Sets the scale's temporal unit type. - -.. note:: - - This is only considered when :py:func:`~QgsRasterLayerTemporalProperties.mode` is :py:class:`Qgis`.RasterTemporalMode.RepresentsTemporalValues. - -.. seealso:: :py:func:`temporalRepresentationScaleUnit` - -.. seealso:: :py:func:`temporalRepresentationScale` - -.. seealso:: :py:func:`setTemporalRepresentationScale` - .. versionadded:: 3.38 %End diff --git a/python/core/auto_generated/raster/qgsrasterlayertemporalproperties.sip.in b/python/core/auto_generated/raster/qgsrasterlayertemporalproperties.sip.in index 65e50c481bb..606ace7eefd 100644 --- a/python/core/auto_generated/raster/qgsrasterlayertemporalproperties.sip.in +++ b/python/core/auto_generated/raster/qgsrasterlayertemporalproperties.sip.in @@ -142,28 +142,28 @@ Returns a filtered list of bands which match the specified ``range``. .. versionadded:: 3.38 %End - int temporalRepresentationBandNumber() const; + int bandNumber() const; %Docstring -Returns the band number from which the temporal values should be taken. +Returns the band number from which temporal values should be taken. .. note:: This is only considered when :py:func:`~QgsRasterLayerTemporalProperties.mode` is :py:class:`Qgis`.RasterTemporalMode.RepresentsTemporalValues. -.. seealso:: :py:func:`setTemporalRepresentationBandNumber` +.. seealso:: :py:func:`setBandNumber` .. versionadded:: 3.38 %End - void setTemporalRepresentationBandNumber( int number ); + void setBandNumber( int number ); %Docstring -Sets the band number from which the temporal values should be taken. +Sets the band number from which temporal values should be taken. .. note:: This is only considered when :py:func:`~QgsRasterLayerTemporalProperties.mode` is :py:class:`Qgis`.RasterTemporalMode.RepresentsTemporalValues. -.. seealso:: :py:func:`temporalRepresentationBandNumber` +.. seealso:: :py:func:`bandNumber` .. versionadded:: 3.38 %End @@ -196,9 +196,9 @@ from the layer. .. versionadded:: 3.38 %End - double temporalRepresentationScale() const; + QgsInterval temporalRepresentationScale() const; %Docstring -Returns the scale, which is a duration factor which should be applied to individual pixel +Returns the scale, which is an interval factor which should be applied to individual pixel values from the layer. .. note:: @@ -207,16 +207,12 @@ values from the layer. .. seealso:: :py:func:`setTemporalRepresentationScale` -.. seealso:: :py:func:`temporalRepresentationScaleUnit` - -.. seealso:: :py:func:`setTemporalRepresentationScaleUnit` - .. versionadded:: 3.38 %End - void setTemporalRepresentationScale( double scale ); + void setTemporalRepresentationScale( QgsInterval scale ); %Docstring -Sets the scale, which is a duration factor which should be applied to individual pixel +Sets the scale, which is an interval factor which should be applied to individual pixel values from the layer. .. note:: @@ -225,44 +221,6 @@ values from the layer. .. seealso:: :py:func:`temporalRepresentationScale` -.. seealso:: :py:func:`temporalRepresentationScaleUnit` - -.. seealso:: :py:func:`setTemporalRepresentationScaleUnit` - -.. versionadded:: 3.38 -%End - - Qgis::TemporalUnit temporalRepresentationScaleUnit() const; -%Docstring -Returns the scale's temporal unit type. - -.. note:: - - This is only considered when :py:func:`~QgsRasterLayerTemporalProperties.mode` is :py:class:`Qgis`.RasterTemporalMode.RepresentsTemporalValues. - -.. seealso:: :py:func:`setTemporalRepresentationScaleUnit` - -.. seealso:: :py:func:`temporalRepresentationScale` - -.. seealso:: :py:func:`setTemporalRepresentationScale` - -.. versionadded:: 3.38 -%End - - void setTemporalRepresentationScaleUnit( Qgis::TemporalUnit unit ); -%Docstring -Sets the scale's temporal unit type. - -.. note:: - - This is only considered when :py:func:`~QgsRasterLayerTemporalProperties.mode` is :py:class:`Qgis`.RasterTemporalMode.RepresentsTemporalValues. - -.. seealso:: :py:func:`temporalRepresentationScaleUnit` - -.. seealso:: :py:func:`temporalRepresentationScale` - -.. seealso:: :py:func:`setTemporalRepresentationScale` - .. versionadded:: 3.38 %End diff --git a/src/core/raster/qgsrasterlayerrenderer.cpp b/src/core/raster/qgsrasterlayerrenderer.cpp index 0e5c4502429..7d3a16b2760 100644 --- a/src/core/raster/qgsrasterlayerrenderer.cpp +++ b/src/core/raster/qgsrasterlayerrenderer.cpp @@ -35,6 +35,7 @@ #include "qgsapplication.h" #include "qgsrastertransparency.h" #include "qgsrasterlayerutils.h" +#include "qgsinterval.h" #include "qgsunittypes.h" #include @@ -303,7 +304,7 @@ QgsRasterLayerRenderer::QgsRasterLayerRenderer( QgsRasterLayer *layer, QgsRender break; case Qgis::RasterTemporalMode::RepresentsTemporalValues: - if ( mPipe->renderer()->usesBands().contains( temporalProperties->temporalRepresentationBandNumber() ) ) + if ( mPipe->renderer()->usesBands().contains( temporalProperties->bandNumber() ) ) { // if layer has elevation settings and we are only rendering a temporal range => we need to filter pixels by temporal values std::unique_ptr< QgsRasterTransparency > transparency; @@ -314,8 +315,9 @@ QgsRasterLayerRenderer::QgsRasterLayerRenderer( QgsRasterLayer *layer, QgsRender QVector transparentPixels = transparency->transparentSingleValuePixelList(); - const double adjustedLower = static_cast< double >( temporalProperties->temporalRepresentationOffset().msecsTo( rendererContext.temporalRange().begin() ) ) * QgsUnitTypes::fromUnitToUnitFactor( Qgis::TemporalUnit::Milliseconds, temporalProperties->temporalRepresentationScaleUnit() ) / temporalProperties->temporalRepresentationScale(); - const double adjustedUpper = static_cast< double >( temporalProperties->temporalRepresentationOffset().msecsTo( rendererContext.temporalRange().end() ) ) * QgsUnitTypes::fromUnitToUnitFactor( Qgis::TemporalUnit::Milliseconds, temporalProperties->temporalRepresentationScaleUnit() ) / temporalProperties->temporalRepresentationScale(); + const QgsInterval scale = temporalProperties->temporalRepresentationScale(); + const double adjustedLower = static_cast< double >( temporalProperties->temporalRepresentationOffset().msecsTo( rendererContext.temporalRange().begin() ) ) * QgsUnitTypes::fromUnitToUnitFactor( Qgis::TemporalUnit::Milliseconds, scale.originalUnit() ) / scale.originalDuration(); + const double adjustedUpper = static_cast< double >( temporalProperties->temporalRepresentationOffset().msecsTo( rendererContext.temporalRange().end() ) ) * QgsUnitTypes::fromUnitToUnitFactor( Qgis::TemporalUnit::Milliseconds, scale.originalUnit() ) / scale.originalDuration(); transparentPixels.append( QgsRasterTransparency::TransparentSingleValuePixel( std::numeric_limits::lowest(), adjustedLower, 0, true, !rendererContext.zRange().includeLower() ) ); transparentPixels.append( QgsRasterTransparency::TransparentSingleValuePixel( adjustedUpper, std::numeric_limits::max(), 0, !rendererContext.zRange().includeUpper(), true ) ); diff --git a/src/core/raster/qgsrasterlayertemporalproperties.cpp b/src/core/raster/qgsrasterlayertemporalproperties.cpp index 564c37cc448..0aef20cfe85 100644 --- a/src/core/raster/qgsrasterlayertemporalproperties.cpp +++ b/src/core/raster/qgsrasterlayertemporalproperties.cpp @@ -22,6 +22,7 @@ QgsRasterLayerTemporalProperties::QgsRasterLayerTemporalProperties( QObject *parent, bool enabled ) : QgsMapLayerTemporalProperties( parent, enabled ) { + mTemporalRepresentationScale.setDays( 1.0 ); } bool QgsRasterLayerTemporalProperties::isVisibleInTemporalRange( const QgsDateTimeRange &range ) const @@ -236,7 +237,7 @@ int QgsRasterLayerTemporalProperties::bandForTemporalRange( QgsRasterLayer *, co } case Qgis::RasterTemporalMode::RepresentsTemporalValues: - return mTemporalRepresentationBandNumber; + return mBandNumber; } BUILTIN_UNREACHABLE } @@ -274,22 +275,22 @@ QList QgsRasterLayerTemporalProperties::filteredBandsForTemporalRange( QgsR } case Qgis::RasterTemporalMode::RepresentsTemporalValues: - return QList() << mTemporalRepresentationBandNumber; + return QList() << mBandNumber; } BUILTIN_UNREACHABLE } -int QgsRasterLayerTemporalProperties::temporalRepresentationBandNumber() const +int QgsRasterLayerTemporalProperties::bandNumber() const { - return mTemporalRepresentationBandNumber; + return mBandNumber; } -void QgsRasterLayerTemporalProperties::setTemporalRepresentationBandNumber( int number ) +void QgsRasterLayerTemporalProperties::setBandNumber( int number ) { - if ( mTemporalRepresentationBandNumber == number ) + if ( mBandNumber == number ) return; - mTemporalRepresentationBandNumber = number; + mBandNumber = number; } QDateTime QgsRasterLayerTemporalProperties::temporalRepresentationOffset() const @@ -305,12 +306,12 @@ void QgsRasterLayerTemporalProperties::setTemporalRepresentationOffset( const QD mTemporalRepresentationOffset = offset; } -double QgsRasterLayerTemporalProperties::temporalRepresentationScale() const +QgsInterval QgsRasterLayerTemporalProperties::temporalRepresentationScale() const { return mTemporalRepresentationScale; } -void QgsRasterLayerTemporalProperties::setTemporalRepresentationScale( double scale ) +void QgsRasterLayerTemporalProperties::setTemporalRepresentationScale( QgsInterval scale ) { if ( mTemporalRepresentationScale == scale ) return; @@ -318,19 +319,6 @@ void QgsRasterLayerTemporalProperties::setTemporalRepresentationScale( double sc mTemporalRepresentationScale = scale; } -Qgis::TemporalUnit QgsRasterLayerTemporalProperties::temporalRepresentationScaleUnit() const -{ - return mTemporalRepresentationScaleUnit; -} - -void QgsRasterLayerTemporalProperties::setTemporalRepresentationScaleUnit( Qgis::TemporalUnit unit ) -{ - if ( mTemporalRepresentationScaleUnit == unit ) - return; - - mTemporalRepresentationScaleUnit = unit; -} - bool QgsRasterLayerTemporalProperties::readXml( const QDomElement &element, const QgsReadWriteContext &context ) { Q_UNUSED( context ) @@ -341,6 +329,7 @@ bool QgsRasterLayerTemporalProperties::readXml( const QDomElement &element, cons setIsActive( temporalNode.attribute( QStringLiteral( "enabled" ), QStringLiteral( "0" ) ).toInt() ); mMode = static_cast< Qgis::RasterTemporalMode >( temporalNode.attribute( QStringLiteral( "mode" ), QStringLiteral( "0" ) ). toInt() ); + mBandNumber = temporalNode.attribute( QStringLiteral( "bandNumber" ), QStringLiteral( "1" ) ).toInt(); mIntervalHandlingMethod = static_cast< Qgis::TemporalIntervalMatchMethod >( temporalNode.attribute( QStringLiteral( "fetchMode" ), QStringLiteral( "0" ) ). toInt() ); switch ( mMode ) @@ -380,10 +369,9 @@ bool QgsRasterLayerTemporalProperties::readXml( const QDomElement &element, cons case Qgis::RasterTemporalMode::RepresentsTemporalValues: { - mTemporalRepresentationBandNumber = temporalNode.attribute( QStringLiteral( "temporalRepresentationBandNumber" ), QStringLiteral( "1" ) ).toInt(); mTemporalRepresentationOffset = QDateTime::fromString( temporalNode.attribute( QStringLiteral( "temporalRepresentationOffset" ) ), Qt::ISODate ); - mTemporalRepresentationScale = temporalNode.attribute( QStringLiteral( "temporalRepresentationScale" ), QStringLiteral( "1" ) ).toDouble(); - mTemporalRepresentationScaleUnit = static_cast< Qgis::TemporalUnit >( temporalNode.attribute( QStringLiteral( "temporalRepresentationScaleUnit" ), QStringLiteral( "4" ) ).toInt() ); + mTemporalRepresentationScale = QgsInterval( temporalNode.attribute( QStringLiteral( "temporalRepresentationScale" ), QStringLiteral( "1" ) ).toDouble(), + static_cast< Qgis::TemporalUnit >( temporalNode.attribute( QStringLiteral( "temporalRepresentationScaleUnit" ), QStringLiteral( "4" ) ).toInt() ) ); break; } @@ -404,6 +392,7 @@ QDomElement QgsRasterLayerTemporalProperties::writeXml( QDomElement &element, QD QDomElement temporalElement = document.createElement( QStringLiteral( "temporal" ) ); temporalElement.setAttribute( QStringLiteral( "enabled" ), isActive() ? QStringLiteral( "1" ) : QStringLiteral( "0" ) ); temporalElement.setAttribute( QStringLiteral( "mode" ), QString::number( static_cast< int >( mMode ) ) ); + temporalElement.setAttribute( QStringLiteral( "bandNumber" ), QString::number( mBandNumber ) ); temporalElement.setAttribute( QStringLiteral( "fetchMode" ), QString::number( static_cast< int >( mIntervalHandlingMethod ) ) ); switch ( mMode ) @@ -446,10 +435,9 @@ QDomElement QgsRasterLayerTemporalProperties::writeXml( QDomElement &element, QD case Qgis::RasterTemporalMode::RepresentsTemporalValues: { - temporalElement.setAttribute( QStringLiteral( "temporalRepresentationBandNumber" ), QString::number( mTemporalRepresentationBandNumber ) ); temporalElement.setAttribute( QStringLiteral( "temporalRepresentationOffset" ), mTemporalRepresentationOffset.toString( Qt::ISODate ) ); - temporalElement.setAttribute( QStringLiteral( "temporalRepresentationScale" ), QString::number( mTemporalRepresentationScale ) ); - temporalElement.setAttribute( QStringLiteral( "temporalRepresentationScaleUnit" ), QString::number( static_cast< int >( mTemporalRepresentationScaleUnit ) ) ); + temporalElement.setAttribute( QStringLiteral( "temporalRepresentationScale" ), QString::number( mTemporalRepresentationScale.originalDuration() ) ); + temporalElement.setAttribute( QStringLiteral( "temporalRepresentationScaleUnit" ), QString::number( static_cast< int >( mTemporalRepresentationScale.originalUnit() ) ) ); break; } diff --git a/src/core/raster/qgsrasterlayertemporalproperties.h b/src/core/raster/qgsrasterlayertemporalproperties.h index b6aa967e37f..166e1081a86 100644 --- a/src/core/raster/qgsrasterlayertemporalproperties.h +++ b/src/core/raster/qgsrasterlayertemporalproperties.h @@ -22,6 +22,7 @@ #include "qgis_core.h" #include "qgis_sip.h" #include "qgis.h" +#include "qgsinterval.h" #include "qgsrange.h" #include "qgsmaplayertemporalproperties.h" @@ -145,22 +146,22 @@ class CORE_EXPORT QgsRasterLayerTemporalProperties : public QgsMapLayerTemporalP QList< int > filteredBandsForTemporalRange( QgsRasterLayer *layer, const QgsDateTimeRange &range ) const; /** - * Returns the band number from which the temporal values should be taken. + * Returns the band number from which temporal values should be taken. * * \note This is only considered when mode() is Qgis::RasterTemporalMode::RepresentsTemporalValues. - * \see setTemporalRepresentationBandNumber() + * \see setBandNumber() * \since QGIS 3.38 */ - int temporalRepresentationBandNumber() const; + int bandNumber() const; /** - * Sets the band number from which the temporal values should be taken. + * Sets the band number from which temporal values should be taken. * * \note This is only considered when mode() is Qgis::RasterTemporalMode::RepresentsTemporalValues. - * \see temporalRepresentationBandNumber() + * \see bandNumber() * \since QGIS 3.38 */ - void setTemporalRepresentationBandNumber( int number ); + void setBandNumber( int number ); /** * Returns the temporal offset, which is a fixed datetime which should be added to individual pixel values @@ -183,50 +184,24 @@ class CORE_EXPORT QgsRasterLayerTemporalProperties : public QgsMapLayerTemporalP void setTemporalRepresentationOffset( const QDateTime &offset ); /** - * Returns the scale, which is a duration factor which should be applied to individual pixel + * Returns the scale, which is an interval factor which should be applied to individual pixel * values from the layer. * * \note This is only considered when mode() is Qgis::RasterTemporalMode::RepresentsTemporalValues. * \see setTemporalRepresentationScale() - * \see temporalRepresentationScaleUnit() - * \see setTemporalRepresentationScaleUnit() * \since QGIS 3.38 */ - double temporalRepresentationScale() const; + QgsInterval temporalRepresentationScale() const; /** - * Sets the scale, which is a duration factor which should be applied to individual pixel + * Sets the scale, which is an interval factor which should be applied to individual pixel * values from the layer. * * \note This is only considered when mode() is Qgis::RasterTemporalMode::RepresentsTemporalValues. * \see temporalRepresentationScale() - * \see temporalRepresentationScaleUnit() - * \see setTemporalRepresentationScaleUnit() * \since QGIS 3.38 */ - void setTemporalRepresentationScale( double scale ); - - /** - * Returns the scale's temporal unit type. - * - * \note This is only considered when mode() is Qgis::RasterTemporalMode::RepresentsTemporalValues. - * \see setTemporalRepresentationScaleUnit() - * \see temporalRepresentationScale() - * \see setTemporalRepresentationScale() - * \since QGIS 3.38 - */ - Qgis::TemporalUnit temporalRepresentationScaleUnit() const; - - /** - * Sets the scale's temporal unit type. - * - * \note This is only considered when mode() is Qgis::RasterTemporalMode::RepresentsTemporalValues. - * \see temporalRepresentationScaleUnit() - * \see temporalRepresentationScale() - * \see setTemporalRepresentationScale() - * \since QGIS 3.38 - */ - void setTemporalRepresentationScaleUnit( Qgis::TemporalUnit unit ); + void setTemporalRepresentationScale( QgsInterval scale ); QDomElement writeXml( QDomElement &element, QDomDocument &doc, const QgsReadWriteContext &context ) override; @@ -247,10 +222,10 @@ class CORE_EXPORT QgsRasterLayerTemporalProperties : public QgsMapLayerTemporalP QMap< int, QgsDateTimeRange > mRangePerBand; - int mTemporalRepresentationBandNumber = 1; + int mBandNumber = 1; + QDateTime mTemporalRepresentationOffset; - double mTemporalRepresentationScale = 1.0; - Qgis::TemporalUnit mTemporalRepresentationScaleUnit = Qgis::TemporalUnit::Days; + QgsInterval mTemporalRepresentationScale; }; #endif // QGSRASTERLAYERTEMPORALPROPERTIES_H diff --git a/src/core/raster/qgsrasterlayerutils.cpp b/src/core/raster/qgsrasterlayerutils.cpp index f5437c9fbc8..2ffd4d62845 100644 --- a/src/core/raster/qgsrasterlayerutils.cpp +++ b/src/core/raster/qgsrasterlayerutils.cpp @@ -72,7 +72,7 @@ int QgsRasterLayerUtils::renderedBandForElevationAndTemporalRange( case Qgis::RasterTemporalMode::RepresentsTemporalValues: { - temporalBands << temporalProperties->temporalRepresentationBandNumber(); + temporalBands << temporalProperties->bandNumber(); break; } } diff --git a/src/gui/raster/qgsrasterlayertemporalpropertieswidget.cpp b/src/gui/raster/qgsrasterlayertemporalpropertieswidget.cpp index f8c3feb1d9e..0e63cad44d5 100644 --- a/src/gui/raster/qgsrasterlayertemporalpropertieswidget.cpp +++ b/src/gui/raster/qgsrasterlayertemporalpropertieswidget.cpp @@ -115,6 +115,7 @@ void QgsRasterLayerTemporalPropertiesWidget::saveTemporalProperties() QgsRasterLayerTemporalProperties *temporalProperties = qobject_cast< QgsRasterLayerTemporalProperties * >( mLayer->temporalProperties() ); temporalProperties->setMode( mModeComboBox->currentData().value< Qgis::RasterTemporalMode >() ); + temporalProperties->setBandNumber( mBandComboBox->currentBand() ); const QgsDateTimeRange normalRange = QgsDateTimeRange( mStartTemporalDateTimeEdit->dateTime(), mEndTemporalDateTimeEdit->dateTime() ); @@ -124,10 +125,8 @@ void QgsRasterLayerTemporalPropertiesWidget::saveTemporalProperties() temporalProperties->setTemporalRepresentationOffset( mOffsetDateTimeEdit->dateTime() ); - temporalProperties->setTemporalRepresentationScale( mScaleSpinBox->value() ); - temporalProperties->setTemporalRepresentationScaleUnit( static_cast< Qgis::TemporalUnit >( mScaleUnitComboBox->currentData().toInt() ) ); - - temporalProperties->setTemporalRepresentationBandNumber( mBandComboBox->currentBand() ); + const QgsInterval scale( mScaleSpinBox->value(), static_cast< Qgis::TemporalUnit >( mScaleUnitComboBox->currentData().toInt() ) ); + temporalProperties->setTemporalRepresentationScale( scale ); for ( QgsMapLayerConfigWidget *widget : std::as_const( mExtraWidgets ) ) { @@ -158,6 +157,9 @@ void QgsRasterLayerTemporalPropertiesWidget::syncToLayer() break; } + mBandComboBox->setLayer( mLayer ); + mBandComboBox->setBand( temporalProperties->bandNumber() ); + mStartTemporalDateTimeEdit->setDateTime( temporalProperties->fixedTemporalRange().begin() ); mEndTemporalDateTimeEdit->setDateTime( temporalProperties->fixedTemporalRange().end() ); @@ -168,11 +170,8 @@ void QgsRasterLayerTemporalPropertiesWidget::syncToLayer() mOffsetDateTimeEdit->setDateTime( temporalProperties->temporalRepresentationOffset() ); - mScaleSpinBox->setValue( temporalProperties->temporalRepresentationScale() ); - mScaleUnitComboBox->setCurrentIndex( mScaleUnitComboBox->findData( static_cast< int >( temporalProperties->temporalRepresentationScaleUnit() ) ) ); - - mBandComboBox->setLayer( mLayer ); - mBandComboBox->setBand( temporalProperties->temporalRepresentationBandNumber() ); + mScaleSpinBox->setValue( temporalProperties->temporalRepresentationScale().originalDuration() ); + mScaleUnitComboBox->setCurrentIndex( mScaleUnitComboBox->findData( static_cast< int >( temporalProperties->temporalRepresentationScale().originalUnit() ) ) ); mTemporalGroupBox->setChecked( temporalProperties->isActive() ); diff --git a/tests/src/python/test_qgsrasterlayerrenderer.py b/tests/src/python/test_qgsrasterlayerrenderer.py index 727a55affca..222e7c6303a 100644 --- a/tests/src/python/test_qgsrasterlayerrenderer.py +++ b/tests/src/python/test_qgsrasterlayerrenderer.py @@ -21,6 +21,7 @@ from qgis.core import ( Qgis, QgsCoordinateReferenceSystem, QgsGeometry, + QgsInterval, QgsMapClippingRegion, QgsMapSettings, QgsRasterLayer, @@ -517,6 +518,57 @@ class TestQgsRasterLayerRenderer(QgisTestCase): map_settings) ) + def test_render_represents_temporal_values(self): + """ + Test rendering a raster with its temporal properties' mode set + to represents temporal values + """ + raster_layer = QgsRasterLayer(os.path.join(TEST_DATA_DIR, 'scaleoffset.tif')) + self.assertTrue(raster_layer.isValid()) + + renderer = QgsSingleBandGrayRenderer(raster_layer.dataProvider(), 1) + raster_layer.setRenderer(renderer) + + # set layer as temporal enabled + raster_layer.temporalProperties().setIsActive(True) + raster_layer.temporalProperties().setMode( + Qgis.RasterTemporalMode.RepresentsTemporalValues + ) + raster_layer.temporalProperties().setBandNumber(1) + raster_layer.temporalProperties().setTemporalRepresentationOffset(QDateTime(QDate(2024, 1, 1), QTime(0, 0, 0))) + raster_layer.temporalProperties().setTemporalRepresentationScale(QgsInterval(1, Qgis.TemporalUnit.Days)) + + map_settings = QgsMapSettings() + map_settings.setOutputSize(QSize(400, 400)) + map_settings.setOutputDpi(96) + map_settings.setDestinationCrs(raster_layer.crs()) + map_settings.setExtent(raster_layer.extent()) + map_settings.setLayers([raster_layer]) + + # no filter on map settings + map_settings.setIsTemporal(False) + self.assertTrue( + self.render_map_settings_check( + 'No temporal range filter on map settings on represents temporal values mode', + 'represents_temporal_values_no_filter', + map_settings) + ) + + # map settings matches part of the overall range + map_settings.setIsTemporal(True) + map_settings.setTemporalRange(QgsDateTimeRange( + QDateTime(QDate(2024, 1, 1), + QTime(0, 0, 0)), + QDateTime(QDate(2024, 1, 5), + QTime(23, 59, 59)) + )) + self.assertTrue( + self.render_map_settings_check( + 'Temporal range filter on map settings on represents temporal values mode', + 'represents_temporal_values_filter', + map_settings) + ) + if __name__ == '__main__': unittest.main() diff --git a/tests/src/python/test_qgsrasterlayertemporalproperties.py b/tests/src/python/test_qgsrasterlayertemporalproperties.py index e16af427eed..ac5588cd903 100644 --- a/tests/src/python/test_qgsrasterlayertemporalproperties.py +++ b/tests/src/python/test_qgsrasterlayertemporalproperties.py @@ -16,6 +16,7 @@ from qgis.PyQt.QtCore import ( from qgis.PyQt.QtXml import QDomDocument from qgis.core import ( Qgis, + QgsInterval, QgsRasterLayerTemporalProperties, QgsReadWriteContext, QgsDateTimeRange @@ -281,23 +282,33 @@ class TestQgsRasterLayerTemporalProperties(QgisTestCase): props.setMode(Qgis.RasterTemporalMode.RepresentsTemporalValues) self.assertEqual(props.mode(), Qgis.RasterTemporalMode.RepresentsTemporalValues) - self.assertEqual(props.temporalRepresentationScale(), 1) - self.assertEqual(props.temporalRepresentationScaleUnit(), Qgis.TemporalUnit.Days) + self.assertEqual(props.bandNumber(), 1) + self.assertEqual(props.temporalRepresentationScale(), QgsInterval(1, Qgis.TemporalUnit.Days)) self.assertEqual(props.temporalRepresentationOffset(), QDateTime()) - self.assertEqual(props.temporalRepresentationBandNumber(), 1) self.assertFalse(props.isActive()) - props.setTemporalRepresentationScale(2.5) - props.setTemporalRepresentationScaleUnit(Qgis.TemporalUnit.Weeks) + props.setBandNumber(2) + props.setTemporalRepresentationScale(QgsInterval(2.5, Qgis.TemporalUnit.Weeks)) props.setTemporalRepresentationOffset(QDateTime(QDate(2024, 1, 1), QTime(0, 0, 0))) - props.setTemporalRepresentationBandNumber(2) props.setIsActive(True) - self.assertEqual(props.temporalRepresentationScale(), 2.5) - self.assertEqual(props.temporalRepresentationScaleUnit(), Qgis.TemporalUnit.Weeks) + self.assertEqual(props.bandNumber(), 2) + self.assertEqual(props.temporalRepresentationScale(), QgsInterval(2.5, Qgis.TemporalUnit.Weeks)) self.assertEqual(props.temporalRepresentationOffset(), QDateTime(QDate(2024, 1, 1), QTime(0, 0, 0))) - self.assertEqual(props.temporalRepresentationBandNumber(), 2) self.assertTrue(props.isActive()) + self.assertEqual(props.bandForTemporalRange(None, QgsDateTimeRange( + QDateTime(QDate(2023, 5, 3), + QTime(12, 13, 14)), + QDateTime(QDate(2023, 5, 4), + QTime(12, 13, 14)) + )), 2) + self.assertEqual(props.filteredBandsForTemporalRange(None, QgsDateTimeRange( + QDateTime(QDate(2023, 5, 3), + QTime(12, 13, 14)), + QDateTime(QDate(2023, 5, 4), + QTime(12, 13, 14)) + )), [2]) + doc = QDomDocument("testdoc") elem = doc.createElement('test') props.writeXml(elem, doc, QgsReadWriteContext()) @@ -306,10 +317,9 @@ class TestQgsRasterLayerTemporalProperties(QgisTestCase): props2.readXml(elem, QgsReadWriteContext()) self.assertEqual(props2.mode(), Qgis.RasterTemporalMode.RepresentsTemporalValues) - self.assertEqual(props2.temporalRepresentationScale(), 2.5) - self.assertEqual(props2.temporalRepresentationScaleUnit(), Qgis.TemporalUnit.Weeks) + self.assertEqual(props.bandNumber(), 2) + self.assertEqual(props2.temporalRepresentationScale(), QgsInterval(2.5, Qgis.TemporalUnit.Weeks)) self.assertEqual(props2.temporalRepresentationOffset(), QDateTime(QDate(2024, 1, 1), QTime(0, 0, 0))) - self.assertEqual(props2.temporalRepresentationBandNumber(), 2) self.assertTrue(props2.isActive()) diff --git a/tests/testdata/control_images/rasterlayerrenderer/expected_represents_temporal_values_filter/expected_represents_temporal_values_filter.png b/tests/testdata/control_images/rasterlayerrenderer/expected_represents_temporal_values_filter/expected_represents_temporal_values_filter.png new file mode 100644 index 0000000000000000000000000000000000000000..ebd0fd00bcdfdc84baf630bf9f033c1083269f7b GIT binary patch literal 471523 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 Yb{stQyubbS)rxzsy>8>sHJ`ipe}~ZQK>z>% literal 0 HcmV?d00001