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
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)