diff --git a/python/core/auto_generated/mesh/qgsmeshdataprovider.sip.in b/python/core/auto_generated/mesh/qgsmeshdataprovider.sip.in index 5ea0fbc78bb..1fd1d03bc86 100644 --- a/python/core/auto_generated/mesh/qgsmeshdataprovider.sip.in +++ b/python/core/auto_generated/mesh/qgsmeshdataprovider.sip.in @@ -417,6 +417,7 @@ Constructs an empty metadata object double minimum, double maximum, int maximumVerticalLevels, + const QDateTime &referenceTime, const QMap &extraOptions ); %Docstring Constructs a valid metadata object @@ -427,6 +428,7 @@ Constructs a valid metadata object :param minimum: minimum value (magnitude for vectors) present among all group's dataset values :param maximum: maximum value (magnitude for vectors) present among all group's dataset values :param maximumVerticalLevels: maximum number of vertical levels for 3d stacked meshes, 0 for 2d meshes +:param referenceTime: reference time of the dataset group :param extraOptions: dataset's extra options stored by the provider. Usually contains the name, time value, time units, data file vendor, ... %End @@ -471,6 +473,13 @@ Returns maximum scalar value/vector magnitude present for whole dataset group %Docstring Returns maximum number of vertical levels for 3d stacked meshes +.. versionadded:: 3.12 +%End + + QDateTime referenceTime() const; +%Docstring +Returns the reference time + .. versionadded:: 3.12 %End diff --git a/python/core/auto_generated/mesh/qgsmeshtimesettings.sip.in b/python/core/auto_generated/mesh/qgsmeshtimesettings.sip.in index 33935738bc1..90061ffa0f6 100644 --- a/python/core/auto_generated/mesh/qgsmeshtimesettings.sip.in +++ b/python/core/auto_generated/mesh/qgsmeshtimesettings.sip.in @@ -23,10 +23,20 @@ Represents a mesh time settings for mesh datasets #include "qgsmeshtimesettings.h" %End public: + + enum TimeUnit + { + //! second unit + seconds, + //! minute unit + minutes, + //! hour unit + hours, + //! day unit + days + }; + QgsMeshTimeSettings(); -%Docstring -Default constructor for relative time format and 0 offset -%End QgsMeshTimeSettings( double relativeTimeOffsetHours, const QString &relativeTimeFormat ); %Docstring Constructs relative time format settings with defined offset in hours @@ -88,6 +98,20 @@ Returns format used for absolute time void setAbsoluteTimeFormat( const QString &absoluteTimeFormat ); %Docstring Sets format used for absolute time +%End + + TimeUnit providerTimeUnit() const; +%Docstring +Returns the provider time unit + +.. versionadded:: 3.12 +%End + + void setProviderTimeUnit( const TimeUnit &providerTimeUnit ); +%Docstring +Sets the provider time unit + +.. versionadded:: 3.12 %End }; diff --git a/src/app/mesh/qgsmeshrendereractivedatasetwidget.cpp b/src/app/mesh/qgsmeshrendereractivedatasetwidget.cpp index 98e42d41911..64906bda9f3 100644 --- a/src/app/mesh/qgsmeshrendereractivedatasetwidget.cpp +++ b/src/app/mesh/qgsmeshrendereractivedatasetwidget.cpp @@ -120,6 +120,7 @@ void QgsMeshRendererActiveDatasetWidget::setTimeRange() // update combobox mTimeComboBox->blockSignals( true ); + int currentIndex = mTimeComboBox->currentIndex(); mTimeComboBox->clear(); if ( groupWithMaximumDatasets > -1 ) { @@ -131,8 +132,9 @@ void QgsMeshRendererActiveDatasetWidget::setTimeRange() mTimeComboBox->addItem( mMeshLayer->formatTime( time ), time ); } } + mTimeComboBox->setCurrentIndex( currentIndex ); mTimeComboBox->blockSignals( false ); - + updateMetadata(); // enable/disable time controls depending on whether the data set is time varying enableTimeControls(); } diff --git a/src/app/mesh/qgsmeshtimeformatdialog.cpp b/src/app/mesh/qgsmeshtimeformatdialog.cpp index 74525c44505..ee51f58edb4 100644 --- a/src/app/mesh/qgsmeshtimeformatdialog.cpp +++ b/src/app/mesh/qgsmeshtimeformatdialog.cpp @@ -17,6 +17,7 @@ #include "qgsmeshtimeformatdialog.h" #include "qgsgui.h" #include "qgsmeshtimesettings.h" +#include "qgsmeshlayerutils.h" QgsMeshTimeFormatDialog::QgsMeshTimeFormatDialog( QgsMeshLayer *meshLayer, QWidget *parent, Qt::WindowFlags f ) : QDialog( parent, f ), @@ -30,14 +31,24 @@ QgsMeshTimeFormatDialog::QgsMeshTimeFormatDialog( QgsMeshLayer *meshLayer, QWidg loadSettings(); + mReloadReferenceTimeButton->setEnabled( layerHasReferenceTime() ); + connect( mUseTimeComboBox, qgis::overload::of( &QComboBox::currentIndexChanged ), this, &QgsMeshTimeFormatDialog::saveSettings ); - connect( mReferenceDateTimeEdit, &QDateTimeEdit::timeChanged, this, &QgsMeshTimeFormatDialog::saveSettings ); + connect( mReferenceDateTimeEdit, &QDateTimeEdit::dateTimeChanged, this, &QgsMeshTimeFormatDialog::saveSettings ); connect( mAbsoluteTimeFormatComboBox, qgis::overload::of( &QComboBox::currentIndexChanged ), this, &QgsMeshTimeFormatDialog::saveSettings ); connect( mUseTimeComboBox, qgis::overload::of( &QComboBox::currentIndexChanged ), this, &QgsMeshTimeFormatDialog::saveSettings ); connect( mRelativeTimeFormatComboBox, qgis::overload::of( &QComboBox::currentIndexChanged ), this, &QgsMeshTimeFormatDialog::saveSettings ); connect( mOffsetHoursSpinBox, qgis::overload::of( &QDoubleSpinBox::valueChanged ), this, &QgsMeshTimeFormatDialog::saveSettings ); connect( mPlaybackIntervalSpinBox, qgis::overload::of( &QDoubleSpinBox::valueChanged ), this, &QgsMeshTimeFormatDialog::saveSettings ); + connect( mProviderTimeUnitComboBox, qgis::overload::of( &QComboBox::currentIndexChanged ), this, &QgsMeshTimeFormatDialog::saveSettings ); + connect( mReloadReferenceTimeButton, &QPushButton::clicked, this, &QgsMeshTimeFormatDialog::loadProviderReferenceTime ); + +} + +void QgsMeshTimeFormatDialog::loadProviderReferenceTime() +{ + mReferenceDateTimeEdit->setDateTime( QgsMeshLayerUtils::firstReferenceTime( mLayer ) ); } void QgsMeshTimeFormatDialog::loadSettings() @@ -54,7 +65,12 @@ void QgsMeshTimeFormatDialog::loadSettings() mUseTimeComboBox->setCurrentIndex( 1 ); } - mReferenceDateTimeEdit->setDateTime( settings.absoluteTimeReferenceTime() ); + // Sets the reference time, if not valid, sets the current date + time 00:00:00 + if ( settings.absoluteTimeReferenceTime().isValid() ) + mReferenceDateTimeEdit->setDateTime( settings.absoluteTimeReferenceTime() ); + else + mReferenceDateTimeEdit->setDateTime( QDateTime( QDate::currentDate(), QTime( 00, 00, 00 ) ) ); + mReferenceDateTimeEdit->setDisplayFormat( settings.absoluteTimeFormat() ); int index = mAbsoluteTimeFormatComboBox->findText( settings.absoluteTimeFormat() ); @@ -75,6 +91,8 @@ void QgsMeshTimeFormatDialog::loadSettings() mOffsetHoursSpinBox->setValue( settings.relativeTimeOffsetHours() ); mPlaybackIntervalSpinBox->setValue( settings.datasetPlaybackInterval() ); + + mProviderTimeUnitComboBox->setCurrentIndex( settings.providerTimeUnit() ); } void QgsMeshTimeFormatDialog::saveSettings() @@ -86,6 +104,7 @@ void QgsMeshTimeFormatDialog::saveSettings() settings.setRelativeTimeOffsetHours( mOffsetHoursSpinBox->value() ); settings.setRelativeTimeFormat( mRelativeTimeFormatComboBox->currentText() ); settings.setDatasetPlaybackInterval( mPlaybackIntervalSpinBox->value() ); + settings.setProviderTimeUnit( static_cast( mProviderTimeUnitComboBox->currentIndex() ) ); enableGroups( settings.useAbsoluteTime() ) ; mLayer->setTimeSettings( settings ); } @@ -96,4 +115,9 @@ void QgsMeshTimeFormatDialog::enableGroups( bool useAbsoluteTime ) mRelativeTimeGroupBox->setEnabled( ! useAbsoluteTime ); } +bool QgsMeshTimeFormatDialog::layerHasReferenceTime() const +{ + return QgsMeshLayerUtils::firstReferenceTime( mLayer ).isValid(); +} + QgsMeshTimeFormatDialog::~QgsMeshTimeFormatDialog() = default; diff --git a/src/app/mesh/qgsmeshtimeformatdialog.h b/src/app/mesh/qgsmeshtimeformatdialog.h index 4791a1f1617..91ec6002e82 100644 --- a/src/app/mesh/qgsmeshtimeformatdialog.h +++ b/src/app/mesh/qgsmeshtimeformatdialog.h @@ -39,12 +39,14 @@ class APP_EXPORT QgsMeshTimeFormatDialog: public QDialog, private Ui::QgsMeshTim ~QgsMeshTimeFormatDialog(); private slots: - + void loadProviderReferenceTime(); private: void loadSettings(); void saveSettings(); void enableGroups( bool useAbsoluteTime ); + bool layerHasReferenceTime() const; + QgsMeshLayer *mLayer; }; diff --git a/src/core/mesh/qgsmeshdataprovider.cpp b/src/core/mesh/qgsmeshdataprovider.cpp index 047b11aaabb..f087ae4d4f4 100644 --- a/src/core/mesh/qgsmeshdataprovider.cpp +++ b/src/core/mesh/qgsmeshdataprovider.cpp @@ -133,6 +133,7 @@ QgsMeshDatasetGroupMetadata::QgsMeshDatasetGroupMetadata( const QString &name, double minimum, double maximum, int maximumVerticalLevels, + const QDateTime &referenceTime, const QMap &extraOptions ) : mName( name ) , mIsScalar( isScalar ) @@ -141,6 +142,7 @@ QgsMeshDatasetGroupMetadata::QgsMeshDatasetGroupMetadata( const QString &name, , mMaximumValue( maximum ) , mExtraOptions( extraOptions ) , mMaximumVerticalLevelsCount( maximumVerticalLevels ) + , mReferenceTime( referenceTime ) { } @@ -184,6 +186,11 @@ int QgsMeshDatasetGroupMetadata::maximumVerticalLevelsCount() const return mMaximumVerticalLevelsCount; } +QDateTime QgsMeshDatasetGroupMetadata::referenceTime() const +{ + return mReferenceTime; +} + int QgsMeshDatasetSourceInterface::datasetCount( QgsMeshDatasetIndex index ) const { return datasetCount( index.group() ); diff --git a/src/core/mesh/qgsmeshdataprovider.h b/src/core/mesh/qgsmeshdataprovider.h index fc723b03857..bcbc08e3610 100644 --- a/src/core/mesh/qgsmeshdataprovider.h +++ b/src/core/mesh/qgsmeshdataprovider.h @@ -388,6 +388,7 @@ class CORE_EXPORT QgsMeshDatasetGroupMetadata * \param minimum minimum value (magnitude for vectors) present among all group's dataset values * \param maximum maximum value (magnitude for vectors) present among all group's dataset values * \param maximumVerticalLevels maximum number of vertical levels for 3d stacked meshes, 0 for 2d meshes + * \param referenceTime reference time of the dataset group * \param extraOptions dataset's extra options stored by the provider. Usually contains the name, time value, time units, data file vendor, ... */ QgsMeshDatasetGroupMetadata( const QString &name, @@ -396,6 +397,7 @@ class CORE_EXPORT QgsMeshDatasetGroupMetadata double minimum, double maximum, int maximumVerticalLevels, + const QDateTime &referenceTime, const QMap &extraOptions ); /** @@ -442,6 +444,13 @@ class CORE_EXPORT QgsMeshDatasetGroupMetadata */ int maximumVerticalLevelsCount() const; + /** + * Returns the reference time + * + * \since QGIS 3.12 + */ + QDateTime referenceTime() const; + private: QString mName; bool mIsScalar = false; @@ -450,6 +459,7 @@ class CORE_EXPORT QgsMeshDatasetGroupMetadata double mMaximumValue = std::numeric_limits::quiet_NaN(); QMap mExtraOptions; int mMaximumVerticalLevelsCount = 0; // for 3d stacked meshes + QDateTime mReferenceTime; }; /** diff --git a/src/core/mesh/qgsmeshlayer.cpp b/src/core/mesh/qgsmeshlayer.cpp index 33214fd967c..e74ad2b8b3d 100644 --- a/src/core/mesh/qgsmeshlayer.cpp +++ b/src/core/mesh/qgsmeshlayer.cpp @@ -531,6 +531,13 @@ bool QgsMeshLayer::setDataProvider( QString const &provider, const QgsDataProvid mDataSource = mDataSource + QStringLiteral( "&uid=%1" ).arg( QUuid::createUuid().toString() ); } + QDateTime referenceTime = QgsMeshLayerUtils::firstReferenceTime( this ); + if ( referenceTime.isValid() ) + { + mTimeSettings.setAbsoluteTimeReferenceTime( referenceTime ); + mTimeSettings.setUseAbsoluteTime( true ); + } + for ( int i = 0; i < mDataProvider->datasetGroupCount(); ++i ) assignDefaultStyleToDatasetGroup( i ); diff --git a/src/core/mesh/qgsmeshlayerutils.cpp b/src/core/mesh/qgsmeshlayerutils.cpp index dc8fc08b09c..3fa86d87097 100644 --- a/src/core/mesh/qgsmeshlayerutils.cpp +++ b/src/core/mesh/qgsmeshlayerutils.cpp @@ -260,6 +260,22 @@ QgsRectangle QgsMeshLayerUtils::triangleBoundingBox( const QgsPointXY &p1, const QString QgsMeshLayerUtils::formatTime( double hours, const QgsMeshTimeSettings &settings ) { QString ret; + + switch ( settings.providerTimeUnit() ) + { + case QgsMeshTimeSettings::seconds: + hours = hours / 3600.0; + break; + case QgsMeshTimeSettings::minutes: + hours = hours / 60.0; + break; + case QgsMeshTimeSettings::hours: + break; + case QgsMeshTimeSettings::days: + hours = hours * 24.0; + break; + } + if ( settings.useAbsoluteTime() ) { QString format( settings.absoluteTimeFormat() ); @@ -346,4 +362,25 @@ QString QgsMeshLayerUtils::formatTime( double hours, const QgsMeshTimeSettings & return ret; } +QDateTime QgsMeshLayerUtils::firstReferenceTime( QgsMeshLayer *meshLayer ) +{ + if ( !meshLayer ) + return QDateTime(); + + QgsMeshDataProvider *provider = meshLayer->dataProvider(); + + if ( !provider ) + return QDateTime(); + + // Searches for the first valid reference time in the dataset groups + for ( int i = 0; i < provider->datasetGroupCount(); ++i ) + { + QgsMeshDatasetGroupMetadata meta = provider->datasetGroupMetadata( i ); + if ( meta.referenceTime().isValid() ) + return meta.referenceTime(); + } + + return QDateTime(); +} + ///@endcond diff --git a/src/core/mesh/qgsmeshlayerutils.h b/src/core/mesh/qgsmeshlayerutils.h index c01d6359c2f..82efd055c8d 100644 --- a/src/core/mesh/qgsmeshlayerutils.h +++ b/src/core/mesh/qgsmeshlayerutils.h @@ -178,6 +178,15 @@ class CORE_EXPORT QgsMeshLayerUtils * Formats hours in human readable string based on settings */ static QString formatTime( double hours, const QgsMeshTimeSettings &settings ); + + /** + * Searches and returns the first valid reference time in layer's dataset group + * \param meshLayer mesh layer to parse + * + * \since QGIS 3.12 + */ + static QDateTime firstReferenceTime( QgsMeshLayer *meshLayer ); + }; ///@endcond diff --git a/src/core/mesh/qgsmeshtimesettings.cpp b/src/core/mesh/qgsmeshtimesettings.cpp index 07a28e45a2c..f3f82518015 100644 --- a/src/core/mesh/qgsmeshtimesettings.cpp +++ b/src/core/mesh/qgsmeshtimesettings.cpp @@ -40,6 +40,7 @@ QDomElement QgsMeshTimeSettings::writeXml( QDomDocument &doc, const QgsReadWrite elem.setAttribute( QStringLiteral( "relative-time-format" ), mRelativeTimeFormat ); elem.setAttribute( QStringLiteral( "absolute-time-reference-time" ), mAbsoluteTimeReferenceTime.toString() ); elem.setAttribute( QStringLiteral( "absolute-time-format" ), mAbsoluteTimeFormat ); + elem.setAttribute( QStringLiteral( "provider-time-unit" ), mProviderTimeUnit ); return elem; } @@ -51,6 +52,7 @@ void QgsMeshTimeSettings::readXml( const QDomElement &elem, const QgsReadWriteCo mRelativeTimeFormat = elem.attribute( QStringLiteral( "relative-time-format" ) ); mAbsoluteTimeReferenceTime = QDateTime::fromString( elem.attribute( QStringLiteral( "absolute-time-reference-time" ) ) ); mAbsoluteTimeFormat = elem.attribute( QStringLiteral( "absolute-time-format" ) ); + mProviderTimeUnit = static_cast( elem.attribute( QStringLiteral( "provider-time-unit" ) ).toInt() ); } bool QgsMeshTimeSettings::useAbsoluteTime() const @@ -113,3 +115,13 @@ void QgsMeshTimeSettings::setAbsoluteTimeFormat( const QString &absoluteTimeForm { mAbsoluteTimeFormat = absoluteTimeFormat; } + +QgsMeshTimeSettings::TimeUnit QgsMeshTimeSettings::providerTimeUnit() const +{ + return mProviderTimeUnit; +} + +void QgsMeshTimeSettings::setProviderTimeUnit( const QgsMeshTimeSettings::TimeUnit &providerTimeUnit ) +{ + mProviderTimeUnit = providerTimeUnit; +} diff --git a/src/core/mesh/qgsmeshtimesettings.h b/src/core/mesh/qgsmeshtimesettings.h index 8e3b6c6034c..db95b3081db 100644 --- a/src/core/mesh/qgsmeshtimesettings.h +++ b/src/core/mesh/qgsmeshtimesettings.h @@ -35,7 +35,23 @@ class CORE_EXPORT QgsMeshTimeSettings { public: - //! Default constructor for relative time format and 0 offset + + /** + * Time units used to display time + * \since QGIS 3.12 + */ + enum TimeUnit + { + //! second unit + seconds = 0, + //! minute unit + minutes, + //! hour unit + hours, + //! day unit + days + }; + QgsMeshTimeSettings(); //! Constructs relative time format settings with defined offset in hours QgsMeshTimeSettings( double relativeTimeOffsetHours, const QString &relativeTimeFormat ); @@ -84,6 +100,18 @@ class CORE_EXPORT QgsMeshTimeSettings //! Sets format used for absolute time void setAbsoluteTimeFormat( const QString &absoluteTimeFormat ); + /** + * Returns the provider time unit + * \since QGIS 3.12 + */ + TimeUnit providerTimeUnit() const; + + /** + * Sets the provider time unit + * \since QGIS 3.12 + */ + void setProviderTimeUnit( const TimeUnit &providerTimeUnit ); + private: bool mUseAbsoluteTime = false; @@ -93,6 +121,8 @@ class CORE_EXPORT QgsMeshTimeSettings QDateTime mAbsoluteTimeReferenceTime; QString mAbsoluteTimeFormat = QStringLiteral( "dd.MM.yyyy hh:mm:ss" ); + + TimeUnit mProviderTimeUnit = TimeUnit::hours; }; Q_DECLARE_METATYPE( QgsMeshTimeSettings ); diff --git a/src/core/providers/meshmemory/qgsmeshmemorydataprovider.cpp b/src/core/providers/meshmemory/qgsmeshmemorydataprovider.cpp index 8b4981183d5..d307af2518a 100644 --- a/src/core/providers/meshmemory/qgsmeshmemorydataprovider.cpp +++ b/src/core/providers/meshmemory/qgsmeshmemorydataprovider.cpp @@ -387,6 +387,7 @@ QgsMeshDatasetGroupMetadata QgsMeshMemoryDatasetGroup::groupMetadata() const minimum, maximum, 0, + QDateTime(), metadata ); } diff --git a/src/providers/mdal/qgsmdalprovider.cpp b/src/providers/mdal/qgsmdalprovider.cpp index 0bd8c73515a..2c5f1aa8b55 100644 --- a/src/providers/mdal/qgsmdalprovider.cpp +++ b/src/providers/mdal/qgsmdalprovider.cpp @@ -493,6 +493,9 @@ QgsMeshDatasetGroupMetadata QgsMdalProvider::datasetGroupMetadata( int groupInde metadata[key] = value; } + QString referenceTimeString( MDAL_G_referenceTime( group ) ); + QDateTime referenceTime = QDateTime::fromString( referenceTimeString, Qt::ISODate ); + QgsMeshDatasetGroupMetadata meta( name, isScalar, @@ -500,6 +503,7 @@ QgsMeshDatasetGroupMetadata QgsMdalProvider::datasetGroupMetadata( int groupInde min, max, maximumVerticalLevels, + referenceTime, metadata ); diff --git a/src/ui/mesh/qgsmeshrenderervectorsettingswidgetbase.ui b/src/ui/mesh/qgsmeshrenderervectorsettingswidgetbase.ui index bceb403bd6f..ef57f9cd738 100644 --- a/src/ui/mesh/qgsmeshrenderervectorsettingswidgetbase.ui +++ b/src/ui/mesh/qgsmeshrenderervectorsettingswidgetbase.ui @@ -6,8 +6,8 @@ 0 0 - 365 - 749 + 340 + 773 @@ -409,6 +409,9 @@ Traces + + QLayout::SetDefaultConstraint + @@ -450,6 +453,24 @@ + + + 0 + 0 + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + 1.000000000000000 diff --git a/src/ui/mesh/qgsmeshtimeformatdialog.ui b/src/ui/mesh/qgsmeshtimeformatdialog.ui index e0cb71b6bc6..81e3007da0d 100644 --- a/src/ui/mesh/qgsmeshtimeformatdialog.ui +++ b/src/ui/mesh/qgsmeshtimeformatdialog.ui @@ -13,6 +13,9 @@ Time Display Options + + Reload from layer + @@ -57,21 +60,48 @@ - - - - 0 - 0 - 0 - 2019 - 1 - 1 - + + + 0 - - true - - + + + + + 0 + 0 + 0 + 2019 + 1 + 1 + + + + true + + + + + + + + 24 + 24 + + + + Qt::NoFocus + + + + + + + :/images/themes/default/mActionRefresh.svg:/images/themes/default/mActionRefresh.svg + + + + @@ -284,9 +314,51 @@ + + + + Provider time settings + + + + + + + seconds + + + + + minutes + + + + + hours + + + + + days + + + + + + + + Time unit + + + + + + - + + + shaftLengthMethodChanged()