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