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