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