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