Skip to content

Commit

Permalink
temporal match methods
Browse files Browse the repository at this point in the history
  • Loading branch information
vcloarec authored and nyalldawson committed May 20, 2020
1 parent daab0ea commit 267af1e
Show file tree
Hide file tree
Showing 13 changed files with 295 additions and 127 deletions.
Expand Up @@ -23,22 +23,37 @@ Class for handling properties relating to a mesh data provider's temporal capabi
%End
public:

enum MatchingTemporalDatasetMethod
{
FindClosestDatasetBeforeStartRangeTime,
FindClosestDatasetFromStartRangeTime
};

QgsMeshDataProviderTemporalCapabilities();
%Docstring
Constructor for QgsMeshDataProviderTemporalCapabilities
%End

QgsMeshDatasetIndex datasetIndexFromRelativeTimeRange( int group, qint64 startTimeSinceGlobalReference, qint64 endTimeSinceGlobalReference ) const;
QgsMeshDatasetIndex datasetIndexClosestBeforeRelativeTime( int group, qint64 timeSinceGlobalReference ) const;
%Docstring
Returns the last dataset whith time less than or equal to ``timeSinceGlobalReference``

Returns invalid dataset index if ``timeSinceGlobalReference`` is outside the time extent of the dataset group

.. note::

for non temporal dataset group, ``timeSinceGlobalReference`` is not used and the unique dataset is returned
%End

