26 static const double eps = 1e-6;
35 std::unique_ptr<QgsMesh3dAveragingMethod> ret;
38 elem.attribute( QStringLiteral(
"method" ) ).toInt() );
63 if ( !hasValidInputs() )
67 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 int volumesBelowFaceCount = verticalLevelsCount[faceIndex];
83 if ( volumesBelowFaceCount <= 0 )
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];
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 volumeRangeForFace( methodLevelTop,
103 verticalLevelsForFace );
105 if ( !std::isnan( methodLevelTop ) && !std::isnan( methodLevelBottom ) )
108 if ( methodLevelTop < methodLevelBottom )
110 std::swap( methodLevelTop, methodLevelBottom );
114 if ( ( methodLevelTop >= faceLevelBottom ) && ( methodLevelBottom <= faceLevelTop ) )
116 averageVolumeValuesForFace(
118 volumesBelowFaceCount,
123 verticalLevelsForFace,
131 startVolumeIndex += volumesBelowFaceCount;
142 void QgsMesh3dAveragingMethod::averageVolumeValuesForFace(
144 int volumesBelowFaceCount,
145 int startVolumeIndex,
146 double methodLevelTop,
147 double methodLevelBottom,
149 const QVector<double> &verticalLevelsForFace,
150 const QVector<double> &volumeValues,
151 QVector<double> &valuesFaces
154 double totalAveragedHeight = 0;
159 for (
int relativeVolumeIndex = 0; relativeVolumeIndex < volumesBelowFaceCount; ++relativeVolumeIndex )
161 const int volumeIndex = startVolumeIndex + relativeVolumeIndex;
162 double volumeLevelTop = verticalLevelsForFace[relativeVolumeIndex];
163 double volumeLevelBottom = verticalLevelsForFace[relativeVolumeIndex + 1];
164 if ( volumeLevelTop < volumeLevelBottom )
166 std::swap( volumeLevelTop, volumeLevelBottom );
169 const double intersectionLevelTop = std::min( methodLevelTop, volumeLevelTop );
170 const double intersectionLevelBottom = std::max( methodLevelBottom, volumeLevelBottom );
171 const double effectiveInterval = intersectionLevelTop - intersectionLevelBottom;
173 if ( effectiveInterval > eps )
177 const double x = volumeValues[2 * volumeIndex ];
178 const double y = volumeValues[ 2 * volumeIndex + 1 ];
179 if ( ! std::isnan( x ) &&
183 nSumX += x * effectiveInterval;
184 nSumY += y * effectiveInterval;
185 totalAveragedHeight += effectiveInterval;
190 const double x = volumeValues[ volumeIndex ];
191 if ( ! std::isnan( x ) )
193 nSumX += x * effectiveInterval;
194 totalAveragedHeight += effectiveInterval;
201 if ( totalAveragedHeight > eps )
205 valuesFaces[2 * faceIndex] = nSumX / totalAveragedHeight;
206 valuesFaces[2 * faceIndex + 1 ] = nSumY / totalAveragedHeight;
210 valuesFaces[faceIndex] = nSumX / totalAveragedHeight;
225 , mStartVerticalLevel( startLevel )
226 , mEndVerticalLevel( endLevel )
227 , mCountedFromTop( countedFromTop )
229 if ( mStartVerticalLevel > mEndVerticalLevel )
231 std::swap( mStartVerticalLevel, mEndVerticalLevel );
242 , mStartVerticalLevel( verticalLevel )
243 , mEndVerticalLevel( verticalLevel )
244 , mCountedFromTop( countedFromTop )
252 QDomElement elem = doc.createElement( QStringLiteral(
"multi-vertical-layers-settings" ) );
254 elem.setAttribute( QStringLiteral(
"end-layer-index" ),
endVerticalLevel() );
260 QDomElement settings = elem.firstChildElement( QStringLiteral(
"multi-vertical-layers-settings" ) );
261 if ( !settings.isNull() )
263 mStartVerticalLevel = settings.attribute( QStringLiteral(
"start-layer-index" ) ).toInt();
264 mEndVerticalLevel = settings.attribute( QStringLiteral(
"end-layer-index" ) ).toInt();
265 if ( mStartVerticalLevel > mEndVerticalLevel )
267 std::swap( mStartVerticalLevel, mEndVerticalLevel );
292 return mStartVerticalLevel;
297 return mEndVerticalLevel;
300 bool QgsMeshMultiLevelsAveragingMethod::hasValidInputs()
const
302 return mStartVerticalLevel >= 1 && mEndVerticalLevel >= mStartVerticalLevel;
305 void QgsMeshMultiLevelsAveragingMethod::volumeRangeForFace(
306 double &startVerticalLevel,
307 double &endVerticalLevel,
308 const QVector<double> &verticalLevels
311 Q_ASSERT( mStartVerticalLevel <= mEndVerticalLevel );
315 int startIndex = mStartVerticalLevel - 1;
316 if ( startIndex >= 0 && startIndex < verticalLevels.size() )
321 if ( mEndVerticalLevel >= 0 && mEndVerticalLevel < verticalLevels.size() )
332 int volumesBelowFaceCount = verticalLevels.size() - 1;
333 int startIndex = volumesBelowFaceCount - mEndVerticalLevel;
334 if ( startIndex >= 0 && startIndex < verticalLevels.size() )
343 int endIndex = volumesBelowFaceCount - mStartVerticalLevel + 1;
344 if ( endIndex >= 0 && endIndex < verticalLevels.size() )
358 , mStartFraction( startFraction )
359 , mEndFraction( endFraction )
361 if ( mStartFraction > mEndFraction )
363 std::swap( mStartFraction, mEndFraction );
371 QDomElement elem = doc.createElement( QStringLiteral(
"sigma-settings" ) );
372 elem.setAttribute( QStringLiteral(
"start-fraction" ),
startFraction() );
373 elem.setAttribute( QStringLiteral(
"end-fraction" ),
endFraction() );
379 QDomElement settings = elem.firstChildElement( QStringLiteral(
"sigma-settings" ) );
380 if ( !settings.isNull() )
382 mStartFraction = settings.attribute( QStringLiteral(
"start-fraction" ) ).toDouble();
383 mEndFraction = settings.attribute( QStringLiteral(
"end-fraction" ) ).toDouble();
384 if ( mStartFraction > mEndFraction )
386 std::swap( mStartFraction, mEndFraction );
408 return mStartFraction;
416 bool QgsMeshSigmaAveragingMethod::hasValidInputs()
const
418 return mStartFraction >= 0 && mEndFraction >= mStartFraction && mEndFraction <= 1;
421 void QgsMeshSigmaAveragingMethod::volumeRangeForFace(
422 double &startVerticalLevel,
423 double &endVerticalLevel,
424 const QVector<double> &verticalLevels
427 const double top = verticalLevels[ 0 ];
428 const double bot = verticalLevels[ verticalLevels.size() - 1 ];
429 const double diff = top - bot;
431 if ( mStartFraction < 0 )
432 startVerticalLevel = bot;
434 startVerticalLevel = bot + diff * mStartFraction;
436 if ( mEndFraction > 1 )
437 endVerticalLevel = top;
439 endVerticalLevel = bot + diff * mEndFraction;
444 return mCountedFromTop;
449 return mStartVerticalLevel == mEndVerticalLevel;
460 , mStartHeight( startDepth )
461 , mEndHeight( endDepth )
462 , mCountedFromTop( countedFromTop )
464 if ( mStartHeight > mEndHeight )
466 std::swap( mStartHeight, mEndHeight );
474 QDomElement elem = doc.createElement( QStringLiteral(
"relative-height-settings" ) );
475 elem.setAttribute( QStringLiteral(
"start-height" ),
startHeight() );
476 elem.setAttribute( QStringLiteral(
"end-height" ),
endHeight() );
482 QDomElement settings = elem.firstChildElement( QStringLiteral(
"relative-height-settings" ) );
483 if ( !settings.isNull() )
485 mStartHeight = settings.attribute( QStringLiteral(
"start-height" ) ).toDouble();
486 mEndHeight = settings.attribute( QStringLiteral(
"end-height" ) ).toDouble();
487 if ( mStartHeight > mEndHeight )
489 std::swap( mStartHeight, mEndHeight );
521 bool QgsMeshRelativeHeightAveragingMethod::hasValidInputs()
const
523 return mStartHeight >= 0 && mEndHeight >= mStartHeight;
526 void QgsMeshRelativeHeightAveragingMethod::volumeRangeForFace(
527 double &startVerticalLevel,
528 double &endVerticalLevel,
529 const QVector<double> &verticalLevels )
const
533 const double top = verticalLevels[ 0 ];
534 startVerticalLevel = top - mStartHeight;
535 endVerticalLevel = top - mEndHeight;
539 const double bot = verticalLevels[verticalLevels.size() - 1];
540 startVerticalLevel = bot + mStartHeight;
541 endVerticalLevel = bot + mEndHeight;
547 return mCountedFromTop;
557 , mStartElevation( startElevation )
558 , mEndElevation( endElevation )
560 if ( mEndElevation > mStartElevation )
562 std::swap( mEndElevation, mStartElevation );
570 QDomElement elem = doc.createElement( QStringLiteral(
"elevation-settings" ) );
571 elem.setAttribute( QStringLiteral(
"start-elevation" ),
startElevation() );
572 elem.setAttribute( QStringLiteral(
"end-elevation" ),
endElevation() );
578 QDomElement settings = elem.firstChildElement( QStringLiteral(
"elevation-settings" ) );
579 if ( !settings.isNull() )
581 mStartElevation = settings.attribute( QStringLiteral(
"start-elevation" ) ).toDouble();
582 mEndElevation = settings.attribute( QStringLiteral(
"end-elevation" ) ).toDouble();
583 if ( mEndElevation > mStartElevation )
585 std::swap( mEndElevation, mStartElevation );
607 return mStartElevation;
612 return mEndElevation;
615 bool QgsMeshElevationAveragingMethod::hasValidInputs()
const
617 return mStartElevation <= 0.0 && mEndElevation <= mStartElevation;
620 void QgsMeshElevationAveragingMethod::volumeRangeForFace(
621 double &startVerticalLevel,
622 double &endVerticalLevel,
623 const QVector<double> &verticalLevels )
const
625 Q_UNUSED( verticalLevels )
626 startVerticalLevel = mStartElevation;
627 endVerticalLevel = mEndElevation;
Base class for feedback objects to be used for cancellation of something running in a worker thread.
bool isCanceled() const SIP_HOLDGIL
Tells whether the operation has been canceled already.
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.
QgsMeshElevationAveragingMethod()
Ctor.
~QgsMeshElevationAveragingMethod() override
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.
~QgsMeshMultiLevelsAveragingMethod() override
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.
~QgsMeshRelativeHeightAveragingMethod() override
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)