25using namespace Qt::StringLiterals;
29QStringList QgsStrahlerOrderAlgorithmBase::tags()
const
31 return QObject::tr(
"dem,strahler,order,stream,channels,hydrology,network,catchment" ).split(
',' );
34void QgsStrahlerOrderAlgorithmBase::addCommonParameters()
39 outputNodataParam->setHelp( QObject::tr(
"The NODATA value to use in the output raster." ) );
41 addParameter( outputNodataParam.release() );
43 auto creationOptsParam = std::make_unique<QgsProcessingParameterString>( u
"CREATION_OPTIONS"_s, QObject::tr(
"Creation options" ), QVariant(),
false,
true );
44 creationOptsParam->setHelp( QObject::tr(
"The raster creation options for the output raster. These options control things like colorimetry, compression, etc." ) );
45 creationOptsParam->setMetadata( QVariantMap( { { u
"widget_wrapper"_s, QVariantMap( { { u
"widget_type"_s, u
"rasteroptions"_s } } ) } } ) );
47 addParameter( creationOptsParam.release() );
49 auto outputParam = std::make_unique<QgsProcessingParameterRasterDestination>( u
"OUTPUT"_s, QObject::tr(
"Strahler order" ) );
50 addParameter( outputParam.release() );
53QVariantMap QgsStrahlerOrderAlgorithmBase::writeOutputRaster(
QgsRasterBlock *outputBlock,
const QString &outputFile,
const QString &outputFormat,
const QString &creationOptions )
55 auto outputWriter = std::make_unique<QgsRasterFileWriter>( outputFile );
56 outputWriter->setOutputProviderKey( u
"gdal"_s );
57 if ( !creationOptions.isEmpty() )
59 outputWriter->setCreationOptions( creationOptions.split(
'|' ) );
61 outputWriter->setOutputFormat( outputFormat );
63 std::unique_ptr<QgsRasterDataProvider> destProvider( outputWriter->createOneBandRaster(
Qgis::DataType::Int16, mLayerWidth, mLayerHeight, mExtent, mCrs ) );
66 if ( !destProvider->isValid() )
69 destProvider->setNoDataValue( 1, mOutputNoData );
70 destProvider->setEditable(
true );
72 if ( !destProvider->writeBlock( outputBlock, 1 ) )
74 throw QgsProcessingException( QObject::tr(
"Could not write raster block: %1" ).arg( destProvider->error().summary() ) );
77 destProvider->setEditable(
false );
80 outputs.insert( u
"OUTPUT"_s, outputFile );
88QString QgsStrahlerOrderFromDemAlgorithm::name()
const
90 return u
"strahlerorderfromdem"_s;
93QString QgsStrahlerOrderFromDemAlgorithm::displayName()
const
95 return QObject::tr(
"Strahler order from DEM" );
98QString QgsStrahlerOrderFromDemAlgorithm::shortDescription()
const
100 return QObject::tr(
"Calculates Strahler stream order directly from an input DEM raster." );
103QString QgsStrahlerOrderFromDemAlgorithm::shortHelpString()
const
106 "This algorithm calculates Strahler stream order from an input elevation raster (DEM).\n\n"
107 "D8 flow directions are computed internally to traverse channel trees topographically.\n"
108 "Confluences of two stream channels of order N produce a downstream channel of order N + 1.\n"
109 "When the threshold is set to 1, raw stream orders (1, 2, 3...) are calculated. "
110 "Higher threshold values mask non-stream cells as NoData and offset stream orders.\n\n"
111 "This algorithm is a port of the Strahler stream order calculation from SAGA 'Channel Network and Drainage Basins' tool."
115void QgsStrahlerOrderFromDemAlgorithm::initAlgorithm(
const QVariantMap & )
118 addCommonParameters();
123 return new QgsStrahlerOrderFromDemAlgorithm();
128 QgsRasterLayer *layer = parameterAsRasterLayer( parameters, u
"INPUT"_s, context );
133 mLayerWidth = layer->
width();
134 mLayerHeight = layer->
height();
135 mExtent = layer->
extent();
145 QGS_MARK_ALGORITHM_SOURCE
147 const int threshold = parameterAsInt( parameters, u
"THRESHOLD"_s, context );
148 const QString creationOptions = parameterAsString( parameters, u
"CREATION_OPTIONS"_s, context ).trimmed();
149 const QString outputFile = parameterAsOutputLayer( parameters, u
"OUTPUT"_s, context );
150 const QString outputFormat = parameterAsOutputRasterFormat( parameters, u
"OUTPUT"_s, context );
151 mOutputNoData = parameterAsInt( parameters, u
"NODATA"_s, context );
153 std::unique_ptr<QgsRasterBlock> demBlock( mDemInterface->block( 1, mExtent, mLayerWidth, mLayerHeight ) );
157 const qgssize totalCells =
static_cast<qgssize>( mLayerWidth ) * mLayerHeight;
161 multiStepFeedback.setCurrentStep( 0 );
162 std::vector<int8_t> d8Directions( totalCells, -1 );
163 for (
int row = 0; row < mLayerHeight; ++row )
165 if ( multiStepFeedback.isCanceled() )
168 multiStepFeedback.setProgress( 100.0 *
static_cast<double>( row ) / mLayerHeight );
169 const qgssize rowOffset =
static_cast<qgssize>( row ) * mLayerWidth;
170 for (
int col = 0; col < mLayerWidth; ++col )
172 const int dir = QgsRasterAnalysisUtils::steepestGradientDirection( demBlock.get(), row, col, mCellSizeX, mCellSizeY,
true,
true );
173 d8Directions[rowOffset + col] =
static_cast<int8_t
>( dir );
178 multiStepFeedback.setCurrentStep( 1 );
179 auto outputBlock = std::make_unique<QgsRasterBlock>(
Qgis::DataType::Int16, mLayerWidth, mLayerHeight );
182 int16_t *outOrder =
reinterpret_cast<int16_t *
>( outputBlock->
bits() );
183 computeStrahlerOrder( demBlock.get(), d8Directions, mLayerWidth, mLayerHeight, threshold, outOrder, &multiStepFeedback, mOutputNoData );
185 if ( multiStepFeedback.isCanceled() )
188 return writeOutputRaster( outputBlock.get(), outputFile, outputFormat, creationOptions );
195QString QgsStrahlerOrderFromFlowDirectionAlgorithm::name()
const
197 return u
"strahlerorderfromflowdirection"_s;
200QString QgsStrahlerOrderFromFlowDirectionAlgorithm::displayName()
const
202 return QObject::tr(
"Strahler order from DEM and flow direction" );
205QString QgsStrahlerOrderFromFlowDirectionAlgorithm::shortDescription()
const
207 return QObject::tr(
"Calculates Strahler stream order using an elevation raster (DEM) and a D8 flow direction raster." );
210QString QgsStrahlerOrderFromFlowDirectionAlgorithm::shortHelpString()
const
213 "This algorithm calculates Strahler stream order from an input elevation raster (DEM) and a pre-computed D8 flow direction raster.\n\n"
214 "Confluences of two stream channels of order N produce a downstream channel of order N + 1.\n"
215 "When the threshold is set to 1, raw stream orders (1, 2, 3...) are calculated. "
216 "Higher threshold values mask non-stream cells as NoData and offset stream orders.\n\n"
217 "This algorithm is a port of the Strahler stream order calculation from SAGA 'Channel Network and Drainage Basins' tool."
221void QgsStrahlerOrderFromFlowDirectionAlgorithm::initAlgorithm(
const QVariantMap & )
225 addCommonParameters();
230 return new QgsStrahlerOrderFromFlowDirectionAlgorithm();
235 QgsRasterLayer *demLayer = parameterAsRasterLayer( parameters, u
"INPUT"_s, context );
239 QgsRasterLayer *flowDirLayer = parameterAsRasterLayer( parameters, u
"INPUT_FLOW_DIRECTION"_s, context );
245 mLayerWidth = demLayer->
width();
246 mLayerHeight = demLayer->
height();
247 mExtent = demLayer->
extent();
248 mCrs = demLayer->
crs();
255 QGS_MARK_ALGORITHM_SOURCE
257 const int threshold = parameterAsInt( parameters, u
"THRESHOLD"_s, context );
258 const QString creationOptions = parameterAsString( parameters, u
"CREATION_OPTIONS"_s, context ).trimmed();
259 const QString outputFile = parameterAsOutputLayer( parameters, u
"OUTPUT"_s, context );
260 const QString outputFormat = parameterAsOutputRasterFormat( parameters, u
"OUTPUT"_s, context );
261 mOutputNoData = parameterAsInt( parameters, u
"NODATA"_s, context );
263 std::unique_ptr<QgsRasterBlock> demBlock( mDemInterface->block( 1, mExtent, mLayerWidth, mLayerHeight ) );
267 std::unique_ptr<QgsRasterBlock> flowDirBlock( mFlowDirInterface->block( 1, mExtent, mLayerWidth, mLayerHeight ) );
271 const qgssize totalCells =
static_cast<qgssize>( mLayerWidth ) * mLayerHeight;
273 std::vector<int8_t> d8Directions( totalCells, -1 );
274 for (
int row = 0; row < mLayerHeight; ++row )
279 bool isNoData =
false;
280 const qgssize rowOffset =
static_cast<qgssize>( row ) * mLayerWidth;
281 for (
int col = 0; col < mLayerWidth; ++col )
283 const double dir = flowDirBlock->valueAndNoData( row, col, isNoData );
286 d8Directions[rowOffset + col] =
static_cast<int8_t
>( dir );
291 auto outputBlock = std::make_unique<QgsRasterBlock>(
Qgis::DataType::Int16, mLayerWidth, mLayerHeight );
294 int16_t *outOrder =
reinterpret_cast<int16_t *
>( outputBlock->
bits() );
295 computeStrahlerOrder( demBlock.get(), d8Directions, mLayerWidth, mLayerHeight, threshold, outOrder, feedback, mOutputNoData );
300 return writeOutputRaster( outputBlock.get(), outputFile, outputFormat, creationOptions );
@ Int16
Sixteen bit signed integer (qint16).
@ Advanced
Parameter is an advanced parameter which should be hidden from users by default.
bool isCanceled() const
Tells whether the operation has been canceled already.
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.
Custom exception class for processing related exceptions.
Base class for providing feedback from a processing algorithm.
Processing feedback object for multi-step operations.
A numeric parameter for processing algorithms.
A raster layer parameter for processing algorithms.
char * bits(int row, int column)
Returns a pointer to block data.
void setNoDataValue(double noDataValue)
Sets cell value that will be considered as "no data".
QgsRasterDataProvider * clone() const override=0
Clone itself, create deep copy.
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.
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...