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