Skip to content

Commit b02fcd6

Browse files
author
Joeperdefloep
committed
Added upslope cell finding
1 parent 4dcf431 commit b02fcd6

File tree

14 files changed

+2426
-3
lines changed

14 files changed

+2426
-3
lines changed

include/richdem/common/grid_cell.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ struct GridCell {
2121
/// Initiate the grid cell without coordinates; should generally be avoided
2222
GridCell() = default;
2323
/// Initiate the grid cell to the coordinates (x0,y0)
24-
GridCell(int x0, int y0):x(x0),y(y0){}
24+
GridCell(int x, int y):x(x),y(y){}
25+
bool operator == (const GridCell &a) const {return x == a.x && y == a.y;}
2526
};
2627

2728

include/richdem/flowmet/OCallaghan1984.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ void FM_OCallaghan(
6969

7070
props(x,y,0) = HAS_FLOW_GEN;
7171

72-
assert(elevations(ci)>=elevations(ci+elevations.nshift(lowest_n))); //Ensure flow goes downhill
72+
// assert(elevations(ci)>=elevations(ci+elevations.nshift(lowest_n))); //Ensure flow goes downhill
7373

7474
props(x,y,lowest_n) = 1;
7575
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#ifndef _richdem_catchment_delineation_hpp_
2+
#define _richdem_catchment_delineation_hpp_
3+
4+
#include <richdem/common/Array2D.hpp>
5+
#include <richdem/common/Array3D.hpp>
6+
#include <richdem/methods/upslope_cells_functions.hpp>
7+
8+
namespace richdem {
9+
10+
template<class T, class U>
11+
void init(
12+
Array2D<T> &to_init,
13+
const Array2D<U> &example,
14+
const int &val
15+
){
16+
to_init.resize(example);
17+
to_init.setAll(val);
18+
to_init.setNoData(val);
19+
}
20+
21+
22+
// TODO: do we have to resize and initialize the results array?
23+
template<class mask_t, class result_t> void UC_mask_props(const Array2D<mask_t> &mask, const Array3D<float> &props, Array2D<result_t> &upslope){init(upslope,mask,0); std::queue<GridCell> expansion = queue_from_mask(mask,upslope) ; upslope_cells_props<Topology::D8>(expansion, props, upslope);}
24+
template<class mask_t, class elev_t, class result_t> void UC_mask_mflow(const Array2D<mask_t> &mask, const Array2D<elev_t> &elev, Array2D<result_t> &upslope){init(upslope,elev,0); std::queue<GridCell> expansion = queue_from_mask(mask,upslope) ; upslope_cells_mflow<Topology::D8>(expansion, elev, upslope);}
25+
template< class result_t> void UC_line_props(int x0, int y0, int x1, int y1, const Array3D<float> &props, Array2D<result_t> &upslope){init(upslope,props,0); std::queue<GridCell> expansion = queue_from_linepoints(x0,y0,x1,y1,upslope); upslope_cells_props<Topology::D8>(expansion, props, upslope);}
26+
template< class elev_t, class result_t> void UC_line_mflow(int x0, int y0, int x1, int y1, const Array2D<elev_t> &elev, Array2D<result_t> &upslope){init(upslope,elev,0); std::queue<GridCell> expansion = queue_from_linepoints(x0,y0,x1,y1,upslope); upslope_cells_mflow<Topology::D8>(expansion, elev, upslope);}
27+
28+
}
29+
#endif
Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
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

Comments
 (0)