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 };
38static constexpr std::array<int, 8> COL_DIRECTION_OFFSETS { 0, 1, 1, 1, 0, -1, -1, -1 };
39static constexpr std::array<int, 8> ROW_DIRECTION_OFFSETS { -1, -1, 0, 1, 1, 1, 0, -1 };
41QString QgsUpslopeAreaAlgorithmBase::group()
const
43 return QObject::tr(
"Raster terrain analysis" );
46QString QgsUpslopeAreaAlgorithmBase::groupId()
const
48 return u
"rasterterrainanalysis"_s;
51QStringList QgsUpslopeAreaAlgorithmBase::tags()
const
53 return QObject::tr(
"upslope,area,flow,accumulation,hydrology,catchment,watershed,target" ).split(
',' );
56QList<QgsAcademicReference> QgsUpslopeAreaAlgorithmBase::academicReferences()
const
59 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 );
62 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 );
65 { 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 },
67 u
"An approach to computing topographic wetness index based on maximum downslope gradient"_s,
68 u
"Precision Agriculture"_s,
75 { u
"Quinn, P. F."_s, u
"Beven, K. J."_s, u
"Chevallier, P."_s, u
"Planchon, O."_s },
77 u
"The prediction of hillslope flow paths for distributed hydrological modelling using digital terrain models"_s,
78 u
"Hydrological Processes"_s,
85 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 );
88 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 );
90 return { freemanReference, ocallaghanReference, qinReference, quinnReference, seibertReference, tarbotonReference };
93QList<QgsProcessingAlgorithm::ExternalLink> QgsUpslopeAreaAlgorithmBase::externalLinks()
const
96 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 }
100void QgsUpslopeAreaAlgorithmBase::addCommonParameters()
102 auto demParam = std::make_unique<QgsProcessingParameterRasterLayer>( u
"ELEVATION"_s, QObject::tr(
"Elevation" ) );
103 demParam->setHelp( QObject::tr(
"Input digital elevation model (DEM) raster layer." ) );
104 addParameter( demParam.release() );
106 auto routeParam = std::make_unique<QgsProcessingParameterRasterLayer>( u
"SINK_ROUTES"_s, QObject::tr(
"Sink routes" ), QVariant(),
true );
107 routeParam->setHelp( QObject::tr(
"Optional raster layer specifying explicit flow routes through sinks/depressions." ) );
108 addParameter( routeParam.release() );
110 const QStringList methods
111 = { 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" ) };
112 auto methodParam = std::make_unique<QgsProcessingParameterEnum>( u
"METHOD"_s, QObject::tr(
"Method" ), methods,
false, 2 );
113 methodParam->setHelp( QObject::tr(
"Flow routing algorithm used to determine flow distribution to downslope cells." ) );
114 addParameter( methodParam.release() );
117 convergeParam->setHelp( QObject::tr(
"Convergence factor for Multiple Flow Direction algorithms." ) );
118 addParameter( convergeParam.release() );
120 auto contourParam = std::make_unique<QgsProcessingParameterBoolean>( u
"MFD_CONTOUR"_s, QObject::tr(
"Use contour length weighting" ),
false );
121 contourParam->setHelp(
122 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)." )
124 addParameter( contourParam.release() );
127 outputNodataParam->setHelp( QObject::tr(
"The NODATA value to use in the output raster." ) );
129 addParameter( outputNodataParam.release() );
131 auto creationOptsParam = std::make_unique<QgsProcessingParameterString>( u
"CREATION_OPTIONS"_s, QObject::tr(
"Creation options" ), QVariant(),
false,
true );
132 creationOptsParam->setHelp( QObject::tr(
"The raster creation options for the output raster. These options control things like colorimetry, compression, etc." ) );
133 creationOptsParam->setMetadata( QVariantMap( { { u
"widget_wrapper"_s, QVariantMap( { { u
"widget_type"_s, u
"rasteroptions"_s } } ) } } ) );
135 addParameter( creationOptsParam.release() );
137 auto outputParam = std::make_unique<QgsProcessingParameterRasterDestination>( u
"OUTPUT"_s, QObject::tr(
"Upslope area" ) );
138 addParameter( outputParam.release() );
143 QgsRasterLayer *demLayer = parameterAsRasterLayer( parameters, u
"ELEVATION"_s, context );
148 mDemCrs = demLayer->
crs();
149 mExtent = demLayer->
extent();
150 mCols = demLayer->
width();
151 mRows = demLayer->
height();
158 QgsRasterLayer *routeLayer = parameterAsRasterLayer( parameters, u
"SINK_ROUTES"_s, context );
170 mMethod =
static_cast<Method
>( parameterAsInt( parameters, u
"METHOD"_s, context ) );
171 mConvergence = parameterAsDouble( parameters, u
"CONVERGE"_s, context );
172 mMfdContour = parameterAsBool( parameters, u
"MFD_CONTOUR"_s, context );
174 mCreationOptions = parameterAsString( parameters, u
"CREATION_OPTIONS"_s, context ).trimmed();
175 mOutputNoData = parameterAsDouble( parameters, u
"NODATA"_s, context );
179double QgsUpslopeAreaAlgorithmBase::neighborLength(
int dir,
double cellSizeX,
double cellSizeY )
190 return std::hypot( cellSizeX, cellSizeY );
194int QgsUpslopeAreaAlgorithmBase::neighborTo(
int dir,
int col,
int &outCol,
int row,
int &outRow,
int cols,
int rows )
196 outCol = col + COL_DIRECTION_OFFSETS[dir];
197 outRow = row + ROW_DIRECTION_OFFSETS[dir];
198 return ( outCol >= 0 && outCol < cols && outRow >= 0 && outRow < rows );
205 std::unique_ptr<QgsRasterBlock> demBlock( mDemProvider->block( 1, mExtent, mCols, mRows ) );
210 if ( mRouteProvider )
212 mRouteData.resize( nCells, -1.0 );
213 std::unique_ptr<QgsRasterBlock> routeBlock( mRouteProvider->block( 1, mExtent, mCols, mRows ) );
216 for (
int r = 0; r < mRows; ++r )
218 for (
int c = 0;
c < mCols; ++
c )
220 mRouteData[
static_cast<qgssize>( r ) * mCols +
c] = routeBlock->value( r,
c );
226 mFlowData.assign( nCells, 0.0 );
230 bool hasValidTarget =
false;
235 QgsRasterAnalysisUtils::mapToPixel( pt.x(), pt.y(), mExtent, mCellSizeX, mCellSizeY, column, row );
236 if ( column >= 0 && column < mCols && row >= 0 && row < mRows )
238 mFlowData[
static_cast<qgssize>( row ) * mCols + column] = 100.0;
239 hasValidTarget =
true;
243 if ( !hasValidTarget )
245 feedback->
reportError( QObject::tr(
"All target point(s) lie outside the DEM extent." ) );
252 const qgssize count = sortedIndex.sortedCount();
253 for (
qgssize i = 0; i < count; ++i )
257 feedback->
setProgress( 100.0 *
static_cast<double>( i ) / count );
258 sortedIndex.sortedColumnRow( i, column, row, Qt::AscendingOrder );
262 if ( mFlowData[
static_cast<qgssize>( row ) * mCols + column] <= 0.0 )
264 computeCellValue( demBlock.get(), column, row, mCols, mRows, mCellSizeX, mCellSizeY, mMethod, mConvergence, mMfdContour );
271 auto writer = std::make_unique<QgsRasterFileWriter>( mOutputPath );
272 writer->setOutputProviderKey( u
"gdal"_s );
273 if ( !mCreationOptions.isEmpty() )
275 writer->setCreationOptions( mCreationOptions.split(
'|' ) );
277 writer->setOutputFormat( mOutputFormat );
279 std::unique_ptr<QgsRasterDataProvider> provider( writer->createOneBandRaster(
Qgis::DataType::Float32, mCols, mRows, mExtent, mDemCrs ) );
282 if ( !provider->isValid() )
285 provider->setNoDataValue( 1, mOutputNoData );
286 provider->setEditable(
true );
289 for (
int r = 0; r < mRows; ++r )
291 for (
int c = 0;
c < mCols; ++
c )
293 outputBlock.setValue( r,
c,
static_cast<float>( mFlowData[
static_cast<qgssize>( r ) * mCols +
c] ) );
297 if ( !provider->writeBlock( &outputBlock, 1 ) )
299 throw QgsProcessingException( QObject::tr(
"Could not write raster block: %1" ).arg( provider->error().summary() ) );
302 provider->setEditable(
false );
306void QgsUpslopeAreaAlgorithmBase::computeCellValue(
const QgsRasterBlock *demBlock,
int col,
int row,
int cols,
int rows,
double cellSizeX,
double cellSizeY, Method method,
double converge,
bool contour )
311 if ( !mRouteData.empty() )
313 const int routeDir =
static_cast<int>( mRouteData[idx] );
314 if ( routeDir >= 0 && routeDir < 8 )
318 if ( neighborTo( routeDir, col, neighborCol, row, neighborRow, cols, rows ) )
320 const double routedFlow = mFlowData[
static_cast<qgssize>( neighborRow ) * cols + neighborCol];
321 if ( routedFlow > 0.0 )
323 mFlowData[idx] = routedFlow;
333 computeD8( demBlock, col, row, cols, rows, cellSizeX, cellSizeY );
336 computeDInf( demBlock, col, row, cols, rows, cellSizeX, cellSizeY );
339 computeMFD( demBlock, col, row, cols, rows, cellSizeX, cellSizeY, converge, contour );
342 computeMDInf( demBlock, col, row, cols, rows, cellSizeX, cellSizeY, converge );
345 computeMMDGFD( demBlock, col, row, cols, rows, cellSizeX, cellSizeY, contour );
350void QgsUpslopeAreaAlgorithmBase::computeD8(
const QgsRasterBlock *demBlock,
int col,
int row,
int cols,
int rows,
double cellSizeX,
double cellSizeY )
352 const double z = demBlock->
value( row, col );
353 double maxGradient = 0.0;
354 int steepestDir = -1;
356 bool isNodata =
false;
357 for (
int dir = 0; dir < 8; ++dir )
361 if ( neighborTo( dir, col, nCol, row, nRow, cols, rows ) )
363 const double nZ = demBlock->
valueAndNoData( nRow, nCol, isNodata );
366 const double dz = z - nZ;
369 const double grad = dz / neighborLength( dir, cellSizeX, cellSizeY );
370 if ( grad > maxGradient )
380 if ( steepestDir >= 0 )
384 neighborTo( steepestDir, col, neighborCol, row, neighborRow, cols, rows );
385 const double neighborFlow = mFlowData[
static_cast<qgssize>( neighborRow ) * cols + neighborCol];
386 if ( neighborFlow > 0.0 )
388 mFlowData[
static_cast<qgssize>( row ) * cols + col] = neighborFlow;
393void QgsUpslopeAreaAlgorithmBase::computeDInf(
const QgsRasterBlock *demBlock,
int col,
int row,
int cols,
int rows,
double cellSizeX,
double cellSizeY )
395 bool isNoData =
false;
400 computeD8( demBlock, col, row, cols, rows, cellSizeX, cellSizeY );
405 double dz[4] = { 0.0, 0.0, 0.0, 0.0 };
406 const std::array<int, 4> dirs { 0, 2, 4, 6 };
407 for (
int i = 0; i < 4; ++i )
409 const int iDir = dirs[i];
410 const int oppositeDir = ( iDir + 4 ) % 8;
414 int oppositeNeighborCol = 0;
415 int oppositeNeighborRow = 0;
416 bool neighborIsNoData =
true;
417 double neighborZ = 0;
418 if ( neighborTo( iDir, col, neighborCol, row, neighborRow, cols, rows ) )
420 neighborZ = demBlock->
valueAndNoData( neighborRow, neighborCol, neighborIsNoData );
422 bool oppositeIsNoData =
true;
423 double oppositeNeighborZ = 0;
424 if ( neighborTo( oppositeDir, col, oppositeNeighborCol, row, oppositeNeighborRow, cols, rows ) )
426 oppositeNeighborZ = demBlock->
valueAndNoData( oppositeNeighborRow, oppositeNeighborCol, oppositeIsNoData );
429 if ( !neighborIsNoData )
431 dz[i] = neighborZ - z;
433 else if ( !oppositeIsNoData )
435 dz[i] = z - oppositeNeighborZ;
443 const double G = ( dz[0] - dz[2] ) / ( 2.0 * cellSizeY );
444 const double H = ( dz[1] - dz[3] ) / ( 2.0 * cellSizeX );
446 double aspect = -1.0;
449 aspect = M_PI + std::atan2( H, G );
451 aspect += 2.0 * M_PI;
452 if ( aspect >= 2.0 * M_PI )
453 aspect -= 2.0 * M_PI;
466 const int i =
static_cast<int>( aspect / ( M_PI / 4.0 ) ) % 8;
467 const int j = ( i + 1 ) % 8;
473 if ( neighborTo( i, col, iCol, row, iRow, cols, rows ) && neighborTo( j, col, jCol, row, jRow, cols, rows ) )
475 bool iIsNoData =
false;
476 const double zi = demBlock->
valueAndNoData( iRow, iCol, iIsNoData );
477 bool jIsNoData =
false;
478 const double zj = demBlock->
valueAndNoData( jRow, jCol, jIsNoData );
479 if ( !iIsNoData && !jIsNoData )
482 if ( zi < z && zj < z )
484 const double aspectFraction = std::fmod( aspect, M_PI / 4.0 ) / ( M_PI / 4.0 );
485 const double flowI = mFlowData[
static_cast<qgssize>( iRow ) * cols + iCol];
486 const double flowJ = mFlowData[
static_cast<qgssize>( jRow ) * cols + jCol];
488 const double accumulatedFlow = flowI * ( 1.0 - aspectFraction ) + flowJ * aspectFraction;
489 if ( accumulatedFlow > 0.0 )
491 mFlowData[
static_cast<qgssize>( row ) * cols + col] = accumulatedFlow;
499 computeD8( demBlock, col, row, cols, rows, cellSizeX, cellSizeY );
502void QgsUpslopeAreaAlgorithmBase::computeMFD(
const QgsRasterBlock *demBlock,
int col,
int row,
int cols,
int rows,
double cellSizeX,
double cellSizeY,
double converge,
bool contour )
504 const double z = demBlock->
value( row, col );
508 bool isNodata =
false;
509 for (
int dir = 0; dir < 8; ++dir )
514 if ( neighborTo( dir, col, neighborCol, row, neighborRow, cols, rows ) )
516 const double nZ = demBlock->
valueAndNoData( neighborRow, neighborCol, isNodata );
519 const double diff = z - nZ;
522 const double length = neighborLength( dir, cellSizeX, cellSizeY );
523 const double weight = std::pow( diff / length, converge ) * ( ( contour && ( dir % 2 ) ) ? ( M_SQRT1_2 ) : 1.0 );
534 for (
int dir = 0; dir < 8; ++dir )
540 neighborTo( dir, col, nCol, row, nRow, cols, rows );
541 const double nFlow = mFlowData[
static_cast<qgssize>( nRow ) * cols + nCol];
544 flow += ( dz[dir] / dzSum ) * nFlow;
551 mFlowData[
static_cast<qgssize>( row ) * cols + col] = flow;
556void QgsUpslopeAreaAlgorithmBase::computeMMDGFD(
const QgsRasterBlock *demBlock,
int col,
int row,
int cols,
int rows,
double cellSizeX,
double cellSizeY,
bool contour )
558 const double z = demBlock->
value( row, col );
562 bool isNodata =
false;
563 for (
int dir = 0; dir < 8; ++dir )
568 if ( neighborTo( dir, col, neighborCol, row, neighborRow, cols, rows ) )
570 const double nZ = demBlock->
valueAndNoData( neighborRow, neighborCol, isNodata );
573 const double diff = z - nZ;
576 dz[dir] = diff / neighborLength( dir, cellSizeX, cellSizeY );
577 if ( dzMax < dz[dir] )
588 const double exponent = ( dzMax < 1.0 ) ? ( 8.9 * dzMax + 1.1 ) : 10.0;
591 for (
int i = 0; i < 8; ++i )
595 dz[i] = std::pow( dz[i], exponent ) * ( ( contour && ( i % 2 ) ) ? M_SQRT1_2 : 1.0 );
603 for (
int i = 0; i < 8; ++i )
609 neighborTo( i, col, neighborCol, row, neighborRow, cols, rows );
610 const double nFlow = mFlowData[
static_cast<qgssize>( neighborRow ) * cols + neighborCol];
613 flow += ( dz[i] / dzSum ) * nFlow;
620 mFlowData[
static_cast<qgssize>( row ) * cols + col] = flow;
626void QgsUpslopeAreaAlgorithmBase::computeMDInf(
const QgsRasterBlock *demBlock,
int col,
int row,
int cols,
int rows,
double cellSizeX,
double cellSizeY,
double converge )
628 const double z = demBlock->
value( row, col );
634 bool isNodata =
false;
635 for (
int i = 0; i < 8; ++i )
643 if ( neighborTo( i, col, neighborCol, row, neighborRow, cols, rows ) )
645 const double nZ = demBlock->
valueAndNoData( neighborRow, neighborCol, isNodata );
654 for (
int i = 0; i < 8; ++i )
661 const int j = ( i < 7 ) ? i + 1 : 0;
665 const double nx = ( dz[j] * SAGA_Y[i] - dz[i] * SAGA_Y[j] ) * cellSizeY;
666 const double ny = ( dz[i] * SAGA_X[j] - dz[j] * SAGA_X[i] ) * cellSizeX;
667 const double nz = ( SAGA_X[i] * SAGA_Y[j] - SAGA_X[j] * SAGA_Y[i] ) * ( cellSizeX * cellSizeY );
669 const double nNorm = std::sqrt( nx * nx + ny * ny + nz * nz );
673 hr = ( ny >= 0.0 ) ? 0.0 : M_PI;
677 hr = ( 1.5 * M_PI ) - std::atan( ny / nx );
681 hr = ( 0.5 * M_PI ) - std::atan( ny / nx );
684 const double cosAngle = std::clamp( nz / nNorm, -1.0, 1.0 );
685 hs = -std::tan( std::acos( cosAngle ) );
687 if ( hr < i * ( M_PI / 4.0 ) || hr > ( i + 1 ) * ( M_PI / 4.0 ) )
691 hr = i * ( M_PI / 4.0 );
692 hs = dz[i] / neighborLength( i, cellSizeX, cellSizeY );
696 hr = j * ( M_PI / 4.0 );
697 hs = dz[j] / neighborLength( j, cellSizeX, cellSizeY );
701 else if ( dz[i] > 0.0 )
703 hr = i * ( M_PI / 4.0 );
704 hs = dz[i] / neighborLength( i, cellSizeX, cellSizeY );
715 for (
int i = 0; i < 8; ++i )
719 int j = ( i < 7 ) ? i + 1 : 0;
721 if ( sFacet[i] > 0.0 )
723 if ( rFacet[i] > i * ( M_PI / 4.0 ) && rFacet[i] < ( i + 1 ) * ( M_PI / 4.0 ) )
725 valley[i] = sFacet[i];
727 else if ( rFacet[i] == rFacet[j] )
729 valley[i] = sFacet[i];
731 else if ( sFacet[j] == -999.0 && rFacet[i] == ( i + 1 ) * ( M_PI / 4.0 ) )
733 valley[i] = sFacet[i];
737 const int k = ( i > 0 ) ? i - 1 : 7;
738 if ( sFacet[k] == -999.0 && rFacet[i] == i * ( M_PI / 4.0 ) )
740 valley[i] = sFacet[i];
744 valley[i] = std::pow( valley[i], converge );
752 for (
int i = 0; i < 8; ++i )
754 const int j = ( i < 7 ) ? i + 1 : 0;
756 if ( i >= 7 && rFacet[i] == 0.0 )
758 rFacet[i] = 2.0 * M_PI;
761 if ( valley[i] > 0.0 )
764 portion[i] += valley[i] * ( ( i + 1 ) * ( M_PI / 4.0 ) - rFacet[i] ) / ( M_PI / 4.0 );
765 portion[j] += valley[i] * ( rFacet[i] - i * ( M_PI / 4.0 ) ) / ( M_PI / 4.0 );
770 for (
int i = 0; i < 8; ++i )
772 if ( portion[i] > 0.0 )
774 int nCol = 0, nRow = 0;
775 if ( neighborTo( i, col, nCol, row, nRow, cols, rows ) )
777 const double nFlow = mFlowData[
static_cast<qgssize>( nRow ) * cols + nCol];
780 flow += nFlow * portion[i];
788 mFlowData[
static_cast<qgssize>( row ) * cols + col] = flow;
798QgsUpslopeAreaPointAlgorithm::QgsUpslopeAreaPointAlgorithm() =
default;
800QString QgsUpslopeAreaPointAlgorithm::name()
const
802 return u
"upslopeareafrompoint"_s;
805QString QgsUpslopeAreaPointAlgorithm::displayName()
const
807 return QObject::tr(
"Upslope area (from point)" );
810QString QgsUpslopeAreaPointAlgorithm::shortDescription()
const
812 return QObject::tr(
"Calculates the upslope contributing area for a specified target point coordinate." );
815QString QgsUpslopeAreaPointAlgorithm::shortHelpString()
const
818 "This algorithm calculates the upslope contributing area (catchment) for a single target coordinate point on a Digital Elevation Model (DEM).\n\n"
819 "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"
820 "Supported flow routing methods are:\n\n"
821 "• Deterministic 8: Single-flow direction algorithm, routing 100% of flow to the steepest downslope neighbor (O'Callaghan & Mark 1984).\n"
822 "• Deterministic Infinity: Continuous single-facet flow direction algorithm, routing flow along triangular facets using a 3×3 finite-difference aspect calculation (Tarboton 1997).\n"
823 "• 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"
824 "• Multiple Triangular Flow Direction: Advanced divergent routing utilizing 3D vector normal cross-products across triangular facets to distribute flow smoothly across complex terrain (Seibert & "
826 "• Multiple Maximum Downslope Gradient: Adaptive MFD variant scaling exponent weights dynamically based on the local maximum gradient (Qin et al. 2011).\n\n"
827 "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"
828 "This algorithm is a port of the SAGA 'Upslope Area' tool."
834 return new QgsUpslopeAreaPointAlgorithm();
837void QgsUpslopeAreaPointAlgorithm::initAlgorithm(
const QVariantMap & )
839 addCommonParameters();
841 auto pointParam = std::make_unique<QgsProcessingParameterPoint>( u
"TARGET_PT"_s, QObject::tr(
"Target point" ) );
842 pointParam->setHelp( QObject::tr(
"World coordinate point defining the target cell." ) );
843 addParameter( pointParam.release() );
848 return prepareBase( parameters, context, feedback );
853 QGS_MARK_ALGORITHM_SOURCE
855 const QgsPointXY targetPt = parameterAsPoint( parameters, u
"TARGET_PT"_s, context, mDemCrs );
857 mOutputPath = parameterAsOutputLayer( parameters, u
"OUTPUT"_s, context );
858 mOutputFormat = parameterAsOutputRasterFormat( parameters, u
"OUTPUT"_s, context );
860 calculateUpslopeArea( { targetPt }, context, feedback );
863 outputs.insert( u
"OUTPUT"_s, mOutputPath );
872QgsUpslopeAreaLayerAlgorithm::QgsUpslopeAreaLayerAlgorithm() =
default;
874QString QgsUpslopeAreaLayerAlgorithm::name()
const
876 return u
"upslopeareafromlayer"_s;
879QString QgsUpslopeAreaLayerAlgorithm::displayName()
const
881 return QObject::tr(
"Upslope area (from layer)" );
884QString QgsUpslopeAreaLayerAlgorithm::shortDescription()
const
886 return QObject::tr(
"Calculates the combined upslope contributing area for target points in a vector layer." );
889QString QgsUpslopeAreaLayerAlgorithm::shortHelpString()
const
891 return QObject::tr(
"This algorithm calculates the combined upslope contributing catchment area for target points provided in an input vector point layer." );
894 "This algorithm calculates the combined upslope contributing area (catchments) for all target point locations provided in an input vector layer.\n\n"
895 "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"
896 "Supported flow routing methods are:\n\n"
897 "• Deterministic 8: Single-flow direction algorithm, routing 100% of flow to the steepest downslope neighbor (O'Callaghan & Mark 1984).\n"
898 "• Deterministic Infinity: Continuous single-facet flow direction algorithm, routing flow along triangular facets using a 3×3 finite-difference aspect calculation (Tarboton 1997).\n"
899 "• 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"
900 "• Multiple Triangular Flow Direction: Advanced divergent routing utilizing 3D vector normal cross-products across triangular facets to distribute flow smoothly across complex terrain (Seibert & "
902 "• Multiple Maximum Downslope Gradient: Adaptive MFD variant scaling exponent weights dynamically based on the local maximum gradient (Qin et al. 2011).\n\n"
903 "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"
904 "This algorithm is a port of the SAGA 'Upslope Area' tool."
910 return new QgsUpslopeAreaLayerAlgorithm();
913void QgsUpslopeAreaLayerAlgorithm::initAlgorithm(
const QVariantMap & )
915 addCommonParameters();
919 layerParam->setHelp( QObject::tr(
"Vector point layer containing target locations." ) );
920 addParameter( layerParam.release() );
925 return prepareBase( parameters, context, feedback );
930 QGS_MARK_ALGORITHM_SOURCE
932 std::unique_ptr<QgsFeatureSource> targetSource( parameterAsSource( parameters, u
"TARGET_LAYER"_s, context ) );
936 std::vector<QgsPointXY> targetPoints;
944 targetPoints.push_back( pt );
948 if ( targetPoints.empty() )
950 throw QgsProcessingException( QObject::tr(
"Input target point layer contains no valid point geometries." ) );
953 mOutputPath = parameterAsOutputLayer( parameters, u
"OUTPUT"_s, context );
954 mOutputFormat = parameterAsOutputRasterFormat( parameters, u
"OUTPUT"_s, context );
956 calculateUpslopeArea( targetPoints, context, feedback );
959 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.