25 static const double eps = 1e-6;
34 std::unique_ptr<QgsMesh3dAveragingMethod> ret;
37 elem.attribute( QStringLiteral(
"method" ) ).toInt() );
62 if ( !hasValidInputs() )
66 int count = block3d.
count();
68 QVector<double> valuesFaces( isVector ? 2 * count : count, std::numeric_limits<double>::quiet_NaN() );
71 const QVector<double> volumeValues = block3d.
values();
73 int startVolumeIndex = 0;
74 for (
int faceIndex = 0; faceIndex < count; ++faceIndex )
81 int volumesBelowFaceCount = verticalLevelsCount[faceIndex];
82 if ( volumesBelowFaceCount <= 0 )
85 int startVerticalLevelIndex = startVolumeIndex + faceIndex;
86 Q_ASSERT( verticalLevels.size() >= startVerticalLevelIndex + volumesBelowFaceCount + 1 );
87 QVector<double> verticalLevelsForFace = verticalLevels.mid( startVerticalLevelIndex, volumesBelowFaceCount + 1 );
88 double faceLevelTop = verticalLevelsForFace[0];
89 double faceLevelBottom = verticalLevelsForFace[verticalLevelsForFace.size() - 1];
92 if ( faceLevelTop < faceLevelBottom )
94 std::swap( faceLevelTop, faceLevelBottom );
97 double methodLevelTop = std::numeric_limits<double>::quiet_NaN();
98 double methodLevelBottom = std::numeric_limits<double>::quiet_NaN();
100 volumeRangeForFace( methodLevelTop,
102 verticalLevelsForFace );
104 if ( !std::isnan( methodLevelTop ) && !std::isnan( methodLevelBottom ) )
107 if ( methodLevelTop < methodLevelBottom )
109 std::swap( methodLevelTop, methodLevelBottom );
113 if ( ( methodLevelTop >= faceLevelBottom ) && ( methodLevelBottom <= faceLevelTop ) )
115 averageVolumeValuesForFace(
117 volumesBelowFaceCount,
122 verticalLevelsForFace,
130 startVolumeIndex += volumesBelowFaceCount;
141 void QgsMesh3dAveragingMethod::averageVolumeValuesForFace(
143 int volumesBelowFaceCount,
144 int startVolumeIndex,
145 double methodLevelTop,
146 double methodLevelBottom,
148 const QVector<double> &verticalLevelsForFace,
149 const QVector<double> &volumeValues,
150 QVector<double> &valuesFaces
153 double totalAveragedHeight = 0;
158 for (
int relativeVolumeIndex = 0; relativeVolumeIndex < volumesBelowFaceCount; ++relativeVolumeIndex )
160 const int volumeIndex = startVolumeIndex + relativeVolumeIndex;
161 double volumeLevelTop = verticalLevelsForFace[relativeVolumeIndex];
162 double volumeLevelBottom = verticalLevelsForFace[relativeVolumeIndex + 1];
163 if ( volumeLevelTop < volumeLevelBottom )
165 std::swap( volumeLevelTop, volumeLevelBottom );
168 const double intersectionLevelTop = std::min( methodLevelTop, volumeLevelTop );
169 const double intersectionLevelBottom = std::max( methodLevelBottom, volumeLevelBottom );
170 const double effectiveInterval = intersectionLevelTop - intersectionLevelBottom;
172 if ( effectiveInterval > eps )
176 const double x = volumeValues[2 * volumeIndex ];
177 const double y = volumeValues[ 2 * volumeIndex + 1 ];
178 if ( ! std::isnan( x ) &&
182 nSumX += x * effectiveInterval;
183 nSumY += y * effectiveInterval;
184 totalAveragedHeight += effectiveInterval;
189 const double x = volumeValues[ volumeIndex ];
190 if ( ! std::isnan( x ) )
192 nSumX += x * effectiveInterval;
193 totalAveragedHeight += effectiveInterval;
200 if ( totalAveragedHeight > eps )
204 valuesFaces[2 * faceIndex] = nSumX / totalAveragedHeight;
205 valuesFaces[2 * faceIndex + 1 ] = nSumY / totalAveragedHeight;
209 valuesFaces[faceIndex] = nSumX / totalAveragedHeight;
224 , mStartVerticalLevel( startLevel )
225 , mEndVerticalLevel( endLevel )
226 , mCountedFromTop( countedFromTop )
228 if ( mStartVerticalLevel > mEndVerticalLevel )
230 std::swap( mStartVerticalLevel, mEndVerticalLevel );
241 , mStartVerticalLevel( verticalLevel )
242 , mEndVerticalLevel( verticalLevel )
243 , mCountedFromTop( countedFromTop )
251 QDomElement elem = doc.createElement( QStringLiteral(
"multi-vertical-layers-settings" ) );
253 elem.setAttribute( QStringLiteral(
"end-layer-index" ),
endVerticalLevel() );
259 QDomElement settings = elem.firstChildElement( QStringLiteral(
"multi-vertical-layers-settings" ) );
260 if ( !settings.isNull() )
262 mStartVerticalLevel = settings.attribute( QStringLiteral(
"start-layer-index" ) ).toInt();
263 mEndVerticalLevel = settings.attribute( QStringLiteral(
"end-layer-index" ) ).toInt();
264 if ( mStartVerticalLevel > mEndVerticalLevel )
266 std::swap( mStartVerticalLevel, mEndVerticalLevel );
291 return mStartVerticalLevel;
296 return mEndVerticalLevel;
299 bool QgsMeshMultiLevelsAveragingMethod::hasValidInputs()
const 301 return mStartVerticalLevel >= 1 && mEndVerticalLevel >= mStartVerticalLevel;
304 void QgsMeshMultiLevelsAveragingMethod::volumeRangeForFace(
307 const QVector<double> &verticalLevels
310 Q_ASSERT( mStartVerticalLevel <= mEndVerticalLevel );
314 int startIndex = mStartVerticalLevel - 1;
315 if ( startIndex >= 0 && startIndex < verticalLevels.size() )
320 if ( mEndVerticalLevel >= 0 && mEndVerticalLevel < verticalLevels.size() )
331 int volumesBelowFaceCount = verticalLevels.size() - 1;
332 int startIndex = volumesBelowFaceCount - mEndVerticalLevel;
333 if ( startIndex >= 0 && startIndex < verticalLevels.size() )
342 int endIndex = volumesBelowFaceCount - mStartVerticalLevel + 1;
343 if ( endIndex >= 0 && endIndex < verticalLevels.size() )
357 , mStartFraction( startFraction )
358 , mEndFraction( endFraction )
360 if ( mStartFraction > mEndFraction )
362 std::swap( mStartFraction, mEndFraction );
370 QDomElement elem = doc.createElement( QStringLiteral(
"sigma-settings" ) );
371 elem.setAttribute( QStringLiteral(
"start-fraction" ),
startFraction() );
372 elem.setAttribute( QStringLiteral(
"end-fraction" ),
endFraction() );
378 QDomElement settings = elem.firstChildElement( QStringLiteral(
"sigma-settings" ) );
379 if ( !settings.isNull() )
381 mStartFraction = settings.attribute( QStringLiteral(
"start-fraction" ) ).toDouble();
382 mEndFraction = settings.attribute( QStringLiteral(
"end-fraction" ) ).toDouble();
383 if ( mStartFraction > mEndFraction )
385 std::swap( mStartFraction, mEndFraction );
407 return mStartFraction;
415 bool QgsMeshSigmaAveragingMethod::hasValidInputs()
const 417 return mStartFraction >= 0 && mEndFraction >= mStartFraction && mEndFraction <= 1;
420 void QgsMeshSigmaAveragingMethod::volumeRangeForFace(
421 double &startVerticalLevel,
422 double &endVerticalLevel,
423 const QVector<double> &verticalLevels
426 const double top = verticalLevels[ 0 ];
427 const double bot = verticalLevels[ verticalLevels.size() - 1 ];
428 const double diff = top - bot;
430 if ( mStartFraction < 0 )
431 startVerticalLevel = bot;
433 startVerticalLevel = bot + diff * mStartFraction;
435 if ( mEndFraction > 1 )
436 endVerticalLevel = top;
438 endVerticalLevel = bot + diff * mEndFraction;
443 return mCountedFromTop;
448 return mStartVerticalLevel == mEndVerticalLevel;
459 , mStartHeight( startDepth )
460 , mEndHeight( endDepth )
461 , mCountedFromTop( countedFromTop )
463 if ( mStartHeight > mEndHeight )
465 std::swap( mStartHeight, mEndHeight );
473 QDomElement elem = doc.createElement( QStringLiteral(
"relative-height-settings" ) );
474 elem.setAttribute( QStringLiteral(
"start-height" ),
startHeight() );
475 elem.setAttribute( QStringLiteral(
"end-height" ),
endHeight() );
481 QDomElement settings = elem.firstChildElement( QStringLiteral(
"relative-height-settings" ) );
482 if ( !settings.isNull() )
484 mStartHeight = settings.attribute( QStringLiteral(
"start-height" ) ).toDouble();
485 mEndHeight = settings.attribute( QStringLiteral(
"end-height" ) ).toDouble();
486 if ( mStartHeight > mEndHeight )
488 std::swap( mStartHeight, mEndHeight );
520 bool QgsMeshRelativeHeightAveragingMethod::hasValidInputs()
const 522 return mStartHeight >= 0 && mEndHeight >= mStartHeight;
525 void QgsMeshRelativeHeightAveragingMethod::volumeRangeForFace(
526 double &startVerticalLevel,
527 double &endVerticalLevel,
528 const QVector<double> &verticalLevels )
const 532 const double top = verticalLevels[ 0 ];
533 startVerticalLevel = top - mStartHeight;
534 endVerticalLevel = top - mEndHeight;
538 const double bot = verticalLevels[verticalLevels.size() - 1];
539 startVerticalLevel = bot + mStartHeight;
540 endVerticalLevel = bot + mEndHeight;
546 return mCountedFromTop;
556 , mStartElevation( startElevation )
557 , mEndElevation( endElevation )
559 if ( mEndElevation > mStartElevation )
561 std::swap( mEndElevation, mStartElevation );
569 QDomElement elem = doc.createElement( QStringLiteral(
"elevation-settings" ) );
570 elem.setAttribute( QStringLiteral(
"start-elevation" ),
startElevation() );
571 elem.setAttribute( QStringLiteral(
"end-elevation" ),
endElevation() );
577 QDomElement settings = elem.firstChildElement( QStringLiteral(
"elevation-settings" ) );
578 if ( !settings.isNull() )
580 mStartElevation = settings.attribute( QStringLiteral(
"start-elevation" ) ).toDouble();
581 mEndElevation = settings.attribute( QStringLiteral(
"end-elevation" ) ).toDouble();
582 if ( mEndElevation > mStartElevation )
584 std::swap( mEndElevation, mStartElevation );
606 return mStartElevation;
611 return mEndElevation;
614 bool QgsMeshElevationAveragingMethod::hasValidInputs()
const 616 return mStartElevation <= 0.0 && mEndElevation <= mStartElevation;
619 void QgsMeshElevationAveragingMethod::volumeRangeForFace(
620 double &startVerticalLevel,
621 double &endVerticalLevel,
622 const QVector<double> &verticalLevels )
const 624 Q_UNUSED( verticalLevels )
625 startVerticalLevel = mStartElevation;
626 endVerticalLevel = mEndElevation;
Method method() const
Returns type of averaging method.
QgsMeshMultiLevelsAveragingMethod()
Constructs single level averaging method for 1st (top) vertical level.
double startElevation() const
Returns start elevation.
Sigma averages over the values between 0 (bed level) and 1 (surface).
bool equals(const QgsMesh3dAveragingMethod *other) const override
Returns whether method equals to other.
QgsMesh3dAveragingMethod * clone() const override
Clone the instance.
Vector double pairs (x1, y1, x2, y2, ... )
QgsMeshSigmaAveragingMethod()
Constructs the sigma method for whole value range 0-1.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
QgsMeshDataBlock is a block of integers/doubles that can be used to retrieve: active flags (e...
bool isSingleLevel() const
Returns whether the averaging method selects only a single vertical level.
QgsMesh3dDataBlock is a block of 3d stacked mesh data related N faces defined on base mesh frame...
Elevation averaging method averages the values based on range defined absolute value to the model's d...
QDomElement writeXml(QDomDocument &doc) const override
Writes configuration to a new DOM element.
double endFraction() const
Returns ending fraction.
QVector< int > verticalLevelsCount() const
Returns number of vertical level above 2d faces.
double endElevation() const
Returns end elevation.
bool isVector() const
Whether we store vector values.
Multi level averaging method specifies limits of vertical layers from the top layer down or reversed...
bool isValid() const
Whether the block is valid.
static bool equals(const QgsMesh3dAveragingMethod *a, const QgsMesh3dAveragingMethod *b)
Returns whether two methods equal.
QgsMesh3dAveragingMethod * clone() const override
Clone the instance.
~QgsMeshRelativeHeightAveragingMethod() override
Base class for feedback objects to be used for cancellation of something running in a worker thread...
int count() const
Number of 2d faces for which the volume data is stored in the block.
~QgsMeshMultiLevelsAveragingMethod() override
static QgsMesh3dAveragingMethod * createFromXml(const QDomElement &elem)
Creates the instance from XML by calling readXml of derived classes.
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.
void readXml(const QDomElement &elem) override
Reads configuration from the given DOM element.
Method to average values between 0 (bed level) and 1 (surface)
QVector< double > values() const
Returns the values at volume centers.
Method to average values defined by range of absolute length units to the model's datum...
bool countedFromTop() const
Returns whether the start and end vertical levels are indexed from top (surface) or bottom (bed) leve...
QgsMeshDataBlock calculate(const QgsMesh3dDataBlock &block3d, QgsFeedback *feedback=nullptr) const
Calculated 2d block values from 3d stacked mesh values.
int startVerticalLevel() const
Returns starting vertical level.
~QgsMeshElevationAveragingMethod() override
QgsMeshElevationAveragingMethod()
Ctor.
double startFraction() const
Returns starting fraction.
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.
Method
Type of averaging method.
QDomElement writeXml(QDomDocument &doc) const override
Writes configuration to a new DOM element.
bool countedFromTop() const
Returns whether the start and end vertical levels are relative to top (surface) or bottom (bed) level...
QDomElement writeXml(QDomDocument &doc) const override
Writes configuration to a new DOM element.
bool isCanceled() const
Tells whether the operation has been canceled already.
QgsMesh3dAveragingMethod(Method method)
Ctor.
QgsMeshRelativeHeightAveragingMethod()
Constructs default depth averaging method.
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.
Abstract class to interpolate 3d stacked mesh data to 2d data.
QgsMesh3dAveragingMethod * clone() const override
Clone the instance.
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.
int endVerticalLevel() const
Returns ending vertical level.
double startHeight() const
Returns starting depth/height.
void setValues(const QVector< double > &vals)
Sets values.
Method to average values defined by range of relative length units to the surface or bed level...
double endHeight() const
Returns ending depth/height.
QgsMesh3dAveragingMethod * clone() const override
Clone the instance.
Method to average values from selected vertical layers.
~QgsMeshSigmaAveragingMethod() override
QVector< double > verticalLevels() const
Returns the vertical levels height.