QGIS API Documentation  3.24.2-Tisler (13c1a02865)
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 
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:1578
QVector< int > QgsMeshFace
List of vertex indexes.
Mesh - vertices, edges and faces.