28using namespace Qt::StringLiterals;
34static constexpr std::array<int, 8> SAGA_X { 0, 1, 1, 1, 0, -1, -1, -1 };
35static constexpr std::array<int, 8> SAGA_Y { 1, 1, 0, -1, -1, -1, 0, 1 };
37QString QgsUpslopeAreaAlgorithmBase::group()
const
39 return QObject::tr(
"Raster terrain analysis" );
42QString QgsUpslopeAreaAlgorithmBase::groupId()
const
44 return u
"rasterterrainanalysis"_s;
47QStringList QgsUpslopeAreaAlgorithmBase::tags()
const
49 return QObject::tr(
"upslope,area,flow,accumulation,hydrology,catchment,watershed,target" ).split(
',' );
52QList<QgsAcademicReference> QgsUpslopeAreaAlgorithmBase::academicReferences()
const
55 createJournalArticle( { u
"Freeman, G. T."_s }, 1991, u
"Calculating catchment area with divergent flow based on a regular grid"_s, u
"Computers and Geosciences"_s, u
"17"_s, QString(), u
"413-422"_s );
58 createJournalArticle( { u
"O'Callaghan, J. F."_s, u
"Mark, D. M."_s }, 1984, u
"The extraction of drainage networks from digital elevation data"_s, u
"Computer Vision, Graphics and Image Processing"_s, u
"28"_s, QString(), u
"323-344"_s );
61 { u
"Qin, C. Z."_s, u
"Zhu, A. X."_s, u
"Pei, T."_s, u
"Li, B. L."_s, u
"Scholten, T."_s, u
"Behrens, T."_s, u
"Zhou, C. H."_s },
63 u
"An approach to computing topographic wetness index based on maximum downslope gradient"_s,
64 u
"Precision Agriculture"_s,
71 { u
"Quinn, P. F."_s, u
"Beven, K. J."_s, u
"Chevallier, P."_s, u
"Planchon, O."_s },
73 u
"The prediction of hillslope flow paths for distributed hydrological modelling using digital terrain models"_s,
74 u
"Hydrological Processes"_s,
81 createJournalArticle( { u
"Seibert, J."_s, u
"McGlynn, B."_s }, 2007, u
"A new triangular multiple flow direction algorithm for computing upslope areas from gridded digital elevation models"_s, u
"Water Resources Research"_s, u
"43"_s, QString(), u
"W04501"_s );
84 createJournalArticle( { u
"Tarboton, D. G."_s }, 1997, u
"A new method for the determination of flow directions and upslope areas in grid digital elevation models"_s, u
"Water Resources Research"_s, u
"33"_s, u
"2"_s, u
"309-319"_s );
86 return { freemanReference, ocallaghanReference, qinReference, quinnReference, seibertReference, tarbotonReference };
89QList<QgsProcessingAlgorithm::ExternalLink> QgsUpslopeAreaAlgorithmBase::externalLinks()
const
92 QgsProcessingAlgorithm::ExternalLink { QObject::tr(
"SAGA tool source code" ), u
"https://sourceforge.net/p/saga-gis/code/ci/f24c137792a79906840f455ce36b1122b83e2f45/tree/saga-gis/src/tools/terrain_analysis/ta_hydrology/Flow_AreaUpslope.cpp"_s }
96void QgsUpslopeAreaAlgorithmBase::addCommonParameters()
98 auto demParam = std::make_unique<QgsProcessingParameterRasterLayer>( u
"ELEVATION"_s, QObject::tr(
"Elevation" ) );
99 demParam->setHelp( QObject::tr(
"Input digital elevation model (DEM) raster layer." ) );
100 addParameter( demParam.release() );
102 auto routeParam = std::make_unique<QgsProcessingParameterRasterLayer>( u
"SINK_ROUTES"_s, QObject::tr(
"Sink routes" ), QVariant(),
true );
103 routeParam->setHelp( QObject::tr(
"Optional raster layer specifying explicit flow routes through sinks/depressions." ) );
104 addParameter( routeParam.release() );
106 const QStringList methods
107 = { QObject::tr(
"Deterministic 8" ), QObject::tr(
"Deterministic Infinity" ), QObject::tr(
"Multiple Flow Direction" ), QObject::tr(
"Multiple Triangular Flow Direction" ), QObject::tr(
"Multiple Maximum Downslope Gradient Based Flow Direction" ) };
108 auto methodParam = std::make_unique<QgsProcessingParameterEnum>( u
"METHOD"_s, QObject::tr(
"Method" ), methods,
false, 2 );
109 methodParam->setHelp( QObject::tr(
"Flow routing algorithm used to determine flow distribution to downslope cells." ) );
110 addParameter( methodParam.release() );
113 convergeParam->setHelp( QObject::tr(
"Convergence factor for Multiple Flow Direction algorithms." ) );
114 addParameter( convergeParam.release() );
116 auto contourParam = std::make_unique<QgsProcessingParameterBoolean>( u
"MFD_CONTOUR"_s, QObject::tr(
"Use contour length weighting" ),
false );
117 contourParam->setHelp(
118 QObject::tr(
"Include pseudo contour length weighting factor in multiple flow routing. Reduces flow to diagonal neighbour cells by a factor of 0.71 (see Quinn et al. 1991 for details)." )
120 addParameter( contourParam.release() );
123 outputNodataParam->setHelp( QObject::tr(
"The NODATA value to use in the output raster." ) );
125 addParameter( outputNodataParam.release() );
127 auto creationOptsParam = std::make_unique<QgsProcessingParameterString>( u
"CREATION_OPTIONS"_s, QObject::tr(
"Creation options" ), QVariant(),
false,
true );
128 creationOptsParam->setHelp( QObject::tr(
"The raster creation options for the output raster. These options control things like colorimetry, compression, etc." ) );
129 creationOptsParam->setMetadata( QVariantMap( { { u
"widget_wrapper"_s, QVariantMap( { { u
"widget_type"_s, u
"rasteroptions"_s } } ) } } ) );
131 addParameter( creationOptsParam.release() );
133 auto outputParam = std::make_unique<QgsProcessingParameterRasterDestination>( u
"OUTPUT"_s, QObject::tr(
"Upslope area" ) );
134 addParameter( outputParam.release() );
139 QgsRasterLayer *demLayer = parameterAsRasterLayer( parameters, u
"ELEVATION"_s, context );
144 mDemCrs = demLayer->
crs();
145 mExtent = demLayer->
extent();
146 mCols = demLayer->
width();
147 mRows = demLayer->
height();
154 QgsRasterLayer *routeLayer = parameterAsRasterLayer( parameters, u
"SINK_ROUTES"_s, context );
166 mMethod =
static_cast<Method
>( parameterAsInt( parameters, u
"METHOD"_s, context ) );
167 mConvergence = parameterAsDouble( parameters, u
"CONVERGE"_s, context );
168 mMfdContour = parameterAsBool( parameters, u
"MFD_CONTOUR"_s, context );
170 mCreationOptions = parameterAsString( parameters, u
"CREATION_OPTIONS"_s, context ).trimmed();
171 mOutputNoData = parameterAsDouble( parameters, u
"NODATA"_s, context );
179 std::unique_ptr<QgsRasterBlock> demBlock( mDemProvider->block( 1, mExtent, mCols, mRows ) );
184 if ( mRouteProvider )
186 mRouteData.resize( nCells, -1.0 );
187 std::unique_ptr<QgsRasterBlock> routeBlock( mRouteProvider->block( 1, mExtent, mCols, mRows ) );
190 for (
int r = 0; r < mRows; ++r )
192 for (
int c = 0;
c < mCols; ++
c )
194 mRouteData[
static_cast<qgssize>( r ) * mCols +
c] = routeBlock->value( r,
c );
200 mFlowData.assign( nCells, 0.0 );
204 bool hasValidTarget =
false;
209 QgsRasterAnalysisUtils::mapToPixel( pt.x(), pt.y(), mExtent, mCellSizeX, mCellSizeY, column, row );
210 if ( column >= 0 && column < mCols && row >= 0 && row < mRows )
212 mFlowData[
static_cast<qgssize>( row ) * mCols + column] = 100.0;
213 hasValidTarget =
true;
217 if ( !hasValidTarget )
219 feedback->
reportError( QObject::tr(
"All target point(s) lie outside the DEM extent." ) );
226 const qgssize count = sortedIndex.sortedCount();
227 for (
qgssize i = 0; i < count; ++i )
231 feedback->
setProgress( 100.0 *
static_cast<double>( i ) / count );
232 sortedIndex.sortedColumnRow( i, column, row, Qt::AscendingOrder );
236 if ( mFlowData[
static_cast<qgssize>( row ) * mCols + column] <= 0.0 )
238 computeCellValue( demBlock.get(), column, row, mCols, mRows, mCellSizeX, mCellSizeY, mMethod, mConvergence, mMfdContour );
245 auto writer = std::make_unique<QgsRasterFileWriter>( mOutputPath );
246 writer->setOutputProviderKey( u
"gdal"_s );
247 if ( !mCreationOptions.isEmpty() )
249 writer->setCreationOptions( mCreationOptions.split(
'|' ) );
251 writer->setOutputFormat( mOutputFormat );
253 std::unique_ptr<QgsRasterDataProvider> provider( writer->createOneBandRaster(
Qgis::DataType::Float32, mCols, mRows, mExtent, mDemCrs ) );
256 if ( !provider->isValid() )
259 provider->setNoDataValue( 1, mOutputNoData );
260 provider->setEditable(
true );
263 for (
int r = 0; r < mRows; ++r )
265 for (
int c = 0;
c < mCols; ++
c )
267 outputBlock.setValue( r,
c,
static_cast<float>( mFlowData[
static_cast<qgssize>( r ) * mCols +
c] ) );
271 if ( !provider->writeBlock( &outputBlock, 1 ) )
273 throw QgsProcessingException( QObject::tr(
"Could not write raster block: %1" ).arg( provider->error().summary() ) );
276 provider->setEditable(
false );
280void QgsUpslopeAreaAlgorithmBase::computeCellValue(
const QgsRasterBlock *demBlock,
int col,
int row,
int cols,
int rows,
double cellSizeX,
double cellSizeY, Method method,
double converge,
bool contour )
285 if ( !mRouteData.empty() )
287 const int routeDir =
static_cast<int>( mRouteData[idx] );
288 if ( routeDir >= 0 && routeDir < 8 )
292 if ( QgsRasterAnalysisUtils::neighborCellCoordinates( routeDir, row, col, neighborRow, neighborCol, row, cols ) )
294 const double routedFlow = mFlowData[
static_cast<qgssize>( neighborRow ) * cols + neighborCol];
295 if ( routedFlow > 0.0 )
297 mFlowData[idx] = routedFlow;
307 computeD8( demBlock, col, row, cols, rows, cellSizeX, cellSizeY );
310 computeDInf( demBlock, col, row, cols, rows, cellSizeX, cellSizeY );
313 computeMFD( demBlock, col, row, cols, rows, cellSizeX, cellSizeY, converge, contour );
316 computeMDInf( demBlock, col, row, cols, rows, cellSizeX, cellSizeY, converge );
319 computeMMDGFD( demBlock, col, row, cols, rows, cellSizeX, cellSizeY, contour );
324void QgsUpslopeAreaAlgorithmBase::computeD8(
const QgsRasterBlock *demBlock,
int col,
int row,
int cols,
int rows,
double cellSizeX,
double cellSizeY )
326 const int steepestDir = QgsRasterAnalysisUtils::steepestGradientDirection( demBlock, row, col, cellSizeX, cellSizeY );
328 if ( steepestDir >= 0 )
332 QgsRasterAnalysisUtils::neighborCellCoordinates( steepestDir, row, col, neighborRow, neighborCol, rows, cols );
333 const double neighborFlow = mFlowData[
static_cast<qgssize>( neighborRow ) * cols + neighborCol];
334 if ( neighborFlow > 0.0 )
336 mFlowData[
static_cast<qgssize>( row ) * cols + col] = neighborFlow;
341void QgsUpslopeAreaAlgorithmBase::computeDInf(
const QgsRasterBlock *demBlock,
int col,
int row,
int cols,
int rows,
double cellSizeX,
double cellSizeY )
343 bool isNoData =
false;
348 computeD8( demBlock, col, row, cols, rows, cellSizeX, cellSizeY );
353 double dz[4] = { 0.0, 0.0, 0.0, 0.0 };
354 const std::array<int, 4> dirs { 0, 2, 4, 6 };
355 for (
int i = 0; i < 4; ++i )
357 const int iDir = dirs[i];
358 const int oppositeDir = ( iDir + 4 ) % 8;
362 int oppositeNeighborCol = 0;
363 int oppositeNeighborRow = 0;
364 bool neighborIsNoData =
true;
365 double neighborZ = 0;
366 if ( QgsRasterAnalysisUtils::neighborCellCoordinates( iDir, row, col, neighborRow, neighborCol, rows, cols ) )
368 neighborZ = demBlock->
valueAndNoData( neighborRow, neighborCol, neighborIsNoData );
370 bool oppositeIsNoData =
true;
371 double oppositeNeighborZ = 0;
372 if ( QgsRasterAnalysisUtils::neighborCellCoordinates( oppositeDir, row, col, oppositeNeighborRow, oppositeNeighborCol, rows, cols ) )
374 oppositeNeighborZ = demBlock->
valueAndNoData( oppositeNeighborRow, oppositeNeighborCol, oppositeIsNoData );
377 if ( !neighborIsNoData )
379 dz[i] = neighborZ - z;
381 else if ( !oppositeIsNoData )
383 dz[i] = z - oppositeNeighborZ;
391 const double G = ( dz[0] - dz[2] ) / ( 2.0 * cellSizeY );
392 const double H = ( dz[1] - dz[3] ) / ( 2.0 * cellSizeX );
394 double aspect = -1.0;
397 aspect = M_PI + std::atan2( H, G );
399 aspect += 2.0 * M_PI;
400 if ( aspect >= 2.0 * M_PI )
401 aspect -= 2.0 * M_PI;
414 const int i =
static_cast<int>( aspect / ( M_PI / 4.0 ) ) % 8;
415 const int j = ( i + 1 ) % 8;
421 if ( QgsRasterAnalysisUtils::neighborCellCoordinates( i, row, col, iRow, iCol, rows, cols ) && QgsRasterAnalysisUtils::neighborCellCoordinates( j, row, col, jRow, jCol, rows, cols ) )
423 bool iIsNoData =
false;
424 const double zi = demBlock->
valueAndNoData( iRow, iCol, iIsNoData );
425 bool jIsNoData =
false;
426 const double zj = demBlock->
valueAndNoData( jRow, jCol, jIsNoData );
427 if ( !iIsNoData && !jIsNoData )
430 if ( zi < z && zj < z )
432 const double aspectFraction = std::fmod( aspect, M_PI / 4.0 ) / ( M_PI / 4.0 );
433 const double flowI = mFlowData[
static_cast<qgssize>( iRow ) * cols + iCol];
434 const double flowJ = mFlowData[
static_cast<qgssize>( jRow ) * cols + jCol];
436 const double accumulatedFlow = flowI * ( 1.0 - aspectFraction ) + flowJ * aspectFraction;
437 if ( accumulatedFlow > 0.0 )
439 mFlowData[
static_cast<qgssize>( row ) * cols + col] = accumulatedFlow;
447 computeD8( demBlock, col, row, cols, rows, cellSizeX, cellSizeY );
450void QgsUpslopeAreaAlgorithmBase::computeMFD(
const QgsRasterBlock *demBlock,
int col,
int row,
int cols,
int rows,
double cellSizeX,
double cellSizeY,
double converge,
bool contour )
452 const double z = demBlock->
value( row, col );
456 bool isNodata =
false;
457 for (
int dir = 0; dir < 8; ++dir )
462 if ( QgsRasterAnalysisUtils::neighborCellCoordinates( dir, row, col, neighborRow, neighborCol, rows, cols ) )
464 const double nZ = demBlock->
valueAndNoData( neighborRow, neighborCol, isNodata );
467 const double diff = z - nZ;
470 const double length = QgsRasterAnalysisUtils::neighborCellDistance( dir, cellSizeX, cellSizeY );
471 const double weight = std::pow( diff / length, converge ) * ( ( contour && ( dir % 2 ) ) ? ( M_SQRT1_2 ) : 1.0 );
482 for (
int dir = 0; dir < 8; ++dir )
488 QgsRasterAnalysisUtils::neighborCellCoordinates( dir, row, col, nRow, nCol, rows, cols );
489 const double nFlow = mFlowData[
static_cast<qgssize>( nRow ) * cols + nCol];
492 flow += ( dz[dir] / dzSum ) * nFlow;
499 mFlowData[
static_cast<qgssize>( row ) * cols + col] = flow;
504void QgsUpslopeAreaAlgorithmBase::computeMMDGFD(
const QgsRasterBlock *demBlock,
int col,
int row,
int cols,
int rows,
double cellSizeX,
double cellSizeY,
bool contour )
506 const double z = demBlock->
value( row, col );
510 bool isNodata =
false;
511 for (
int dir = 0; dir < 8; ++dir )
516 if ( QgsRasterAnalysisUtils::neighborCellCoordinates( dir, row, col, neighborRow, neighborCol, rows, cols ) )
518 const double nZ = demBlock->
valueAndNoData( neighborRow, neighborCol, isNodata );
521 const double diff = z - nZ;
524 dz[dir] = diff / QgsRasterAnalysisUtils::neighborCellDistance( dir, cellSizeX, cellSizeY );
525 if ( dzMax < dz[dir] )
536 const double exponent = ( dzMax < 1.0 ) ? ( 8.9 * dzMax + 1.1 ) : 10.0;
539 for (
int i = 0; i < 8; ++i )
543 dz[i] = std::pow( dz[i], exponent ) * ( ( contour && ( i % 2 ) ) ? M_SQRT1_2 : 1.0 );
551 for (
int i = 0; i < 8; ++i )
557 QgsRasterAnalysisUtils::neighborCellCoordinates( i, row, col, neighborRow, neighborCol, rows, cols );
558 const double nFlow = mFlowData[
static_cast<qgssize>( neighborRow ) * cols + neighborCol];
561 flow += ( dz[i] / dzSum ) * nFlow;
568 mFlowData[
static_cast<qgssize>( row ) * cols + col] = flow;
574void QgsUpslopeAreaAlgorithmBase::computeMDInf(
const QgsRasterBlock *demBlock,
int col,
int row,
int cols,
int rows,
double cellSizeX,
double cellSizeY,
double converge )
576 const double z = demBlock->
value( row, col );
582 bool isNodata =
false;
583 for (
int i = 0; i < 8; ++i )
591 if ( QgsRasterAnalysisUtils::neighborCellCoordinates( i, row, col, neighborRow, neighborCol, rows, cols ) )
593 const double nZ = demBlock->
valueAndNoData( neighborRow, neighborCol, isNodata );
602 for (
int i = 0; i < 8; ++i )
609 const int j = ( i < 7 ) ? i + 1 : 0;
613 const double nx = ( dz[j] * SAGA_Y[i] - dz[i] * SAGA_Y[j] ) * cellSizeY;
614 const double ny = ( dz[i] * SAGA_X[j] - dz[j] * SAGA_X[i] ) * cellSizeX;
615 const double nz = ( SAGA_X[i] * SAGA_Y[j] - SAGA_X[j] * SAGA_Y[i] ) * ( cellSizeX * cellSizeY );
617 const double nNorm = std::sqrt( nx * nx + ny * ny + nz * nz );
621 hr = ( ny >= 0.0 ) ? 0.0 : M_PI;
625 hr = ( 1.5 * M_PI ) - std::atan( ny / nx );
629 hr = ( 0.5 * M_PI ) - std::atan( ny / nx );
632 const double cosAngle = std::clamp( nz / nNorm, -1.0, 1.0 );
633 hs = -std::tan( std::acos( cosAngle ) );
635 if ( hr < i * ( M_PI / 4.0 ) || hr > ( i + 1 ) * ( M_PI / 4.0 ) )
639 hr = i * ( M_PI / 4.0 );
640 hs = dz[i] / QgsRasterAnalysisUtils::neighborCellDistance( i, cellSizeX, cellSizeY );
644 hr = j * ( M_PI / 4.0 );
645 hs = dz[j] / QgsRasterAnalysisUtils::neighborCellDistance( j, cellSizeX, cellSizeY );
649 else if ( dz[i] > 0.0 )
651 hr = i * ( M_PI / 4.0 );
652 hs = dz[i] / QgsRasterAnalysisUtils::neighborCellDistance( i, cellSizeX, cellSizeY );
663 for (
int i = 0; i < 8; ++i )
667 int j = ( i < 7 ) ? i + 1 : 0;
669 if ( sFacet[i] > 0.0 )
671 if ( rFacet[i] > i * ( M_PI / 4.0 ) && rFacet[i] < ( i + 1 ) * ( M_PI / 4.0 ) )
673 valley[i] = sFacet[i];
675 else if ( rFacet[i] == rFacet[j] )
677 valley[i] = sFacet[i];
679 else if ( sFacet[j] == -999.0 && rFacet[i] == ( i + 1 ) * ( M_PI / 4.0 ) )
681 valley[i] = sFacet[i];
685 const int k = ( i > 0 ) ? i - 1 : 7;
686 if ( sFacet[k] == -999.0 && rFacet[i] == i * ( M_PI / 4.0 ) )
688 valley[i] = sFacet[i];
692 valley[i] = std::pow( valley[i], converge );
700 for (
int i = 0; i < 8; ++i )
702 const int j = ( i < 7 ) ? i + 1 : 0;
704 if ( i >= 7 && rFacet[i] == 0.0 )
706 rFacet[i] = 2.0 * M_PI;
709 if ( valley[i] > 0.0 )
712 portion[i] += valley[i] * ( ( i + 1 ) * ( M_PI / 4.0 ) - rFacet[i] ) / ( M_PI / 4.0 );
713 portion[j] += valley[i] * ( rFacet[i] - i * ( M_PI / 4.0 ) ) / ( M_PI / 4.0 );
718 for (
int i = 0; i < 8; ++i )
720 if ( portion[i] > 0.0 )
722 int nCol = 0, nRow = 0;
723 if ( QgsRasterAnalysisUtils::neighborCellCoordinates( i, row, col, nRow, nCol, rows, cols ) )
725 const double nFlow = mFlowData[
static_cast<qgssize>( nRow ) * cols + nCol];
728 flow += nFlow * portion[i];
736 mFlowData[
static_cast<qgssize>( row ) * cols + col] = flow;
746QgsUpslopeAreaPointAlgorithm::QgsUpslopeAreaPointAlgorithm() =
default;
748QString QgsUpslopeAreaPointAlgorithm::name()
const
750 return u
"upslopeareafrompoint"_s;
753QString QgsUpslopeAreaPointAlgorithm::displayName()
const
755 return QObject::tr(
"Upslope area (from point)" );
758QString QgsUpslopeAreaPointAlgorithm::shortDescription()
const
760 return QObject::tr(
"Calculates the upslope contributing area for a specified target point coordinate." );
763QString QgsUpslopeAreaPointAlgorithm::shortHelpString()
const
766 "This algorithm calculates the upslope contributing area (catchment) for a single target coordinate point on a Digital Elevation Model (DEM).\n\n"
767 "Each output raster cell value represents the percentage (0% to 100%) of surface flow originating at that cell that drains to or passes through the target point.\n\n"
768 "Supported flow routing methods are:\n\n"
769 "• Deterministic 8: Single-flow direction algorithm, routing 100% of flow to the steepest downslope neighbor (O'Callaghan & Mark 1984).\n"
770 "• Deterministic Infinity: Continuous single-facet flow direction algorithm, routing flow along triangular facets using a 3×3 finite-difference aspect calculation (Tarboton 1997).\n"
771 "• Multiple Flow Direction: Divergent flow distribution to all lower-elevation neighbors, weighted by slope and a configurable convergence exponent (Freeman 1991, Quinn et al. 1991).\n"
772 "• Multiple Triangular Flow Direction: Advanced divergent routing utilizing 3D vector normal cross-products across triangular facets to distribute flow smoothly across complex terrain (Seibert & "
774 "• Multiple Maximum Downslope Gradient: Adaptive MFD variant scaling exponent weights dynamically based on the local maximum gradient (Qin et al. 2011).\n\n"
775 "An optional sink routes raster layer can be provided to explicitly override topographic flow and direct water through karst features, culverts, or artificial depressions.\n\n"
776 "This algorithm is a port of the SAGA 'Upslope Area' tool."
782 return new QgsUpslopeAreaPointAlgorithm();
785void QgsUpslopeAreaPointAlgorithm::initAlgorithm(
const QVariantMap & )
787 addCommonParameters();
789 auto pointParam = std::make_unique<QgsProcessingParameterPoint>( u
"TARGET_PT"_s, QObject::tr(
"Target point" ) );
790 pointParam->setHelp( QObject::tr(
"World coordinate point defining the target cell." ) );
791 addParameter( pointParam.release() );
796 return prepareBase( parameters, context, feedback );
801 QGS_MARK_ALGORITHM_SOURCE
803 const QgsPointXY targetPt = parameterAsPoint( parameters, u
"TARGET_PT"_s, context, mDemCrs );
805 mOutputPath = parameterAsOutputLayer( parameters, u
"OUTPUT"_s, context );
806 mOutputFormat = parameterAsOutputRasterFormat( parameters, u
"OUTPUT"_s, context );
808 calculateUpslopeArea( { targetPt }, context, feedback );
811 outputs.insert( u
"OUTPUT"_s, mOutputPath );
820QgsUpslopeAreaLayerAlgorithm::QgsUpslopeAreaLayerAlgorithm() =
default;
822QString QgsUpslopeAreaLayerAlgorithm::name()
const
824 return u
"upslopeareafromlayer"_s;
827QString QgsUpslopeAreaLayerAlgorithm::displayName()
const
829 return QObject::tr(
"Upslope area (from layer)" );
832QString QgsUpslopeAreaLayerAlgorithm::shortDescription()
const
834 return QObject::tr(
"Calculates the combined upslope contributing area for target points in a vector layer." );
837QString QgsUpslopeAreaLayerAlgorithm::shortHelpString()
const
839 return QObject::tr(
"This algorithm calculates the combined upslope contributing catchment area for target points provided in an input vector point layer." );
842 "This algorithm calculates the combined upslope contributing area (catchments) for all target point locations provided in an input vector layer.\n\n"
843 "Each output raster cell value represents the percentage (0% to 100%) of surface flow originating at that cell that reaches at least one of the target points in the input vector layer.\n\n"
844 "Supported flow routing methods are:\n\n"
845 "• Deterministic 8: Single-flow direction algorithm, routing 100% of flow to the steepest downslope neighbor (O'Callaghan & Mark 1984).\n"
846 "• Deterministic Infinity: Continuous single-facet flow direction algorithm, routing flow along triangular facets using a 3×3 finite-difference aspect calculation (Tarboton 1997).\n"
847 "• Multiple Flow Direction: Divergent flow distribution to all lower-elevation neighbors, weighted by slope and a configurable convergence exponent (Freeman 1991, Quinn et al. 1991).\n"
848 "• Multiple Triangular Flow Direction: Advanced divergent routing utilizing 3D vector normal cross-products across triangular facets to distribute flow smoothly across complex terrain (Seibert & "
850 "• Multiple Maximum Downslope Gradient: Adaptive MFD variant scaling exponent weights dynamically based on the local maximum gradient (Qin et al. 2011).\n\n"
851 "An optional sink routes raster layer can be provided to explicitly override topographic flow and direct water through karst features, culverts, or artificial depressions.\n\n"
852 "This algorithm is a port of the SAGA 'Upslope Area' tool."
858 return new QgsUpslopeAreaLayerAlgorithm();
861void QgsUpslopeAreaLayerAlgorithm::initAlgorithm(
const QVariantMap & )
863 addCommonParameters();
867 layerParam->setHelp( QObject::tr(
"Vector point layer containing target locations." ) );
868 addParameter( layerParam.release() );
873 return prepareBase( parameters, context, feedback );
878 QGS_MARK_ALGORITHM_SOURCE
880 std::unique_ptr<QgsFeatureSource> targetSource( parameterAsSource( parameters, u
"TARGET_LAYER"_s, context ) );
884 std::vector<QgsPointXY> targetPoints;
892 targetPoints.push_back( pt );
896 if ( targetPoints.empty() )
898 throw QgsProcessingException( QObject::tr(
"Input target point layer contains no valid point geometries." ) );
901 mOutputPath = parameterAsOutputLayer( parameters, u
"OUTPUT"_s, context );
902 mOutputFormat = parameterAsOutputRasterFormat( parameters, u
"OUTPUT"_s, context );
904 calculateUpslopeArea( targetPoints, context, feedback );
907 outputs.insert( u
"OUTPUT"_s, mOutputPath );
@ VectorPoint
Vector point layers.
@ Float32
Thirty two bit floating point (float).
@ Advanced
Parameter is an advanced parameter which should be hidden from users by default.
@ Double
Double/float values.
Encapsulates an academic reference and formats it according to style guidelines.
static QgsAcademicReference createJournalArticle(const QStringList &authors, int year, const QString &title, const QString &journal, const QString &volume=QString(), const QString &issue=QString(), const QString &pages=QString())
Creates a journal article reference.
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
Fetch next feature and stores in f, returns true on success.
Wraps a request for features to a vector layer (or directly its vector data provider).
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
bool hasGeometry() const
Returns true if the feature has an associated geometry.
bool isCanceled() const
Tells whether the operation has been canceled already.
void setProgress(double progress)
Sets the current progress for the feedback object.
QgsPointXY asPoint() const
Returns the contents of the geometry as a 2-dimensional point.
virtual Q_INVOKABLE QgsRectangle extent() const
Returns the extent of the layer.
QgsCoordinateReferenceSystem crs
Abstract base class for processing algorithms.
Contains information about the context in which a processing algorithm is executed.
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context.
Custom exception class for processing related exceptions.
Base class for providing feedback from a processing algorithm.
virtual void reportError(const QString &error, bool fatalError=false)
Reports that the algorithm encountered an error while executing.
double value(int row, int column) const
Read a single value if type of block is numeric.
double valueAndNoData(int row, int column, bool &isNoData) const
Reads a single value from the pixel at row and column, if type of block is numeric.
QgsRasterDataProvider * clone() const override=0
Clone itself, create deep copy.
virtual bool sourceHasNoDataValue(int bandNo) const
Returns true if source band has no data value.
virtual double sourceNoDataValue(int bandNo) const
Value representing no data value.
Represents a raster layer.
int height() const
Returns the height of the (unclipped) raster.
double rasterUnitsPerPixelX() const
Returns the number of raster units per each raster pixel in X axis.
QgsRasterDataProvider * dataProvider() override
Returns the source data provider.
double rasterUnitsPerPixelY() const
Returns the number of raster units per each raster pixel in Y axis.
int width() const
Returns the width of the (unclipped) raster.
Creates a flat index over a QgsRasterBlock, sorted by cell values.
static bool isNull(const QVariant &variant, bool silenceNullWarnings=false)
Returns true if the specified variant should be considered a NULL value.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
unsigned long long qgssize
Qgssize is used instead of size_t, because size_t is stdlib type, unknown by SIP, and it would be har...
Encapsulates details of an external link describing an algorithm's behavior or source.