Skip to content
Permalink
Browse files

[mesh] Fixes time reference for mesh layer #32186 #33399 #31933 (#33410)

[FEATURE] [mesh] Load reference time from MDAL when available

Also adds combo box to let the user set the provider time unit. This is particularly useful when MDAL incorrectly recognised the time units in the raw dat format (for example format does nof follow spec and it is not possible to determine if time interval is in hours or days)

fix #32186 
fix #33399
fix #31933
  • Loading branch information
vcloarec authored and PeterPetrik committed Dec 17, 2019
1 parent ead3b62 commit c252a3ad4cc7230d8fabb930ae4e927a9fb08787
@@ -417,6 +417,7 @@ Constructs an empty metadata object
double minimum,
double maximum,
int maximumVerticalLevels,
const QDateTime &referenceTime,
const QMap<QString, QString> &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

@@ -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

};
@@ -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();
}
@@ -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<int>::of( &QComboBox::currentIndexChanged ), this, &QgsMeshTimeFormatDialog::saveSettings );
connect( mReferenceDateTimeEdit, &QDateTimeEdit::timeChanged, this, &QgsMeshTimeFormatDialog::saveSettings );
connect( mReferenceDateTimeEdit, &QDateTimeEdit::dateTimeChanged, this, &QgsMeshTimeFormatDialog::saveSettings );
connect( mAbsoluteTimeFormatComboBox, qgis::overload<int>::of( &QComboBox::currentIndexChanged ), this, &QgsMeshTimeFormatDialog::saveSettings );
connect( mUseTimeComboBox, qgis::overload<int>::of( &QComboBox::currentIndexChanged ), this, &QgsMeshTimeFormatDialog::saveSettings );
connect( mRelativeTimeFormatComboBox, qgis::overload<int>::of( &QComboBox::currentIndexChanged ), this, &QgsMeshTimeFormatDialog::saveSettings );
connect( mOffsetHoursSpinBox, qgis::overload<double>::of( &QDoubleSpinBox::valueChanged ), this, &QgsMeshTimeFormatDialog::saveSettings );
connect( mPlaybackIntervalSpinBox, qgis::overload<double>::of( &QDoubleSpinBox::valueChanged ), this, &QgsMeshTimeFormatDialog::saveSettings );
connect( mProviderTimeUnitComboBox, qgis::overload<int>::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<QgsMeshTimeSettings::TimeUnit>( 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;
@@ -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;
};

@@ -133,6 +133,7 @@ QgsMeshDatasetGroupMetadata::QgsMeshDatasetGroupMetadata( const QString &name,
double minimum,
double maximum,
int maximumVerticalLevels,
const QDateTime &referenceTime,
const QMap<QString, QString> &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() );
@@ -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<QString, QString> &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<double>::quiet_NaN();
QMap<QString, QString> mExtraOptions;
int mMaximumVerticalLevelsCount = 0; // for 3d stacked meshes
QDateTime mReferenceTime;
};

/**
@@ -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 );

@@ -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
@@ -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
@@ -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<QgsMeshTimeSettings::TimeUnit>( 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;
}

0 comments on commit c252a3a

Please sign in to comment.
You can’t perform that action at this time.