QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
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 <QFileInfo>
19#include <limits>
20#include <memory>
21
22#include "qgsfeedback.h"
23#include "qgsmeshcalcnode.h"
24#include "qgsmeshcalculator.h"
25#include "qgsmeshcalcutils.h"
26#include "qgsmeshlayer.h"
27#include "qgsmeshmemorydataprovider.h"
29#include "qgis.h"
30
31QgsMeshCalculator::QgsMeshCalculator( const QString &formulaString,
32 const QString &outputFile,
33 const QgsRectangle &outputExtent,
34 double startTime,
35 double endTime,
36 QgsMeshLayer *layer )
37 : mFormulaString( formulaString )
38 , mOutputDriver( QStringLiteral( "DAT" ) )
39 , mOutputFile( outputFile )
40 , mOutputExtent( outputExtent )
41 , mUseMask( false )
42 , mStartTime( startTime )
43 , mEndTime( endTime )
44 , mMeshLayer( layer )
45{
46 if ( !mOutputFile.isEmpty() )
47 mOutputGroupName = QFileInfo( mOutputFile ).baseName();
48}
49
50QgsMeshCalculator::QgsMeshCalculator( const QString &formulaString,
51 const QString &outputFile,
52 const QgsGeometry &outputMask,
53 double startTime,
54 double endTime,
55 QgsMeshLayer *layer )
56 : mFormulaString( formulaString )
57 , mOutputDriver( QStringLiteral( "DAT" ) )
58 , mOutputFile( outputFile )
59 , mOutputMask( outputMask )
60 , mUseMask( true )
61 , mStartTime( startTime )
62 , mEndTime( endTime )
63 , mMeshLayer( layer )
64{
65 if ( !mOutputFile.isEmpty() )
66 mOutputGroupName = QFileInfo( mOutputFile ).baseName();
67}
68
69
70QgsMeshCalculator::QgsMeshCalculator( const QString &formulaString,
71 const QString &outputDriver,
72 const QString &outputGroupName,
73 const QString &outputFile,
74 const QgsRectangle &outputExtent,
75 double startTime,
76 double endTime,
77 QgsMeshLayer *layer )
78 : mFormulaString( formulaString )
79 , mOutputDriver( outputDriver )
80 , mOutputGroupName( outputGroupName )
81 , mOutputFile( outputFile )
82 , mOutputExtent( outputExtent )
83 , mUseMask( false )
84 , mDestination( QgsMeshDatasetGroup::Persistent )
85 , mStartTime( startTime )
86 , mEndTime( endTime )
87 , mMeshLayer( layer )
88{
89}
90
91QgsMeshCalculator::QgsMeshCalculator( const QString &formulaString,
92 const QString &outputDriver,
93 const QString &outputGroupName,
94 const QString &outputFile,
95 const QgsGeometry &outputMask,
96 double startTime,
97 double endTime,
98 QgsMeshLayer *layer )
99 : mFormulaString( formulaString )
100 , mOutputDriver( outputDriver )
101 , mOutputGroupName( outputGroupName )
102 , mOutputFile( outputFile )
103 , mOutputMask( outputMask )
104 , mUseMask( true )
105 , mDestination( QgsMeshDatasetGroup::Persistent )
106 , mStartTime( startTime )
107 , mEndTime( endTime )
108 , mMeshLayer( layer )
109{
110}
111
112QgsMeshCalculator::QgsMeshCalculator( const QString &formulaString,
113 const QString &outputGroupName,
114 const QgsRectangle &outputExtent,
115 const QgsMeshDatasetGroup::Type &destination,
116 QgsMeshLayer *layer,
117 double startTime,
118 double endTime )
119 : mFormulaString( formulaString )
120 , mOutputGroupName( outputGroupName )
121 , mOutputExtent( outputExtent )
122 , mUseMask( false )
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
171 requiredCapability = dataType == QgsMeshDatasetGroupMetadata::DataOnFaces ? QgsMeshDriverMetadata::MeshDriverCapability::CanWriteFaceDatasets :
172 QgsMeshDriverMetadata::MeshDriverCapability::CanWriteVertexDatasets;
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() != QStringLiteral( "mdal" )
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 std::unique_ptr<QgsMeshMemoryDatasetGroup> 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: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.
Definition: qgsgeometry.h:162
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.
QgsMeshDatasetGroupMetadata is a collection of dataset group metadata such as whether the data is vec...
DataType
Location of where data is specified for datasets in the dataset group.
@ DataOnFaces
Data is defined on faces.
Abstract class that represents a dataset group.
Type
Type of the dataset group.
@ Virtual
Temporary dataset group in memory.
@ Memory
Dataset group store in a file.
@ Persistent
Generic type used for non typed dataset group.
virtual Q_DECL_DEPRECATED bool persistDatasetGroup(const QString &path, const QgsMeshDatasetGroupMetadata &meta, const QVector< QgsMeshDataBlock > &datasetValues, const QVector< QgsMeshDataBlock > &datasetActive, const QVector< double > &times)
Creates a new dataset group from a data and persists it into a destination path.
MeshDriverCapability
Flags for the capabilities of the driver.
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.
Definition: qgsmeshlayer.h:101
bool addDatasets(const QString &path, const QDateTime &defaultReferenceTime=QDateTime())
Adds datasets to the mesh from file with path.
QgsMeshDataProvider * dataProvider() override
Returns the layer's data provider, it may be nullptr.
QgsMapLayerTemporalProperties * temporalProperties() override
Returns the layer's temporal properties.
QString providerType() const
Returns the provider type for this layer.
A rectangle specified with double values.
Definition: qgsrectangle.h:42