fix aggregate functions with mesh virtual dataset group (#45446)

This commit is contained in:
Vincent Cloarec 2021-10-11 08:28:11 -04:00 committed by GitHub
parent 18a782f1fb
commit a840cbf98c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 514 additions and 28 deletions

View File

@ -10,6 +10,7 @@
class QgsMeshCalculator
{
%Docstring(signature="appended")

View File

@ -390,6 +390,24 @@ Returns the dataset index of the dataset in a specific dataset group at ``time``
:param method: the method used to check the time
:return: the dataset index
%End
QList<QgsMeshDatasetIndex> datasetIndexInTimeInterval( const QDateTime &referenceTime,
int groupIndex,
qint64 time1,
qint64 time2 ) const;
%Docstring
Returns a list of dataset indexes of the dataset in a specific dataset group that are between ``time1`` and ``time2`` from the ``reference`` time
:param referenceTime: the reference time from where to find the dataset
:param groupIndex: the index of the dataset group
:param time1: the first relative time of the time intervale from reference time
:param time2: the second relative time of the time intervale from reference time
:return: the dataset index
.. versionadded:: 3.22
%End
protected:

View File

@ -566,6 +566,26 @@ Dataset index is valid even the temporal properties is inactive. This method is
.. versionadded:: 3.16
%End
QList<QgsMeshDatasetIndex> datasetIndexInRelativeTimeInterval( const QgsInterval &startRelativeTime, const QgsInterval &endRelativeTime, int datasetGroupIndex ) const;
%Docstring
Returns a list of dataset indexes from datasets group that are in a interval time from the layer reference time.
Dataset index is valid even the temporal properties is inactive. This method is used for calculation on mesh layer.
:param startRelativeTime: the start time of the relative interval from the reference time.
:param endRelativeTime: the end time of the relative interval from the reference time.
:param datasetGroupIndex: the index of the dataset group
:return: dataset index
.. note::
indexes are used to distinguish all the dataset groups handled by the layer (from dataprovider, extra dataset group,...)
In the layer scope, those indexes are different from the data provider indexes.
.. versionadded:: 3.22
%End
QgsMeshDatasetIndex activeScalarDatasetAtTime( const QgsDateTimeRange &timeRange ) const;

View File

@ -104,11 +104,132 @@ QStringList QgsMeshCalcNode::usedDatasetGroupNames() const
return res;
}
bool QgsMeshCalcNode::calculate( const QgsMeshCalcUtils &dsu, QgsMeshMemoryDatasetGroup &result ) const
QStringList QgsMeshCalcNode::aggregatedUsedDatasetGroupNames() const
{
QStringList res;
switch ( mOperator )
{
case QgsMeshCalcNode::opPLUS:
case QgsMeshCalcNode::opMINUS:
case QgsMeshCalcNode::opMUL:
case QgsMeshCalcNode::opDIV:
case QgsMeshCalcNode::opPOW:
case QgsMeshCalcNode::opEQ:
case QgsMeshCalcNode::opNE:
case QgsMeshCalcNode::opGT:
case QgsMeshCalcNode::opLT:
case QgsMeshCalcNode::opGE:
case QgsMeshCalcNode::opLE:
case QgsMeshCalcNode::opAND:
case QgsMeshCalcNode::opOR:
case QgsMeshCalcNode::opNOT:
case QgsMeshCalcNode::opIF:
case QgsMeshCalcNode::opSIGN:
case QgsMeshCalcNode::opMIN:
case QgsMeshCalcNode::opMAX:
case QgsMeshCalcNode::opABS:
case QgsMeshCalcNode::opNONE:
if ( mLeft )
{
res += mLeft->aggregatedUsedDatasetGroupNames();
}
if ( mRight )
{
res += mRight->aggregatedUsedDatasetGroupNames();
}
if ( mCondition )
{
res += mCondition->aggregatedUsedDatasetGroupNames();
}
break;
case QgsMeshCalcNode::opSUM_AGGR:
case QgsMeshCalcNode::opMAX_AGGR:
case QgsMeshCalcNode::opMIN_AGGR:
case QgsMeshCalcNode::opAVG_AGGR:
if ( mLeft )
{
res += mLeft->usedDatasetGroupNames();
}
if ( mRight )
{
res += mRight->usedDatasetGroupNames();
}
if ( mCondition )
{
res += mCondition->usedDatasetGroupNames();
}
break;
}
return res;
}
QStringList QgsMeshCalcNode::notAggregatedUsedDatasetGroupNames() const
{
QStringList res;
if ( mType == tDatasetGroupRef )
{
res.append( mDatasetGroupName );
}
switch ( mOperator )
{
case QgsMeshCalcNode::opPLUS:
case QgsMeshCalcNode::opMINUS:
case QgsMeshCalcNode::opMUL:
case QgsMeshCalcNode::opDIV:
case QgsMeshCalcNode::opPOW:
case QgsMeshCalcNode::opEQ:
case QgsMeshCalcNode::opNE:
case QgsMeshCalcNode::opGT:
case QgsMeshCalcNode::opLT:
case QgsMeshCalcNode::opGE:
case QgsMeshCalcNode::opLE:
case QgsMeshCalcNode::opAND:
case QgsMeshCalcNode::opOR:
case QgsMeshCalcNode::opNOT:
case QgsMeshCalcNode::opIF:
case QgsMeshCalcNode::opSIGN:
case QgsMeshCalcNode::opMIN:
case QgsMeshCalcNode::opMAX:
case QgsMeshCalcNode::opABS:
if ( mLeft )
{
res += mLeft->notAggregatedUsedDatasetGroupNames();
}
if ( mRight )
{
res += mRight->notAggregatedUsedDatasetGroupNames();
}
if ( mCondition )
{
res += mCondition->notAggregatedUsedDatasetGroupNames();
}
break;
case QgsMeshCalcNode::opSUM_AGGR:
case QgsMeshCalcNode::opMAX_AGGR:
case QgsMeshCalcNode::opMIN_AGGR:
case QgsMeshCalcNode::opAVG_AGGR:
case QgsMeshCalcNode::opNONE:
break;
}
return res;
}
bool QgsMeshCalcNode::calculate( const QgsMeshCalcUtils &dsu, QgsMeshMemoryDatasetGroup &result, bool isAggregate ) const
{
if ( mType == tDatasetGroupRef )
{
dsu.copy( result, mDatasetGroupName );
dsu.copy( result, mDatasetGroupName, isAggregate );
return true;
}
else if ( mType == tOperator )
@ -116,11 +237,16 @@ bool QgsMeshCalcNode::calculate( const QgsMeshCalcUtils &dsu, QgsMeshMemoryData
QgsMeshMemoryDatasetGroup leftDatasetGroup( "left", dsu.outputType() );
QgsMeshMemoryDatasetGroup rightDatasetGroup( "right", dsu.outputType() );
if ( !mLeft || !mLeft->calculate( dsu, leftDatasetGroup ) )
bool currentOperatorIsAggregate = mOperator == opSUM_AGGR ||
mOperator == opMAX_AGGR ||
mOperator == opMIN_AGGR ||
mOperator == opAVG_AGGR;
if ( !mLeft || !mLeft->calculate( dsu, leftDatasetGroup, isAggregate || currentOperatorIsAggregate ) )
{
return false;
}
if ( mRight && !mRight->calculate( dsu, rightDatasetGroup ) )
if ( mRight && !mRight->calculate( dsu, rightDatasetGroup, isAggregate || currentOperatorIsAggregate ) )
{
return false;
}

View File

@ -132,11 +132,17 @@ class CORE_EXPORT QgsMeshCalcNode
* \param result destination dataset group for calculation results
* \returns TRUE on success, FALSE on failure
*/
bool calculate( const QgsMeshCalcUtils &dsu, QgsMeshMemoryDatasetGroup &result ) const;
bool calculate( const QgsMeshCalcUtils &dsu, QgsMeshMemoryDatasetGroup &result, bool isAggregate = false ) const;
//! Returns all dataset group names used in formula
QStringList usedDatasetGroupNames() const;
//! Returns dataset group names used in formula involved in aggregate function
QStringList aggregatedUsedDatasetGroupNames() const;
//! Returns dataset group names used in formula not involved in aggregate function
QStringList notAggregatedUsedDatasetGroupNames() const;
/**
* Parses string to calculation node. Caller takes responsibility to delete the node
* \param str string with formula definition

View File

@ -19,9 +19,11 @@
#include <limits>
#include <memory>
#include "qgsfeedback.h"
#include "qgsmeshcalcnode.h"
#include "qgsmeshcalculator.h"
#include "qgsmeshcalcutils.h"
#include "qgsmeshlayer.h"
#include "qgsmeshmemorydataprovider.h"
#include "qgsmeshvirtualdatasetgroup.h"
#include "qgis.h"

View File

@ -25,10 +25,12 @@
#include "qgis_core.h"
#include "qgis_sip.h"
#include "qgsrectangle.h"
#include "qgsmeshlayer.h"
#include "qgsmeshdataprovider.h"
#include "qgsgeometry.h"
#include "qgsmeshdataset.h"
#include "qgsprovidermetadata.h"
#include "qgsfeedback.h"
class QgsMeshLayer;
class QgsFeedback;
/**
* \ingroup core

View File

@ -31,7 +31,7 @@ const double D_TRUE = 1.0;
const double D_FALSE = 0.0;
const double D_NODATA = std::numeric_limits<double>::quiet_NaN();
std::shared_ptr<QgsMeshMemoryDatasetGroup> QgsMeshCalcUtils::createMemoryDatasetGroup( const QString &datasetGroupName, const QgsInterval &relativeTime ) const
std::shared_ptr<QgsMeshMemoryDatasetGroup> QgsMeshCalcUtils::createMemoryDatasetGroup( const QString &datasetGroupName, const QgsInterval &relativeTime, const QgsInterval &startTime, const QgsInterval &endTime ) const
{
std::shared_ptr<QgsMeshMemoryDatasetGroup> grp;
const QList<int> &indexes = mMeshLayer->datasetGroupsIndexes();
@ -52,18 +52,27 @@ std::shared_ptr<QgsMeshMemoryDatasetGroup> QgsMeshCalcUtils::createMemoryDataset
grp->setMinimumMaximum( meta.minimum(), meta.maximum() );
grp->setName( meta.name() );
if ( !relativeTime.isValid() )
if ( !relativeTime.isValid() && ( !endTime.isValid() || !startTime.isValid() ) )
{
for ( int index = 0; index < mMeshLayer->datasetCount( groupIndex ); ++index )
grp->addDataset( createMemoryDataset( QgsMeshDatasetIndex( groupIndex, index ) ) );
}
else
else if ( relativeTime.isValid() )
{
const QgsMeshDatasetIndex datasetIndex = mMeshLayer->datasetIndexAtRelativeTime( relativeTime, groupIndex );
if ( datasetIndex.isValid() )
grp->addDataset( createMemoryDataset( datasetIndex ) );
}
else //only start time and end time are valid
{
QList<QgsMeshDatasetIndex> datasetIndexes = mMeshLayer->datasetIndexInRelativeTimeInterval( startTime, endTime, groupIndex );
if ( datasetIndexes.isEmpty() ) // if empty, at least one dataset corresponding to startTime
datasetIndexes.append( mMeshLayer->datasetIndexAtRelativeTime( startTime, groupIndex ) );
for ( const QgsMeshDatasetIndex &index : datasetIndexes )
grp->addDataset( createMemoryDataset( index ) );
}
break;
}
@ -333,6 +342,62 @@ QgsMeshCalcUtils::QgsMeshCalcUtils( QgsMeshLayer *layer, const QStringList &used
mIsValid = true;
}
QgsMeshCalcUtils::QgsMeshCalcUtils( QgsMeshLayer *layer,
const QStringList &usedGroupNames,
const QStringList &usedGroupNamesForAggregate,
const QgsInterval &relativeTime,
const QgsInterval &startTime,
const QgsInterval &endTime )
: mMeshLayer( layer )
, mIsValid( false )
{
// Layer must be valid
if ( !mMeshLayer || !mMeshLayer->dataProvider() )
return;
// Resolve output type of the calculation
mOutputType = determineResultDataType( layer, usedGroupNames + usedGroupNamesForAggregate );
// Data on edges are not implemented
if ( mOutputType == QgsMeshDatasetGroupMetadata::DataOnEdges )
return;
// Support for meshes with edges are not implemented
if ( mMeshLayer->dataProvider()->contains( QgsMesh::ElementType::Edge ) )
return;
for ( const QString &groupName : usedGroupNamesForAggregate )
{
const std::shared_ptr<QgsMeshMemoryDatasetGroup> dsg = createMemoryDatasetGroup( groupName, QgsInterval(), startTime, endTime );
if ( !dsg )
return;
mDatasetGroupMapForAggregate.insert( groupName, dsg );
}
for ( const QString &groupName : usedGroupNames )
{
const std::shared_ptr<QgsMeshMemoryDatasetGroup> ds = createMemoryDatasetGroup( groupName, relativeTime );
if ( ( !ds || ds->memoryDatasets.isEmpty() ) )
{
if ( mDatasetGroupMapForAggregate.contains( groupName ) )
continue;
else
return;
}
mDatasetGroupMap.insert( groupName, ds );
}
QgsInterval usedInterval = relativeTime;
if ( !usedInterval.isValid() )
usedInterval = QgsInterval( 0 );
mTimes.append( usedInterval.hours() );
mIsValid = true;
mIgnoreTime = true;
}
bool QgsMeshCalcUtils::isValid() const
{
return mIsValid;
@ -343,6 +408,14 @@ const QgsMeshLayer *QgsMeshCalcUtils::layer() const
return mMeshLayer;
}
std::shared_ptr<const QgsMeshMemoryDatasetGroup> QgsMeshCalcUtils::group( const QString &datasetName, bool isAggregate ) const
{
if ( isAggregate )
return mDatasetGroupMapForAggregate.value( datasetName );
else
return mDatasetGroupMap.value( datasetName );
}
std::shared_ptr<const QgsMeshMemoryDatasetGroup> QgsMeshCalcUtils::group( const QString &datasetName ) const
{
return mDatasetGroupMap[datasetName];
@ -494,11 +567,11 @@ std::shared_ptr<QgsMeshMemoryDataset> QgsMeshCalcUtils::copy(
return output;
}
void QgsMeshCalcUtils::copy( QgsMeshMemoryDatasetGroup &group1, const QString &groupName ) const
void QgsMeshCalcUtils::copy( QgsMeshMemoryDatasetGroup &group1, const QString &groupName, bool isAggregate ) const
{
Q_ASSERT( isValid() );
const std::shared_ptr<const QgsMeshMemoryDatasetGroup> group2 = group( groupName );
const std::shared_ptr<const QgsMeshMemoryDatasetGroup> group2 = group( groupName, isAggregate );
Q_ASSERT( group2 );
if ( group2->datasetCount() == 1 )
@ -513,7 +586,8 @@ void QgsMeshCalcUtils::copy( QgsMeshMemoryDatasetGroup &group1, const QString &g
for ( int output_index = 0; output_index < group2->datasetCount(); ++output_index )
{
const std::shared_ptr<const QgsMeshMemoryDataset> o0 = group2->constDataset( output_index );
if ( qgsDoubleNear( o0->time, mTimes.first() ) ||
if ( mIgnoreTime ||
qgsDoubleNear( o0->time, mTimes.first() ) ||
qgsDoubleNear( o0->time, mTimes.last() ) ||
( ( o0->time >= mTimes.first() ) && ( o0->time <= mTimes.last() ) )
)
@ -552,7 +626,12 @@ void QgsMeshCalcUtils::expand( QgsMeshMemoryDatasetGroup &group1, const QgsMeshM
for ( int i = 1; i < group2.datasetCount(); ++i )
{
const std::shared_ptr<QgsMeshMemoryDataset> o = copy( o0 );
o->time = mTimes[i];
if ( mIgnoreTime )
o->time = mTimes[0];
else
o->time = mTimes[i];
group1.addDataset( o );
}
}
@ -604,7 +683,10 @@ int QgsMeshCalcUtils::datasetCount(
if ( ( group1.datasetCount() > 1 ) || ( group2.datasetCount() > 1 ) )
{
return mTimes.size();
if ( mIgnoreTime )
return std::max( group1.datasetCount(), group2.datasetCount() );
else
return mTimes.size();
}
else
{

View File

@ -66,19 +66,49 @@ class CORE_EXPORT QgsMeshCalcUtils
double endTime );
/**
* Creates the utils and validates the input
* Creates the utils and validates the input for a calculation only for a dataset at time \a relativeTime
*
* The constructor fetches dataset values from selected dataset corresponding to the relative time \a relativeTime
* (see QgsMeshLayer::datasetIndexAtRelativeTime() and creates memory datasets from them.
* (see QgsMeshLayer::datasetIndexAtRelativeTime()) and creates memory datasets from them.
* There are only one dataset per group, selected with the matching method defined for the layer.
*
* \param layer mesh layer
* \param usedGroupNames dataset group's names that are used in the expression
* \param timeRange time range
* \param relativeTime time of the calculation
*
* \note this instance do not support aggregate functions
*
* \deprecated QGIS 3.22 because the constructor does not specify any time interval to calculate aggregate functions
*/
Q_DECL_DEPRECATED QgsMeshCalcUtils( QgsMeshLayer *layer,
const QStringList &usedGroupNames,
const QgsInterval &relativeTime );
/**
* Creates the utils and validates the input for a calculation only for a dataset at time \a relativeTime
*
* The constructor fetches dataset values from selected dataset corresponding to the relative time \a relativeTime
* (see QgsMeshLayer::datasetIndexAtRelativeTime()) and creates memory datasets from them.
* There are only one dataset per group, selected with the matching method defined for the layer,
* excepted when an aggregate function is involved upstream of a node. In this case,
* all the dataset that are between start time and end time are selected.
*
* \param layer mesh layer
* \param usedGroupNames dataset group's names that are used in the expression and not involved in a aggregate function
* \param usedGroupNamesForAggregate dataset group's names that are used in the expression and involved in a aggregate function
* \param relativeTime time of the calculation
* \param startTime retlative start time for aggregate functions
* \param endTime relative end time for aggregate functions
*
* \since QGIS 3.22
*/
QgsMeshCalcUtils( QgsMeshLayer *layer,
const QStringList &usedGroupNames,
const QgsInterval &relativeTime );
const QStringList &usedGroupNamesForAggregate,
const QgsInterval &relativeTime,
const QgsInterval &startTime,
const QgsInterval &endTime );
//! Returns whether the input parameters are consistent and valid for given mesh layer
bool isValid() const;
@ -99,7 +129,7 @@ class CORE_EXPORT QgsMeshCalcUtils
std::shared_ptr<QgsMeshMemoryDataset> number( double val, double time ) const;
//! Creates a deepcopy of group with groupName to group1. Does not copy datasets for filtered out times.
void copy( QgsMeshMemoryDatasetGroup &group1, const QString &groupName ) const;
void copy( QgsMeshMemoryDatasetGroup &group1, const QString &groupName, bool forAggregate = false ) const;
//! Creates a deepcopy of dataset0
std::shared_ptr<QgsMeshMemoryDataset> copy( std::shared_ptr<const QgsMeshMemoryDataset> dataset0 ) const;
@ -229,7 +259,20 @@ class CORE_EXPORT QgsMeshCalcUtils
* memory dataset group. Returns NULLPTR if no such dataset group
* exists. Resulting datasets are guaranteed to have the same mOutputType type
*/
std::shared_ptr<QgsMeshMemoryDatasetGroup> createMemoryDatasetGroup( const QString &datasetGroupName, const QgsInterval &relativeTime = QgsInterval() ) const;
std::shared_ptr<QgsMeshMemoryDatasetGroup> createMemoryDatasetGroup( const QString &datasetGroupName,
const QgsInterval &relativeTime = QgsInterval(),
const QgsInterval &startTime = QgsInterval(),
const QgsInterval &endTime = QgsInterval() ) const;
/**
* Returns dataset group based on name, the dataset count contained in the group will depend on \a isAggregate.
* If isAggregate is TRUE, the dataset group will contained all dataset needed to calculate aggregate function.
* If isAggregate isFALSE, the datasetgroup will only contain dataset group needed to calculate non aggregate function.
* For example, if \a this instance is created with a relative time, a start time and an end time, that is a calculation that
* will be operated only for this relative time, dataset group involved in a aggregate function will have all the dataset between
* start time and end time, other dataset will only have the dataset corresponding to relative time.
*/
std::shared_ptr<const QgsMeshMemoryDatasetGroup> group( const QString &groupName, bool isAggregate ) const;
/**
* Creates dataset based on group. Initializes values and active based on group type.
@ -303,6 +346,9 @@ class CORE_EXPORT QgsMeshCalcUtils
//!< E.g. one dataset with element outputs and one with node outputs
QVector<double> mTimes;
QMap < QString, std::shared_ptr<QgsMeshMemoryDatasetGroup> > mDatasetGroupMap; //!< Groups that are referenced in the expression
QMap < QString, std::shared_ptr<QgsMeshMemoryDatasetGroup> > mDatasetGroupMapForAggregate; //!< Groups that are referenced in the expression and used for aggregate function
bool mIgnoreTime = false; // with virtual datasetgroup, we only consider the current time step, except for aggregate function where we don't care about time value
};
///@endcond

View File

@ -72,6 +72,35 @@ QgsMeshDatasetIndex QgsMeshDatasetSourceInterface::datasetIndexAtTime(
return QgsMeshDatasetIndex();
}
QList<QgsMeshDatasetIndex> QgsMeshDatasetSourceInterface::datasetIndexInTimeInterval( const QDateTime &referenceTime, int groupIndex, qint64 time1, qint64 time2 ) const
{
const QDateTime requestDateTime = referenceTime.addMSecs( time1 );
qint64 providerTime1;
qint64 providerTime2;
const QDateTime providerReferenceTime = mTemporalCapabilities->referenceTime();
if ( mTemporalCapabilities->referenceTime().isValid() )
{
providerTime1 = providerReferenceTime.msecsTo( requestDateTime );
providerTime2 = providerTime1 - time1 + time2;
}
else
{
providerTime1 = time1;
providerTime2 = time2;
}
QList<QgsMeshDatasetIndex> ret;
for ( int i = 0; i < datasetCount( groupIndex ); ++i )
{
QgsMeshDatasetIndex datasetIndex( groupIndex, i );
qint64 time = mTemporalCapabilities->datasetTime( datasetIndex );
if ( time >= providerTime1 && time <= providerTime2 )
ret.append( datasetIndex );
}
return ret;
}
QgsMeshDatasetSourceInterface::QgsMeshDatasetSourceInterface():
mTemporalCapabilities( std::make_unique<QgsMeshDataProviderTemporalCapabilities>() ) {}

View File

@ -401,6 +401,23 @@ class CORE_EXPORT QgsMeshDatasetSourceInterface SIP_ABSTRACT
qint64 time,
QgsMeshDataProviderTemporalCapabilities::MatchingTemporalDatasetMethod method ) const;
/**
* Returns a list of dataset indexes of the dataset in a specific dataset group that are between \a time1 and \a time2 from the \a reference time
*
* \param referenceTime the reference time from where to find the dataset
* \param groupIndex the index of the dataset group
* \param time1 the first relative time of the time intervale from reference time
* \param time2 the second relative time of the time intervale from reference time
*
* \return the dataset index
*
* \since QGIS 3.22
*/
QList<QgsMeshDatasetIndex> datasetIndexInTimeInterval( const QDateTime &referenceTime,
int groupIndex,
qint64 time1,
qint64 time2 ) const;
protected:
std::unique_ptr<QgsMeshDataProviderTemporalCapabilities> mTemporalCapabilities;
};

View File

@ -237,6 +237,28 @@ QgsMeshDatasetIndex QgsMeshDatasetGroupStore::datasetIndexAtTime(
group.first->datasetIndexAtTime( referenceTime, group.second, time, method ).dataset() );
}
QList<QgsMeshDatasetIndex> QgsMeshDatasetGroupStore::datasetIndexInTimeInterval(
qint64 time1,
qint64 time2,
int groupIndex ) const
{
const QgsMeshDatasetGroupStore::DatasetGroup group = datasetGroup( groupIndex );
if ( !group.first )
return QList<QgsMeshDatasetIndex>();
const QDateTime &referenceTime = mPersistentProvider ? mPersistentProvider->temporalCapabilities()->referenceTime() : QDateTime();
const QList<QgsMeshDatasetIndex> datasetIndexes = group.first->datasetIndexInTimeInterval( referenceTime, group.second, time1, time2 );
QList<QgsMeshDatasetIndex> ret;
ret.reserve( datasetIndexes.count() );
for ( const QgsMeshDatasetIndex &sourceDatasetIndex : datasetIndexes )
ret.append( QgsMeshDatasetIndex( groupIndex, sourceDatasetIndex.dataset() ) );
return ret;
}
qint64 QgsMeshDatasetGroupStore::datasetRelativeTime( const QgsMeshDatasetIndex &index ) const
{
QgsMeshDatasetGroupStore::DatasetGroup group = datasetGroup( index.group() );

View File

@ -198,6 +198,13 @@ class QgsMeshDatasetGroupStore: public QObject
int groupIndex,
QgsMeshDataProviderTemporalCapabilities::MatchingTemporalDatasetMethod method ) const;
/**
* Returns the global dataset index of the dataset int the dataset group with \a groupIndex, that is between relative times \a time1 and \a time2
*
* Since QGIS 3.22
*/
QList<QgsMeshDatasetIndex> datasetIndexInTimeInterval( qint64 time1, qint64 time2, int groupIndex ) const;
//! Returns the relative time of the dataset from the persistent provider reference time
qint64 datasetRelativeTime( const QgsMeshDatasetIndex &index ) const;

