26static const double eps = 1e-6;
35 std::unique_ptr<QgsMesh3DAveragingMethod> ret;
38 elem.attribute( QStringLiteral(
"method" ) ).toInt() );
63 if ( !hasValidInputs() )
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() );
72 const QVector<double> volumeValues = block3d.
values();
74 int startVolumeIndex = 0;
75 for (
int faceIndex = 0; faceIndex < count; ++faceIndex )
82 const int volumesBelowFaceCount = verticalLevelsCount[faceIndex];
83 if ( volumesBelowFaceCount <= 0 )
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];
93 if ( faceLevelTop < faceLevelBottom )
95 std::swap( faceLevelTop, faceLevelBottom );
98 double methodLevelTop = std::numeric_limits<double>::quiet_NaN();
99 double methodLevelBottom = std::numeric_limits<double>::quiet_NaN();
101 int singleVerticalIndex = -1;
102 volumeRangeForFace( methodLevelTop,
105 verticalLevelsForFace );
107 if ( singleVerticalIndex != -1 )
109 int volumeIndex = singleVerticalIndex + startVolumeIndex;
112 valuesFaces[2 * faceIndex] = volumeValues.at( 2 * volumeIndex );
113 valuesFaces[2 * faceIndex + 1 ] = volumeValues.at( 2 * volumeIndex + 1 );
117 valuesFaces[faceIndex] = volumeValues.at( volumeIndex );
120 else if ( !std::isnan( methodLevelTop ) && !std::isnan( methodLevelBottom ) )
123 if ( methodLevelTop < methodLevelBottom )
125 std::swap( methodLevelTop, methodLevelBottom );
129 if ( ( methodLevelTop >= faceLevelBottom ) && ( methodLevelBottom <= faceLevelTop ) )
131 averageVolumeValuesForFace(
133 volumesBelowFaceCount,
138 verticalLevelsForFace,
146 startVolumeIndex += volumesBelowFaceCount;
157void QgsMesh3DAveragingMethod::averageVolumeValuesForFace(
159 int volumesBelowFaceCount,
160 int startVolumeIndex,
161 double methodLevelTop,
162 double methodLevelBottom,
164 const QVector<double> &verticalLevelsForFace,
165 const QVector<double> &volumeValues,
166 QVector<double> &valuesFaces
169 double totalAveragedHeight = 0;
174 for (
int relativeVolumeIndex = 0; relativeVolumeIndex < volumesBelowFaceCount; ++relativeVolumeIndex )
176 const int volumeIndex = startVolumeIndex + relativeVolumeIndex;
177 double volumeLevelTop = verticalLevelsForFace[relativeVolumeIndex];
178 double volumeLevelBottom = verticalLevelsForFace[relativeVolumeIndex + 1];
179 if ( volumeLevelTop < volumeLevelBottom )
181 std::swap( volumeLevelTop, volumeLevelBottom );
184 const double intersectionLevelTop = std::min( methodLevelTop, volumeLevelTop );
185 const double intersectionLevelBottom = std::max( methodLevelBottom, volumeLevelBottom );
186 const double effectiveInterval = intersectionLevelTop - intersectionLevelBottom;
188 if ( effectiveInterval > eps )
192 const double x = volumeValues[2 * volumeIndex ];
193 const double y = volumeValues[ 2 * volumeIndex + 1 ];
194 if ( ! std::isnan( x ) &&
198 nSumX += x * effectiveInterval;
199 nSumY += y * effectiveInterval;
200 totalAveragedHeight += effectiveInterval;
205 const double x = volumeValues[ volumeIndex ];
206 if ( ! std::isnan( x ) )
208 nSumX += x * effectiveInterval;
209 totalAveragedHeight += effectiveInterval;
216 if ( totalAveragedHeight > eps )
220 valuesFaces[2 * faceIndex] = nSumX / totalAveragedHeight;
221 valuesFaces[2 * faceIndex + 1 ] = nSumY / totalAveragedHeight;
225 valuesFaces[faceIndex] = nSumX / totalAveragedHeight;
240 , mStartVerticalLevel( startLevel )
241 , mEndVerticalLevel( endLevel )
242 , mCountedFromTop( countedFromTop )
244 if ( mStartVerticalLevel > mEndVerticalLevel )
246 std::swap( mStartVerticalLevel, mEndVerticalLevel );
257 , mStartVerticalLevel( verticalLevel )
258 , mEndVerticalLevel( verticalLevel )
259 , mCountedFromTop( countedFromTop )
267 QDomElement elem = doc.createElement( QStringLiteral(
"multi-vertical-layers-settings" ) );
269 elem.setAttribute( QStringLiteral(
"end-layer-index" ),
endVerticalLevel() );
275 const QDomElement settings = elem.firstChildElement( QStringLiteral(
"multi-vertical-layers-settings" ) );
276 if ( !settings.isNull() )
278 mStartVerticalLevel = settings.attribute( QStringLiteral(
"start-layer-index" ) ).toInt();
279 mEndVerticalLevel = settings.attribute( QStringLiteral(
"end-layer-index" ) ).toInt();
280 if ( mStartVerticalLevel > mEndVerticalLevel )
282 std::swap( mStartVerticalLevel, mEndVerticalLevel );
307 return mStartVerticalLevel;
312 return mEndVerticalLevel;
315bool QgsMeshMultiLevelsAveragingMethod::hasValidInputs()
const
317 return mStartVerticalLevel >= 1 && mEndVerticalLevel >= mStartVerticalLevel;
320void QgsMeshMultiLevelsAveragingMethod::volumeRangeForFace(
double &startVerticalLevel,
321 double &endVerticalLevel,
322 int &singleVerticalIndex,
323 const QVector<double> &verticalLevels )
const
325 Q_ASSERT( mStartVerticalLevel <= mEndVerticalLevel );
329 const int startIndex = mStartVerticalLevel - 1;
330 if ( mStartVerticalLevel == mEndVerticalLevel )
332 if ( startIndex >= 0 && startIndex < verticalLevels.size() - 1 )
333 singleVerticalIndex = startIndex;
337 if ( startIndex >= 0 && startIndex < verticalLevels.size() )
342 if ( mEndVerticalLevel >= 0 && mEndVerticalLevel < verticalLevels.size() )
354 const int volumesBelowFaceCount = verticalLevels.size() - 1;
355 const int startIndex = volumesBelowFaceCount - mEndVerticalLevel;
356 if ( mStartVerticalLevel == mEndVerticalLevel )
358 if ( startIndex >= 0 && startIndex < verticalLevels.size() - 1 )
359 singleVerticalIndex = startIndex;
363 if ( startIndex >= 0 && startIndex < verticalLevels.size() )
372 const int endIndex = volumesBelowFaceCount - mStartVerticalLevel + 1;
373 if ( endIndex >= 0 && endIndex < verticalLevels.size() )
388 , mStartFraction( startFraction )
389 , mEndFraction( endFraction )
391 if ( mStartFraction > mEndFraction )
393 std::swap( mStartFraction, mEndFraction );
401 QDomElement elem = doc.createElement( QStringLiteral(
"sigma-settings" ) );
402 elem.setAttribute( QStringLiteral(
"start-fraction" ),
startFraction() );
403 elem.setAttribute( QStringLiteral(
"end-fraction" ),
endFraction() );
409 const QDomElement settings = elem.firstChildElement( QStringLiteral(
"sigma-settings" ) );
410 if ( !settings.isNull() )
412 mStartFraction = settings.attribute( QStringLiteral(
"start-fraction" ) ).toDouble();
413 mEndFraction = settings.attribute( QStringLiteral(
"end-fraction" ) ).toDouble();
414 if ( mStartFraction > mEndFraction )
416 std::swap( mStartFraction, mEndFraction );
438 return mStartFraction;
446bool QgsMeshSigmaAveragingMethod::hasValidInputs()
const
448 return mStartFraction >= 0 && mEndFraction >= mStartFraction && mEndFraction <= 1;
451void QgsMeshSigmaAveragingMethod::volumeRangeForFace(
double &startVerticalLevel,
452 double &endVerticalLevel,
454 const QVector<double> &verticalLevels )
const
456 const double top = verticalLevels[ 0 ];
457 const double bot = verticalLevels[ verticalLevels.size() - 1 ];
458 const double diff = top - bot;
460 if ( mStartFraction < 0 )
461 startVerticalLevel = bot;
463 startVerticalLevel = bot + diff * mStartFraction;
465 if ( mEndFraction > 1 )
466 endVerticalLevel = top;
468 endVerticalLevel = bot + diff * mEndFraction;
473 return mCountedFromTop;
478 return mStartVerticalLevel == mEndVerticalLevel;
489 , mStartHeight( startDepth )
490 , mEndHeight( endDepth )
491 , mCountedFromTop( countedFromTop )
493 if ( mStartHeight > mEndHeight )
495 std::swap( mStartHeight, mEndHeight );
503 QDomElement elem = doc.createElement( QStringLiteral(
"relative-height-settings" ) );
504 elem.setAttribute( QStringLiteral(
"start-height" ),
startHeight() );
505 elem.setAttribute( QStringLiteral(
"end-height" ),
endHeight() );
511 const QDomElement settings = elem.firstChildElement( QStringLiteral(
"relative-height-settings" ) );
512 if ( !settings.isNull() )
514 mStartHeight = settings.attribute( QStringLiteral(
"start-height" ) ).toDouble();
515 mEndHeight = settings.attribute( QStringLiteral(
"end-height" ) ).toDouble();
516 if ( mStartHeight > mEndHeight )
518 std::swap( mStartHeight, mEndHeight );
550bool QgsMeshRelativeHeightAveragingMethod::hasValidInputs()
const
552 return mStartHeight >= 0 && mEndHeight >= mStartHeight;
555void QgsMeshRelativeHeightAveragingMethod::volumeRangeForFace(
double &startVerticalLevel,
556 double &endVerticalLevel,
558 const QVector<double> &verticalLevels )
const
562 const double top = verticalLevels[ 0 ];
563 startVerticalLevel = top - mStartHeight;
564 endVerticalLevel = top - mEndHeight;
568 const double bot = verticalLevels[verticalLevels.size() - 1];
569 startVerticalLevel = bot + mStartHeight;
570 endVerticalLevel = bot + mEndHeight;
576 return mCountedFromTop;
586 , mStartElevation( startElevation )
587 , mEndElevation( endElevation )
589 if ( mEndElevation > mStartElevation )
591 std::swap( mEndElevation, mStartElevation );
599 QDomElement elem = doc.createElement( QStringLiteral(
"elevation-settings" ) );
600 elem.setAttribute( QStringLiteral(
"start-elevation" ),
startElevation() );
601 elem.setAttribute( QStringLiteral(
"end-elevation" ),
endElevation() );
607 const QDomElement settings = elem.firstChildElement( QStringLiteral(
"elevation-settings" ) );
608 if ( !settings.isNull() )
610 mStartElevation = settings.attribute( QStringLiteral(
"start-elevation" ) ).toDouble();
611 mEndElevation = settings.attribute( QStringLiteral(
"end-elevation" ) ).toDouble();
612 if ( mEndElevation > mStartElevation )
614 std::swap( mEndElevation, mStartElevation );
636 return mStartElevation;
641 return mEndElevation;
644bool QgsMeshElevationAveragingMethod::hasValidInputs()
const
646 return mStartElevation <= 0.0 && mEndElevation <= mStartElevation;
649void QgsMeshElevationAveragingMethod::volumeRangeForFace(
double &startVerticalLevel,
650 double &endVerticalLevel,
652 const QVector<double> &verticalLevels )
const
654 Q_UNUSED( verticalLevels )
655 startVerticalLevel = mStartElevation;
656 endVerticalLevel = mEndElevation;
Base class for feedback objects to be used for cancellation of something running in a worker thread.
bool isCanceled() const
Tells whether the operation has been canceled already.
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.
QgsMeshElevationAveragingMethod()
~QgsMeshElevationAveragingMethod() override
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.
~QgsMeshMultiLevelsAveragingMethod() override
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() override
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)