QGIS API Documentation 3.99.0-Master (e9821da5c6b)
Loading...
Searching...
No Matches
qgsmeshcalculator.cpp
Go to the documentation of this file.
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 "qgsmeshcalculator.h"
19
20#include <limits>
21#include <memory>
22
23#include "qgis.h"
24#include "qgsfeedback.h"
25#include "qgsmeshcalcnode.h"
26#include "qgsmeshcalcutils.h"
27#include "qgsmeshlayer.h"
28#include "qgsmeshmemorydataprovider.h"
30
31#include <QFileInfo>
32#include <QString>
33
34using namespace Qt::StringLiterals;
35
36QgsMeshCalculator::QgsMeshCalculator( const QString &formulaString,
37 const QString &outputFile,
38 const QgsRectangle &outputExtent,
39 double startTime,
40 double endTime,
41 QgsMeshLayer *layer )
42 : mFormulaString( formulaString )
43 , mOutputDriver( u"DAT"_s )
44 , mOutputFile( outputFile )
45 , mOutputExtent( outputExtent )
46 , mStartTime( startTime )
47 , mEndTime( endTime )
48 , mMeshLayer( layer )
49{
50 if ( !mOutputFile.isEmpty() )
51 mOutputGroupName = QFileInfo( mOutputFile ).baseName();
52}
53
54QgsMeshCalculator::QgsMeshCalculator( const QString &formulaString,
55 const QString &outputFile,
56 const QgsGeometry &outputMask,
57 double startTime,
58 double endTime,
59 QgsMeshLayer *layer )
60 : mFormulaString( formulaString )
61 , mOutputDriver( u"DAT"_s )
62 , mOutputFile( outputFile )
63 , mOutputMask( outputMask )
64 , mUseMask( true )
65 , mStartTime( startTime )
66 , mEndTime( endTime )
67 , mMeshLayer( layer )
68{
69 if ( !mOutputFile.isEmpty() )
70 mOutputGroupName = QFileInfo( mOutputFile ).baseName();
71}
72
73
74QgsMeshCalculator::QgsMeshCalculator( const QString &formulaString,
75 const QString &outputDriver,
76 const QString &outputGroupName,
77 const QString &outputFile,
78 const QgsRectangle &outputExtent,
79 double startTime,
80 double endTime,
81 QgsMeshLayer *layer )
82 : mFormulaString( formulaString )
83 , mOutputDriver( outputDriver )
84 , mOutputGroupName( outputGroupName )
85 , mOutputFile( outputFile )
86 , mOutputExtent( outputExtent )
87 , mStartTime( startTime )
88 , mEndTime( endTime )
89 , mMeshLayer( layer )
90{
91}
92
93QgsMeshCalculator::QgsMeshCalculator( const QString &formulaString,
94 const QString &outputDriver,
95 const QString &outputGroupName,
96 const QString &outputFile,
97 const QgsGeometry &outputMask,
98 double startTime,
99 double endTime,
100 QgsMeshLayer *layer )
101 : mFormulaString( formulaString )
102 , mOutputDriver( outputDriver )
103 , mOutputGroupName( outputGroupName )
104 , mOutputFile( outputFile )
105 , mOutputMask( outputMask )
106 , mUseMask( true )
107 , mStartTime( startTime )
108 , mEndTime( endTime )
109 , mMeshLayer( layer )
110{
111}
112
113QgsMeshCalculator::QgsMeshCalculator( const QString &formulaString,
114 const QString &outputGroupName,
115 const QgsRectangle &outputExtent,
116 const QgsMeshDatasetGroup::Type &destination,
117 QgsMeshLayer *layer,
118 double startTime,
119 double endTime )
120 : mFormulaString( formulaString )
121 , mOutputGroupName( outputGroupName )
122 , mOutputExtent( outputExtent )
123 , mDestination( destination )
124 , mStartTime( startTime )
125 , mEndTime( endTime )
126 , mMeshLayer( layer )
127{
128}
129
130QgsMeshCalculator::QgsMeshCalculator( const QString &formulaString,
131 const QString &outputGroupName,
132 const QgsGeometry &outputMask,
133 const QgsMeshDatasetGroup::Type &destination,
134 QgsMeshLayer *layer,
135 double startTime,
136 double endTime )
137 : mFormulaString( formulaString )
138 , mOutputGroupName( outputGroupName )
139 , mOutputMask( outputMask )
140 , mUseMask( true )
141 , mDestination( destination )
142 , mStartTime( startTime )
143 , mEndTime( endTime )
144 , mMeshLayer( layer )
145{
146}
147
149 const QString &formulaString,
150 QgsMeshLayer *layer )
151{
153 return QgsMeshCalculator::expressionIsValid( formulaString, layer, cap );
154}
155
157 const QString &formulaString,
158 QgsMeshLayer *layer,
160{
161 QString errorString;
162 std::unique_ptr< QgsMeshCalcNode > calcNode( QgsMeshCalcNode::parseMeshCalcString( formulaString, errorString ) );
163 if ( !calcNode )
164 return ParserError;
165
166 if ( !layer || !layer->dataProvider() )
167 return InputLayerError;
168
169 const QgsMeshDatasetGroupMetadata::DataType dataType = QgsMeshCalcUtils::determineResultDataType( layer, calcNode->usedDatasetGroupNames() );
170
173
174 return Success;
175}
176
178{
179 // check input
180 if ( mOutputFile.isEmpty() && mDestination == QgsMeshDatasetGroup::Persistent )
181 {
182 return CreateOutputError;
183 }
184
185 if ( !mMeshLayer ||
186 !mMeshLayer->dataProvider() ||
187 mMeshLayer->providerType() != u"mdal"_s
188 )
189 {
190 return CreateOutputError;
191 }
192
193 //prepare search string / tree
194 QString errorString;
195 std::unique_ptr< QgsMeshCalcNode > calcNode( QgsMeshCalcNode::parseMeshCalcString( mFormulaString, errorString ) );
196 if ( !calcNode )
197 {
198 return ParserError;
199 }
200
201 // proceed eventually on the fly
202 bool err;
203 if ( mDestination == QgsMeshDatasetGroup::Virtual )
204 {
205 std::unique_ptr<QgsMeshDatasetGroup> virtualDatasetGroup =
206 std::make_unique<QgsMeshVirtualDatasetGroup> ( mOutputGroupName, mFormulaString, mMeshLayer, mStartTime * 3600 * 1000, mEndTime * 3600 * 1000 );
207 virtualDatasetGroup->initialize();
208 virtualDatasetGroup->setReferenceTime( static_cast<QgsMeshLayerTemporalProperties *>( mMeshLayer->temporalProperties() )->referenceTime() );
209 err = !mMeshLayer->addDatasets( virtualDatasetGroup.release() );
210 if ( err )
211 {
212 return CreateOutputError;
213 }
214
215 if ( feedback )
216 {
217 feedback->setProgress( 100.0 );
218 }
219 return Success;
220 }
221
222 //open output dataset
223 const QgsMeshCalcUtils dsu( mMeshLayer, calcNode->usedDatasetGroupNames(), mStartTime, mEndTime );
224 if ( !dsu.isValid() )
225 {
226 return InvalidDatasets;
227 }
228
229 auto outputGroup = std::make_unique<QgsMeshMemoryDatasetGroup> ( mOutputGroupName, dsu.outputType() );
230
231 // calculate
232 const bool ok = calcNode->calculate( dsu, *outputGroup );
233 if ( !ok )
234 {
235 return EvaluateError;
236 }
237
238 if ( feedback && feedback->isCanceled() )
239 {
240 return Canceled;
241 }
242 if ( feedback )
243 {
244 feedback->setProgress( 60.0 );
245 }
246
247 // Finalize dataset
248 if ( mUseMask )
249 {
250 dsu.filter( *outputGroup, mOutputMask );
251 }
252 else
253 {
254 dsu.filter( *outputGroup, mOutputExtent );
255 }
256 outputGroup->setIsScalar( true );
257
258 // before storing the file, find out if the process is not already canceled
259 if ( feedback && feedback->isCanceled() )
260 {
261 return Canceled;
262 }
263 if ( feedback )
264 {
265 feedback->setProgress( 80.0 );
266 }
267
268 // store to file or in memory
269 QVector<QgsMeshDataBlock> datasetValues;
270 QVector<QgsMeshDataBlock> datasetActive;
271 QVector<double> times;
272
273 const auto datasize = outputGroup->datasetCount();
274 datasetValues.reserve( datasize );
275 times.reserve( datasize );
276
277 for ( int i = 0; i < datasize; ++i )
278 {
279 const std::shared_ptr<QgsMeshMemoryDataset> dataset = outputGroup->memoryDatasets.at( i );
280
281 times.push_back( dataset->time );
282 datasetValues.push_back(
283 dataset->datasetValues( outputGroup->isScalar(),
284 0,
285 dataset->values.size() )
286 );
287 if ( !dataset->active.isEmpty() )
288 {
289 datasetActive.push_back(
290 dataset->areFacesActive(
291 0,
292 dataset->active.size() )
293 );
294 }
295 }
296
297 // calculate statistics
298 outputGroup->initialize();
299 outputGroup->setReferenceTime( static_cast<QgsMeshLayerTemporalProperties *>( mMeshLayer->temporalProperties() )->referenceTime() );
300
301 const QgsMeshDatasetGroupMetadata meta = outputGroup->groupMetadata();
302
303 if ( mDestination == QgsMeshDatasetGroup::Memory )
304 {
305 err = !mMeshLayer->addDatasets( outputGroup.release() );
306 }
307 else
308 {
309 err = mMeshLayer->dataProvider()->persistDatasetGroup(
310 mOutputFile,
311 mOutputDriver,
312 meta,
313 datasetValues,
314 datasetActive,
315 times
316 );
317 }
318
319
320 if ( err )
321 {
322 return CreateOutputError;
323 }
324
325 if ( feedback )
326 {
327 feedback->setProgress( 100.0 );
328 }
329 return Success;
330}
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Definition qgsfeedback.h:44
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition qgsfeedback.h:55
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition qgsfeedback.h:63
A geometry is the spatial representation of a feature.
Result
Result of the calculation.
@ InvalidDatasets
Datasets with different time outputs or not part of the mesh.
@ CreateOutputError
Error creating output data file.
@ Success
Calculation successful.
@ EvaluateError
Error during evaluation.
@ ParserError
Error parsing formula.
@ Canceled
Calculation canceled.
@ InputLayerError
Error reading input layer.
Q_DECL_DEPRECATED QgsMeshCalculator(const QString &formulaString, const QString &outputFile, const QgsRectangle &outputExtent, double startTime, double endTime, QgsMeshLayer *layer)
Creates calculator with bounding box (rectangular) mask.
static Q_DECL_DEPRECATED Result expression_valid(const QString &formulaString, QgsMeshLayer *layer)
Returns whether formula is valid for particular mesh layer.
Result processCalculation(QgsFeedback *feedback=nullptr)
Starts the calculation, creates new dataset group and adds it to the mesh layer.
static Result expressionIsValid(const QString &formulaString, QgsMeshLayer *layer, QgsMeshDriverMetadata::MeshDriverCapability &requiredCapability)
Returns whether formula is valid for particular mesh layer.
A collection of dataset group metadata such as whether the data is vector or scalar,...
DataType
Location of where data is specified for datasets in the dataset group.
@ DataOnFaces
Data is defined on faces.
Type
Type of the dataset group.
@ Virtual
Virtual Dataset group defined by a formula.
@ Memory
Temporary dataset group in memory.
@ Persistent
Dataset group store in a file.
MeshDriverCapability
Flags for the capabilities of the driver.
@ CanWriteVertexDatasets
If the driver can persist datasets defined on vertices.
@ CanWriteFaceDatasets
If the driver can persist datasets defined on faces.
Implementation of map layer temporal properties for mesh layers.
QDateTime referenceTime() const
Returns the reference time.
Represents a mesh layer supporting display of data on structured or unstructured meshes.
QgsMeshDataProvider * dataProvider() override
Returns the layer's data provider, it may be nullptr.
A rectangle specified with double values.