QgsMeshDatasetIndex datasetIndexClosestFromRelativeTime( int group, qint64 timeSinceGlobalReference ) const;
%Docstring
Returns the first dataset that are include in the range [``startTimeSinceGlobalReference``,``endTimeSinceGlobalReference``[ (in milliseconds)
from the dataset ``group``. If no dataset is present in this range return the last dataset before this range if it not the last one
of whole the dataset group
Returns the closest dataset index from the ``timeSinceGlobalReference``

Returns invalid dataset index if there is no data set in the range
Returns invalid dataset index if ``timeSinceGlobalReference`` is outside the time extent of the dataset group

.. note::

for non temporal dataset group, the range is not used and the unique dataset is returned
for non temporal dataset group, ``timeSinceGlobalReference`` is not used and the unique dataset is returned
%End


Expand Down
19 changes: 19 additions & 0 deletions python/core/auto_generated/mesh/qgsmeshlayer.sip.in
Expand Up @@ -292,6 +292,11 @@ If the temporal properties is not active, return the static dataset

:return: dataset index

.. note::

the returned dataset index depends on the matching method, see setTemporalMatchingMethod()


.. versionadded:: 3.14
%End

Expand All @@ -304,6 +309,11 @@ If the temporal properties is not active, return the static dataset

:return: dataset index

.. note::

the returned dataset index depends on the matching method, see setTemporalMatchingMethod()


.. versionadded:: 3.14
%End

Expand All @@ -329,6 +339,15 @@ Sets the reference time of the layer

:param referenceTime: the reference time

.. versionadded:: 3.14
%End

void setTemporalMatchingMethod( const QgsMeshDataProviderTemporalCapabilities::MatchingTemporalDatasetMethod &matchingMethod );
%Docstring
Sets the method used to match the temporal dataset from a requested time, see activeVectorDatasetAtTime()

:param matchingMethod: the matching method

.. versionadded:: 3.14
%End

Expand Down
Expand Up @@ -74,6 +74,18 @@ if the temporal capabilities is null, set a void time extent (reference time to

:param referenceTime: the reference time
:param capabilities: the temporal capabilities of the data provider
%End

QgsMeshDataProviderTemporalCapabilities::MatchingTemporalDatasetMethod matchingMethod() const;
%Docstring
Returns the method used to match dataset from temporal capabilities
%End

void setMatchingMethod( const QgsMeshDataProviderTemporalCapabilities::MatchingTemporalDatasetMethod &matchingMethod );
%Docstring
Sets the method used to match dataset from temporal capabilities

:param matchingMethod: the matching method
%End

};
Expand Down
2 changes: 2 additions & 0 deletions python/gui/auto_additions/qgssublayersdialog.py
@@ -0,0 +1,2 @@
# The following has been generated automatically from src/gui/qgssublayersdialog.h
QgsSublayersDialog.PromptMode.baseClass = QgsSublayersDialog
9 changes: 9 additions & 0 deletions src/app/mesh/qgsmeshlayerproperties.cpp
Expand Up @@ -95,6 +95,11 @@ QgsMeshLayerProperties::QgsMeshLayerProperties( QgsMapLayer *lyr, QgsMapCanvas *
delete mOptsPage_3DView; // removes both the "3d view" list item and its page
#endif

mComboBoxTemporalDatasetMatchingMethod->addItem( tr( "Find closest dataset before requested time" ),
QgsMeshDataProviderTemporalCapabilities::FindClosestDatasetBeforeStartRangeTime );
mComboBoxTemporalDatasetMatchingMethod->addItem( tr( "Find closest dataset from requested time (after or before)" ),
QgsMeshDataProviderTemporalCapabilities::FindClosestDatasetFromStartRangeTime );

// update based on lyr's current state
syncToLayer();

Expand Down Expand Up @@ -209,6 +214,8 @@ void QgsMeshLayerProperties::syncToLayer()
mTemporalProviderTimeUnitComboBox->setCurrentIndex(
mTemporalProviderTimeUnitComboBox->findData( mMeshLayer->dataProvider()->temporalCapabilities()->temporalUnit() ) );
}
mComboBoxTemporalDatasetMatchingMethod->setCurrentIndex(
mComboBoxTemporalDatasetMatchingMethod->findData( temporalProperties->matchingMethod() ) );

mStaticScalarWidget->syncToLayer();
mStaticScalarWidget->setVisible( !mMeshLayer->temporalProperties()->isActive() );
Expand Down Expand Up @@ -371,6 +378,8 @@ void QgsMeshLayerProperties::apply()
mStaticScalarWidget->apply();
bool needEmitRendererChanged = mMeshLayer->temporalProperties()->isActive() == mTemporalStaticDatasetCheckBox->isChecked();
mMeshLayer->temporalProperties()->setIsActive( !mTemporalStaticDatasetCheckBox->isChecked() );
mMeshLayer->setTemporalMatchingMethod( static_cast<QgsMeshDataProviderTemporalCapabilities::MatchingTemporalDatasetMethod>(
mComboBoxTemporalDatasetMatchingMethod->currentData().toInt() ) );

if ( needMeshUpdating )
mMeshLayer->reload();
Expand Down
54 changes: 37 additions & 17 deletions src/core/mesh/qgsmeshdataprovidertemporalcapabilities.cpp
Expand Up @@ -21,38 +21,58 @@
QgsMeshDataProviderTemporalCapabilities::QgsMeshDataProviderTemporalCapabilities(): QgsDataProviderTemporalCapabilities()
{}

QgsMeshDatasetIndex QgsMeshDataProviderTemporalCapabilities::datasetIndexFromRelativeTimeRange( int group, qint64 startTimeSinceGlobalReference, qint64 endTimeSinceGlobalReference ) const
QgsMeshDatasetIndex QgsMeshDataProviderTemporalCapabilities::datasetIndexClosestFromRelativeTime( int group, qint64 timeSinceGlobalReference ) const
{
// No time --> non temporal dataset, so return the dataset that has to be the only one
const QList<qint64> &datasetTimes = mDatasetTimeSinceGroupReference[group];
if ( datasetTimes.isEmpty() )
return QgsMeshDatasetIndex( group, 0 );
const QDateTime groupReference = mGroupsReferenceDateTime[group];
const qint64 startTimeSinceGroupReference =
startTimeSinceGlobalReference - mGlobalReferenceDateTime.msecsTo( groupReference );
const qint64 endTimeSinceGroupReference =
endTimeSinceGlobalReference - mGlobalReferenceDateTime.msecsTo( groupReference );
const qint64 timeSinceGroupReference =
timeSinceGlobalReference - mGlobalReferenceDateTime.msecsTo( groupReference );

if ( startTimeSinceGroupReference > datasetTimes.last() )
if ( timeSinceGroupReference > datasetTimes.last() // after last time
|| timeSinceGroupReference < datasetTimes.first() ) // before first time
return QgsMeshDatasetIndex();

if ( endTimeSinceGroupReference < datasetTimes.first() )
return QgsMeshDatasetIndex();

for ( int i = 0; i < datasetTimes.count(); ++i )
for ( int i = 1 ; i < datasetTimes.count(); ++i )
{
qint64 time = datasetTimes.at( i );
if ( startTimeSinceGroupReference <= time )
qint64 time1 = datasetTimes.at( i - 1 );
qint64 time2 = datasetTimes.at( i );
if ( time1 <= timeSinceGroupReference && timeSinceGroupReference <= time2 )
{
if ( endTimeSinceGroupReference < time ) // Start and end of range are before the current time step
return QgsMeshDatasetIndex( group, i - 1 ); // --> return the previous time step, invalid if i=0
if ( abs( timeSinceGroupReference - time2 ) < abs( timeSinceGroupReference - time1 ) )
return QgsMeshDatasetIndex( group, i );
else
return QgsMeshDatasetIndex( group, i ); // current time step are included in [start,end] --> return current
return QgsMeshDatasetIndex( group, i - 1 );
}
}

// if we are here (normally, this could no happen), return invalid dataset index
return QgsMeshDatasetIndex();
return QgsMeshDatasetIndex( QgsMeshDatasetIndex( group, datasetTimes.count() - 1 ) );
}

QgsMeshDatasetIndex QgsMeshDataProviderTemporalCapabilities::datasetIndexClosestBeforeRelativeTime( int group, qint64 timeSinceGlobalReference ) const
{
// No time --> non temporal dataset, so return the dataset that has to be the only one
const QList<qint64> &datasetTimes = mDatasetTimeSinceGroupReference[group];
if ( datasetTimes.isEmpty() )
return QgsMeshDatasetIndex( group, 0 );
const QDateTime groupReference = mGroupsReferenceDateTime[group];
const qint64 timeSinceGroupReference =
timeSinceGlobalReference - mGlobalReferenceDateTime.msecsTo( groupReference );

if ( timeSinceGroupReference > datasetTimes.last() // after last time
|| timeSinceGroupReference < datasetTimes.first() ) // before first time
return QgsMeshDatasetIndex();

for ( int i = 1; i < datasetTimes.count(); ++i )
{
qint64 time = datasetTimes.at( i );
if ( timeSinceGroupReference < time )
return QgsMeshDatasetIndex( group, i - 1 );
}

return QgsMeshDatasetIndex( QgsMeshDatasetIndex( group, datasetTimes.count() - 1 ) );
}

void QgsMeshDataProviderTemporalCapabilities::addGroupReferenceDateTime( int group, const QDateTime &reference )
Expand Down
28 changes: 22 additions & 6 deletions src/core/mesh/qgsmeshdataprovidertemporalcapabilities.h
Expand Up @@ -34,21 +34,37 @@ class CORE_EXPORT QgsMeshDataProviderTemporalCapabilities: public QgsDataProvide
{
public:

/**
* Method to use when requesting a tempral dataset from a time
**/
enum MatchingTemporalDatasetMethod
{
FindClosestDatasetBeforeStartRangeTime, //! Find the closest dataset which have its time before the requested start range time
FindClosestDatasetFromStartRangeTime //! Find the closest dataset before or after the requested start range time
};

/**
* Constructor for QgsMeshDataProviderTemporalCapabilities
*/
QgsMeshDataProviderTemporalCapabilities();

/**
* Returns the first dataset that are include in the range [\a startTimeSinceGlobalReference,\a endTimeSinceGlobalReference[ (in milliseconds)
* from the dataset \a group. If no dataset is present in this range return the last dataset before this range if it not the last one
* of whole the dataset group
* Returns the last dataset whith time less than or equal to \a timeSinceGlobalReference
*
* Returns invalid dataset index if \a timeSinceGlobalReference is outside the time extent of the dataset group
*
* \note for non temporal dataset group, \a timeSinceGlobalReference is not used and the unique dataset is returned
*/
QgsMeshDatasetIndex datasetIndexClosestBeforeRelativeTime( int group, qint64 timeSinceGlobalReference ) const;

/**
* Returns the closest dataset index from the \a timeSinceGlobalReference
*
* Returns invalid dataset index if there is no data set in the range
*Returns invalid dataset index if \a timeSinceGlobalReference is outside the time extent of the dataset group
*
* \note for non temporal dataset group, the range is not used and the unique dataset is returned
* \note for non temporal dataset group, \a timeSinceGlobalReference is not used and the unique dataset is returned
*/
QgsMeshDatasetIndex datasetIndexFromRelativeTimeRange( int group, qint64 startTimeSinceGlobalReference, qint64 endTimeSinceGlobalReference ) const;
QgsMeshDatasetIndex datasetIndexClosestFromRelativeTime( int group, qint64 timeSinceGlobalReference ) const;

/**
* Adds a \a reference date/time from a dataset \a group
Expand Down
22 changes: 15 additions & 7 deletions src/core/mesh/qgsmeshlayer.cpp
Expand Up @@ -82,9 +82,7 @@ void QgsMeshLayer::setDefaultRendererSettings()
meta.minimum() == std::numeric_limits<double>::quiet_NaN() )
meshSettings.setEnabled( true );

// If the mesh is non temporal, set the static scalar dataset
if ( !mDataProvider->temporalCapabilities()->hasTemporalCapabilities() )
setStaticScalarDatasetIndex( QgsMeshDatasetIndex( 0, 0 ) );
setStaticScalarDatasetIndex( QgsMeshDatasetIndex( 0, 0 ) );
}
else
{
Expand Down Expand Up @@ -435,12 +433,17 @@ QgsMeshDatasetIndex QgsMeshLayer::datasetIndexAtTime( const QgsDateTimeRange &ti
{
const QDateTime layerReferenceTime = mTemporalProperties->referenceTime();
qint64 startTime = layerReferenceTime.msecsTo( timeRange.begin() );
qint64 endTime = layerReferenceTime.msecsTo( timeRange.end() );

if ( dataProvider() )
return dataProvider()->temporalCapabilities()->datasetIndexFromRelativeTimeRange( datasetGroupIndex, startTime, endTime );
else
return QgsMeshDatasetIndex();
switch ( mTemporalProperties->matchingMethod() )
{
case QgsMeshDataProviderTemporalCapabilities::FindClosestDatasetBeforeStartRangeTime:
return dataProvider()->temporalCapabilities()->datasetIndexClosestBeforeRelativeTime( datasetGroupIndex, startTime );
case QgsMeshDataProviderTemporalCapabilities::FindClosestDatasetFromStartRangeTime:
return dataProvider()->temporalCapabilities()->datasetIndexClosestFromRelativeTime( datasetGroupIndex, startTime );
}

return QgsMeshDatasetIndex();
}

void QgsMeshLayer::applyClassificationOnScalarSettings( const QgsMeshDatasetGroupMetadata &meta, QgsMeshRendererScalarSettings &scalarSettings ) const
Expand Down Expand Up @@ -637,6 +640,11 @@ void QgsMeshLayer::setReferenceTime( const QDateTime &referenceTime )
mTemporalProperties->setReferenceTime( referenceTime, nullptr );
}

void QgsMeshLayer::setTemporalMatchingMethod( const QgsMeshDataProviderTemporalCapabilities::MatchingTemporalDatasetMethod &matchingMethod )
{
mTemporalProperties->setMatchingMethod( matchingMethod );
}

QgsPointXY QgsMeshLayer::snapOnVertex( const QgsPointXY &point, double searchRadius )
{
const QgsTriangularMesh *mesh = triangularMesh();
Expand Down
13 changes: 13 additions & 0 deletions src/core/mesh/qgsmeshlayer.h
Expand Up @@ -332,6 +332,8 @@ class CORE_EXPORT QgsMeshLayer : public QgsMapLayer
* \param timeRange the time range
* \returns dataset index
*
* \note the returned dataset index depends on the matching method, see setTemporalMatchingMethod()
*
* \since QGIS 3.14
*/
QgsMeshDatasetIndex activeScalarDatasetAtTime( const QgsDateTimeRange &timeRange ) const;
Expand All @@ -343,6 +345,8 @@ class CORE_EXPORT QgsMeshLayer : public QgsMapLayer
* \param timeRange the time range
* \returns dataset index
*
* \note the returned dataset index depends on the matching method, see setTemporalMatchingMethod()
*
* \since QGIS 3.14
*/
QgsMeshDatasetIndex activeVectorDatasetAtTime( const QgsDateTimeRange &timeRange ) const;
Expand Down Expand Up @@ -388,6 +392,15 @@ class CORE_EXPORT QgsMeshLayer : public QgsMapLayer
*/
void setReferenceTime( const QDateTime &referenceTime );

/**
* Sets the method used to match the temporal dataset from a requested time, see activeVectorDatasetAtTime()
*
* \param matchingMethod the matching method
*
* \since QGIS 3.14
*/
void setTemporalMatchingMethod( const QgsMeshDataProviderTemporalCapabilities::MatchingTemporalDatasetMethod &matchingMethod );

/**
* Returns the position of the snapped point on the mesh element closest to \a point intersecting with
* the searching area defined by \a point and \a searchRadius
Expand Down
14 changes: 14 additions & 0 deletions src/core/mesh/qgsmeshlayertemporalproperties.cpp
Expand Up @@ -33,6 +33,7 @@ QDomElement QgsMeshLayerTemporalProperties::writeXml( QDomElement &element, QDom
temporalElement.setAttribute( QStringLiteral( "reference-time" ), mReferenceTime.toTimeSpec( Qt::UTC ).toString( Qt::ISODate ) );
temporalElement.setAttribute( QStringLiteral( "start-time-extent" ), mTimeExtent.begin().toTimeSpec( Qt::UTC ).toString( Qt::ISODate ) );
temporalElement.setAttribute( QStringLiteral( "end-time-extent" ), mTimeExtent.end().toTimeSpec( Qt::UTC ).toString( Qt::ISODate ) );
temporalElement.setAttribute( QStringLiteral( "matching-method" ), mMatchingMethod );

element.appendChild( temporalElement );

Expand All @@ -57,6 +58,9 @@ bool QgsMeshLayerTemporalProperties::readXml( const QDomElement &element, const
mTimeExtent = QgsDateTimeRange( start, end );
}

mMatchingMethod = static_cast<QgsMeshDataProviderTemporalCapabilities::MatchingTemporalDatasetMethod>(
temporalElement.attribute( QStringLiteral( "matching-method" ) ).toInt() );

return true;
}

Expand Down Expand Up @@ -98,3 +102,13 @@ void QgsMeshLayerTemporalProperties::setReferenceTime( const QDateTime &referenc
else
mTimeExtent = QgsDateTimeRange( referenceTime, referenceTime );
}

QgsMeshDataProviderTemporalCapabilities::MatchingTemporalDatasetMethod QgsMeshLayerTemporalProperties::matchingMethod() const
{
return mMatchingMethod;
}

void QgsMeshLayerTemporalProperties::setMatchingMethod( const QgsMeshDataProviderTemporalCapabilities::MatchingTemporalDatasetMethod &matchingMethod )
{
mMatchingMethod = matchingMethod;
}
15 changes: 15 additions & 0 deletions src/core/mesh/qgsmeshlayertemporalproperties.h
Expand Up @@ -19,6 +19,7 @@
#define QGSMESHLAYERTEMPORALPROPERTIES_H

#include "qgsmaplayertemporalproperties.h"
#include "qgsmeshdataprovidertemporalcapabilities.h"


/**
Expand Down Expand Up @@ -86,9 +87,23 @@ class CORE_EXPORT QgsMeshLayerTemporalProperties : public QgsMapLayerTemporalPro
*/
void setReferenceTime( const QDateTime &referenceTime, const QgsDataProviderTemporalCapabilities *capabilities );

/**
* Returns the method used to match dataset from temporal capabilities
*/
QgsMeshDataProviderTemporalCapabilities::MatchingTemporalDatasetMethod matchingMethod() const;

/**
* Sets the method used to match dataset from temporal capabilities
*
* \param matchingMethod the matching method
*/
void setMatchingMethod( const QgsMeshDataProviderTemporalCapabilities::MatchingTemporalDatasetMethod &matchingMethod );

private:
QDateTime mReferenceTime;
QgsDateTimeRange mTimeExtent;
QgsMeshDataProviderTemporalCapabilities::MatchingTemporalDatasetMethod mMatchingMethod =
QgsMeshDataProviderTemporalCapabilities::FindClosestDatasetBeforeStartRangeTime;
};

#endif // QGSMESHLAYERTEMPORALPROPERTIES_H

0 comments on commit 267af1e

Please sign in to comment.