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 for interpolating 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.
 
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.
 
A block of integers/doubles from a mesh dataset.
 
@ 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 which averages the values based on range defined relative to bed ele...
 
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)