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