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