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