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