QGIS API Documentation  3.20.0-Odense (decaadbb31)
qgsmesh3daveraging.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsmesh3daveraging.cpp
3  ----------------------
4  begin : November 2019
5  copyright : (C) 2019 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 
18 #include <memory>
19 
20 #include "qgsmesh3daveraging.h"
21 #include "qgsmeshdataprovider.h"
23 #include "qgsfeedback.h"
24 
25 // threshold for length intervals, to avoid division by 0
26 static const double eps = 1e-6;
27 
29  : mMethod( method )
30 {
31 }
32 
34 {
35  std::unique_ptr<QgsMesh3dAveragingMethod> ret;
36 
38  elem.attribute( QStringLiteral( "method" ) ).toInt() );
39  switch ( method )
40  {
42  ret.reset( new QgsMeshMultiLevelsAveragingMethod() );
43  break;
45  ret.reset( new QgsMeshSigmaAveragingMethod() );
46  break;
48  ret.reset( new QgsMeshRelativeHeightAveragingMethod() );
49  break;
51  ret.reset( new QgsMeshElevationAveragingMethod() );
52  break;
53  }
54  ret->readXml( elem );
55  return ret.release();
56 }
57 
59 {
60  if ( !block3d.isValid() )
61  return QgsMeshDataBlock();
62 
63  if ( !hasValidInputs() )
64  return QgsMeshDataBlock();
65 
66  bool isVector = block3d.isVector();
67  int count = block3d.count();
69  QVector<double> valuesFaces( isVector ? 2 * count : count, std::numeric_limits<double>::quiet_NaN() );
70  const QVector<int> verticalLevelsCount = block3d.verticalLevelsCount();
71  const QVector<double> verticalLevels = block3d.verticalLevels();
72  const QVector<double> volumeValues = block3d.values();
73 
74  int startVolumeIndex = 0;
75  for ( int faceIndex = 0; faceIndex < count; ++faceIndex )
76  {
77  if ( feedback && feedback->isCanceled() )
78  {
79  return QgsMeshDataBlock();
80  }
81 
82  int volumesBelowFaceCount = verticalLevelsCount[faceIndex];
83  if ( volumesBelowFaceCount <= 0 )
84  continue;
85 
86  int startVerticalLevelIndex = startVolumeIndex + faceIndex;
87  Q_ASSERT( verticalLevels.size() >= startVerticalLevelIndex + volumesBelowFaceCount + 1 );
88  QVector<double> verticalLevelsForFace = verticalLevels.mid( startVerticalLevelIndex, volumesBelowFaceCount + 1 );
89  double faceLevelTop = verticalLevelsForFace[0];
90  double faceLevelBottom = verticalLevelsForFace[verticalLevelsForFace.size() - 1];
91 
92  // the level is value below surface, so top level (-0.1m) is usually higher number than bottom level (e.g. -1.2m)
93  if ( faceLevelTop < faceLevelBottom )
94  {
95  std::swap( faceLevelTop, faceLevelBottom );
96  }
97 
98  double methodLevelTop = std::numeric_limits<double>::quiet_NaN();
99  double methodLevelBottom = std::numeric_limits<double>::quiet_NaN();
100 
101  volumeRangeForFace( methodLevelTop,
102  methodLevelBottom,
103  verticalLevelsForFace );
104 
105  if ( !std::isnan( methodLevelTop ) && !std::isnan( methodLevelBottom ) )
106  {
107  // the level is value below surface, so top level (-0.1m) is usually higher number than bottom level (e.g. -1.2m)
108  if ( methodLevelTop < methodLevelBottom )
109  {
110  std::swap( methodLevelTop, methodLevelBottom );
111  }
112 
113  // check if we are completely outside the limits
114  if ( ( methodLevelTop >= faceLevelBottom ) && ( methodLevelBottom <= faceLevelTop ) )
115  {
116  averageVolumeValuesForFace(
117  faceIndex,
118  volumesBelowFaceCount,
119  startVolumeIndex,
120  methodLevelTop,
121  methodLevelBottom,
122  isVector,
123  verticalLevelsForFace,
124  volumeValues,
125  valuesFaces
126  );
127  }
128  }
129 
130  // move to next face and associated volumes
131  startVolumeIndex += volumesBelowFaceCount;
132  }
133  result.setValues( valuesFaces );
134  return result;
135 }
136 
138 {
139  return mMethod;
140 }
141 
142 void QgsMesh3dAveragingMethod::averageVolumeValuesForFace(
143  int faceIndex,
144  int volumesBelowFaceCount,
145  int startVolumeIndex,
146  double methodLevelTop,
147  double methodLevelBottom,
148  bool isVector,
149  const QVector<double> &verticalLevelsForFace,
150  const QVector<double> &volumeValues,
151  QVector<double> &valuesFaces
152 ) const
153 {
154  double totalAveragedHeight = 0;
155  double nSumX = 0.0;
156  double nSumY = 0.0;
157 
158  // Now go through all volumes below face and check if we need to take that volume into consideration
159  for ( int relativeVolumeIndex = 0; relativeVolumeIndex < volumesBelowFaceCount; ++relativeVolumeIndex )
160  {
161  const int volumeIndex = startVolumeIndex + relativeVolumeIndex;
162  double volumeLevelTop = verticalLevelsForFace[relativeVolumeIndex];
163  double volumeLevelBottom = verticalLevelsForFace[relativeVolumeIndex + 1];
164  if ( volumeLevelTop < volumeLevelBottom )
165  {
166  std::swap( volumeLevelTop, volumeLevelBottom );
167  }
168 
169  const double intersectionLevelTop = std::min( methodLevelTop, volumeLevelTop );
170  const double intersectionLevelBottom = std::max( methodLevelBottom, volumeLevelBottom );
171  const double effectiveInterval = intersectionLevelTop - intersectionLevelBottom;
172 
173  if ( effectiveInterval > eps )
174  {
175  if ( isVector )
176  {
177  const double x = volumeValues[2 * volumeIndex ];
178  const double y = volumeValues[ 2 * volumeIndex + 1 ];
179  if ( ! std::isnan( x ) &&
180  ! std::isnan( y )
181  )
182  {
183  nSumX += x * effectiveInterval;
184  nSumY += y * effectiveInterval;
185  totalAveragedHeight += effectiveInterval;
186  }
187  }
188  else
189  {
190  const double x = volumeValues[ volumeIndex ];
191  if ( ! std::isnan( x ) )
192  {
193  nSumX += x * effectiveInterval;
194  totalAveragedHeight += effectiveInterval;
195  }
196  }
197  }
198  }
199 
200  // calculate average
201  if ( totalAveragedHeight > eps )
202  {
203  if ( isVector )
204  {
205  valuesFaces[2 * faceIndex] = nSumX / totalAveragedHeight;
206  valuesFaces[2 * faceIndex + 1 ] = nSumY / totalAveragedHeight;
207  }
208  else
209  {
210  valuesFaces[faceIndex] = nSumX / totalAveragedHeight;
211  }
212  }
213 }
214 
216 {
217  if ( a )
218  return a->equals( b );
219  else
220  return !b;
221 }
222 
223 QgsMeshMultiLevelsAveragingMethod::QgsMeshMultiLevelsAveragingMethod( int startLevel, int endLevel, bool countedFromTop )
224  : QgsMesh3dAveragingMethod( QgsMesh3dAveragingMethod::MultiLevelsAveragingMethod )
225  , mStartVerticalLevel( startLevel )
226  , mEndVerticalLevel( endLevel )
227  , mCountedFromTop( countedFromTop )
228 {
229  if ( mStartVerticalLevel > mEndVerticalLevel )
230  {
231  std::swap( mStartVerticalLevel, mEndVerticalLevel );
232  }
233 }
234 
236  : QgsMesh3dAveragingMethod( QgsMesh3dAveragingMethod::MultiLevelsAveragingMethod )
237 {
238 }
239 
241  : QgsMesh3dAveragingMethod( QgsMesh3dAveragingMethod::MultiLevelsAveragingMethod )
242  , mStartVerticalLevel( verticalLevel )
243  , mEndVerticalLevel( verticalLevel )
244  , mCountedFromTop( countedFromTop )
245 {
246 }
247 
249 
250 QDomElement QgsMeshMultiLevelsAveragingMethod::writeXml( QDomDocument &doc ) const
251 {
252  QDomElement elem = doc.createElement( QStringLiteral( "multi-vertical-layers-settings" ) );
253  elem.setAttribute( QStringLiteral( "start-layer-index" ), startVerticalLevel() );
254  elem.setAttribute( QStringLiteral( "end-layer-index" ), endVerticalLevel() );
255  return elem;
256 }
257 
258 void QgsMeshMultiLevelsAveragingMethod::readXml( const QDomElement &elem )
259 {
260  QDomElement settings = elem.firstChildElement( QStringLiteral( "multi-vertical-layers-settings" ) );
261  if ( !settings.isNull() )
262  {
263  mStartVerticalLevel = settings.attribute( QStringLiteral( "start-layer-index" ) ).toInt();
264  mEndVerticalLevel = settings.attribute( QStringLiteral( "end-layer-index" ) ).toInt();
265  if ( mStartVerticalLevel > mEndVerticalLevel )
266  {
267  std::swap( mStartVerticalLevel, mEndVerticalLevel );
268  }
269  }
270 }
271 
273 {
274  if ( !other || other->method() != method() )
275  return false;
276 
277  const QgsMeshMultiLevelsAveragingMethod *otherMethod = static_cast<const QgsMeshMultiLevelsAveragingMethod *>( other );
278 
279  return ( otherMethod->startVerticalLevel() == startVerticalLevel() ) &&
280  ( otherMethod->endVerticalLevel() == endVerticalLevel() ) &&
281  ( otherMethod->countedFromTop() == countedFromTop() );
282 }
283 
285 {
287 }
288 
289 
291 {
292  return mStartVerticalLevel;
293 }
294 
296 {
297  return mEndVerticalLevel;
298 }
299 
300 bool QgsMeshMultiLevelsAveragingMethod::hasValidInputs() const
301 {
302  return mStartVerticalLevel >= 1 && mEndVerticalLevel >= mStartVerticalLevel;
303 }
304 
305 void QgsMeshMultiLevelsAveragingMethod::volumeRangeForFace(
306  double &startVerticalLevel,
307  double &endVerticalLevel,
308  const QVector<double> &verticalLevels
309 ) const
310 {
311  Q_ASSERT( mStartVerticalLevel <= mEndVerticalLevel );
312 
313  if ( countedFromTop() )
314  {
315  int startIndex = mStartVerticalLevel - 1;
316  if ( startIndex >= 0 && startIndex < verticalLevels.size() )
317  {
318  startVerticalLevel = verticalLevels[ startIndex ];
319  }
320 
321  if ( mEndVerticalLevel >= 0 && mEndVerticalLevel < verticalLevels.size() )
322  {
323  endVerticalLevel = verticalLevels[ mEndVerticalLevel ];
324  }
325  else
326  {
327  endVerticalLevel = verticalLevels[ verticalLevels.size() - 1 ];
328  }
329  }
330  else
331  {
332  int volumesBelowFaceCount = verticalLevels.size() - 1;
333  int startIndex = volumesBelowFaceCount - mEndVerticalLevel;
334  if ( startIndex >= 0 && startIndex < verticalLevels.size() )
335  {
336  startVerticalLevel = verticalLevels[ startIndex ];
337  }
338  else
339  {
340  startVerticalLevel = verticalLevels[ 0 ];
341  }
342 
343  int endIndex = volumesBelowFaceCount - mStartVerticalLevel + 1;
344  if ( endIndex >= 0 && endIndex < verticalLevels.size() )
345  {
346  endVerticalLevel = verticalLevels[ endIndex ];
347  }
348  }
349 }
350 
352  : QgsMesh3dAveragingMethod( QgsMesh3dAveragingMethod::SigmaAveragingMethod )
353 {
354 }
355 
356 QgsMeshSigmaAveragingMethod::QgsMeshSigmaAveragingMethod( double startFraction, double endFraction )
357  : QgsMesh3dAveragingMethod( QgsMesh3dAveragingMethod::SigmaAveragingMethod )
358  , mStartFraction( startFraction )
359  , mEndFraction( endFraction )
360 {
361  if ( mStartFraction > mEndFraction )
362  {
363  std::swap( mStartFraction, mEndFraction );
364  }
365 }
366 
368 
369 QDomElement QgsMeshSigmaAveragingMethod::writeXml( QDomDocument &doc ) const
370 {
371  QDomElement elem = doc.createElement( QStringLiteral( "sigma-settings" ) );
372  elem.setAttribute( QStringLiteral( "start-fraction" ), startFraction() );
373  elem.setAttribute( QStringLiteral( "end-fraction" ), endFraction() );
374  return elem;
375 }
376 
377 void QgsMeshSigmaAveragingMethod::readXml( const QDomElement &elem )
378 {
379  QDomElement settings = elem.firstChildElement( QStringLiteral( "sigma-settings" ) );
380  if ( !settings.isNull() )
381  {
382  mStartFraction = settings.attribute( QStringLiteral( "start-fraction" ) ).toDouble();
383  mEndFraction = settings.attribute( QStringLiteral( "end-fraction" ) ).toDouble();
384  if ( mStartFraction > mEndFraction )
385  {
386  std::swap( mStartFraction, mEndFraction );
387  }
388  }
389 }
390 
392 {
393  if ( !other || other->method() != method() )
394  return false;
395 
396  const QgsMeshSigmaAveragingMethod *otherMethod = static_cast<const QgsMeshSigmaAveragingMethod *>( other );
397 
398  return qgsDoubleNear( otherMethod->startFraction(), startFraction() ) && qgsDoubleNear( otherMethod->endFraction(), endFraction() ) ;
399 }
400 
402 {
404 }
405 
407 {
408  return mStartFraction;
409 }
410 
412 {
413  return mEndFraction;
414 }
415 
416 bool QgsMeshSigmaAveragingMethod::hasValidInputs() const
417 {
418  return mStartFraction >= 0 && mEndFraction >= mStartFraction && mEndFraction <= 1;
419 }
420 
421 void QgsMeshSigmaAveragingMethod::volumeRangeForFace(
422  double &startVerticalLevel,
423  double &endVerticalLevel,
424  const QVector<double> &verticalLevels
425 ) const
426 {
427  const double top = verticalLevels[ 0 ];
428  const double bot = verticalLevels[ verticalLevels.size() - 1 ];
429  const double diff = top - bot;
430 
431  if ( mStartFraction < 0 )
432  startVerticalLevel = bot;
433  else
434  startVerticalLevel = bot + diff * mStartFraction;
435 
436  if ( mEndFraction > 1 )
437  endVerticalLevel = top;
438  else
439  endVerticalLevel = bot + diff * mEndFraction;
440 }
441 
443 {
444  return mCountedFromTop;
445 }
446 
448 {
449  return mStartVerticalLevel == mEndVerticalLevel;
450 }
451 
452 
454  : QgsMesh3dAveragingMethod( QgsMesh3dAveragingMethod::RelativeHeightAveragingMethod )
455 {
456 }
457 
458 QgsMeshRelativeHeightAveragingMethod::QgsMeshRelativeHeightAveragingMethod( double startDepth, double endDepth, bool countedFromTop )
459  : QgsMesh3dAveragingMethod( QgsMesh3dAveragingMethod::RelativeHeightAveragingMethod )
460  , mStartHeight( startDepth )
461  , mEndHeight( endDepth )
462  , mCountedFromTop( countedFromTop )
463 {
464  if ( mStartHeight > mEndHeight )
465  {
466  std::swap( mStartHeight, mEndHeight );
467  }
468 }
469 
471 
472 QDomElement QgsMeshRelativeHeightAveragingMethod::writeXml( QDomDocument &doc ) const
473 {
474  QDomElement elem = doc.createElement( QStringLiteral( "relative-height-settings" ) );
475  elem.setAttribute( QStringLiteral( "start-height" ), startHeight() );
476  elem.setAttribute( QStringLiteral( "end-height" ), endHeight() );
477  return elem;
478 }
479 
480 void QgsMeshRelativeHeightAveragingMethod::readXml( const QDomElement &elem )
481 {
482  QDomElement settings = elem.firstChildElement( QStringLiteral( "relative-height-settings" ) );
483  if ( !settings.isNull() )
484  {
485  mStartHeight = settings.attribute( QStringLiteral( "start-height" ) ).toDouble();
486  mEndHeight = settings.attribute( QStringLiteral( "end-height" ) ).toDouble();
487  if ( mStartHeight > mEndHeight )
488  {
489  std::swap( mStartHeight, mEndHeight );
490  }
491  }
492 }
493 
495 {
496  if ( !other || other->method() != method() )
497  return false;
498 
499  const QgsMeshRelativeHeightAveragingMethod *otherMethod = static_cast<const QgsMeshRelativeHeightAveragingMethod *>( other );
500 
501  return qgsDoubleNear( otherMethod->startHeight(), startHeight() ) &&
502  qgsDoubleNear( otherMethod->endHeight(), endHeight() ) &&
503  otherMethod->countedFromTop() == countedFromTop();
504 }
505 
507 {
509 }
510 
512 {
513  return mStartHeight;
514 }
515 
517 {
518  return mEndHeight;
519 }
520 
521 bool QgsMeshRelativeHeightAveragingMethod::hasValidInputs() const
522 {
523  return mStartHeight >= 0 && mEndHeight >= mStartHeight;
524 }
525 
526 void QgsMeshRelativeHeightAveragingMethod::volumeRangeForFace(
527  double &startVerticalLevel,
528  double &endVerticalLevel,
529  const QVector<double> &verticalLevels ) const
530 {
531  if ( countedFromTop() )
532  {
533  const double top = verticalLevels[ 0 ];
534  startVerticalLevel = top - mStartHeight;
535  endVerticalLevel = top - mEndHeight;
536  }
537  else
538  {
539  const double bot = verticalLevels[verticalLevels.size() - 1];
540  startVerticalLevel = bot + mStartHeight;
541  endVerticalLevel = bot + mEndHeight;
542  }
543 }
544 
546 {
547  return mCountedFromTop;
548 }
549 
551  : QgsMesh3dAveragingMethod( QgsMesh3dAveragingMethod::ElevationAveragingMethod )
552 {
553 }
554 
555 QgsMeshElevationAveragingMethod::QgsMeshElevationAveragingMethod( double startElevation, double endElevation )
556  : QgsMesh3dAveragingMethod( QgsMesh3dAveragingMethod::ElevationAveragingMethod )
557  , mStartElevation( startElevation )
558  , mEndElevation( endElevation )
559 {
560  if ( mEndElevation > mStartElevation )
561  {
562  std::swap( mEndElevation, mStartElevation );
563  }
564 }
565 
567 
568 QDomElement QgsMeshElevationAveragingMethod::writeXml( QDomDocument &doc ) const
569 {
570  QDomElement elem = doc.createElement( QStringLiteral( "elevation-settings" ) );
571  elem.setAttribute( QStringLiteral( "start-elevation" ), startElevation() );
572  elem.setAttribute( QStringLiteral( "end-elevation" ), endElevation() );
573  return elem;
574 }
575 
576 void QgsMeshElevationAveragingMethod::readXml( const QDomElement &elem )
577 {
578  QDomElement settings = elem.firstChildElement( QStringLiteral( "elevation-settings" ) );
579  if ( !settings.isNull() )
580  {
581  mStartElevation = settings.attribute( QStringLiteral( "start-elevation" ) ).toDouble();
582  mEndElevation = settings.attribute( QStringLiteral( "end-elevation" ) ).toDouble();
583  if ( mEndElevation > mStartElevation )
584  {
585  std::swap( mEndElevation, mStartElevation );
586  }
587  }
588 }
589 
591 {
592  if ( !other || other->method() != method() )
593  return false;
594 
595  const QgsMeshElevationAveragingMethod *otherMethod = static_cast<const QgsMeshElevationAveragingMethod *>( other );
596 
597  return qgsDoubleNear( otherMethod->startElevation(), startElevation() ) && qgsDoubleNear( otherMethod->endElevation(), endElevation() ) ;
598 }
599 
601 {
603 }
604 
606 {
607  return mStartElevation;
608 }
609 
611 {
612  return mEndElevation;
613 }
614 
615 bool QgsMeshElevationAveragingMethod::hasValidInputs() const
616 {
617  return mStartElevation <= 0.0 && mEndElevation <= mStartElevation;
618 }
619 
620 void QgsMeshElevationAveragingMethod::volumeRangeForFace(
621  double &startVerticalLevel,
622  double &endVerticalLevel,
623  const QVector<double> &verticalLevels ) const
624 {
625  Q_UNUSED( verticalLevels )
626  startVerticalLevel = mStartElevation;
627  endVerticalLevel = mEndElevation;
628 }
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Definition: qgsfeedback.h:45
bool isCanceled() const SIP_HOLDGIL
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:54
Abstract class to interpolate 3d stacked mesh data to 2d data.
Method method() const
Returns type of averaging method.
Method
Type of averaging method.
@ RelativeHeightAveragingMethod
Method to average values defined by range of relative length units to the surface or bed level.
@ MultiLevelsAveragingMethod
Method to average values from selected vertical layers.
@ ElevationAveragingMethod
Method to average values defined by range of absolute length units to the model's datum.
@ SigmaAveragingMethod
Method to average values between 0 (bed level) and 1 (surface)
QgsMesh3dAveragingMethod(Method method)
Ctor.
QgsMeshDataBlock calculate(const QgsMesh3dDataBlock &block3d, QgsFeedback *feedback=nullptr) const
Calculated 2d block values from 3d stacked mesh values.
static QgsMesh3dAveragingMethod * createFromXml(const QDomElement &elem)
Creates the instance from XML by calling readXml of derived classes.
static bool equals(const QgsMesh3dAveragingMethod *a, const QgsMesh3dAveragingMethod *b)
Returns whether two methods equal.
QgsMesh3dDataBlock is a block of 3d stacked mesh data related N faces defined on base mesh frame.
bool isValid() const
Whether the block is valid.
bool isVector() const
Whether we store vector values.
QVector< int > verticalLevelsCount() const
Returns number of vertical level above 2d faces.
int count() const
Number of 2d faces for which the volume data is stored in the block.
QVector< double > verticalLevels() const
Returns the vertical levels height.
QVector< double > values() const
Returns the values at volume centers.
QgsMeshDataBlock is a block of integers/doubles that can be used to retrieve: active flags (e....
@ ScalarDouble
Scalar double values.
@ Vector2DDouble
Vector double pairs (x1, y1, x2, y2, ... )
void setValues(const QVector< double > &vals)
Sets values.
Elevation averaging method averages the values based on range defined absolute value to the model's d...
double startElevation() const
Returns start elevation.
void readXml(const QDomElement &elem) override
Reads configuration from the given DOM element.
QgsMesh3dAveragingMethod * clone() const override
Clone the instance.
double endElevation() const
Returns end elevation.
bool equals(const QgsMesh3dAveragingMethod *other) const override
Returns whether method equals to other.
QDomElement writeXml(QDomDocument &doc) const override
Writes configuration to a new DOM element.
Multi level averaging method specifies limits of vertical layers from the top layer down or reversed.
QDomElement writeXml(QDomDocument &doc) const override
Writes configuration to a new DOM element.
QgsMeshMultiLevelsAveragingMethod()
Constructs single level averaging method for 1st (top) vertical level.
int endVerticalLevel() const
Returns ending vertical level.
bool equals(const QgsMesh3dAveragingMethod *other) const override
Returns whether method equals to other.
bool countedFromTop() const
Returns whether the start and end vertical levels are indexed from top (surface) or bottom (bed) leve...
bool isSingleLevel() const
Returns whether the averaging method selects only a single vertical level.
QgsMesh3dAveragingMethod * clone() const override
Clone the instance.
void readXml(const QDomElement &elem) override
Reads configuration from the given DOM element.
int startVerticalLevel() const
Returns starting vertical level.
Relative height averaging method averages the values based on range defined relative to bed elevation...
void readXml(const QDomElement &elem) override
Reads configuration from the given DOM element.
double startHeight() const
Returns starting depth/height.
QgsMesh3dAveragingMethod * clone() const override
Clone the instance.
QgsMeshRelativeHeightAveragingMethod()
Constructs default depth averaging method.
bool countedFromTop() const
Returns whether the start and end vertical levels are relative to top (surface) or bottom (bed) level...
bool equals(const QgsMesh3dAveragingMethod *other) const override
Returns whether method equals to other.
QDomElement writeXml(QDomDocument &doc) const override
Writes configuration to a new DOM element.
double endHeight() const
Returns ending depth/height.
Sigma averages over the values between 0 (bed level) and 1 (surface).
double endFraction() const
Returns ending fraction.
QgsMeshSigmaAveragingMethod()
Constructs the sigma method for whole value range 0-1.
void readXml(const QDomElement &elem) override
Reads configuration from the given DOM element.
QDomElement writeXml(QDomDocument &doc) const override
Writes configuration to a new DOM element.
bool equals(const QgsMesh3dAveragingMethod *other) const override
Returns whether method equals to other.
QgsMesh3dAveragingMethod * clone() const override
Clone the instance.
~QgsMeshSigmaAveragingMethod() override
double startFraction() const
Returns starting fraction.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:598