QGIS API Documentation 3.41.0-Master (45a0abf3bec)
Loading...
Searching...
No Matches
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 const QgsMesh *res = mMeshLayer->nativeMesh();
846 Q_ASSERT( res );
847 return res;
848}
849
850void QgsMeshCalcUtils::updateMesh() const
851{
852 if ( ! mMeshLayer->nativeMesh() )
853 {
854 //calling this method creates the triangular mesh if it doesn't exist
855 mMeshLayer->updateTriangularMesh();
856 }
857}
858
859QgsMeshDatasetGroupMetadata::DataType QgsMeshCalcUtils::outputType() const
860{
861 return mOutputType;
862}
863
864void QgsMeshCalcUtils::addIf( QgsMeshMemoryDatasetGroup &trueGroup,
865 const QgsMeshMemoryDatasetGroup &falseGroup,
866 const QgsMeshMemoryDatasetGroup &condition ) const
867{
868 Q_ASSERT( isValid() );
869
870 // Make sure we have enough outputs in the resulting dataset
871 expand( trueGroup, condition );
872 expand( trueGroup, falseGroup );
873
874 Q_ASSERT( trueGroup.dataType() == falseGroup.dataType() ); // we do not support mixed output types
875 Q_ASSERT( trueGroup.dataType() == condition.dataType() ); // we do not support mixed output types
876
877 for ( int time_index = 0; time_index < trueGroup.datasetCount(); ++time_index )
878 {
879 const std::shared_ptr<QgsMeshMemoryDataset> true_o = canditateDataset( trueGroup, time_index );
880 const std::shared_ptr<const QgsMeshMemoryDataset> false_o = constCandidateDataset( falseGroup, time_index );
881 const std::shared_ptr<const QgsMeshMemoryDataset> condition_o = constCandidateDataset( condition, time_index );
882 for ( int n = 0; n < true_o->values.size(); ++n )
883 {
884 const double conditionValue = condition_o->values[n].scalar();
885 double resultValue = D_NODATA;
886 if ( !std::isnan( conditionValue ) )
887 {
888 if ( qgsDoubleNear( conditionValue, D_TRUE ) )
889 resultValue = true_o->values[n].scalar();
890 else
891 resultValue = false_o->values[n].scalar();
892 }
893 true_o->values[n] = resultValue;
894 }
895
897 {
898 // This is not ideal, as we do not check for true/false branch here in activate
899 // problem is that activate is on elements, but condition is on nodes...
900 activate( true_o, condition_o );
901 }
902 }
903}
904
905
906void QgsMeshCalcUtils::activate( QgsMeshMemoryDatasetGroup &group ) const
907{
908 Q_ASSERT( isValid() );
909
911 {
912 for ( int datasetIndex = 0; datasetIndex < group.datasetCount(); ++datasetIndex )
913 {
914 const std::shared_ptr<QgsMeshMemoryDataset> o1 = canditateDataset( group, datasetIndex );
916 activate( o1 );
917 }
918 }
919 // Groups with data on faces do not have activate flags
920}
921
922void QgsMeshCalcUtils::activate(
923 std::shared_ptr<QgsMeshMemoryDataset> dataset,
924 std::shared_ptr<const QgsMeshMemoryDataset> refDataset /*=0*/
925) const
926{
927
928 Q_ASSERT( isValid() );
929 Q_ASSERT( dataset );
930
931 // Activate only faces that has some data and all vertices
932 for ( int idx = 0; idx < mMeshLayer->dataProvider()->faceCount(); ++idx )
933 {
934 if ( refDataset && !refDataset->active.isEmpty() && ( !refDataset->active[idx] ) )
935 {
936 dataset->active[idx] = false;
937 continue;
938 }
939
940 if ( !dataset->active[idx] )
941 {
942 continue;
943 }
944
945 QgsMeshFace face = nativeMesh()->face( idx );
946
947 bool isActive = true; //ACTIVE
948 for ( int j = 0; j < face.size(); ++j )
949 {
950 if ( std::isnan( dataset->values[face[j]].scalar() ) )
951 {
952 isActive = false; //NOT ACTIVE
953 break;
954 }
955 }
956 dataset->active[idx] = isActive;
957 }
958}
959
960double QgsMeshCalcUtils::ffilter( double val1, double filter ) const
961{
962 Q_ASSERT( !std::isnan( val1 ) );
963
964 if ( qgsDoubleNear( filter, D_TRUE ) )
965 return val1;
966 else
967 return D_NODATA;
968}
969
970double QgsMeshCalcUtils::fadd( double val1, double val2 ) const
971{
972 Q_ASSERT( !std::isnan( val1 ) );
973 Q_ASSERT( !std::isnan( val2 ) );
974 return val1 + val2;
975
976}
977
978double QgsMeshCalcUtils::fsubtract( double val1, double val2 ) const
979{
980 Q_ASSERT( !std::isnan( val1 ) );
981 Q_ASSERT( !std::isnan( val2 ) );
982 return val1 - val2;
983
984}
985
986double QgsMeshCalcUtils::fmultiply( double val1, double val2 ) const
987{
988 Q_ASSERT( !std::isnan( val1 ) );
989 Q_ASSERT( !std::isnan( val2 ) );
990 return val1 * val2;
991
992}
993
994double QgsMeshCalcUtils::fdivide( double val1, double val2 ) const
995{
996 Q_ASSERT( !std::isnan( val1 ) );
997 Q_ASSERT( !std::isnan( val2 ) );
998 if ( qgsDoubleNear( val2, 0.0 ) )
999 return D_NODATA;
1000 else
1001 return val1 / val2;
1002
1003}
1004
1005double QgsMeshCalcUtils::fpower( double val1, double val2 ) const
1006{
1007 Q_ASSERT( !std::isnan( val1 ) );
1008 Q_ASSERT( !std::isnan( val2 ) );
1009 return pow( val1, val2 );
1010
1011}
1012
1013double QgsMeshCalcUtils::fequal( double val1, double val2 ) const
1014{
1015 Q_ASSERT( !std::isnan( val1 ) );
1016 Q_ASSERT( !std::isnan( val2 ) );
1017 if ( qgsDoubleNear( val1, val2 ) )
1018 {
1019 return D_TRUE;
1020 }
1021 else
1022 {
1023 return D_FALSE;
1024 }
1025
1026}
1027
1028double QgsMeshCalcUtils::fnotEqual( double val1, double val2 ) const
1029{
1030 Q_ASSERT( !std::isnan( val1 ) );
1031 Q_ASSERT( !std::isnan( val2 ) );
1032 if ( qgsDoubleNear( val1, val2 ) )
1033 {
1034 return D_FALSE;
1035 }
1036 else
1037 {
1038 return D_TRUE;
1039 }
1040
1041}
1042
1043double QgsMeshCalcUtils::fgreaterThan( double val1, double val2 ) const
1044{
1045 Q_ASSERT( !std::isnan( val1 ) );
1046 Q_ASSERT( !std::isnan( val2 ) );
1047 if ( val1 > val2 )
1048 {
1049 return D_TRUE;
1050 }
1051 else
1052 {
1053 return D_FALSE;
1054 }
1055
1056}
1057
1058double QgsMeshCalcUtils::flesserThan( double val1, double val2 ) const
1059{
1060 Q_ASSERT( !std::isnan( val1 ) );
1061 Q_ASSERT( !std::isnan( val2 ) );
1062 if ( val1 < val2 )
1063 {
1064 return D_TRUE;
1065 }
1066 else
1067 {
1068 return D_FALSE;
1069 }
1070
1071}
1072
1073double QgsMeshCalcUtils::flesserEqual( double val1, double val2 ) const
1074{
1075 Q_ASSERT( !std::isnan( val1 ) );
1076 Q_ASSERT( !std::isnan( val2 ) );
1077 if ( val1 <= val2 )
1078 {
1079 return D_TRUE;
1080 }
1081 else
1082 {
1083 return D_FALSE;
1084 }
1085
1086}
1087
1088double QgsMeshCalcUtils::fgreaterEqual( double val1, double val2 ) const
1089{
1090 Q_ASSERT( !std::isnan( val1 ) );
1091 Q_ASSERT( !std::isnan( val2 ) );
1092 if ( val1 >= val2 )
1093 {
1094 return D_TRUE;
1095 }
1096 else
1097 {
1098 return D_FALSE;
1099 }
1100
1101}
1102
1103
1104double QgsMeshCalcUtils::flogicalAnd( double val1, double val2 ) const
1105{
1106 Q_ASSERT( !std::isnan( val1 ) );
1107 Q_ASSERT( !std::isnan( val2 ) );
1108 const bool bval1 = qgsDoubleNear( val1, D_TRUE );
1109 const bool bval2 = qgsDoubleNear( val2, D_TRUE );
1110 if ( bval1 && bval2 )
1111 return D_TRUE;
1112 else
1113 return D_FALSE;
1114
1115}
1116
1117double QgsMeshCalcUtils::flogicalOr( double val1, double val2 ) const
1118{
1119 Q_ASSERT( !std::isnan( val1 ) );
1120 Q_ASSERT( !std::isnan( val2 ) );
1121 const bool bval1 = qgsDoubleNear( val1, D_TRUE );
1122 const bool bval2 = qgsDoubleNear( val2, D_TRUE );
1123 if ( bval1 || bval2 )
1124 return D_TRUE;
1125 else
1126 return D_FALSE;
1127
1128}
1129
1130double QgsMeshCalcUtils::flogicalNot( double val1 ) const
1131{
1132 Q_ASSERT( !std::isnan( val1 ) );
1133 const bool bval1 = qgsDoubleNear( val1, D_TRUE );
1134 if ( bval1 )
1135 return D_FALSE;
1136 else
1137 return D_TRUE;
1138
1139}
1140
1141double QgsMeshCalcUtils::fchangeSign( double val1 ) const
1142{
1143 Q_ASSERT( !std::isnan( val1 ) );
1144 return -val1;
1145}
1146
1147double QgsMeshCalcUtils::fmin( double val1, double val2 ) const
1148{
1149 Q_ASSERT( !std::isnan( val1 ) );
1150 if ( val1 > val2 )
1151 {
1152 return val2;
1153 }
1154 else
1155 {
1156 return val1;
1157 }
1158}
1159
1160
1161double QgsMeshCalcUtils::fmax( double val1, double val2 ) const
1162{
1163 Q_ASSERT( !std::isnan( val1 ) );
1164 Q_ASSERT( !std::isnan( val2 ) );
1165 if ( val1 < val2 )
1166 {
1167 return val2;
1168 }
1169 else
1170 {
1171 return val1;
1172 }
1173
1174}
1175
1176double QgsMeshCalcUtils::fabs( double val1 ) const
1177{
1178 Q_ASSERT( !std::isnan( val1 ) );
1179 if ( val1 > 0 )
1180 {
1181 return val1;
1182 }
1183 else
1184 {
1185 return -val1;
1186 }
1187
1188}
1189
1190double QgsMeshCalcUtils::fsumAggregated( QVector<double> &vals ) const
1191{
1192 Q_ASSERT( !vals.contains( D_NODATA ) );
1193 Q_ASSERT( !vals.isEmpty() );
1194 return std::accumulate( vals.begin(), vals.end(), 0.0 );
1195}
1196
1197double QgsMeshCalcUtils::fminimumAggregated( QVector<double> &vals ) const
1198{
1199 Q_ASSERT( !vals.contains( D_NODATA ) );
1200 Q_ASSERT( !vals.isEmpty() );
1201 return *std::min_element( vals.begin(), vals.end() );
1202}
1203
1204double QgsMeshCalcUtils::fmaximumAggregated( QVector<double> &vals ) const
1205{
1206 Q_ASSERT( !vals.contains( D_NODATA ) );
1207 Q_ASSERT( !vals.isEmpty() );
1208 return *std::max_element( vals.begin(), vals.end() );
1209}
1210
1211double QgsMeshCalcUtils::faverageAggregated( QVector<double> &vals ) const
1212{
1213 Q_ASSERT( !vals.contains( D_NODATA ) );
1214 Q_ASSERT( !vals.isEmpty() );
1215 return fsumAggregated( vals ) / vals.size();
1216}
1217
1218void QgsMeshCalcUtils::logicalNot( QgsMeshMemoryDatasetGroup &group1 ) const
1219{
1220 return func1( group1, std::bind( & QgsMeshCalcUtils::flogicalNot, this, std::placeholders::_1 ) );
1221}
1222
1223void QgsMeshCalcUtils::changeSign( QgsMeshMemoryDatasetGroup &group1 ) const
1224{
1225 return func1( group1, std::bind( & QgsMeshCalcUtils::fchangeSign, this, std::placeholders::_1 ) );
1226}
1227
1228void QgsMeshCalcUtils::abs( QgsMeshMemoryDatasetGroup &group1 ) const
1229{
1230 return func1( group1, std::bind( & QgsMeshCalcUtils::fabs, this, std::placeholders::_1 ) );
1231}
1232
1233void QgsMeshCalcUtils::add( QgsMeshMemoryDatasetGroup &group1, const QgsMeshMemoryDatasetGroup &group2 ) const
1234{
1235 return func2( group1, group2, std::bind( & QgsMeshCalcUtils::fadd, this, std::placeholders::_1, std::placeholders::_2 ) );
1236}
1237
1238void QgsMeshCalcUtils::subtract( QgsMeshMemoryDatasetGroup &group1, const QgsMeshMemoryDatasetGroup &group2 ) const
1239{
1240 return func2( group1, group2, std::bind( & QgsMeshCalcUtils::fsubtract, this, std::placeholders::_1, std::placeholders::_2 ) );
1241}
1242
1243void QgsMeshCalcUtils::multiply( QgsMeshMemoryDatasetGroup &group1, const QgsMeshMemoryDatasetGroup &group2 ) const
1244{
1245 return func2( group1, group2, std::bind( & QgsMeshCalcUtils::fmultiply, this, std::placeholders::_1, std::placeholders::_2 ) );
1246}
1247
1248void QgsMeshCalcUtils::divide( QgsMeshMemoryDatasetGroup &group1, const QgsMeshMemoryDatasetGroup &group2 ) const
1249{
1250 return func2( group1, group2, std::bind( & QgsMeshCalcUtils::fdivide, this, std::placeholders::_1, std::placeholders::_2 ) );
1251}
1252
1253void QgsMeshCalcUtils::power( QgsMeshMemoryDatasetGroup &group1, const QgsMeshMemoryDatasetGroup &group2 ) const
1254{
1255 return func2( group1, group2, std::bind( & QgsMeshCalcUtils::fpower, this, std::placeholders::_1, std::placeholders::_2 ) );
1256}
1257
1258void QgsMeshCalcUtils::equal( QgsMeshMemoryDatasetGroup &group1, const QgsMeshMemoryDatasetGroup &group2 ) const
1259{
1260 return func2( group1, group2, std::bind( & QgsMeshCalcUtils::fequal, this, std::placeholders::_1, std::placeholders::_2 ) );
1261}
1262
1263void QgsMeshCalcUtils::notEqual( QgsMeshMemoryDatasetGroup &group1, const QgsMeshMemoryDatasetGroup &group2 ) const
1264{
1265 return func2( group1, group2, std::bind( & QgsMeshCalcUtils::fnotEqual, this, std::placeholders::_1, std::placeholders::_2 ) );
1266}
1267
1268void QgsMeshCalcUtils::greaterThan( QgsMeshMemoryDatasetGroup &group1, const QgsMeshMemoryDatasetGroup &group2 ) const
1269{
1270 return func2( group1, group2, std::bind( & QgsMeshCalcUtils::fgreaterThan, this, std::placeholders::_1, std::placeholders::_2 ) );
1271}
1272
1273void QgsMeshCalcUtils::lesserThan( QgsMeshMemoryDatasetGroup &group1, const QgsMeshMemoryDatasetGroup &group2 ) const
1274{
1275 return func2( group1, group2, std::bind( & QgsMeshCalcUtils::flesserThan, this, std::placeholders::_1, std::placeholders::_2 ) );
1276}
1277
1278void QgsMeshCalcUtils::lesserEqual( QgsMeshMemoryDatasetGroup &group1, const QgsMeshMemoryDatasetGroup &group2 ) const
1279{
1280 return func2( group1, group2, std::bind( & QgsMeshCalcUtils::flesserEqual, this, std::placeholders::_1, std::placeholders::_2 ) );
1281}
1282
1283void QgsMeshCalcUtils::greaterEqual( QgsMeshMemoryDatasetGroup &group1, const QgsMeshMemoryDatasetGroup &group2 ) const
1284{
1285 return func2( group1, group2, std::bind( & QgsMeshCalcUtils::fgreaterEqual, this, std::placeholders::_1, std::placeholders::_2 ) );
1286}
1287
1288void QgsMeshCalcUtils::logicalAnd( QgsMeshMemoryDatasetGroup &group1, const QgsMeshMemoryDatasetGroup &group2 ) const
1289{
1290 return func2( group1, group2, std::bind( & QgsMeshCalcUtils::flogicalAnd, this, std::placeholders::_1, std::placeholders::_2 ) );
1291}
1292
1293void QgsMeshCalcUtils::logicalOr( QgsMeshMemoryDatasetGroup &group1, const QgsMeshMemoryDatasetGroup &group2 ) const
1294{
1295 return func2( group1, group2, std::bind( & QgsMeshCalcUtils::flogicalOr, this, std::placeholders::_1, std::placeholders::_2 ) );
1296}
1297
1298void QgsMeshCalcUtils::minimum( QgsMeshMemoryDatasetGroup &group1, const QgsMeshMemoryDatasetGroup &group2 ) const
1299{
1300 return func2( group1, group2, std::bind( & QgsMeshCalcUtils::fmin, this, std::placeholders::_1, std::placeholders::_2 ) );
1301}
1302
1303void QgsMeshCalcUtils::maximum( QgsMeshMemoryDatasetGroup &group1, const QgsMeshMemoryDatasetGroup &group2 ) const
1304{
1305 return func2( group1, group2, std::bind( & QgsMeshCalcUtils::fmax, this, std::placeholders::_1, std::placeholders::_2 ) );
1306}
1307
1308QgsMeshDatasetGroupMetadata::DataType QgsMeshCalcUtils::determineResultDataType( QgsMeshLayer *layer, const QStringList &usedGroupNames )
1309{
1310 QHash<QString, int> names;
1311 const QList<int> &groupIndexes = layer->datasetGroupsIndexes();
1312 for ( const int groupId : groupIndexes )
1313 {
1314 const QgsMeshDatasetGroupMetadata meta = layer->datasetGroupMetadata( groupId );
1315 const QString name = meta.name();
1316 names[ name ] = groupId;
1317 }
1318 for ( const QString &datasetGroupName : usedGroupNames )
1319 {
1320 if ( names.contains( datasetGroupName ) )
1321 {
1322 const int groupId = names.value( datasetGroupName );
1323 const QgsMeshDatasetGroupMetadata meta = layer->datasetGroupMetadata( groupId );
1325 {
1327 }
1329 {
1331 }
1332 }
1333 }
1335}
1336
1337void QgsMeshCalcUtils::filter( QgsMeshMemoryDatasetGroup &group1, const QgsRectangle &extent ) const
1338{
1339 QgsMeshMemoryDatasetGroup filter( "filter", outputType() );
1340 populateSpatialFilter( filter, extent );
1341 return func2( group1, filter, std::bind( & QgsMeshCalcUtils::ffilter, this, std::placeholders::_1, std::placeholders::_2 ) );
1342}
1343
1344void QgsMeshCalcUtils::filter( QgsMeshMemoryDatasetGroup &group1, const QgsGeometry &mask ) const
1345{
1346 QgsMeshMemoryDatasetGroup filter( "filter", outputType() );
1347 populateMaskFilter( filter, mask );
1348 return func2( group1, filter, std::bind( & QgsMeshCalcUtils::ffilter, this, std::placeholders::_1, std::placeholders::_2 ) );
1349}
1350
1351void QgsMeshCalcUtils::sumAggregated( QgsMeshMemoryDatasetGroup &group1 ) const
1352{
1353 return funcAggr( group1, std::bind( & QgsMeshCalcUtils::fsumAggregated, this, std::placeholders::_1 ) );
1354}
1355
1356void QgsMeshCalcUtils::minimumAggregated( QgsMeshMemoryDatasetGroup &group1 ) const
1357{
1358 return funcAggr( group1, std::bind( & QgsMeshCalcUtils::fminimumAggregated, this, std::placeholders::_1 ) );
1359}
1360
1361void QgsMeshCalcUtils::maximumAggregated( QgsMeshMemoryDatasetGroup &group1 ) const
1362{
1363 return funcAggr( group1, std::bind( & QgsMeshCalcUtils::fmaximumAggregated, this, std::placeholders::_1 ) );
1364}
1365
1366void QgsMeshCalcUtils::averageAggregated( QgsMeshMemoryDatasetGroup &group1 ) const
1367{
1368 return funcAggr( group1, std::bind( & QgsMeshCalcUtils::faverageAggregated, this, std::placeholders::_1 ) );
1369}
1370
A geometry is the spatial representation of a feature.
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.
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.
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.
void set(const QgsPointXY &p1, const QgsPointXY &p2, bool normalize=true)
Sets the rectangle from two QgsPoints.
Triangular/Derived Mesh is mesh with vertices in map coordinates.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition qgis.h:5958
QVector< int > QgsMeshFace
List of vertex indexes.
Mesh - vertices, edges and faces.