QGIS API Documentation  3.23.0-Master (dd0cd13a00)
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 
31 QgsMeshCalculator::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 
50 QgsMeshCalculator::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 
70 QgsMeshCalculator::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 
91 QgsMeshCalculator::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 
112 QgsMeshCalculator::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 
130 QgsMeshCalculator::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,
159  QgsMeshDriverMetadata::MeshDriverCapability &requiredCapability )
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: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:125
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:97
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