Branch data Line data Source code
1 : : /***************************************************************************
2 : : qgsmeshcalculator.cpp
3 : : ---------------------
4 : : begin : December 18th, 2018
5 : : copyright : (C) 2018 by Peter Petrik
6 : : email : zilolv 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 <QFileInfo>
19 : : #include <limits>
20 : : #include <memory>
21 : :
22 : : #include "qgsmeshcalcnode.h"
23 : : #include "qgsmeshcalculator.h"
24 : : #include "qgsmeshcalcutils.h"
25 : : #include "qgsmeshmemorydataprovider.h"
26 : : #include "qgsmeshvirtualdatasetgroup.h"
27 : : #include "qgis.h"
28 : :
29 : 0 : QgsMeshCalculator::QgsMeshCalculator( const QString &formulaString,
30 : : const QString &outputFile,
31 : : const QgsRectangle &outputExtent,
32 : : double startTime,
33 : : double endTime,
34 : : QgsMeshLayer *layer )
35 : 0 : : mFormulaString( formulaString )
36 : 0 : , mOutputDriver( QStringLiteral( "DAT" ) )
37 : 0 : , mOutputFile( outputFile )
38 : 0 : , mOutputExtent( outputExtent )
39 : 0 : , mUseMask( false )
40 : 0 : , mStartTime( startTime )
41 : 0 : , mEndTime( endTime )
42 : 0 : , mMeshLayer( layer )
43 : : {
44 : 0 : if ( !mOutputFile.isEmpty() )
45 : 0 : mOutputGroupName = QFileInfo( mOutputFile ).baseName();
46 : 0 : }
47 : :
48 : 0 : QgsMeshCalculator::QgsMeshCalculator( const QString &formulaString,
49 : : const QString &outputFile,
50 : : const QgsGeometry &outputMask,
51 : : double startTime,
52 : : double endTime,
53 : : QgsMeshLayer *layer )
54 : 0 : : mFormulaString( formulaString )
55 : 0 : , mOutputDriver( QStringLiteral( "DAT" ) )
56 : 0 : , mOutputFile( outputFile )
57 : 0 : , mOutputMask( outputMask )
58 : 0 : , mUseMask( true )
59 : 0 : , mStartTime( startTime )
60 : 0 : , mEndTime( endTime )
61 : 0 : , mMeshLayer( layer )
62 : : {
63 : 0 : if ( !mOutputFile.isEmpty() )
64 : 0 : mOutputGroupName = QFileInfo( mOutputFile ).baseName();
65 : 0 : }
66 : :
67 : :
68 : 0 : QgsMeshCalculator::QgsMeshCalculator( const QString &formulaString,
69 : : const QString &outputDriver,
70 : : const QString &outputGroupName,
71 : : const QString &outputFile,
72 : : const QgsRectangle &outputExtent,
73 : : double startTime,
74 : : double endTime,
75 : : QgsMeshLayer *layer )
76 : 0 : : mFormulaString( formulaString )
77 : 0 : , mOutputDriver( outputDriver )
78 : 0 : , mOutputGroupName( outputGroupName )
79 : 0 : , mOutputFile( outputFile )
80 : 0 : , mOutputExtent( outputExtent )
81 : 0 : , mUseMask( false )
82 : 0 : , mDestination( QgsMeshDatasetGroup::Persistent )
83 : 0 : , mStartTime( startTime )
84 : 0 : , mEndTime( endTime )
85 : 0 : , mMeshLayer( layer )
86 : : {
87 : 0 : }
88 : :
89 : 0 : QgsMeshCalculator::QgsMeshCalculator( const QString &formulaString,
90 : : const QString &outputDriver,
91 : : const QString &outputGroupName,
92 : : const QString &outputFile,
93 : : const QgsGeometry &outputMask,
94 : : double startTime,
95 : : double endTime,
96 : : QgsMeshLayer *layer )
97 : 0 : : mFormulaString( formulaString )
98 : 0 : , mOutputDriver( outputDriver )
99 : 0 : , mOutputGroupName( outputGroupName )
100 : 0 : , mOutputFile( outputFile )
101 : 0 : , mOutputMask( outputMask )
102 : 0 : , mUseMask( true )
103 : 0 : , mDestination( QgsMeshDatasetGroup::Persistent )
104 : 0 : , mStartTime( startTime )
105 : 0 : , mEndTime( endTime )
106 : 0 : , mMeshLayer( layer )
107 : : {
108 : 0 : }
109 : :
110 : 0 : QgsMeshCalculator::QgsMeshCalculator( const QString &formulaString,
111 : : const QString &outputGroupName,
112 : : const QgsRectangle &outputExtent,
113 : : const QgsMeshDatasetGroup::Type &destination,
114 : : QgsMeshLayer *layer,
115 : : double startTime,
116 : : double endTime )
117 : 0 : : mFormulaString( formulaString )
118 : 0 : , mOutputGroupName( outputGroupName )
119 : 0 : , mOutputExtent( outputExtent )
120 : 0 : , mUseMask( false )
121 : 0 : , mDestination( destination )
122 : 0 : , mStartTime( startTime )
123 : 0 : , mEndTime( endTime )
124 : 0 : , mMeshLayer( layer )
125 : : {
126 : 0 : }
127 : :
128 : 0 : QgsMeshCalculator::QgsMeshCalculator( const QString &formulaString,
129 : : const QString &outputGroupName,
130 : : const QgsGeometry &outputMask,
131 : : const QgsMeshDatasetGroup::Type &destination,
132 : : QgsMeshLayer *layer,
133 : : double startTime,
134 : : double endTime )
135 : 0 : : mFormulaString( formulaString )
136 : 0 : , mOutputGroupName( outputGroupName )
137 : 0 : , mOutputMask( outputMask )
138 : 0 : , mUseMask( true )
139 : 0 : , mDestination( destination )
140 : 0 : , mStartTime( startTime )
141 : 0 : , mEndTime( endTime )
142 : 0 : , mMeshLayer( layer )
143 : : {
144 : 0 : }
145 : :
146 : 0 : QgsMeshCalculator::Result QgsMeshCalculator::expression_valid(
147 : : const QString &formulaString,
148 : : QgsMeshLayer *layer )
149 : : {
150 : : QgsMeshDriverMetadata::MeshDriverCapability cap;
151 : 0 : return QgsMeshCalculator::expressionIsValid( formulaString, layer, cap );
152 : : }
153 : :
154 : 0 : QgsMeshCalculator::Result QgsMeshCalculator::expressionIsValid(
155 : : const QString &formulaString,
156 : : QgsMeshLayer *layer,
157 : : QgsMeshDriverMetadata::MeshDriverCapability &requiredCapability )
158 : : {
159 : 0 : QString errorString;
160 : 0 : std::unique_ptr< QgsMeshCalcNode > calcNode( QgsMeshCalcNode::parseMeshCalcString( formulaString, errorString ) );
161 : 0 : if ( !calcNode )
162 : 0 : return ParserError;
163 : :
164 : 0 : if ( !layer || !layer->dataProvider() )
165 : 0 : return InputLayerError;
166 : :
167 : 0 : QgsMeshDatasetGroupMetadata::DataType dataType = QgsMeshCalcUtils::determineResultDataType( layer, calcNode->usedDatasetGroupNames() );
168 : :
169 : 0 : requiredCapability = dataType == QgsMeshDatasetGroupMetadata::DataOnFaces ? QgsMeshDriverMetadata::MeshDriverCapability::CanWriteFaceDatasets :
170 : : QgsMeshDriverMetadata::MeshDriverCapability::CanWriteVertexDatasets;
171 : :
172 : 0 : return Success;
173 : 0 : }
174 : :
175 : 0 : QgsMeshCalculator::Result QgsMeshCalculator::processCalculation( QgsFeedback *feedback )
176 : : {
177 : : // check input
178 : 0 : if ( mOutputFile.isEmpty() && mDestination == QgsMeshDatasetGroup::Persistent )
179 : : {
180 : 0 : return CreateOutputError;
181 : : }
182 : :
183 : 0 : if ( !mMeshLayer ||
184 : 0 : !mMeshLayer->dataProvider() ||
185 : 0 : mMeshLayer->providerType() != QStringLiteral( "mdal" )
186 : : )
187 : : {
188 : 0 : return CreateOutputError;
189 : : }
190 : :
191 : : //prepare search string / tree
192 : 0 : QString errorString;
193 : 0 : std::unique_ptr< QgsMeshCalcNode > calcNode( QgsMeshCalcNode::parseMeshCalcString( mFormulaString, errorString ) );
194 : 0 : if ( !calcNode )
195 : : {
196 : 0 : return ParserError;
197 : : }
198 : :
199 : : // proceed eventually on the fly
200 : : bool err;
201 : 0 : if ( mDestination == QgsMeshDatasetGroup::Virtual )
202 : : {
203 : : std::unique_ptr<QgsMeshDatasetGroup> virtualDatasetGroup =
204 : 0 : std::make_unique<QgsMeshVirtualDatasetGroup> ( mOutputGroupName, mFormulaString, mMeshLayer, mStartTime * 3600 * 1000, mEndTime * 3600 * 1000 );
205 : 0 : virtualDatasetGroup->initialize();
206 : 0 : virtualDatasetGroup->setReferenceTime( static_cast<QgsMeshLayerTemporalProperties *>( mMeshLayer->temporalProperties() )->referenceTime() );
207 : 0 : err = !mMeshLayer->addDatasets( virtualDatasetGroup.release() );
208 : 0 : if ( err )
209 : : {
210 : 0 : return CreateOutputError;
211 : : }
212 : :
213 : 0 : if ( feedback )
214 : : {
215 : 0 : feedback->setProgress( 100.0 );
216 : 0 : }
217 : 0 : return Success;
218 : 0 : }
219 : :
220 : : //open output dataset
221 : 0 : QgsMeshCalcUtils dsu( mMeshLayer, calcNode->usedDatasetGroupNames(), mStartTime, mEndTime );
222 : 0 : if ( !dsu.isValid() )
223 : : {
224 : 0 : return InvalidDatasets;
225 : : }
226 : :
227 : 0 : std::unique_ptr<QgsMeshMemoryDatasetGroup> outputGroup = std::make_unique<QgsMeshMemoryDatasetGroup> ( mOutputGroupName, dsu.outputType() );
228 : 0 :
229 : : // calculate
230 : 0 : bool ok = calcNode->calculate( dsu, *outputGroup );
231 : 0 : if ( !ok )
232 : : {
233 : 0 : return EvaluateError;
234 : : }
235 : :
236 : 0 : if ( feedback && feedback->isCanceled() )
237 : : {
238 : 0 : return Canceled;
239 : : }
240 : 0 : if ( feedback )
241 : : {
242 : 0 : feedback->setProgress( 60.0 );
243 : 0 : }
244 : :
245 : : // Finalize dataset
246 : 0 : if ( mUseMask )
247 : : {
248 : 0 : dsu.filter( *outputGroup, mOutputMask );
249 : 0 : }
250 : : else
251 : : {
252 : 0 : dsu.filter( *outputGroup, mOutputExtent );
253 : : }
254 : 0 : outputGroup->setIsScalar( true );
255 : :
256 : : // before storing the file, find out if the process is not already canceled
257 : 0 : if ( feedback && feedback->isCanceled() )
258 : : {
259 : 0 : return Canceled;
260 : : }
261 : 0 : if ( feedback )
262 : : {
263 : 0 : feedback->setProgress( 80.0 );
264 : 0 : }
265 : :
266 : : // store to file or in memory
267 : 0 : QVector<QgsMeshDataBlock> datasetValues;
268 : 0 : QVector<QgsMeshDataBlock> datasetActive;
269 : 0 : QVector<double> times;
270 : :
271 : 0 : const auto datasize = outputGroup->datasetCount();
272 : 0 : datasetValues.reserve( datasize );
273 : 0 : times.reserve( datasize );
274 : :
275 : 0 : for ( int i = 0; i < datasize; ++i )
276 : : {
277 : 0 : const std::shared_ptr<QgsMeshMemoryDataset> dataset = outputGroup->memoryDatasets.at( i );
278 : :
279 : 0 : times.push_back( dataset->time );
280 : 0 : datasetValues.push_back(
281 : 0 : dataset->datasetValues( outputGroup->isScalar(),
282 : : 0,
283 : 0 : dataset->values.size() )
284 : : );
285 : 0 : if ( !dataset->active.isEmpty() )
286 : : {
287 : 0 : datasetActive.push_back(
288 : 0 : dataset->areFacesActive(
289 : : 0,
290 : 0 : dataset->active.size() )
291 : : );
292 : 0 : }
293 : 0 : }
294 : :
295 : : // calculate statistics
296 : 0 : outputGroup->initialize();
297 : 0 : outputGroup->setReferenceTime( static_cast<QgsMeshLayerTemporalProperties *>( mMeshLayer->temporalProperties() )->referenceTime() );
298 : :
299 : 0 : const QgsMeshDatasetGroupMetadata meta = outputGroup->groupMetadata();
300 : :
301 : 0 : if ( mDestination == QgsMeshDatasetGroup::Memory )
302 : : {
303 : 0 : err = !mMeshLayer->addDatasets( outputGroup.release() );
304 : 0 : }
305 : : else
306 : : {
307 : 0 : err = mMeshLayer->dataProvider()->persistDatasetGroup(
308 : 0 : mOutputFile,
309 : 0 : mOutputDriver,
310 : : meta,
311 : : datasetValues,
312 : : datasetActive,
313 : : times
314 : : );
315 : : }
316 : :
317 : :
318 : 0 : if ( err )
319 : : {
320 : 0 : return CreateOutputError;
321 : : }
322 : :
323 : 0 : if ( feedback )
324 : : {
325 : 0 : feedback->setProgress( 100.0 );
326 : 0 : }
327 : 0 : return Success;
328 : 0 : }
|