QGIS API Documentation  3.22.4-Białowieża (ce8e65e95e)
qgsmeshcalcutils.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsmeshcalcutils.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  ***************************************************************************/
18 
19 #include <QFileInfo>
20 
21 #include "qgsmeshcalcnode.h"
22 #include "qgsmeshcalcutils.h"
23 #include "qgsmeshmemorydataprovider.h"
24 #include "qgstriangularmesh.h"
25 #include "qgsmapsettings.h"
26 #include "qgsmeshlayerutils.h"
27 #include "qgsmeshlayerrenderer.h"
28 #include "qgsproject.h"
29 
30 const double D_TRUE = 1.0;
31 const double D_FALSE = 0.0;
32 const double D_NODATA = std::numeric_limits<double>::quiet_NaN();
33 
34 std::shared_ptr<QgsMeshMemoryDatasetGroup> QgsMeshCalcUtils::createMemoryDatasetGroup( const QString &datasetGroupName, const QgsInterval &relativeTime, const QgsInterval &startTime, const QgsInterval &endTime ) const
35 {
36  std::shared_ptr<QgsMeshMemoryDatasetGroup> grp;
37  const QList<int> &indexes = mMeshLayer->datasetGroupsIndexes();
38  for ( const int groupIndex : indexes )
39  {
40  const QgsMeshDatasetGroupMetadata meta = mMeshLayer->datasetGroupMetadata( groupIndex );
41  const QString name = meta.name();
42  if ( name == datasetGroupName )
43  {
44  // we need to convert the native type to the requested type
45  // only possibility that cannot happen is to convert vertex dataset to
46  // face dataset. This would suggest bug in determineResultDataType()
47  Q_ASSERT( !( ( meta.dataType() == QgsMeshDatasetGroupMetadata::DataOnVertices ) && ( mOutputType == QgsMeshDatasetGroupMetadata::DataOnFaces ) ) );
48 
49  grp = std::make_shared<QgsMeshMemoryDatasetGroup>();
50  grp->setIsScalar( meta.isScalar() );
51  grp->setDataType( mOutputType );
52  grp->setMinimumMaximum( meta.minimum(), meta.maximum() );
53  grp->setName( meta.name() );
54 
55  if ( !relativeTime.isValid() && ( !endTime.isValid() || !startTime.isValid() ) )
56  {
57  for ( int index = 0; index < mMeshLayer->datasetCount( groupIndex ); ++index )
58  grp->addDataset( createMemoryDataset( QgsMeshDatasetIndex( groupIndex, index ) ) );
59  }
60  else if ( relativeTime.isValid() )
61  {
62  const QgsMeshDatasetIndex datasetIndex = mMeshLayer->datasetIndexAtRelativeTime( relativeTime, groupIndex );
63  if ( datasetIndex.isValid() )
64  grp->addDataset( createMemoryDataset( datasetIndex ) );
65  }
66  else //only start time and end time are valid
67  {
68  QList<QgsMeshDatasetIndex> datasetIndexes = mMeshLayer->datasetIndexInRelativeTimeInterval( startTime, endTime, groupIndex );
69 
70  if ( datasetIndexes.isEmpty() ) // if empty, at least one dataset corresponding to startTime
71  datasetIndexes.append( mMeshLayer->datasetIndexAtRelativeTime( startTime, groupIndex ) );
72 
73  for ( const QgsMeshDatasetIndex &index : datasetIndexes )
74  grp->addDataset( createMemoryDataset( index ) );
75  }
76 
77  break;
78  }
79  }
80 
81  return grp;
82 }
83 
84 std::shared_ptr<QgsMeshMemoryDataset> QgsMeshCalcUtils::createMemoryDataset( const QgsMeshMemoryDatasetGroup &grp ) const
85 {
86  return createMemoryDataset( grp.dataType() );
87 }
88 
89 std::shared_ptr<QgsMeshMemoryDataset> QgsMeshCalcUtils::createMemoryDataset( const QgsMeshDatasetIndex &datasetIndex ) const
90 {
91  const QgsMeshDataProvider *dp = mMeshLayer->dataProvider();
92  const int groupIndex = datasetIndex.group();
93  const auto meta = mMeshLayer->datasetGroupMetadata( groupIndex );
94 
95  const int nativeCount = ( meta.dataType() == QgsMeshDatasetGroupMetadata::DataOnVertices ) ? dp->vertexCount() : dp->faceCount();
96  const int resultCount = ( mOutputType == QgsMeshDatasetGroupMetadata::DataOnVertices ) ? dp->vertexCount() : dp->faceCount();
97 
98  const QgsMeshDatasetMetadata dsMeta = mMeshLayer->datasetMetadata( datasetIndex );
99  std::shared_ptr<QgsMeshMemoryDataset> ds = createMemoryDataset( mOutputType );
100  ds->maximum = dsMeta.maximum();
101  ds->minimum = dsMeta.minimum();
102  ds->time = dsMeta.time();
103  ds->valid = dsMeta.isValid();
104 
105  // the function already averages volume datasets to face dataset values
106  const QgsMeshDataBlock block = QgsMeshLayerUtils::datasetValues( mMeshLayer, datasetIndex, 0, nativeCount );
107  // it is 2D memory datasets, so it shouldn't be invalid
108  Q_ASSERT( block.isValid() );
109  Q_ASSERT( block.count() == nativeCount );
110 
111  // for data on faces, there could be request to interpolate the data to vertices
113  {
114  if ( meta.isScalar() )
115  {
116  QVector<double> data =
117  QgsMeshLayerUtils::interpolateFromFacesData(
118  block.values(),
119  nativeMesh(),
120  triangularMesh(),
121  nullptr,
123  );
124  Q_ASSERT( data.size() == resultCount );
125  for ( int valueIndex = 0; valueIndex < resultCount; ++valueIndex )
126  ds->values[valueIndex] = QgsMeshDatasetValue( data[valueIndex] );
127  }
128  else
129  {
130  QVector<double> buf = block.values();
131  QVector<double> x( nativeCount );
132  QVector<double> y( nativeCount );
133  for ( int value_i = 0; value_i < nativeCount; ++value_i )
134  {
135  x[value_i] = buf[2 * value_i];
136  y[value_i] = buf[2 * value_i + 1];
137  }
138 
139  QVector<double> dataX =
140  QgsMeshLayerUtils::interpolateFromFacesData(
141  x,
142  mMeshLayer->nativeMesh(),
143  mMeshLayer->triangularMesh(),
144  nullptr,
145  mMeshLayer->rendererSettings().scalarSettings( groupIndex ).dataResamplingMethod()
146  );
147  Q_ASSERT( dataX.size() == resultCount );
148  QVector<double> dataY =
149  QgsMeshLayerUtils::interpolateFromFacesData(
150  y,
151  mMeshLayer->nativeMesh(),
152  mMeshLayer->triangularMesh(),
153  nullptr,
154  mMeshLayer->rendererSettings().scalarSettings( groupIndex ).dataResamplingMethod()
155  );
156 
157  Q_ASSERT( dataY.size() == resultCount );
158 
159  for ( int value_i = 0; value_i < resultCount; ++value_i )
160  {
161  ds->values[value_i] = QgsMeshDatasetValue( dataX[value_i], dataY[value_i] );
162  }
163  }
164  }
165  else
166  {
167  for ( int value_i = 0; value_i < resultCount; ++value_i )
168  ds->values[value_i] = block.value( value_i );
169  }
170 
171  if ( mOutputType == QgsMeshDatasetGroupMetadata::DataOnVertices )
172  {
173  const QgsMeshDataBlock active = mMeshLayer->areFacesActive( datasetIndex, 0, dp->faceCount() );
174  Q_ASSERT( active.count() == dp->faceCount() );
175  for ( int value_i = 0; value_i < dp->faceCount(); ++value_i )
176  ds->active[value_i] = active.active( value_i );
177  }
178 
179  return ds;
180 }
181 
182 std::shared_ptr<QgsMeshMemoryDataset> QgsMeshCalcUtils::createMemoryDataset( const QgsMeshDatasetGroupMetadata::DataType type ) const
183 {
184  Q_ASSERT( type != QgsMeshDatasetGroupMetadata::DataOnVolumes );
185 
186  std::shared_ptr<QgsMeshMemoryDataset> ds = std::make_shared<QgsMeshMemoryDataset>();
188  {
189  ds->values.resize( mMeshLayer->dataProvider()->vertexCount() );
190  ds->active.resize( mMeshLayer->dataProvider()->faceCount() );
191  memset( ds->active.data(), 1, static_cast<size_t>( ds->active.size() ) * sizeof( int ) );
192  }
193  else
194  {
195  ds->values.resize( mMeshLayer->dataProvider()->faceCount() );
196  }
197  ds->valid = true;
198  return ds;
199 }
200 
201 QgsMeshCalcUtils:: QgsMeshCalcUtils( QgsMeshLayer *layer,
202  const QStringList &usedGroupNames,
203  double startTime,
204  double endTime )
205  : mMeshLayer( layer )
206  , mIsValid( false )
207 {
208  // Layer must be valid
209  if ( !mMeshLayer || !mMeshLayer->dataProvider() )
210  return;
211 
212  // Resolve output type of the calculation
213  mOutputType = determineResultDataType( layer, usedGroupNames );
214 
215  // Data on edges are not implemented
216  if ( mOutputType == QgsMeshDatasetGroupMetadata::DataOnEdges )
217  return;
218 
219  // Support for meshes with edges are not implemented
220  if ( mMeshLayer->dataProvider()->contains( QgsMesh::ElementType::Edge ) )
221  return;
222 
223  // First populate group's names map and see if we have all groups present
224  // And basically fetch all data from any mesh provider to memory
225  for ( const QString &groupName : usedGroupNames )
226  {
227  const std::shared_ptr<QgsMeshMemoryDatasetGroup> ds = createMemoryDatasetGroup( groupName );
228  if ( !ds )
229  return;
230 
231  mDatasetGroupMap.insert( groupName, ds );
232  }
233 
234  // Now populate used times and check that all datasets do have some times
235  // OR just one time (== one output)
236  bool timesPopulated = false;
237  const QList<std::shared_ptr<QgsMeshMemoryDatasetGroup>> vals = mDatasetGroupMap.values();
238  for ( const std::shared_ptr<QgsMeshMemoryDatasetGroup> &ds : vals )
239  {
240  if ( ds->datasetCount() == 0 )
241  {
242  // dataset must have at least 1 output
243  return;
244  }
245 
246  if ( ds->datasetCount() > 1 )
247  {
248  if ( timesPopulated )
249  {
250  if ( ds->datasetCount() != mTimes.size() )
251  {
252  // different number of datasets in the groups
253  return;
254  }
255  }
256 
257  for ( int datasetIndex = 0; datasetIndex < ds->datasetCount(); ++datasetIndex )
258  {
259  const std::shared_ptr<const QgsMeshMemoryDataset> o = ds->constDataset( datasetIndex );
260  if ( timesPopulated )
261  {
262  if ( !qgsDoubleNear( mTimes[datasetIndex], o->time ) )
263  {
264  // error, the times in different datasets differ
265  return;
266  }
267  }
268  else
269  {
270  mTimes.append( o->time );
271  }
272  }
273 
274  timesPopulated = true;
275  }
276  }
277 
278  // case of all group are not time varying or usedGroupNames is empty
279  if ( mTimes.isEmpty() )
280  {
281  mTimes.push_back( 0.0 );
282  }
283  else
284  {
285  // filter out times we do not need to speed up calculations
286  for ( QVector<double>::iterator it = mTimes.begin(); it != mTimes.end(); )
287  {
288  if ( qgsDoubleNear( *it, startTime ) ||
289  qgsDoubleNear( *it, endTime ) ||
290  ( ( *it >= startTime ) && ( *it <= endTime ) ) )
291  ++it;
292  else
293  it = mTimes.erase( it );
294  }
295  }
296 
297  // check that all datasets are of the same type
298  for ( const std::shared_ptr<QgsMeshMemoryDatasetGroup> &ds : vals )
299  {
300  if ( ds->dataType() != mOutputType )
301  return;
302  }
303 
304  // All is valid!
305  mIsValid = true;
306 }
307 
308 QgsMeshCalcUtils::QgsMeshCalcUtils( QgsMeshLayer *layer, const QStringList &usedGroupNames, const QgsInterval &relativeTime )
309  : mMeshLayer( layer )
310  , mIsValid( false )
311 {
312  // Layer must be valid
313  if ( !mMeshLayer || !mMeshLayer->dataProvider() )
314  return;
315 
316  // Resolve output type of the calculation
317  mOutputType = determineResultDataType( layer, usedGroupNames );
318 
319  // Data on edges are not implemented
320  if ( mOutputType == QgsMeshDatasetGroupMetadata::DataOnEdges )
321  return;
322 
323  // Support for meshes with edges are not implemented
324  if ( mMeshLayer->dataProvider()->contains( QgsMesh::ElementType::Edge ) )
325  return;
326 
327  QgsInterval usedInterval = relativeTime;
328  if ( !usedInterval.isValid() )
329  usedInterval = QgsInterval( 0 );
330 
331  for ( const QString &groupName : usedGroupNames )
332  {
333  const std::shared_ptr<QgsMeshMemoryDatasetGroup> ds = createMemoryDatasetGroup( groupName, relativeTime );
334  if ( !ds || ds->memoryDatasets.isEmpty() )
335  return;
336 
337  mDatasetGroupMap.insert( groupName, ds );
338  }
339 
340  mTimes.push_back( usedInterval.hours() );
341 
342  mIsValid = true;
343 }
344 
345 QgsMeshCalcUtils::QgsMeshCalcUtils( QgsMeshLayer *layer,
346  const QStringList &usedGroupNames,
347  const QStringList &usedGroupNamesForAggregate,
348  const QgsInterval &relativeTime,
349  const QgsInterval &startTime,
350  const QgsInterval &endTime )
351  : mMeshLayer( layer )
352  , mIsValid( false )
353 {
354  // Layer must be valid
355  if ( !mMeshLayer || !mMeshLayer->dataProvider() )
356  return;
357 
358  // Resolve output type of the calculation
359 
360  mOutputType = determineResultDataType( layer, usedGroupNames + usedGroupNamesForAggregate );
361 
362  // Data on edges are not implemented
363  if ( mOutputType == QgsMeshDatasetGroupMetadata::DataOnEdges )
364  return;
365 
366  // Support for meshes with edges are not implemented
367  if ( mMeshLayer->dataProvider()->contains( QgsMesh::ElementType::Edge ) )
368  return;
369 
370  for ( const QString &groupName : usedGroupNamesForAggregate )
371  {
372  const std::shared_ptr<QgsMeshMemoryDatasetGroup> dsg = createMemoryDatasetGroup( groupName, QgsInterval(), startTime, endTime );
373  if ( !dsg )
374  return;
375 
376  mDatasetGroupMapForAggregate.insert( groupName, dsg );
377  }
378 
379  for ( const QString &groupName : usedGroupNames )
380  {
381  const std::shared_ptr<QgsMeshMemoryDatasetGroup> ds = createMemoryDatasetGroup( groupName, relativeTime );
382  if ( ( !ds || ds->memoryDatasets.isEmpty() ) )
383  {
384  if ( mDatasetGroupMapForAggregate.contains( groupName ) )
385  continue;
386  else
387  return;
388  }
389  mDatasetGroupMap.insert( groupName, ds );
390  }
391 
392  QgsInterval usedInterval = relativeTime;
393  if ( !usedInterval.isValid() )
394  usedInterval = QgsInterval( 0 );
395  mTimes.append( usedInterval.hours() );
396 
397  mIsValid = true;
398  mIgnoreTime = true;
399 }
400 
401 bool QgsMeshCalcUtils::isValid() const
402 {
403  return mIsValid;
404 }
405 
406 const QgsMeshLayer *QgsMeshCalcUtils::layer() const
407 {
408  return mMeshLayer;
409 }
410 
411 std::shared_ptr<const QgsMeshMemoryDatasetGroup> QgsMeshCalcUtils::group( const QString &datasetName, bool isAggregate ) const
412 {
413  if ( isAggregate )
414  return mDatasetGroupMapForAggregate.value( datasetName );
415  else
416  return mDatasetGroupMap.value( datasetName );
417 }
418 
419 std::shared_ptr<const QgsMeshMemoryDatasetGroup> QgsMeshCalcUtils::group( const QString &datasetName ) const
420 {
421  return mDatasetGroupMap[datasetName];
422 }
423 
424 void QgsMeshCalcUtils::populateSpatialFilter( QgsMeshMemoryDatasetGroup &filter, const QgsRectangle &extent ) const
425 {
426  Q_ASSERT( mOutputType != QgsMeshDatasetGroupMetadata::DataOnVolumes );
427 
428  filter.clearDatasets();
429 
430  const std::shared_ptr<QgsMeshMemoryDataset> output = createMemoryDataset( filter );
431  output->time = mTimes[0];
432 
433  const QList<int> faceIndexesForRectangle = triangularMesh()->faceIndexesForRectangle( extent );
434  const QVector<int> trianglesToNativeFaces = triangularMesh()->trianglesToNativeFaces();
435 
436  if ( mOutputType == QgsMeshDatasetGroupMetadata::DataOnVertices )
437  {
438  for ( const int faceIndex : faceIndexesForRectangle )
439  {
440  const int nativeIndex = trianglesToNativeFaces[faceIndex];
441  const QgsMeshFace face = nativeMesh()->face( nativeIndex );
442  for ( const int vertexIndex : face )
443  {
444  output->values[vertexIndex].set( D_TRUE );
445  }
446  }
447  }
448  else
449  {
450  for ( const int faceIndex : faceIndexesForRectangle )
451  {
452  const int nativeIndex = trianglesToNativeFaces[faceIndex];
453  output->values[nativeIndex].set( D_TRUE );
454  }
455  }
456  filter.addDataset( output );
457 }
458 
459 
460 void QgsMeshCalcUtils::populateMaskFilter( QgsMeshMemoryDatasetGroup &filter, const QgsGeometry &mask ) const
461 {
462  Q_ASSERT( mOutputType != QgsMeshDatasetGroupMetadata::DataOnVolumes );
463 
464  filter.clearDatasets();
465  const std::shared_ptr<QgsMeshMemoryDataset> output = createMemoryDataset( filter );
466  output->time = mTimes[0];
467 
468  const QVector<QgsMeshVertex> &vertices = triangularMesh()->vertices();
469 
470  if ( mOutputType == QgsMeshDatasetGroupMetadata::DataOnVertices )
471  {
472  const int nativeVertexCount = mMeshLayer->dataProvider()->vertexCount();
473 
474  for ( int i = 0; i < nativeVertexCount; ++i )
475  {
476  const QgsPointXY point( vertices[i] );
477  if ( mask.contains( &point ) )
478  {
479  output->values[i].set( D_TRUE );
480  }
481  else
482  {
483  output->values[i].set( D_FALSE );
484  }
485  }
486  }
487  else
488  {
489  const QVector<QgsMeshFace> &triangles = triangularMesh()->triangles();
490  for ( int i = 0; i < triangles.size(); ++i )
491  {
492  const QgsMeshFace face = triangles[i];
493  const QgsGeometry geom = QgsMeshUtils::toGeometry( face, vertices );
494  const QgsRectangle bbox = geom.boundingBox();
495  if ( mask.intersects( bbox ) )
496  {
497  output->values[i].set( D_TRUE );
498  }
499  else
500  {
501  output->values[i].set( D_FALSE );
502  }
503  }
504  }
505  filter.addDataset( output );
506 }
507 
508 std::shared_ptr<QgsMeshMemoryDataset> QgsMeshCalcUtils::number( double val, double time ) const
509 {
510  Q_ASSERT( isValid() );
511 
512  std::shared_ptr<QgsMeshMemoryDataset> output = createMemoryDataset( mOutputType );
513  output->time = time;
514 
515  // by default it is initialized to 1
516  if ( std::isnan( val ) )
517  {
518  if ( mOutputType == QgsMeshDatasetGroupMetadata::DataOnVertices )
519  memset( output->active.data(), 0, static_cast<size_t>( output->active.size() ) * sizeof( int ) );
520  }
521  else
522  {
523  for ( int i = 0; i < output->values.size(); ++i ) // Using for loop we are initializing
524  {
525  output->values[i].set( val );
526  }
527  }
528 
529  return output;
530 }
531 
532 void QgsMeshCalcUtils::number( QgsMeshMemoryDatasetGroup &group1, double val ) const
533 {
534  Q_ASSERT( isValid() );
535 
536  group1.clearDatasets();
537  const std::shared_ptr<QgsMeshMemoryDataset> output = number( val, mTimes[0] );
538  group1.addDataset( output );
539 }
540 
541 
542 void QgsMeshCalcUtils::ones( QgsMeshMemoryDatasetGroup &group1 ) const
543 {
544  Q_ASSERT( isValid() );
545  number( group1, 1.0 );
546 }
547 
548 void QgsMeshCalcUtils::nodata( QgsMeshMemoryDatasetGroup &group1 ) const
549 {
550  Q_ASSERT( isValid() );
551  number( group1, D_NODATA );
552 }
553 
554 
555 std::shared_ptr<QgsMeshMemoryDataset> QgsMeshCalcUtils::copy(
556  std::shared_ptr<const QgsMeshMemoryDataset> dataset0
557 ) const
558 {
559  Q_ASSERT( isValid() );
560  Q_ASSERT( dataset0 );
561 
562  std::shared_ptr<QgsMeshMemoryDataset> output = std::make_shared<QgsMeshMemoryDataset>();
563  output->values = dataset0->values; //deep copy
564  output->active = dataset0->active; //deep copy
565  output->time = dataset0->time;
566  output->valid = dataset0->valid;
567  return output;
568 }
569 
570 void QgsMeshCalcUtils::copy( QgsMeshMemoryDatasetGroup &group1, const QString &groupName, bool isAggregate ) const
571 {
572  Q_ASSERT( isValid() );
573 
574  const std::shared_ptr<const QgsMeshMemoryDatasetGroup> group2 = group( groupName, isAggregate );
575  Q_ASSERT( group2 );
576 
577  if ( group2->datasetCount() == 1 )
578  {
579  // Always copy
580  const std::shared_ptr<const QgsMeshMemoryDataset> o0 = group2->constDataset( 0 );
581  const std::shared_ptr<QgsMeshMemoryDataset> output = copy( o0 );
582  group1.addDataset( output );
583  }
584  else
585  {
586  for ( int output_index = 0; output_index < group2->datasetCount(); ++output_index )
587  {
588  const std::shared_ptr<const QgsMeshMemoryDataset> o0 = group2->constDataset( output_index );
589  if ( mIgnoreTime ||
590  qgsDoubleNear( o0->time, mTimes.first() ) ||
591  qgsDoubleNear( o0->time, mTimes.last() ) ||
592  ( ( o0->time >= mTimes.first() ) && ( o0->time <= mTimes.last() ) )
593  )
594  {
595  const std::shared_ptr<QgsMeshMemoryDataset> output = copy( o0 );
596  group1.addDataset( output );
597  }
598  }
599  }
600 }
601 
602 void QgsMeshCalcUtils::transferDatasets( QgsMeshMemoryDatasetGroup &group1, QgsMeshMemoryDatasetGroup &group2 ) const
603 {
604  Q_ASSERT( isValid() );
605 
606  group1.clearDatasets();
607  for ( int i = 0; i < group2.datasetCount(); ++i )
608  {
609  const std::shared_ptr<QgsMeshMemoryDataset> o = group2.memoryDatasets[i];
610  Q_ASSERT( o );
611  group1.addDataset( o );
612  }
613  group2.clearDatasets();
614 }
615 
616 void QgsMeshCalcUtils::expand( QgsMeshMemoryDatasetGroup &group1, const QgsMeshMemoryDatasetGroup &group2 ) const
617 {
618  Q_ASSERT( isValid() );
619 
620  if ( group2.datasetCount() > 1 )
621  {
622  if ( group1.datasetCount() == 1 )
623  {
624  const std::shared_ptr<QgsMeshMemoryDataset> o0 = group1.memoryDatasets[0];
625  Q_ASSERT( o0 );
626  for ( int i = 1; i < group2.datasetCount(); ++i )
627  {
628  const std::shared_ptr<QgsMeshMemoryDataset> o = copy( o0 );
629 
630  if ( mIgnoreTime )
631  o->time = mTimes[0];
632  else
633  o->time = mTimes[i];
634 
635  group1.addDataset( o );
636  }
637  }
638  }
639 }
640 
641 
642 std::shared_ptr<QgsMeshMemoryDataset> QgsMeshCalcUtils::canditateDataset(
644  int datasetIndex ) const
645 {
646  Q_ASSERT( isValid() );
647 
648  if ( group.datasetCount() > 1 )
649  {
650  Q_ASSERT( group.datasetCount() > datasetIndex );
651  return group.memoryDatasets[datasetIndex];
652  }
653  else
654  {
655  Q_ASSERT( group.datasetCount() == 1 );
656  return group.memoryDatasets[0];
657  }
658 }
659 
660 std::shared_ptr<const QgsMeshMemoryDataset> QgsMeshCalcUtils::constCandidateDataset(
661  const QgsMeshMemoryDatasetGroup &group,
662  int datasetIndex ) const
663 {
664  Q_ASSERT( isValid() );
665 
666  if ( group.datasetCount() > 1 )
667  {
668  Q_ASSERT( group.datasetCount() > datasetIndex );
669  return group.constDataset( datasetIndex );
670  }
671  else
672  {
673  Q_ASSERT( group.datasetCount() == 1 );
674  return group.constDataset( 0 );
675  }
676 }
677 
678 int QgsMeshCalcUtils::datasetCount(
679  const QgsMeshMemoryDatasetGroup &group1,
680  const QgsMeshMemoryDatasetGroup &group2 ) const
681 {
682  Q_ASSERT( isValid() );
683 
684  if ( ( group1.datasetCount() > 1 ) || ( group2.datasetCount() > 1 ) )
685  {
686  if ( mIgnoreTime )
687  return std::max( group1.datasetCount(), group2.datasetCount() );
688  else
689  return mTimes.size();
690  }
691  else
692  {
693  return 1;
694  }
695 }
696 
697 void QgsMeshCalcUtils::func1( QgsMeshMemoryDatasetGroup &group,
698  std::function<double( double )> func ) const
699 {
700  Q_ASSERT( isValid() );
701 
702  for ( int time_index = 0; time_index < group.datasetCount(); ++time_index )
703  {
704  const std::shared_ptr<QgsMeshMemoryDataset> output = canditateDataset( group, time_index );
705 
706  for ( int n = 0; n < output->values.size(); ++n )
707  {
708  const double val1 = output->values[n].scalar();
709  double res_val = D_NODATA;
710  if ( !std::isnan( val1 ) )
711  res_val = func( val1 );
712  output->values[n] = res_val;
713  }
714 
716  activate( output );
717  }
718 }
719 
720 
721 void QgsMeshCalcUtils::func2( QgsMeshMemoryDatasetGroup &group1,
722  const QgsMeshMemoryDatasetGroup &group2,
723  std::function<double( double, double )> func ) const
724 {
725  Q_ASSERT( isValid() );
726  Q_ASSERT( group1.dataType() == group2.dataType() ); // we do not support mixed output types
727 
728  expand( group1, group2 );
729 
730  for ( int time_index = 0; time_index < datasetCount( group1, group2 ); ++time_index )
731  {
732  const std::shared_ptr<QgsMeshMemoryDataset> o1 = canditateDataset( group1, time_index );
733  const std::shared_ptr<const QgsMeshMemoryDataset> o2 = constCandidateDataset( group2, time_index );
734 
735  for ( int n = 0; n < o2->values.size(); ++n )
736  {
737  const double val1 = o1->values[n].scalar();
738  const double val2 = o2->values[n].scalar();
739  double res_val = D_NODATA;
740  if ( !std::isnan( val1 ) && !std::isnan( val2 ) )
741  res_val = func( val1, val2 );
742  o1->values[n] = res_val;
743  }
744 
746  {
747  activate( o1, o2 );
748  }
749 
750  }
751 }
752 
753 void QgsMeshCalcUtils::funcAggr(
755  std::function<double( QVector<double>& )> func
756 ) const
757 {
758  Q_ASSERT( isValid() );
759 
761  {
762  const std::shared_ptr<QgsMeshMemoryDataset> output = QgsMeshCalcUtils::createMemoryDataset( QgsMeshDatasetGroupMetadata::DataOnVertices );
763  output->time = mTimes[0];
764  for ( int n = 0; n < mMeshLayer->dataProvider()->vertexCount(); ++n )
765  {
766  QVector < double > vals;
767  for ( int datasetIndex = 0; datasetIndex < group1.datasetCount(); ++datasetIndex )
768  {
769  const std::shared_ptr<QgsMeshMemoryDataset> o1 = canditateDataset( group1, datasetIndex );
770 
771  const double val1 = o1->values[n].scalar();
772  // ideally we should take only values from cells that are active.
773  // but the problem is that the node can be part of multiple cells,
774  // few active and few not, ...
775  if ( !std::isnan( val1 ) )
776  {
777  vals.push_back( val1 );
778  }
779  }
780 
781  double res_val = D_NODATA;
782  if ( !vals.isEmpty() )
783  {
784  res_val = func( vals );
785  }
786 
787  output->values[n] = res_val;
788  }
789 
790  // lets do activation purely on NODATA values as we did aggregation here
791  activate( output );
792 
793  group1.clearDatasets();
794  group1.addDataset( output );
795 
796  }
797  else
798  {
799  const std::shared_ptr<QgsMeshMemoryDataset> output = QgsMeshCalcUtils::createMemoryDataset( QgsMeshDatasetGroupMetadata::DataOnFaces );
800  output->time = mTimes[0];
801 
802  const int facesCount = mMeshLayer->dataProvider()->faceCount();
803  output->values.resize( facesCount );
804 
805  for ( int n = 0; n < mMeshLayer->dataProvider()->faceCount(); ++n )
806  {
807  QVector < double > vals;
808  for ( int datasetIndex = 0; datasetIndex < group1.datasetCount(); ++datasetIndex )
809  {
810  const std::shared_ptr<QgsMeshMemoryDataset> o1 = canditateDataset( group1, datasetIndex );
811  const double val1 = o1->values[n].scalar();
812  if ( !std::isnan( val1 ) )
813  {
814  vals.push_back( val1 );
815  }
816  }
817 
818  double res_val = D_NODATA;
819  if ( !vals.isEmpty() )
820  {
821  res_val = func( vals );
822  }
823 
824  output->values[n] = res_val;
825  }
826 
827  group1.clearDatasets();
828  group1.addDataset( output );
829  }
830 }
831 
832 const QgsTriangularMesh *QgsMeshCalcUtils::triangularMesh() const
833 {
834  updateMesh();
835  Q_ASSERT( mMeshLayer->triangularMesh() );
836  return mMeshLayer->triangularMesh();
837 }
838 
839 const QgsMesh *QgsMeshCalcUtils::nativeMesh() const
840 {
841  updateMesh();
842  Q_ASSERT( mMeshLayer->nativeMesh() );
843  return mMeshLayer->nativeMesh();
844 }
845 
846 void QgsMeshCalcUtils::updateMesh() const
847 {
848  if ( ! mMeshLayer->nativeMesh() )
849  {
850  //calling this method creates the triangular mesh if it doesn't exist
851  mMeshLayer->updateTriangularMesh();
852  }
853 }
854 
855 QgsMeshDatasetGroupMetadata::DataType QgsMeshCalcUtils::outputType() const
856 {
857  return mOutputType;
858 }
859 
860 void QgsMeshCalcUtils::addIf( QgsMeshMemoryDatasetGroup &trueGroup,
861  const QgsMeshMemoryDatasetGroup &falseGroup,
862  const QgsMeshMemoryDatasetGroup &condition ) const
863 {
864  Q_ASSERT( isValid() );
865 
866  // Make sure we have enough outputs in the resulting dataset
867  expand( trueGroup, condition );
868  expand( trueGroup, falseGroup );
869 
870  Q_ASSERT( trueGroup.dataType() == falseGroup.dataType() ); // we do not support mixed output types
871  Q_ASSERT( trueGroup.dataType() == condition.dataType() ); // we do not support mixed output types
872 
873  for ( int time_index = 0; time_index < trueGroup.datasetCount(); ++time_index )
874  {
875  const std::shared_ptr<QgsMeshMemoryDataset> true_o = canditateDataset( trueGroup, time_index );
876  const std::shared_ptr<const QgsMeshMemoryDataset> false_o = constCandidateDataset( falseGroup, time_index );
877  const std::shared_ptr<const QgsMeshMemoryDataset> condition_o = constCandidateDataset( condition, time_index );
878  for ( int n = 0; n < true_o->values.size(); ++n )
879  {
880  const double conditionValue = condition_o->values[n].scalar();
881  double resultValue = D_NODATA;
882  if ( !std::isnan( conditionValue ) )
883  {
884  if ( qgsDoubleNear( conditionValue, D_TRUE ) )
885  resultValue = true_o->values[n].scalar();
886  else
887  resultValue = false_o->values[n].scalar();
888  }
889  true_o->values[n] = resultValue;
890  }
891 
893  {
894  // This is not ideal, as we do not check for true/false branch here in activate
895  // problem is that activate is on elements, but condition is on nodes...
896  activate( true_o, condition_o );
897  }
898  }
899 }
900 
901 
902 void QgsMeshCalcUtils::activate( QgsMeshMemoryDatasetGroup &group ) const
903 {
904  Q_ASSERT( isValid() );
905 
906  if ( mOutputType == QgsMeshDatasetGroupMetadata::DataOnVertices )
907  {
908  for ( int datasetIndex = 0; datasetIndex < group.datasetCount(); ++datasetIndex )
909  {
910  const std::shared_ptr<QgsMeshMemoryDataset> o1 = canditateDataset( group, datasetIndex );
912  activate( o1 );
913  }
914  }
915  // Groups with data on faces do not have activate flags
916 }
917 
918 void QgsMeshCalcUtils::activate(
919  std::shared_ptr<QgsMeshMemoryDataset> dataset,
920  std::shared_ptr<const QgsMeshMemoryDataset> refDataset /*=0*/
921 ) const
922 {
923 
924  Q_ASSERT( isValid() );
925  Q_ASSERT( dataset );
926 
927  // Activate only faces that has some data and all vertices
928  for ( int idx = 0; idx < mMeshLayer->dataProvider()->faceCount(); ++idx )
929  {
930  if ( refDataset && !refDataset->active.isEmpty() && ( !refDataset->active[idx] ) )
931  {
932  dataset->active[idx] = false;
933  continue;
934  }
935 
936  if ( !dataset->active[idx] )
937  {
938  continue;
939  }
940 
941  QgsMeshFace face = nativeMesh()->face( idx );
942 
943  bool isActive = true; //ACTIVE
944  for ( int j = 0; j < face.size(); ++j )
945  {
946  if ( std::isnan( dataset->values[face[j]].scalar() ) )
947  {
948  isActive = false; //NOT ACTIVE
949  break;
950  }
951  }
952  dataset->active[idx] = isActive;
953  }
954 }
955 
956 double QgsMeshCalcUtils::ffilter( double val1, double filter ) const
957 {
958  Q_ASSERT( !std::isnan( val1 ) );
959 
960  if ( qgsDoubleNear( filter, D_TRUE ) )
961  return val1;
962  else
963  return D_NODATA;
964 }
965 
966 double QgsMeshCalcUtils::fadd( double val1, double val2 ) const
967 {
968  Q_ASSERT( !std::isnan( val1 ) );
969  Q_ASSERT( !std::isnan( val2 ) );
970  return val1 + val2;
971 
972 }
973 
974 double QgsMeshCalcUtils::fsubtract( double val1, double val2 ) const
975 {
976  Q_ASSERT( !std::isnan( val1 ) );
977  Q_ASSERT( !std::isnan( val2 ) );
978  return val1 - val2;
979 
980 }
981 
982 double QgsMeshCalcUtils::fmultiply( double val1, double val2 ) const
983 {
984  Q_ASSERT( !std::isnan( val1 ) );
985  Q_ASSERT( !std::isnan( val2 ) );
986  return val1 * val2;
987 
988 }
989 
990 double QgsMeshCalcUtils::fdivide( double val1, double val2 ) const
991 {
992  Q_ASSERT( !std::isnan( val1 ) );
993  Q_ASSERT( !std::isnan( val2 ) );
994  if ( qgsDoubleNear( val2, 0.0 ) )
995  return D_NODATA;
996  else
997  return val1 / val2;
998 
999 }
1000 
1001 double QgsMeshCalcUtils::fpower( double val1, double val2 ) const
1002 {
1003  Q_ASSERT( !std::isnan( val1 ) );
1004  Q_ASSERT( !std::isnan( val2 ) );
1005  return pow( val1, val2 );
1006 
1007 }
1008 
1009 double QgsMeshCalcUtils::fequal( double val1, double val2 ) const
1010 {
1011  Q_ASSERT( !std::isnan( val1 ) );
1012  Q_ASSERT( !std::isnan( val2 ) );
1013  if ( qgsDoubleNear( val1, val2 ) )
1014  {
1015  return D_TRUE;
1016  }
1017  else
1018  {
1019  return D_FALSE;
1020  }
1021 
1022 }
1023 
1024 double QgsMeshCalcUtils::fnotEqual( double val1, double val2 ) const
1025 {
1026  Q_ASSERT( !std::isnan( val1 ) );
1027  Q_ASSERT( !std::isnan( val2 ) );
1028  if ( qgsDoubleNear( val1, val2 ) )
1029  {
1030  return D_FALSE;
1031  }
1032  else
1033  {
1034  return D_TRUE;
1035  }
1036 
1037 }
1038 
1039 double QgsMeshCalcUtils::fgreaterThan( double val1, double val2 ) const
1040 {
1041  Q_ASSERT( !std::isnan( val1 ) );
1042  Q_ASSERT( !std::isnan( val2 ) );
1043  if ( val1 > val2 )
1044  {
1045  return D_TRUE;
1046  }
1047  else
1048  {
1049  return D_FALSE;
1050  }
1051 
1052 }
1053 
1054 double QgsMeshCalcUtils::flesserThan( double val1, double val2 ) const
1055 {
1056  Q_ASSERT( !std::isnan( val1 ) );
1057  Q_ASSERT( !std::isnan( val2 ) );
1058  if ( val1 < val2 )
1059  {
1060  return D_TRUE;
1061  }
1062  else
1063  {
1064  return D_FALSE;
1065  }
1066 
1067 }
1068 
1069 double QgsMeshCalcUtils::flesserEqual( double val1, double val2 ) const
1070 {
1071  Q_ASSERT( !std::isnan( val1 ) );
1072  Q_ASSERT( !std::isnan( val2 ) );
1073  if ( val1 <= val2 )
1074  {
1075  return D_TRUE;
1076  }
1077  else
1078  {
1079  return D_FALSE;
1080  }
1081 
1082 }
1083 
1084 double QgsMeshCalcUtils::fgreaterEqual( double val1, double val2 ) const
1085 {
1086  Q_ASSERT( !std::isnan( val1 ) );
1087  Q_ASSERT( !std::isnan( val2 ) );
1088  if ( val1 >= val2 )
1089  {
1090  return D_TRUE;
1091  }
1092  else
1093  {
1094  return D_FALSE;
1095  }
1096 
1097 }
1098 
1099 
1100 double QgsMeshCalcUtils::flogicalAnd( double val1, double val2 ) const
1101 {
1102  Q_ASSERT( !std::isnan( val1 ) );
1103  Q_ASSERT( !std::isnan( val2 ) );
1104  const bool bval1 = qgsDoubleNear( val1, D_TRUE );
1105  const bool bval2 = qgsDoubleNear( val2, D_TRUE );
1106  if ( bval1 && bval2 )
1107  return D_TRUE;
1108  else
1109  return D_FALSE;
1110 
1111 }
1112 
1113 double QgsMeshCalcUtils::flogicalOr( double val1, double val2 ) const
1114 {
1115  Q_ASSERT( !std::isnan( val1 ) );
1116  Q_ASSERT( !std::isnan( val2 ) );
1117  const bool bval1 = qgsDoubleNear( val1, D_TRUE );
1118  const bool bval2 = qgsDoubleNear( val2, D_TRUE );
1119  if ( bval1 || bval2 )
1120  return D_TRUE;
1121  else
1122  return D_FALSE;
1123 
1124 }
1125 
1126 double QgsMeshCalcUtils::flogicalNot( double val1 ) const
1127 {
1128  Q_ASSERT( !std::isnan( val1 ) );
1129  const bool bval1 = qgsDoubleNear( val1, D_TRUE );
1130  if ( bval1 )
1131  return D_FALSE;
1132  else
1133  return D_TRUE;
1134 
1135 }
1136 
1137 double QgsMeshCalcUtils::fchangeSign( double val1 ) const
1138 {
1139  Q_ASSERT( !std::isnan( val1 ) );
1140  return -val1;
1141 }
1142 
1143 double QgsMeshCalcUtils::fmin( double val1, double val2 ) const
1144 {
1145  Q_ASSERT( !std::isnan( val1 ) );
1146  if ( val1 > val2 )
1147  {
1148  return val2;
1149  }
1150  else
1151  {
1152  return val1;
1153  }
1154 }
1155 
1156 
1157 double QgsMeshCalcUtils::fmax( double val1, double val2 ) const
1158 {
1159  Q_ASSERT( !std::isnan( val1 ) );
1160  Q_ASSERT( !std::isnan( val2 ) );
1161  if ( val1 < val2 )
1162  {
1163  return val2;
1164  }
1165  else
1166  {
1167  return val1;
1168  }
1169 
1170 }
1171 
1172 double QgsMeshCalcUtils::fabs( double val1 ) const
1173 {
1174  Q_ASSERT( !std::isnan( val1 ) );
1175  if ( val1 > 0 )
1176  {
1177  return val1;
1178  }
1179  else
1180  {
1181  return -val1;
1182  }
1183 
1184 }
1185 
1186 double QgsMeshCalcUtils::fsumAggregated( QVector<double> &vals ) const
1187 {
1188  Q_ASSERT( !vals.contains( D_NODATA ) );
1189  Q_ASSERT( !vals.isEmpty() );
1190  return std::accumulate( vals.begin(), vals.end(), 0.0 );
1191 }
1192 
1193 double QgsMeshCalcUtils::fminimumAggregated( QVector<double> &vals ) const
1194 {
1195  Q_ASSERT( !vals.contains( D_NODATA ) );
1196  Q_ASSERT( !vals.isEmpty() );
1197  return *std::min_element( vals.begin(), vals.end() );
1198 }
1199 
1200 double QgsMeshCalcUtils::fmaximumAggregated( QVector<double> &vals ) const
1201 {
1202  Q_ASSERT( !vals.contains( D_NODATA ) );
1203  Q_ASSERT( !vals.isEmpty() );
1204  return *std::max_element( vals.begin(), vals.end() );
1205 }
1206 
1207 double QgsMeshCalcUtils::faverageAggregated( QVector<double> &vals ) const
1208 {
1209  Q_ASSERT( !vals.contains( D_NODATA ) );
1210  Q_ASSERT( !vals.isEmpty() );
1211  return fsumAggregated( vals ) / vals.size();
1212 }
1213 
1214 void QgsMeshCalcUtils::logicalNot( QgsMeshMemoryDatasetGroup &group1 ) const
1215 {
1216  return func1( group1, std::bind( & QgsMeshCalcUtils::flogicalNot, this, std::placeholders::_1 ) );
1217 }
1218 
1219 void QgsMeshCalcUtils::changeSign( QgsMeshMemoryDatasetGroup &group1 ) const
1220 {
1221  return func1( group1, std::bind( & QgsMeshCalcUtils::fchangeSign, this, std::placeholders::_1 ) );
1222 }
1223 
1224 void QgsMeshCalcUtils::abs( QgsMeshMemoryDatasetGroup &group1 ) const
1225 {
1226  return func1( group1, std::bind( & QgsMeshCalcUtils::fabs, this, std::placeholders::_1 ) );
1227 }
1228 
1229 void QgsMeshCalcUtils::add( QgsMeshMemoryDatasetGroup &group1, const QgsMeshMemoryDatasetGroup &group2 ) const
1230 {
1231  return func2( group1, group2, std::bind( & QgsMeshCalcUtils::fadd, this, std::placeholders::_1, std::placeholders::_2 ) );
1232 }
1233 
1234 void QgsMeshCalcUtils::subtract( QgsMeshMemoryDatasetGroup &group1, const QgsMeshMemoryDatasetGroup &group2 ) const
1235 {
1236  return func2( group1, group2, std::bind( & QgsMeshCalcUtils::fsubtract, this, std::placeholders::_1, std::placeholders::_2 ) );
1237 }
1238 
1239 void QgsMeshCalcUtils::multiply( QgsMeshMemoryDatasetGroup &group1, const QgsMeshMemoryDatasetGroup &group2 ) const
1240 {
1241  return func2( group1, group2, std::bind( & QgsMeshCalcUtils::fmultiply, this, std::placeholders::_1, std::placeholders::_2 ) );
1242 }
1243 
1244 void QgsMeshCalcUtils::divide( QgsMeshMemoryDatasetGroup &group1, const QgsMeshMemoryDatasetGroup &group2 ) const
1245 {
1246  return func2( group1, group2, std::bind( & QgsMeshCalcUtils::fdivide, this, std::placeholders::_1, std::placeholders::_2 ) );
1247 }
1248 
1249 void QgsMeshCalcUtils::power( QgsMeshMemoryDatasetGroup &group1, const QgsMeshMemoryDatasetGroup &group2 ) const
1250 {
1251  return func2( group1, group2, std::bind( & QgsMeshCalcUtils::fpower, this, std::placeholders::_1, std::placeholders::_2 ) );
1252 }
1253 
1254 void QgsMeshCalcUtils::equal( QgsMeshMemoryDatasetGroup &group1, const QgsMeshMemoryDatasetGroup &group2 ) const
1255 {
1256  return func2( group1, group2, std::bind( & QgsMeshCalcUtils::fequal, this, std::placeholders::_1, std::placeholders::_2 ) );
1257 }
1258 
1259 void QgsMeshCalcUtils::notEqual( QgsMeshMemoryDatasetGroup &group1, const QgsMeshMemoryDatasetGroup &group2 ) const
1260 {
1261  return func2( group1, group2, std::bind( & QgsMeshCalcUtils::fnotEqual, this, std::placeholders::_1, std::placeholders::_2 ) );
1262 }
1263 
1264 void QgsMeshCalcUtils::greaterThan( QgsMeshMemoryDatasetGroup &group1, const QgsMeshMemoryDatasetGroup &group2 ) const
1265 {
1266  return func2( group1, group2, std::bind( & QgsMeshCalcUtils::fgreaterThan, this, std::placeholders::_1, std::placeholders::_2 ) );
1267 }
1268 
1269 void QgsMeshCalcUtils::lesserThan( QgsMeshMemoryDatasetGroup &group1, const QgsMeshMemoryDatasetGroup &group2 ) const
1270 {
1271  return func2( group1, group2, std::bind( & QgsMeshCalcUtils::flesserThan, this, std::placeholders::_1, std::placeholders::_2 ) );
1272 }
1273 
1274 void QgsMeshCalcUtils::lesserEqual( QgsMeshMemoryDatasetGroup &group1, const QgsMeshMemoryDatasetGroup &group2 ) const
1275 {
1276  return func2( group1, group2, std::bind( & QgsMeshCalcUtils::flesserEqual, this, std::placeholders::_1, std::placeholders::_2 ) );
1277 }
1278 
1279 void QgsMeshCalcUtils::greaterEqual( QgsMeshMemoryDatasetGroup &group1, const QgsMeshMemoryDatasetGroup &group2 ) const
1280 {
1281  return func2( group1, group2, std::bind( & QgsMeshCalcUtils::fgreaterEqual, this, std::placeholders::_1, std::placeholders::_2 ) );
1282 }
1283 
1284 void QgsMeshCalcUtils::logicalAnd( QgsMeshMemoryDatasetGroup &group1, const QgsMeshMemoryDatasetGroup &group2 ) const
1285 {
1286  return func2( group1, group2, std::bind( & QgsMeshCalcUtils::flogicalAnd, this, std::placeholders::_1, std::placeholders::_2 ) );
1287 }
1288 
1289 void QgsMeshCalcUtils::logicalOr( QgsMeshMemoryDatasetGroup &group1, const QgsMeshMemoryDatasetGroup &group2 ) const
1290 {
1291  return func2( group1, group2, std::bind( & QgsMeshCalcUtils::flogicalOr, this, std::placeholders::_1, std::placeholders::_2 ) );
1292 }
1293 
1294 void QgsMeshCalcUtils::minimum( QgsMeshMemoryDatasetGroup &group1, const QgsMeshMemoryDatasetGroup &group2 ) const
1295 {
1296  return func2( group1, group2, std::bind( & QgsMeshCalcUtils::fmin, this, std::placeholders::_1, std::placeholders::_2 ) );
1297 }
1298 
1299 void QgsMeshCalcUtils::maximum( QgsMeshMemoryDatasetGroup &group1, const QgsMeshMemoryDatasetGroup &group2 ) const
1300 {
1301  return func2( group1, group2, std::bind( & QgsMeshCalcUtils::fmax, this, std::placeholders::_1, std::placeholders::_2 ) );
1302 }
1303 
1304 QgsMeshDatasetGroupMetadata::DataType QgsMeshCalcUtils::determineResultDataType( QgsMeshLayer *layer, const QStringList &usedGroupNames )
1305 {
1306  QHash<QString, int> names;
1307  const QList<int> &groupIndexes = layer->datasetGroupsIndexes();
1308  for ( const int groupId : groupIndexes )
1309  {
1310  const QgsMeshDatasetGroupMetadata meta = layer->datasetGroupMetadata( groupId );
1311  const QString name = meta.name();
1312  names[ name ] = groupId;
1313  }
1314  for ( const QString &datasetGroupName : usedGroupNames )
1315  {
1316  if ( names.contains( datasetGroupName ) )
1317  {
1318  const int groupId = names.value( datasetGroupName );
1319  const QgsMeshDatasetGroupMetadata meta = layer->datasetGroupMetadata( groupId );
1321  {
1323  }
1325  {
1327  }
1328  }
1329  }
1331 }
1332 
1333 void QgsMeshCalcUtils::filter( QgsMeshMemoryDatasetGroup &group1, const QgsRectangle &extent ) const
1334 {
1335  QgsMeshMemoryDatasetGroup filter( "filter", outputType() );
1336  populateSpatialFilter( filter, extent );
1337  return func2( group1, filter, std::bind( & QgsMeshCalcUtils::ffilter, this, std::placeholders::_1, std::placeholders::_2 ) );
1338 }
1339 
1340 void QgsMeshCalcUtils::filter( QgsMeshMemoryDatasetGroup &group1, const QgsGeometry &mask ) const
1341 {
1342  QgsMeshMemoryDatasetGroup filter( "filter", outputType() );
1343  populateMaskFilter( filter, mask );
1344  return func2( group1, filter, std::bind( & QgsMeshCalcUtils::ffilter, this, std::placeholders::_1, std::placeholders::_2 ) );
1345 }
1346 
1347 void QgsMeshCalcUtils::sumAggregated( QgsMeshMemoryDatasetGroup &group1 ) const
1348 {
1349  return funcAggr( group1, std::bind( & QgsMeshCalcUtils::fsumAggregated, this, std::placeholders::_1 ) );
1350 }
1351 
1352 void QgsMeshCalcUtils::minimumAggregated( QgsMeshMemoryDatasetGroup &group1 ) const
1353 {
1354  return funcAggr( group1, std::bind( & QgsMeshCalcUtils::fminimumAggregated, this, std::placeholders::_1 ) );
1355 }
1356 
1357 void QgsMeshCalcUtils::maximumAggregated( QgsMeshMemoryDatasetGroup &group1 ) const
1358 {
1359  return funcAggr( group1, std::bind( & QgsMeshCalcUtils::fmaximumAggregated, this, std::placeholders::_1 ) );
1360 }
1361 
1362 void QgsMeshCalcUtils::averageAggregated( QgsMeshMemoryDatasetGroup &group1 ) const
1363 {
1364  return funcAggr( group1, std::bind( & QgsMeshCalcUtils::faverageAggregated, this, std::placeholders::_1 ) );
1365 }
1366 
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:125
bool contains(const QgsPointXY *p) const
Returns true if the geometry contains the point p.
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
bool intersects(const QgsRectangle &rectangle) const
Returns true if this geometry exactly intersects with a rectangle.
A representation of the interval between two datetime values.
Definition: qgsinterval.h:42
bool isValid() const
Returns true if the interval is valid.
Definition: qgsinterval.h:255
double hours() const
Returns the interval duration in hours.
QgsMeshDataBlock is a block of integers/doubles that can be used to retrieve: active flags (e....
QgsMeshDatasetValue value(int index) const
Returns a value represented by the index For active flag the behavior is undefined.
QVector< double > values() const
Returns buffer to the array with values For vector it is pairs (x1, y1, x2, y2, .....
bool isValid() const
Whether the block is valid.
bool active(int index) const
Returns a value for active flag by the index For scalar and vector 2d the behavior is undefined.
int count() const
Number of items stored in the block.
Base class for providing data for QgsMeshLayer.
virtual int vertexCount() const =0
Returns number of vertices in the native mesh.
virtual int faceCount() const =0
Returns number of faces in the native mesh.
QgsMeshDatasetGroupMetadata is a collection of dataset group metadata such as whether the data is vec...
QString name() const
Returns name of the dataset group.
bool isScalar() const
Returns whether dataset group has scalar data.
DataType dataType() const
Returns whether dataset group data is defined on vertices or faces or volumes.
double minimum() const
Returns minimum scalar value/vector magnitude present for whole dataset group.
double maximum() const
Returns maximum scalar value/vector magnitude present for whole dataset group.
DataType
Location of where data is specified for datasets in the dataset group.
@ DataOnEdges
Data is defined on edges.
@ DataOnFaces
Data is defined on faces.
@ DataOnVertices
Data is defined on vertices.
@ DataOnVolumes
Data is defined on volumes.
QgsMeshDatasetGroupMetadata::DataType dataType() const
Returns the data type of the dataset group.
QgsMeshDatasetIndex is index that identifies the dataset group (e.g.
bool isValid() const
Returns whether index is valid, ie at least groups is set.
int group() const
Returns a group index.
QgsMeshDatasetMetadata is a collection of mesh dataset metadata such as whether the data is valid or ...
double maximum() const
Returns maximum scalar value/vector magnitude present for the dataset.
double minimum() const
Returns minimum scalar value/vector magnitude present for the dataset.
double time() const
Returns the time value for this dataset.
bool isValid() const
Returns whether dataset is valid.
QgsMeshDatasetValue represents single dataset value.
Represents a mesh layer supporting display of data on structured or unstructured meshes.
Definition: qgsmeshlayer.h:97
QList< int > datasetGroupsIndexes() const
Returns the list of indexes of dataset groups handled by the layer.
QgsMeshDatasetGroupMetadata datasetGroupMetadata(const QgsMeshDatasetIndex &index) const
Returns the dataset groups metadata.
Class that represents a dataset group stored in memory.
void addDataset(std::shared_ptr< QgsMeshMemoryDataset > dataset)
Adds a memory dataset to the group.
void clearDatasets()
Removes all the datasets from the group.
std::shared_ptr< const QgsMeshMemoryDataset > constDataset(int index) const
Returns the dataset with index.
QVector< std::shared_ptr< QgsMeshMemoryDataset > > memoryDatasets
Contains all the memory datasets.
int datasetCount() const override
Returns the count of datasets in the group.
@ NeighbourAverage
Does a simple average of values defined for all surrounding faces/vertices.
A class to represent a 2D point.
Definition: qgspointxy.h:59
A rectangle specified with double values.
Definition: qgsrectangle.h:42
void set(const QgsPointXY &p1, const QgsPointXY &p2, bool normalize=true)
Sets the rectangle from two QgsPoints.
Definition: qgsrectangle.h:122
Triangular/Derived Mesh is mesh with vertices in map coordinates.
CORE_EXPORT QgsGeometry toGeometry(const QgsMeshFace &face, const QVector< QgsMeshVertex > &vertices)
Returns face as polygon geometry.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:1246
QVector< int > QgsMeshFace
List of vertex indexes.
Mesh - vertices, edges and faces.