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