Skip to content

Commit

Permalink
If a wms-t layer is the first temporal layer loaded into a project,
Browse files Browse the repository at this point in the history
use the wms-t capabilities to set a sensible default time step
for the temporal controller (just like we do for mesh layers)
  • Loading branch information
nyalldawson committed Mar 25, 2021
1 parent 89491b5 commit 929b708
Show file tree
Hide file tree
Showing 9 changed files with 114 additions and 27 deletions.
Expand Up @@ -120,6 +120,26 @@ extent of datetime values available for reference temporal ranges from the provi
%Docstring
Returns the requested temporal range.
Intended to be used by the provider in fetching data.
%End

QgsInterval defaultInterval() const;
%Docstring
Returns the default time step interval corresponding to the available
datetime values for the provider.

.. seealso:: :py:func:`setDefaultInterval`

.. versionadded:: 3.20
%End

void setDefaultInterval( const QgsInterval &interval );
%Docstring
Sets the default time step ``interval`` corresponding to the available
datetime values for the provider.

.. seealso:: :py:func:`defaultInterval`

.. versionadded:: 3.20
%End

};
Expand Down
5 changes: 5 additions & 0 deletions src/core/qgstemporalutils.cpp
Expand Up @@ -278,6 +278,11 @@ QList<QDateTime> QgsTemporalUtils::calculateDateTimesFromISO8601( const QString
// QgsTimeDuration
//

QgsInterval QgsTimeDuration::toInterval() const
{
return QgsInterval( years, months, weeks, days, hours, minutes, seconds );
}

QString QgsTimeDuration::toString() const
{
QString text( "P" );
Expand Down
5 changes: 5 additions & 0 deletions src/core/qgstemporalutils.h
Expand Up @@ -77,6 +77,11 @@ class CORE_EXPORT QgsTimeDuration
return !( *this == other );
}

/**
* Converts the duration to an interval value.
*/
QgsInterval toInterval() const;

/**
* Converts the duration to an ISO8601 duration string.
*/
Expand Down
10 changes: 10 additions & 0 deletions src/core/raster/qgsrasterdataprovidertemporalcapabilities.cpp
Expand Up @@ -63,6 +63,16 @@ void QgsRasterDataProviderTemporalCapabilities::setRequestedTemporalRange( const
mRequestedRange = dateTimeRange;
}

QgsInterval QgsRasterDataProviderTemporalCapabilities::defaultInterval() const
{
return mDefaultInterval;
}

void QgsRasterDataProviderTemporalCapabilities::setDefaultInterval( const QgsInterval &defaultInterval )
{
mDefaultInterval = defaultInterval;
}

const QgsDateTimeRange &QgsRasterDataProviderTemporalCapabilities::requestedTemporalRange() const
{
return mRequestedRange;
Expand Down
21 changes: 21 additions & 0 deletions src/core/raster/qgsrasterdataprovidertemporalcapabilities.h
Expand Up @@ -21,6 +21,7 @@
#include "qgis_core.h"
#include "qgis_sip.h"
#include "qgsrange.h"
#include "qgsinterval.h"
#include "qgsdataprovidertemporalcapabilities.h"

/**
Expand Down Expand Up @@ -134,6 +135,24 @@ class CORE_EXPORT QgsRasterDataProviderTemporalCapabilities : public QgsDataProv
*/
const QgsDateTimeRange &requestedTemporalRange() const;

/**
* Returns the default time step interval corresponding to the available
* datetime values for the provider.
*
* \see setDefaultInterval()
* \since QGIS 3.20
*/
QgsInterval defaultInterval() const;

/**
* Sets the default time step \a interval corresponding to the available
* datetime values for the provider.
*
* \see defaultInterval()
* \since QGIS 3.20
*/
void setDefaultInterval( const QgsInterval &interval );

private:

/**
Expand Down Expand Up @@ -172,6 +191,8 @@ class CORE_EXPORT QgsRasterDataProviderTemporalCapabilities : public QgsDataProv
*/
QgsDateTimeRange mAvailableReferenceRange;

QgsInterval mDefaultInterval;

//! Interval handling method
IntervalHandlingMethod mIntervalMatchMethod = MatchUsingWholeRange;

Expand Down
74 changes: 47 additions & 27 deletions src/gui/qgstemporalcontrollerwidget.cpp
Expand Up @@ -25,6 +25,9 @@
#include "qgstemporalutils.h"
#include "qgsmaplayertemporalproperties.h"
#include "qgsmeshlayer.h"
#include "qgsrasterlayer.h"
#include "qgsrasterdataprovider.h"
#include "qgsrasterdataprovidertemporalcapabilities.h"

#include <QAction>
#include <QMenu>
Expand Down Expand Up @@ -443,14 +446,23 @@ void QgsTemporalControllerWidget::firstTemporalLayerLoaded( QgsMapLayer *layer )
{
setDatesToProjectTime();

QgsMeshLayer *meshLayer = qobject_cast<QgsMeshLayer *>( layer );
if ( meshLayer )
if ( QgsMeshLayer *meshLayer = qobject_cast<QgsMeshLayer *>( layer ) )
{
mBlockFrameDurationUpdates++;
setTimeStep( meshLayer->firstValidTimeStep() );
mBlockFrameDurationUpdates--;
updateFrameDuration();
}
else if ( QgsRasterLayer *rasterLayer = qobject_cast<QgsRasterLayer *>( layer ) )
{
if ( rasterLayer->dataProvider() && rasterLayer->dataProvider()->temporalCapabilities() )
{
mBlockFrameDurationUpdates++;
setTimeStep( rasterLayer->dataProvider()->temporalCapabilities()->defaultInterval() );
mBlockFrameDurationUpdates--;
updateFrameDuration();
}
}
}

void QgsTemporalControllerWidget::onProjectCleared()
Expand Down Expand Up @@ -560,38 +572,46 @@ void QgsTemporalControllerWidget::setTimeStep( const QgsInterval &timeStep )
if ( ! timeStep.isValid() || timeStep.seconds() <= 0 )
return;

// Search the time unit the most appropriate :
// the one that gives the smallest time step value for double spin box with round value (if possible) and/or the less signifiant digits

int selectedUnit = -1;
int stringSize = std::numeric_limits<int>::max();
int precision = mStepSpinBox->decimals();
double selectedValue = std::numeric_limits<double>::max();
for ( int i = 0; i < mTimeStepsComboBox->count(); ++i )
if ( timeStep.originalUnit() != QgsUnitTypes::TemporalIrregularStep )
{
QgsUnitTypes::TemporalUnit unit = static_cast<QgsUnitTypes::TemporalUnit>( mTimeStepsComboBox->itemData( i ).toInt() );
double value = timeStep.seconds() * QgsUnitTypes::fromUnitToUnitFactor( QgsUnitTypes::TemporalSeconds, unit );
QString string = QString::number( value, 'f', precision );
string.remove( QRegExp( "0+$" ) ); //remove trailing zero
string.remove( QRegExp( "[.]+$" ) ); //remove last point if present
// Search the time unit the most appropriate :
// the one that gives the smallest time step value for double spin box with round value (if possible) and/or the less signifiant digits

if ( value >= 1
&& string.size() <= stringSize // less significant digit than currently selected
&& value < selectedValue ) // less than currently selected
{
selectedUnit = i;
selectedValue = value;
stringSize = string.size();
}
else if ( string != '0'
&& string.size() < precision + 2 //round value (ex: 0.xx with precision=3)
&& string.size() < stringSize ) //less significant digit than currently selected
int stringSize = std::numeric_limits<int>::max();
int precision = mStepSpinBox->decimals();
for ( int i = 0; i < mTimeStepsComboBox->count(); ++i )
{
selectedUnit = i ;
selectedValue = value ;
stringSize = string.size();
QgsUnitTypes::TemporalUnit unit = static_cast<QgsUnitTypes::TemporalUnit>( mTimeStepsComboBox->itemData( i ).toInt() );
double value = timeStep.seconds() * QgsUnitTypes::fromUnitToUnitFactor( QgsUnitTypes::TemporalSeconds, unit );
QString string = QString::number( value, 'f', precision );
string.remove( QRegExp( "0+$" ) ); //remove trailing zero
string.remove( QRegExp( "[.]+$" ) ); //remove last point if present

if ( value >= 1
&& string.size() <= stringSize // less significant digit than currently selected
&& value < selectedValue ) // less than currently selected
{
selectedUnit = i;
selectedValue = value;
stringSize = string.size();
}
else if ( string != '0'
&& string.size() < precision + 2 //round value (ex: 0.xx with precision=3)
&& string.size() < stringSize ) //less significant digit than currently selected
{
selectedUnit = i ;
selectedValue = value ;
stringSize = string.size();
}
}
}
else
{
selectedUnit = mTimeStepsComboBox->findData( static_cast< int >( timeStep.originalUnit() ) );
selectedValue = 1;
}

if ( selectedUnit >= 0 )
{
Expand Down
3 changes: 3 additions & 0 deletions src/providers/wms/qgswmscapabilities.cpp
Expand Up @@ -124,10 +124,13 @@ bool QgsWmsSettings::parseUri( const QString &uriString )
{
mAllRanges.append( QgsDateTimeRange( begin, end ) );
}

mDefaultInterval = extent.resolution.toInterval();
}
else
{
mAllRanges.append( QgsDateTimeRange( begin, end ) );
mDefaultInterval = QgsInterval( 1, QgsUnitTypes::TemporalIrregularStep );
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/providers/wms/qgswmscapabilities.h
Expand Up @@ -786,6 +786,8 @@ class QgsWmsSettings
//! All available temporal ranges
QList< QgsDateTimeRange > mAllRanges;

QgsInterval mDefaultInterval;

//! Fixed reference temporal range for the data provider
QgsDateTimeRange mFixedReferenceRange;

Expand Down
1 change: 1 addition & 0 deletions src/providers/wms/qgswmsprovider.cpp
Expand Up @@ -173,6 +173,7 @@ QgsWmsProvider::QgsWmsProvider( QString const &uri, const ProviderOptions &optio
temporalCapabilities()->setHasTemporalCapabilities( true );
temporalCapabilities()->setAvailableTemporalRange( mSettings.mFixedRange );
temporalCapabilities()->setAllAvailableTemporalRanges( mSettings.mAllRanges );
temporalCapabilities()->setDefaultInterval( mSettings.mDefaultInterval );

temporalCapabilities()->setIntervalHandlingMethod(
QgsRasterDataProviderTemporalCapabilities::MatchExactUsingStartOfRange );
Expand Down

0 comments on commit 929b708

Please sign in to comment.