QGIS API Documentation 3.41.0-Master (45a0abf3bec)
Loading...
Searching...
No Matches
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
26static 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 const bool isVector = block3d.isVector();
67 const 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 const int volumesBelowFaceCount = verticalLevelsCount[faceIndex];
83 if ( volumesBelowFaceCount <= 0 )
84 continue;
85
86 const 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 int singleVerticalIndex = -1;
102 volumeRangeForFace( methodLevelTop,
103 methodLevelBottom,
104 singleVerticalIndex,
105 verticalLevelsForFace );
106
107 if ( singleVerticalIndex != -1 )
108 {
109 int volumeIndex = singleVerticalIndex + startVolumeIndex;
110 if ( isVector )
111 {
112 valuesFaces[2 * faceIndex] = volumeValues.at( 2 * volumeIndex );
113 valuesFaces[2 * faceIndex + 1 ] = volumeValues.at( 2 * volumeIndex + 1 );
114 }
115 else
116 {
117 valuesFaces[faceIndex] = volumeValues.at( volumeIndex );
118 }
119 }
120 else if ( !std::isnan( methodLevelTop ) && !std::isnan( methodLevelBottom ) )
121 {
122 // the level is value below surface, so top level (-0.1m) is usually higher number than bottom level (e.g. -1.2m)
123 if ( methodLevelTop < methodLevelBottom )
124 {
125 std::swap( methodLevelTop, methodLevelBottom );
126 }
127
128 // check if we are completely outside the limits
129 if ( ( methodLevelTop >= faceLevelBottom ) && ( methodLevelBottom <= faceLevelTop ) )
130 {
131 averageVolumeValuesForFace(
132 faceIndex,
133 volumesBelowFaceCount,
134 startVolumeIndex,
135 methodLevelTop,
136 methodLevelBottom,
137 isVector,
138 verticalLevelsForFace,
139 volumeValues,
140 valuesFaces
141 );
142 }
143 }
144
145 // move to next face and associated volumes
146 startVolumeIndex += volumesBelowFaceCount;
147 }
148 result.setValues( valuesFaces );
149 return result;
150}
151
156
157void QgsMesh3DAveragingMethod::averageVolumeValuesForFace(
158 int faceIndex,
159 int volumesBelowFaceCount,
160 int startVolumeIndex,
161 double methodLevelTop,
162 double methodLevelBottom,
163 bool isVector,
164 const QVector<double> &verticalLevelsForFace,
165 const QVector<double> &volumeValues,
166 QVector<double> &valuesFaces
167) const
168{
169 double totalAveragedHeight = 0;
170 double nSumX = 0.0;
171 double nSumY = 0.0;
172
173 // Now go through all volumes below face and check if we need to take that volume into consideration
174 for ( int relativeVolumeIndex = 0; relativeVolumeIndex < volumesBelowFaceCount; ++relativeVolumeIndex )
175 {
176 const int volumeIndex = startVolumeIndex + relativeVolumeIndex;
177 double volumeLevelTop = verticalLevelsForFace[relativeVolumeIndex];
178 double volumeLevelBottom = verticalLevelsForFace[relativeVolumeIndex + 1];
179 if ( volumeLevelTop < volumeLevelBottom )
180 {
181 std::swap( volumeLevelTop, volumeLevelBottom );
182 }
183
184 const double intersectionLevelTop = std::min( methodLevelTop, volumeLevelTop );
185 const double intersectionLevelBottom = std::max( methodLevelBottom, volumeLevelBottom );
186 const double effectiveInterval = intersectionLevelTop - intersectionLevelBottom;
187
188 if ( effectiveInterval > eps )
189 {
190 if ( isVector )
191 {
192 const double x = volumeValues[2 * volumeIndex ];
193 const double y = volumeValues[ 2 * volumeIndex + 1 ];
194 if ( ! std::isnan( x ) &&
195 ! std::isnan( y )
196 )
197 {
198 nSumX += x * effectiveInterval;
199 nSumY += y * effectiveInterval;
200 totalAveragedHeight += effectiveInterval;
201 }
202 }
203 else
204 {
205 const double x = volumeValues[ volumeIndex ];
206 if ( ! std::isnan( x ) )
207 {
208 nSumX += x * effectiveInterval;
209 totalAveragedHeight += effectiveInterval;
210 }
211 }
212 }
213 }
214
215 // calculate average
216 if ( totalAveragedHeight > eps )
217 {
218 if ( isVector )
219 {
220 valuesFaces[2 * faceIndex] = nSumX / totalAveragedHeight;
221 valuesFaces[2 * faceIndex + 1 ] = nSumY / totalAveragedHeight;
222 }
223 else
224 {
225 valuesFaces[faceIndex] = nSumX / totalAveragedHeight;
226 }
227 }
228}
229
231{
232 if ( a )
233 return a->equals( b );
234 else
235 return !b;
236}
237
238QgsMeshMultiLevelsAveragingMethod::QgsMeshMultiLevelsAveragingMethod( int startLevel, int endLevel, bool countedFromTop )
239 : QgsMesh3DAveragingMethod( QgsMesh3DAveragingMethod::MultiLevelsAveragingMethod )
240 , mStartVerticalLevel( startLevel )
241 , mEndVerticalLevel( endLevel )
242 , mCountedFromTop( countedFromTop )
243{
244 if ( mStartVerticalLevel > mEndVerticalLevel )
245 {
246 std::swap( mStartVerticalLevel, mEndVerticalLevel );
247 }
248}
249
254
256 : QgsMesh3DAveragingMethod( QgsMesh3DAveragingMethod::MultiLevelsAveragingMethod )
257 , mStartVerticalLevel( verticalLevel )
258 , mEndVerticalLevel( verticalLevel )
259 , mCountedFromTop( countedFromTop )
260{
261}
262
264
265QDomElement QgsMeshMultiLevelsAveragingMethod::writeXml( QDomDocument &doc ) const
266{
267 QDomElement elem = doc.createElement( QStringLiteral( "multi-vertical-layers-settings" ) );
268 elem.setAttribute( QStringLiteral( "start-layer-index" ), startVerticalLevel() );
269 elem.setAttribute( QStringLiteral( "end-layer-index" ), endVerticalLevel() );
270 return elem;
271}
272
273void QgsMeshMultiLevelsAveragingMethod::readXml( const QDomElement &elem )
274{
275 const QDomElement settings = elem.firstChildElement( QStringLiteral( "multi-vertical-layers-settings" ) );
276 if ( !settings.isNull() )
277 {
278 mStartVerticalLevel = settings.attribute( QStringLiteral( "start-layer-index" ) ).toInt();
279 mEndVerticalLevel = settings.attribute( QStringLiteral( "end-layer-index" ) ).toInt();
280 if ( mStartVerticalLevel > mEndVerticalLevel )
281 {
282 std::swap( mStartVerticalLevel, mEndVerticalLevel );
283 }
284 }
285}
286
288{
289 if ( !other || other->method() != method() )
290 return false;
291
292 const QgsMeshMultiLevelsAveragingMethod *otherMethod = static_cast<const QgsMeshMultiLevelsAveragingMethod *>( other );
293
294 return ( otherMethod->startVerticalLevel() == startVerticalLevel() ) &&
295 ( otherMethod->endVerticalLevel() == endVerticalLevel() ) &&
296 ( otherMethod->countedFromTop() == countedFromTop() );
297}
298
303
304
306{
307 return mStartVerticalLevel;
308}
309
311{
312 return mEndVerticalLevel;
313}
314
315bool QgsMeshMultiLevelsAveragingMethod::hasValidInputs() const
316{
317 return mStartVerticalLevel >= 1 && mEndVerticalLevel >= mStartVerticalLevel;
318}
319
320void QgsMeshMultiLevelsAveragingMethod::volumeRangeForFace( double &startVerticalLevel,
321 double &endVerticalLevel,
322 int &singleVerticalIndex,
323 const QVector<double> &verticalLevels ) const
324{
325 Q_ASSERT( mStartVerticalLevel <= mEndVerticalLevel );
326
327 if ( countedFromTop() )
328 {
329 const int startIndex = mStartVerticalLevel - 1;
330 if ( mStartVerticalLevel == mEndVerticalLevel )
331 {
332 if ( startIndex >= 0 && startIndex < verticalLevels.size() - 1 )
333 singleVerticalIndex = startIndex;
334 }
335 else
336 {
337 if ( startIndex >= 0 && startIndex < verticalLevels.size() )
338 {
339 startVerticalLevel = verticalLevels[ startIndex ];
340 }
341
342 if ( mEndVerticalLevel >= 0 && mEndVerticalLevel < verticalLevels.size() )
343 {
344 endVerticalLevel = verticalLevels[ mEndVerticalLevel ];
345 }
346 else
347 {
348 endVerticalLevel = verticalLevels[ verticalLevels.size() - 1 ];
349 }
350 }
351 }
352 else
353 {
354 const int volumesBelowFaceCount = verticalLevels.size() - 1;
355 const int startIndex = volumesBelowFaceCount - mEndVerticalLevel;
356 if ( mStartVerticalLevel == mEndVerticalLevel )
357 {
358 if ( startIndex >= 0 && startIndex < verticalLevels.size() - 1 )
359 singleVerticalIndex = startIndex;
360 }
361 else
362 {
363 if ( startIndex >= 0 && startIndex < verticalLevels.size() )
364 {
365 startVerticalLevel = verticalLevels[ startIndex ];
366 }
367 else
368 {
369 startVerticalLevel = verticalLevels[ 0 ];
370 }
371
372 const int endIndex = volumesBelowFaceCount - mStartVerticalLevel + 1;
373 if ( endIndex >= 0 && endIndex < verticalLevels.size() )
374 {
375 endVerticalLevel = verticalLevels[ endIndex ];
376 }
377 }
378 }
379}
380
385
386QgsMeshSigmaAveragingMethod::QgsMeshSigmaAveragingMethod( double startFraction, double endFraction )
387 : QgsMesh3DAveragingMethod( QgsMesh3DAveragingMethod::SigmaAveragingMethod )
388 , mStartFraction( startFraction )
389 , mEndFraction( endFraction )
390{
391 if ( mStartFraction > mEndFraction )
392 {
393 std::swap( mStartFraction, mEndFraction );
394 }
395}
396
398
399QDomElement QgsMeshSigmaAveragingMethod::writeXml( QDomDocument &doc ) const
400{
401 QDomElement elem = doc.createElement( QStringLiteral( "sigma-settings" ) );
402 elem.setAttribute( QStringLiteral( "start-fraction" ), startFraction() );
403 elem.setAttribute( QStringLiteral( "end-fraction" ), endFraction() );
404 return elem;
405}
406
407void QgsMeshSigmaAveragingMethod::readXml( const QDomElement &elem )
408{
409 const QDomElement settings = elem.firstChildElement( QStringLiteral( "sigma-settings" ) );
410 if ( !settings.isNull() )
411 {
412 mStartFraction = settings.attribute( QStringLiteral( "start-fraction" ) ).toDouble();
413 mEndFraction = settings.attribute( QStringLiteral( "end-fraction" ) ).toDouble();
414 if ( mStartFraction > mEndFraction )
415 {
416 std::swap( mStartFraction, mEndFraction );
417 }
418 }
419}
420
422{
423 if ( !other || other->method() != method() )
424 return false;
425
426 const QgsMeshSigmaAveragingMethod *otherMethod = static_cast<const QgsMeshSigmaAveragingMethod *>( other );
427
428 return qgsDoubleNear( otherMethod->startFraction(), startFraction() ) && qgsDoubleNear( otherMethod->endFraction(), endFraction() ) ;
429}
430
435
437{
438 return mStartFraction;
439}
440
442{
443 return mEndFraction;
444}
445
446bool QgsMeshSigmaAveragingMethod::hasValidInputs() const
447{
448 return mStartFraction >= 0 && mEndFraction >= mStartFraction && mEndFraction <= 1;
449}
450
451void QgsMeshSigmaAveragingMethod::volumeRangeForFace( double &startVerticalLevel,
452 double &endVerticalLevel,
453 int &,
454 const QVector<double> &verticalLevels ) const
455{
456 const double top = verticalLevels[ 0 ];
457 const double bot = verticalLevels[ verticalLevels.size() - 1 ];
458 const double diff = top - bot;
459
460 if ( mStartFraction < 0 )
461 startVerticalLevel = bot;
462 else
463 startVerticalLevel = bot + diff * mStartFraction;
464
465 if ( mEndFraction > 1 )
466 endVerticalLevel = top;
467 else
468 endVerticalLevel = bot + diff * mEndFraction;
469}
470
472{
473 return mCountedFromTop;
474}
475
477{
478 return mStartVerticalLevel == mEndVerticalLevel;
479}
480
481
486
487QgsMeshRelativeHeightAveragingMethod::QgsMeshRelativeHeightAveragingMethod( double startDepth, double endDepth, bool countedFromTop )
488 : QgsMesh3DAveragingMethod( QgsMesh3DAveragingMethod::RelativeHeightAveragingMethod )
489 , mStartHeight( startDepth )
490 , mEndHeight( endDepth )
491 , mCountedFromTop( countedFromTop )
492{
493 if ( mStartHeight > mEndHeight )
494 {
495 std::swap( mStartHeight, mEndHeight );
496 }
497}
498
500
501QDomElement QgsMeshRelativeHeightAveragingMethod::writeXml( QDomDocument &doc ) const
502{
503 QDomElement elem = doc.createElement( QStringLiteral( "relative-height-settings" ) );
504 elem.setAttribute( QStringLiteral( "start-height" ), startHeight() );
505 elem.setAttribute( QStringLiteral( "end-height" ), endHeight() );
506 return elem;
507}
508
510{
511 const QDomElement settings = elem.firstChildElement( QStringLiteral( "relative-height-settings" ) );
512 if ( !settings.isNull() )
513 {
514 mStartHeight = settings.attribute( QStringLiteral( "start-height" ) ).toDouble();
515 mEndHeight = settings.attribute( QStringLiteral( "end-height" ) ).toDouble();
516 if ( mStartHeight > mEndHeight )
517 {
518 std::swap( mStartHeight, mEndHeight );
519 }
520 }
521}
522
524{
525 if ( !other || other->method() != method() )
526 return false;
527
528 const QgsMeshRelativeHeightAveragingMethod *otherMethod = static_cast<const QgsMeshRelativeHeightAveragingMethod *>( other );
529
530 return qgsDoubleNear( otherMethod->startHeight(), startHeight() ) &&
531 qgsDoubleNear( otherMethod->endHeight(), endHeight() ) &&
532 otherMethod->countedFromTop() == countedFromTop();
533}
534
539
541{
542 return mStartHeight;
543}
544
546{
547 return mEndHeight;
548}
549
550bool QgsMeshRelativeHeightAveragingMethod::hasValidInputs() const
551{
552 return mStartHeight >= 0 && mEndHeight >= mStartHeight;
553}
554
555void QgsMeshRelativeHeightAveragingMethod::volumeRangeForFace( double &startVerticalLevel,
556 double &endVerticalLevel,
557 int &,
558 const QVector<double> &verticalLevels ) const
559{
560 if ( countedFromTop() )
561 {
562 const double top = verticalLevels[ 0 ];
563 startVerticalLevel = top - mStartHeight;
564 endVerticalLevel = top - mEndHeight;
565 }
566 else
567 {
568 const double bot = verticalLevels[verticalLevels.size() - 1];
569 startVerticalLevel = bot + mStartHeight;
570 endVerticalLevel = bot + mEndHeight;
571 }
572}
573
575{
576 return mCountedFromTop;
577}
578
583
584QgsMeshElevationAveragingMethod::QgsMeshElevationAveragingMethod( double startElevation, double endElevation )
585 : QgsMesh3DAveragingMethod( QgsMesh3DAveragingMethod::ElevationAveragingMethod )
586 , mStartElevation( startElevation )
587 , mEndElevation( endElevation )
588{
589 if ( mEndElevation > mStartElevation )
590 {
591 std::swap( mEndElevation, mStartElevation );
592 }
593}
594
596
597QDomElement QgsMeshElevationAveragingMethod::writeXml( QDomDocument &doc ) const
598{
599 QDomElement elem = doc.createElement( QStringLiteral( "elevation-settings" ) );
600 elem.setAttribute( QStringLiteral( "start-elevation" ), startElevation() );
601 elem.setAttribute( QStringLiteral( "end-elevation" ), endElevation() );
602 return elem;
603}
604
605void QgsMeshElevationAveragingMethod::readXml( const QDomElement &elem )
606{
607 const QDomElement settings = elem.firstChildElement( QStringLiteral( "elevation-settings" ) );
608 if ( !settings.isNull() )
609 {
610 mStartElevation = settings.attribute( QStringLiteral( "start-elevation" ) ).toDouble();
611 mEndElevation = settings.attribute( QStringLiteral( "end-elevation" ) ).toDouble();
612 if ( mEndElevation > mStartElevation )
613 {
614 std::swap( mEndElevation, mStartElevation );
615 }
616 }
617}
618
620{
621 if ( !other || other->method() != method() )
622 return false;
623
624 const QgsMeshElevationAveragingMethod *otherMethod = static_cast<const QgsMeshElevationAveragingMethod *>( other );
625
626 return qgsDoubleNear( otherMethod->startElevation(), startElevation() ) && qgsDoubleNear( otherMethod->endElevation(), endElevation() ) ;
627}
628
633
635{
636 return mStartElevation;
637}
638
640{
641 return mEndElevation;
642}
643
644bool QgsMeshElevationAveragingMethod::hasValidInputs() const
645{
646 return mStartElevation <= 0.0 && mEndElevation <= mStartElevation;
647}
648
649void QgsMeshElevationAveragingMethod::volumeRangeForFace( double &startVerticalLevel,
650 double &endVerticalLevel,
651 int &,
652 const QVector<double> &verticalLevels ) const
653{
654 Q_UNUSED( verticalLevels )
655 startVerticalLevel = mStartElevation;
656 endVerticalLevel = mEndElevation;
657}
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Definition qgsfeedback.h:44
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition qgsfeedback.h:53
Abstract class to interpolate 3d stacked mesh data to 2d data.
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.
QgsMeshDataBlock calculate(const QgsMesh3DDataBlock &block3d, QgsFeedback *feedback=nullptr) const
Calculated 2d block values from 3d stacked mesh values.
virtual void readXml(const QDomElement &elem)=0
Reads configuration from the given DOM element.
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.
QgsMesh3DDataBlock is a block of 3d stacked mesh data related N faces defined on base mesh frame.
QVector< double > values() const
Returns the values at volume centers.
bool isVector() const
Whether we store vector values.
int count() const
Number of 2d faces for which the volume data is stored in the block.
QVector< int > verticalLevelsCount() const
Returns number of vertical level above 2d faces.
bool isValid() const
Whether the block is valid.
QVector< double > verticalLevels() const
Returns the vertical levels height.
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.
double endElevation() const
Returns end elevation.
QgsMesh3DAveragingMethod * clone() const override
Clone the instance.
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.
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.
QgsMesh3DAveragingMethod * clone() const override
Clone the instance.
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.
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.
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.
QgsMesh3DAveragingMethod * clone() const override
Clone the instance.
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.
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.
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:5958