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