1 /***************************************************************************
2 qgsmeshvirtualdatasetgroup.cpp
3 ---------------------
4 begin : June 2020
5 copyright : (C) 2020 by Vincent Cloarec
6 email : vcloarec at gmail dot com
7 ***************************************************************************/
8
9 /***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
18 #include "qgsmeshvirtualdatasetgroup.h"
19 #include "qgsmeshlayertemporalproperties.h"
20
QgsMeshVirtualDatasetGroup(const QString & name,const QString & formulaString,QgsMeshLayer * layer,qint64 relativeStartTime,qint64 relativeEndTime)21 QgsMeshVirtualDatasetGroup::QgsMeshVirtualDatasetGroup(
22 const QString &name,
23 const QString &formulaString,
24 QgsMeshLayer *layer,
25 qint64 relativeStartTime,
26 qint64 relativeEndTime ):
27 QgsMeshDatasetGroup( name )
28 , mFormula( formulaString )
29 , mLayer( layer )
30 , mStartTime( relativeStartTime )
31 , mEndTime( relativeEndTime )
32 {
33 }
34
initialize()35 void QgsMeshVirtualDatasetGroup::initialize()
36 {
37 QString errMessage;
38 mCalcNode.reset( QgsMeshCalcNode::parseMeshCalcString( mFormula, errMessage ) );
39
40 if ( !mCalcNode || !mLayer )
41 return;
42
43 mDatasetGroupNameUsed = mCalcNode->notAggregatedUsedDatasetGroupNames();
44 mDatasetGroupNameUsedForAggregate = mCalcNode->aggregatedUsedDatasetGroupNames();
45 setDataType( QgsMeshCalcUtils::determineResultDataType( mLayer,
46 mDatasetGroupNameUsed + mDatasetGroupNameUsedForAggregate ) );
47
48 //populate used group indexes
49 QMap<QString, int> usedDatasetGroupindexes;
50 const QList<int> &indexes = mLayer->datasetGroupsIndexes();
51 for ( const int i : indexes )
52 {
53 const QString usedName = mLayer->datasetGroupMetadata( i ).name();
54 if ( mDatasetGroupNameUsed.contains( usedName ) )
55 usedDatasetGroupindexes[usedName] = i;
56 }
57
58 QSet<qint64> times;
59 if ( !mCalcNode->isNonTemporal() )
60 {
61 //populate dataset index with time;
62 const QList<int> &usedIndexes = usedDatasetGroupindexes.values();
63 for ( const int groupIndex : usedIndexes )
64 {
65 const int dsCount = mLayer->datasetCount( groupIndex );
66 if ( dsCount == 0 )
67 return;
68
69 if ( dsCount == 1 ) //non temporal dataset group
70 continue;
71 for ( int i = 0; i < dsCount; i++ )
72 {
73 const qint64 time = mLayer->datasetRelativeTimeInMilliseconds( QgsMeshDatasetIndex( groupIndex, i ) );
74 if ( time != INVALID_MESHLAYER_TIME )
75 times.insert( time );
76 }
77 }
78 }
79
80 if ( times.isEmpty() )
81 times.insert( 0 );
82
83 mDatasetTimes = qgis::setToList( times );
84 std::sort( mDatasetTimes.begin(), mDatasetTimes.end() );
85
86 mDatasetMetaData = QVector<QgsMeshDatasetMetadata>( mDatasetTimes.count() );
87
88 //to fill metadata, calculate all the datasets one time
89 int i = 0;
90 while ( i < mDatasetTimes.count() )
91 {
92 mCurrentDatasetIndex = i;
93 if ( calculateDataset() )
94 ++i; //calculation succeeds
95 else
96 mDatasetTimes.removeAt( i ); //calculation fails, remove this time step
97 }
98
99 calculateStatistic();
100 }
101
datasetCount() const102 int QgsMeshVirtualDatasetGroup::datasetCount() const
103 {
104 return mDatasetTimes.count();
105 }
106
dataset(int index) const107 QgsMeshDataset *QgsMeshVirtualDatasetGroup::dataset( int index ) const
108 {
109 if ( index < 0 || index >= mDatasetTimes.count() )
110 return nullptr;
111
112 if ( index != mCurrentDatasetIndex )
113 {
114 mCurrentDatasetIndex = index;
115 calculateDataset();
116 }
117
118 return mCacheDataset.get();
119 }
120
datasetMetadata(int datasetIndex) const121 QgsMeshDatasetMetadata QgsMeshVirtualDatasetGroup::datasetMetadata( int datasetIndex ) const
122 {
123 if ( datasetIndex < 0 && datasetIndex >= mDatasetMetaData.count() )
124 return QgsMeshDatasetMetadata();
125
126 return mDatasetMetaData.at( datasetIndex );
127 }
128
datasetGroupNamesDependentOn() const129 QStringList QgsMeshVirtualDatasetGroup::datasetGroupNamesDependentOn() const
130 {
131 return mDatasetGroupNameUsed;
132 }
133
writeXml(QDomDocument & doc,const QgsReadWriteContext & context) const134 QDomElement QgsMeshVirtualDatasetGroup::writeXml( QDomDocument &doc, const QgsReadWriteContext &context ) const
135 {
136 Q_UNUSED( context )
137 QDomElement elemDataset = doc.createElement( QStringLiteral( "mesh-dataset" ) );
138 elemDataset.setAttribute( QStringLiteral( "source-type" ), QStringLiteral( "virtual" ) );
139 elemDataset.setAttribute( QStringLiteral( "name" ), name() );
140 elemDataset.setAttribute( QStringLiteral( "formula" ), mFormula );
141 elemDataset.setAttribute( QStringLiteral( "start-time" ), mStartTime );
142 elemDataset.setAttribute( QStringLiteral( "end-time" ), mEndTime );
143
144 return elemDataset;
145 }
146
description() const147 QString QgsMeshVirtualDatasetGroup::description() const
148 {
149 return mFormula;
150 }
151
calculateDataset() const152 bool QgsMeshVirtualDatasetGroup::calculateDataset() const
153 {
154 if ( !mLayer )
155 return false;
156
157 const QgsMeshCalcUtils dsu( mLayer,
158 mDatasetGroupNameUsed,
159 mDatasetGroupNameUsedForAggregate,
160 QgsInterval( mDatasetTimes[mCurrentDatasetIndex] / 1000.0 ),
161 QgsInterval( mStartTime / 1000.0 ),
162 QgsInterval( mEndTime / 1000.0 ) );
163
164 if ( !dsu.isValid() )
165 return false;
166
167 //open output dataset
168 std::unique_ptr<QgsMeshMemoryDatasetGroup> outputGroup = std::make_unique<QgsMeshMemoryDatasetGroup> ( QString(), dsu.outputType() );
169 mCalcNode->calculate( dsu, *outputGroup );
170
171 if ( outputGroup->memoryDatasets.isEmpty() )
172 return false;
173
174 mCacheDataset = outputGroup->memoryDatasets[0];
175 if ( !mDatasetMetaData[mCurrentDatasetIndex].isValid() )
176 {
177 mCacheDataset->calculateMinMax();
178 mCacheDataset->time = mDatasetTimes[mCurrentDatasetIndex] / 3600.0 / 1000.0;
179 mDatasetMetaData[mCurrentDatasetIndex] = mCacheDataset->metadata();
180 }
181
182 return true;
183 }
184