QGIS API Documentation 4.3.0-Master (45633be667c)
Loading...
Searching...
No Matches
qgsalgorithmd8base.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsalgorithmd8base.cpp
3 ---------------------
4 begin : September 2026
5 copyright : (C) 2026 by Nyall Dawson
6 email : nyall dot dawson at gmail dot com
7 ***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
18#include "qgsalgorithmd8base.h"
19
22#include "qgsrasterfilewriter.h"
23
24#include <QString>
25
26using namespace Qt::StringLiterals;
27
29QString QgsD8AnalysisAlgorithmBase::group() const
30{
31 return QObject::tr( "Raster terrain analysis" );
32}
33
34QString QgsD8AnalysisAlgorithmBase::groupId() const
35{
36 return u"rasterterrainanalysis"_s;
37}
38
39QList<QgsAcademicReference> QgsD8AnalysisAlgorithmBase::academicReferences() const
40{
41 return {
42 QgsAcademicReference::createJournalArticle( { u"Strahler, A. N."_s }, 1957, u"Quantitative analysis of watershed geomorphology"_s, u"Eos, Transactions American Geophysical Union"_s, u"38"_s, u"6"_s, u"913-920"_s ),
44 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 )
45 };
46}
47
48QList<QgsProcessingAlgorithm::ExternalLink> QgsD8AnalysisAlgorithmBase::externalLinks() const
49{
50 return {
51 QgsProcessingAlgorithm::ExternalLink { QObject::tr( "SAGA tool source code" ), u"https://sourceforge.net/p/saga-gis/code/ci/33d1062b7120c696c9dd258378c48d86dc33560c/tree/saga-gis/src/tools/terrain_analysis/ta_channels/D8_Flow_Analysis.cpp"_s }
52 };
53}
54
55void QgsD8AnalysisAlgorithmBase::computeStrahlerOrder(
56 const QgsRasterBlock *demBlock, const std::vector<int8_t> &d8Directions, int width, int height, int threshold, int16_t *outOrder, QgsProcessingFeedback *feedback, int outputNoData
57)
58{
59 const std::size_t totalCells = static_cast<std::size_t>( width ) * height;
60 std::fill_n( outOrder, totalCells, static_cast<int16_t>( 0 ) );
61
62 // see CStack in SAGA's CD8_Flow_Analysis
63 struct StackFrame
64 {
65 int column;
66 int row;
67 int dir;
68 int maxOrderCount;
69 int maxOrder;
70 };
71
72 std::vector<StackFrame> stack;
73 stack.reserve( 1024 );
74
75 for ( int row = 0; row < height; ++row )
76 {
77 if ( feedback->isCanceled() )
78 return;
79
80 feedback->setProgress( 100.0 * static_cast<double>( row ) / height );
81
82 const qgssize rowOffset = static_cast<qgssize>( row ) * width;
83 for ( int column = 0; column < width; ++column )
84 {
85 const qgssize startIdx = rowOffset + column;
86 if ( demBlock->isNoData( row, column ) || outOrder[startIdx] >= 1 )
87 continue;
88
89 // stack will always be empty here -- so just like SAGA's CD8_Flow_Analysis::Get_Order, we start
90 // with an empty stack for each unique pixel. But reusing the same stack object here avoids
91 // reallocating memory for every pixel...
92 stack.push_back( { .column = column, .row = row, .dir = 0, .maxOrderCount = 0, .maxOrder = 1 } );
93
94 while ( !stack.empty() )
95 {
96 StackFrame &current = stack.back();
97 const qgssize currentIdx = static_cast<qgssize>( current.row ) * width + current.column;
98
99 bool pushedChild = false;
100 for ( ; current.dir < 8; )
101 {
102 const int oppositeDir = ( current.dir + 4 ) % 8;
103 int neighborColumn = 0;
104 int neighborRow = 0;
105 if ( QgsRasterAnalysisUtils::neighborCellCoordinates( oppositeDir, current.row, current.column, neighborRow, neighborColumn, height, width ) )
106 {
107 const qgssize neighborIdx = static_cast<qgssize>( neighborRow ) * width + neighborColumn;
108 if ( d8Directions[neighborIdx] == current.dir )
109 {
110 const int16_t neighborOrder = outOrder[neighborIdx];
111 if ( neighborOrder < 1 )
112 {
113 // neighbour has not been processed yet!
114 stack.push_back( { neighborColumn, neighborRow, 0, 0, 1 } );
115 pushedChild = true;
116 break;
117 }
118 else
119 {
120 if ( current.maxOrder < neighborOrder )
121 {
122 current.maxOrder = neighborOrder;
123 current.maxOrderCount = 1;
124 }
125 else if ( current.maxOrder == neighborOrder )
126 {
127 current.maxOrderCount++;
128 }
129 }
130 }
131 }
132 current.dir++;
133 }
134
135 if ( !pushedChild )
136 {
137 int finalOrder = current.maxOrder;
138 if ( current.maxOrderCount > 1 )
139 {
140 finalOrder++;
141 }
142 outOrder[currentIdx] = static_cast<int16_t>( finalOrder );
143 stack.pop_back();
144 }
145 }
146 }
147 }
148
149 if ( threshold > 1 )
150 {
151 const int shift = 1 - threshold;
152 for ( std::size_t i = 0; i < totalCells; ++i )
153 {
154 if ( outOrder[i] >= threshold )
155 {
156 outOrder[i] += static_cast<int16_t>( shift );
157 }
158 else
159 {
160 outOrder[i] = outputNoData;
161 }
162 }
163 }
164 else
165 {
166 for ( std::size_t i = 0; i < totalCells; ++i )
167 {
168 if ( outOrder[i] < 1 )
169 {
170 outOrder[i] = outputNoData;
171 }
172 }
173 }
174}
175
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.
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition qgsfeedback.h:56
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition qgsfeedback.h:65
Base class for providing feedback from a processing algorithm.
Raster data container.
bool isNoData(int row, int column) const
Checks if value at position is no data.
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...
Definition qgis.h:8310