1
+ #ifndef _richdem_catchment_delineation_generic_hpp_
2
+ #define _richdem_catchment_delineation_generic_hpp_
3
+
4
+ #include < richdem/common/Array2D.hpp>
5
+ #include < richdem/common/Array3D.hpp>
6
+ #include < richdem/common/logger.hpp>
7
+ #include < richdem/common/ProgressBar.hpp>
8
+ #include < queue>
9
+
10
+ namespace richdem {
11
+
12
+ /* *
13
+ * @brief Add all non-nodata cells to the return queue and sets the
14
+ * ``upslope_cells`` value to 2 there.
15
+ *
16
+ * @tparam T upslope cells dtype
17
+ * @tparam U mask dtype
18
+ * @param[in] mask The mask
19
+ * @param[out] upslope_cells grid for indicating upslope cells
20
+ * @return std::queue<GridCell>
21
+ */
22
+ template <class T , class U >
23
+ std::queue<GridCell> queue_from_mask (
24
+ const Array2D<U> &mask,
25
+ Array2D<T> &upslope_cells
26
+ ){
27
+ std::queue<GridCell> expansion;
28
+ // this cannot be parallelized, because it appends everything to the same queue
29
+ for (auto x=0 ;x<mask.width ();x++){
30
+ for (auto y=0 ;y<mask.height ();y++){
31
+ if (mask (x,y)!=mask.noData ()){
32
+ upslope_cells (x,y)=2 ;
33
+ expansion.emplace (x,y);
34
+ }
35
+ }
36
+ }
37
+
38
+ return expansion;
39
+ }
40
+
41
+ /* *
42
+ * @brief Draws a line between the points (x0,y0) and (x1,y1). Adds visited
43
+ * cells to the return queue and sets them to 2 in ``upslope_cells``.
44
+ *
45
+ * @tparam T upslope cells dtype
46
+ * @param[in] x0 x coordinate of first point
47
+ * @param[in] y0 y coordinate of first point
48
+ * @param[in] x1 x coordinate of second point
49
+ * @param[in] y1 y coordinate of second point
50
+ * @param[out] upslope_cells grid for indicating upslope cells
51
+ * @return std::queue<GridCell> A queue with gridcells that were visited
52
+ */
53
+ template <class T >
54
+ std::queue<GridCell> queue_from_linepoints (
55
+ int x0,
56
+ int y0,
57
+ int x1,
58
+ int y1,
59
+ Array2D<T> &upslope_cells
60
+ ){
61
+ std::queue<GridCell> expansion;
62
+
63
+ // if the slope>1, swap x and y coordinates.
64
+ // It works exatly the same, but points
65
+ // are drawn with swapped coordinates
66
+ bool swapxy = false ;
67
+ if (std::abs (float (y0-y1)/float (x0-x1))>1 ){
68
+ std::cout << " swapped x and y" << std::endl;
69
+ std::swap (x0,y0);
70
+ std::swap (x1,y1);
71
+ swapxy= true ;
72
+ }
73
+
74
+ if (x0>x1){
75
+ std::swap (x0,x1);
76
+ std::swap (y0,y1);
77
+ }
78
+
79
+ // modified Bresenham Line-Drawing Algorithm from
80
+ // https://www.geeksforgeeks.org/bresenhams-line-generation-algorithm/
81
+ int deltaerr = 2 *(y1-y0);
82
+ int error = deltaerr - (x1-x0);
83
+
84
+ RDLOG_MISC<<" Line slope is " <<deltaerr;
85
+ int y=y0;
86
+ for (int x=x0;x<=x1;x++){
87
+ if (!swapxy){
88
+ expansion.emplace (x,y);
89
+ upslope_cells (x,y)=2 ;
90
+ } else {
91
+ expansion.emplace (y,x);
92
+ upslope_cells (y,x)=2 ;
93
+ }
94
+ error += deltaerr;
95
+ if (error>=0 && x!=x1) { // safeguard for segfault if we draw to the edge of the grid
96
+ // Draw the point above if we move to te next pixel
97
+ // the difference between a "solid" and non-solid line:
98
+ // o o X x x <--the X
99
+ // x x x 0 0
100
+ if (!swapxy){
101
+ expansion.emplace (x+1 ,y);
102
+ upslope_cells (x+1 ,y) = 2 ;
103
+ } else {
104
+ expansion.emplace (y,x+1 );
105
+ upslope_cells (y,x+1 ) = 2 ;
106
+ }
107
+ y++;
108
+ error -= 2 *(x1-x0);
109
+ }
110
+ }
111
+ return expansion;
112
+ }
113
+
114
+ // upslope_from_props
115
+ /* *
116
+ * @brief Calculates uplsope cells for a given set of input cells, given a
117
+ * proportions matrix of flow. All cells that have flow into input cells will be added
118
+ *
119
+ * @param[in] &expansion queue with starting cells
120
+ * @param[in] &elevation DEM
121
+ * @param[out] &upslope_cells A grid of 1/2/NoData
122
+ */
123
+ template <Topology topo, class T , class U >
124
+ void upslope_cells_props (
125
+ std::queue<GridCell> &expansion,
126
+ const Array3D<T> &props,
127
+ Array2D<U> &upslope_cells
128
+ ){
129
+ // TODO: ALG NAME?
130
+ RDLOG_PROGRESS<<" Setting up the upslope_cells matrix..." <<std::flush;
131
+ // upslope_cells.resize(props.width(),props.height());
132
+ // upslope_cells.setAll(0);
133
+ // upslope_cells.setNoData(0);
134
+
135
+ static_assert (topo==Topology::D8 || topo==Topology::D4);
136
+ constexpr auto dx = get_dx_for_topology<topo>();
137
+ constexpr auto dy = get_dy_for_topology<topo>();
138
+ constexpr auto nmax = get_nmax_for_topology<topo>();
139
+
140
+ ProgressBar progress;
141
+
142
+ progress.start (props.size ());
143
+ long int ccount=0 ;
144
+ while (expansion.size ()>0 ){
145
+ GridCell c=expansion.front ();
146
+ expansion.pop ();
147
+
148
+ progress.update (ccount++);
149
+
150
+ for (int n=1 ;n<=8 ;n++)
151
+ if (!props.inGrid (c.x +dx[n],c.y +dy[n]))
152
+ continue ;
153
+ else if (upslope_cells.isNoData (c.x +dx[n],c.y +dy[n]) && props (c.x +dx[n],c.y +dy[n],d8_inverse[n])>0 ) {
154
+ expansion.emplace (c.x +dx[n],c.y +dy[n]);
155
+ upslope_cells (c.x +dx[n],c.y +dy[n])=1 ;
156
+ }
157
+ }
158
+ RDLOG_TIME_USE<<" Succeeded in " <<progress.stop ();
159
+ RDLOG_MISC<<" Found " <<ccount<<" up-slope cells." ; // TODO
160
+ }
161
+
162
+ // upslope_cells multiple flow implementation
163
+ /* *
164
+ * @brief Calculates uplsope cells for a given set of input cells, assuming
165
+ * multiple flow. That is, all cells that are higher than the cell being
166
+ * processed will be added, regardless of whether the current cell is the lowest
167
+ * neighbour.
168
+ *
169
+ * @param[in] &expansion queue with starting cells
170
+ * @param[in] &elevation DEM
171
+ * @param[out] &upslope_cells A grid of 1/2/NoData
172
+ */
173
+ template <Topology topo, class T , class U >
174
+ void upslope_cells_mflow (
175
+ std::queue<GridCell> &expansion,
176
+ const Array2D<T> &elevation,
177
+ Array2D<U> &upslope_cells
178
+ ){
179
+ // TODO: ALG NAME?
180
+ RDLOG_PROGRESS<<" Setting up the upslope_cells matrix..." <<std::flush;
181
+ // upslope_cells.resize(elevation);
182
+ // upslope_cells.setAll(0);
183
+ // upslope_cells.setNoData(0);
184
+
185
+ static_assert (topo==Topology::D8 || topo==Topology::D4);
186
+ constexpr auto dx = get_dx_for_topology<topo>();
187
+ constexpr auto dy = get_dy_for_topology<topo>();
188
+ constexpr auto nmax = get_nmax_for_topology<topo>();
189
+
190
+ ProgressBar progress;
191
+
192
+ progress.start (elevation.size ());
193
+ long int ccount=0 ;
194
+ while (expansion.size ()>0 ){
195
+ GridCell c=expansion.front ();
196
+ expansion.pop ();
197
+
198
+ progress.update (ccount++);
199
+
200
+ for (int n=1 ;n<=8 ;n++)
201
+ if (!elevation.inGrid (c.x +dx[n],c.y +dy[n]))
202
+ continue ;
203
+ else if (elevation.isNoData (c.x +dx[n],c.y +dy[n]))
204
+ continue ;
205
+ else if (upslope_cells.isNoData (c.x +dx[n],c.y +dy[n]) && elevation (c.x ,c.y )<elevation (c.x +dx[n],c.y +dy[n])) {
206
+ expansion.emplace (c.x +dx[n],c.y +dy[n]);
207
+ upslope_cells (c.x +dx[n],c.y +dy[n])=1 ;
208
+ }
209
+ }
210
+ RDLOG_TIME_USE<<" Succeeded in " <<progress.stop ();
211
+ RDLOG_MISC<<" Found " <<ccount<<" up-slope cells." ; // TODO
212
+ }
213
+
214
+ }
215
+ #endif
0 commit comments