View File

@ -588,6 +588,24 @@ QgsMeshDatasetIndex QgsMeshLayer::datasetIndexAtRelativeTime( const QgsInterval
return mDatasetGroupStore->datasetIndexAtTime( relativeTime.seconds() * 1000, datasetGroupIndex, mTemporalProperties->matchingMethod() );
}
QList<QgsMeshDatasetIndex> QgsMeshLayer::datasetIndexInRelativeTimeInterval( const QgsInterval &startRelativeTime, const QgsInterval &endRelativeTime, int datasetGroupIndex ) const
{
qint64 usedRelativeTime1 = startRelativeTime.seconds() * 1000;
qint64 usedRelativeTime2 = endRelativeTime.seconds() * 1000;
//adjust relative time if layer reference time is different from provider reference time
if ( mTemporalProperties->referenceTime().isValid() &&
mDataProvider &&
mDataProvider->isValid() &&
mTemporalProperties->referenceTime() != mDataProvider->temporalCapabilities()->referenceTime() )
{
usedRelativeTime1 = usedRelativeTime1 + mTemporalProperties->referenceTime().msecsTo( mDataProvider->temporalCapabilities()->referenceTime() );
usedRelativeTime2 = usedRelativeTime2 + mTemporalProperties->referenceTime().msecsTo( mDataProvider->temporalCapabilities()->referenceTime() );
}
return mDatasetGroupStore->datasetIndexInTimeInterval( usedRelativeTime1, usedRelativeTime2, datasetGroupIndex );
}
void QgsMeshLayer::applyClassificationOnScalarSettings( const QgsMeshDatasetGroupMetadata &meta, QgsMeshRendererScalarSettings &scalarSettings ) const
{
if ( meta.extraOptions().contains( QStringLiteral( "classification" ) ) )

View File

@ -582,6 +582,22 @@ class CORE_EXPORT QgsMeshLayer : public QgsMapLayer
*/
QgsMeshDatasetIndex datasetIndexAtRelativeTime( const QgsInterval &relativeTime, int datasetGroupIndex ) const;
/**
* Returns a list of dataset indexes from datasets group that are in a interval time from the layer reference time.
* Dataset index is valid even the temporal properties is inactive. This method is used for calculation on mesh layer.
*
* \param startRelativeTime the start time of the relative interval from the reference time.
* \param endRelativeTime the end time of the relative interval from the reference time.
* \param datasetGroupIndex the index of the dataset group
* \returns dataset index
*
* \note indexes are used to distinguish all the dataset groups handled by the layer (from dataprovider, extra dataset group,...)
* In the layer scope, those indexes are different from the data provider indexes.
*
* \since QGIS 3.22
*/
QList<QgsMeshDatasetIndex> datasetIndexInRelativeTimeInterval( const QgsInterval &startRelativeTime, const QgsInterval &endRelativeTime, int datasetGroupIndex ) const;
/**
* Returns dataset index from active scalar group depending on the time range.
* If the temporal properties is not active, return the static dataset

View File

@ -40,8 +40,10 @@ void QgsMeshVirtualDatasetGroup::initialize()
if ( !mCalcNode || !mLayer )
return;
mDatasetGroupNameUsed = mCalcNode->usedDatasetGroupNames();
setDataType( QgsMeshCalcUtils::determineResultDataType( mLayer, mDatasetGroupNameUsed ) );
mDatasetGroupNameUsed = mCalcNode->notAggregatedUsedDatasetGroupNames();
mDatasetGroupNameUsedForAggregate = mCalcNode->aggregatedUsedDatasetGroupNames();
setDataType( QgsMeshCalcUtils::determineResultDataType( mLayer,
mDatasetGroupNameUsed + mDatasetGroupNameUsedForAggregate ) );
//populate used group indexes
QMap<QString, int> usedDatasetGroupindexes;
@ -152,7 +154,12 @@ bool QgsMeshVirtualDatasetGroup::calculateDataset() const
if ( !mLayer )
return false;
const QgsMeshCalcUtils dsu( mLayer, mDatasetGroupNameUsed, QgsInterval( mDatasetTimes[mCurrentDatasetIndex] / 1000.0 ) );
const QgsMeshCalcUtils dsu( mLayer,
mDatasetGroupNameUsed,
mDatasetGroupNameUsedForAggregate,
QgsInterval( mDatasetTimes[mCurrentDatasetIndex] / 1000.0 ),
QgsInterval( mStartTime / 1000.0 ),
QgsInterval( mEndTime / 1000.0 ) );
if ( !dsu.isValid() )
return false;

View File

@ -66,9 +66,10 @@ class CORE_EXPORT QgsMeshVirtualDatasetGroup: public QgsMeshDatasetGroup
QString mFormula;
std::unique_ptr<QgsMeshCalcNode> mCalcNode;
QgsMeshLayer *mLayer = nullptr;
qint64 mStartTime = 0.0;
qint64 mEndTime = 0.0;
qint64 mStartTime = 0;
qint64 mEndTime = 0;
QStringList mDatasetGroupNameUsed;
QStringList mDatasetGroupNameUsedForAggregate;
QList<qint64> mDatasetTimes;
mutable std::shared_ptr<QgsMeshMemoryDataset> mCacheDataset;

View File

@ -362,6 +362,71 @@ void TestQgsMeshCalculator::virtualDatasetGroup()
QCOMPARE( dataset->datasetValue( 2 ).scalar(), 7.0 );
QCOMPARE( dataset->datasetValue( 3 ).scalar(), 5.5 );
QCOMPARE( dataset->datasetValue( 4 ).scalar(), 4.0 );
formula = QStringLiteral( "\"VertexScalarDataset\" + max_aggr (\"VertexScalarDataset\")" );
virtualDatasetGroup = QgsMeshVirtualDatasetGroup( "Virtual Dataset group", formula, mpMeshLayer, 0, 10000000 );
virtualDatasetGroup.initialize();
QCOMPARE( virtualDatasetGroup.datasetCount(), 2 );
dataset = virtualDatasetGroup.dataset( 0 );
QCOMPARE( dataset->valuesCount(), 5 );
QCOMPARE( dataset->datasetValue( 0 ).scalar(), 3.0 );
QCOMPARE( dataset->datasetValue( 1 ).scalar(), 5.0 );
QCOMPARE( dataset->datasetValue( 2 ).scalar(), 7.0 );
QCOMPARE( dataset->datasetValue( 3 ).scalar(), 5.0 );
QCOMPARE( dataset->datasetValue( 4 ).scalar(), 3.0 );
dataset = virtualDatasetGroup.dataset( 1 );
QCOMPARE( dataset->valuesCount(), 5 );
QCOMPARE( dataset->datasetValue( 0 ).scalar(), 4.0 );
QCOMPARE( dataset->datasetValue( 1 ).scalar(), 6.0 );
QCOMPARE( dataset->datasetValue( 2 ).scalar(), 8.0 );
QCOMPARE( dataset->datasetValue( 3 ).scalar(), 6.0 );
QCOMPARE( dataset->datasetValue( 4 ).scalar(), 4.0 );
formula = QStringLiteral( "max_aggr (\"FaceScalarDataset\") + min_aggr (\"FaceScalarDataset\")" );
virtualDatasetGroup = QgsMeshVirtualDatasetGroup( "Virtual Dataset group", formula, mpMeshLayer, 0, 10000000 );
virtualDatasetGroup.initialize();
QCOMPARE( virtualDatasetGroup.datasetCount(), 1 );
dataset = virtualDatasetGroup.dataset( 0 );
QCOMPARE( dataset->valuesCount(), 2 );
QCOMPARE( dataset->datasetValue( 0 ).scalar(), 3.0 );
QCOMPARE( dataset->datasetValue( 1 ).scalar(), 5.0 );
formula = QStringLiteral( "max_aggr (\"FaceScalarDataset\") + \"VertexScalarDataset\"" );
virtualDatasetGroup = QgsMeshVirtualDatasetGroup( "Virtual Dataset group", formula, mpMeshLayer, 0, 10000000 );
virtualDatasetGroup.initialize();
QCOMPARE( virtualDatasetGroup.datasetCount(), 2 );
dataset = virtualDatasetGroup.dataset( 0 );
QCOMPARE( dataset->valuesCount(), 5 );
QCOMPARE( dataset->datasetValue( 0 ).scalar(), 3.0 );
QCOMPARE( dataset->datasetValue( 1 ).scalar(), 4.5 );
QCOMPARE( dataset->datasetValue( 2 ).scalar(), 6.0 );
QCOMPARE( dataset->datasetValue( 3 ).scalar(), 4.5 );
QCOMPARE( dataset->datasetValue( 4 ).scalar(), 3.0 );
dataset = virtualDatasetGroup.dataset( 1 );
QCOMPARE( dataset->valuesCount(), 5 );
QCOMPARE( dataset->datasetValue( 0 ).scalar(), 4.0 );
QCOMPARE( dataset->datasetValue( 1 ).scalar(), 5.5 );
QCOMPARE( dataset->datasetValue( 2 ).scalar(), 7.0 );
QCOMPARE( dataset->datasetValue( 3 ).scalar(), 5.5 );
QCOMPARE( dataset->datasetValue( 4 ).scalar(), 4.0 );
formula = QStringLiteral( "max_aggr (\"FaceScalarDataset\" + \"VertexScalarDataset\")" );
virtualDatasetGroup = QgsMeshVirtualDatasetGroup( "Virtual Dataset group", formula, mpMeshLayer, 0, 10000000 );
virtualDatasetGroup.initialize();
QCOMPARE( virtualDatasetGroup.datasetCount(), 1 );
dataset = virtualDatasetGroup.dataset( 0 );
QCOMPARE( dataset->valuesCount(), 5 );
QCOMPARE( dataset->datasetValue( 0 ).scalar(), 4.0 );
QCOMPARE( dataset->datasetValue( 1 ).scalar(), 5.5 );
QCOMPARE( dataset->datasetValue( 2 ).scalar(), 7.0 );
QCOMPARE( dataset->datasetValue( 3 ).scalar(), 5.5 );
QCOMPARE( dataset->datasetValue( 4 ).scalar(), 4.0 );
}
@ -378,6 +443,7 @@ void TestQgsMeshCalculator::test_dataset_group_dependency()
{
const std::shared_ptr<QgsMeshMemoryDataset> ds = std::make_shared<QgsMeshMemoryDataset>();
ds->time = i / 3600.0;
ds->valid = true;
for ( int v = 0; v < vertexCount; ++v )
ds->values.append( QgsMeshDatasetValue( v / 2.0 + dsg ) );
@ -396,7 +462,7 @@ void TestQgsMeshCalculator::test_dataset_group_dependency()
formulas.append( QStringLiteral( " max_aggr ( \"VertexScalarDataset\") + \"virtual_0\"" ) );
formulas.append( QStringLiteral( " \"virtual_0\" + max_aggr ( \"VertexScalarDataset\") + 1" ) );
formulas.append( QStringLiteral( "if ( \"FaceScalarDataset\" = \"VertexScalarDataset\" , 0 , 1 )" ) ); //temporal one, must have several datasets
formulas.append( QStringLiteral( "if ( 2 = 1 , 0 , 1 )" ) ); //dtatic one, must have one dataset
formulas.append( QStringLiteral( "if ( 2 = 1 , 0 , 1 )" ) ); //static one, must have one dataset
formulas.append( QStringLiteral( "if ( 2 = 1 , \"FaceScalarDataset\" , 1 )" ) ); //temporal one, must have several datasets
QVector<int> sizes{10, 10, 2, 1, 1, 10, 10, 2, 1, 2};