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