Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added catchment delineation functions and exposed to Python #53

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/richdem/common/grid_cell.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ struct GridCell {
GridCell() = default;
/// Initiate the grid cell to the coordinates (x0,y0)
GridCell(int x0, int y0):x(x0),y(y0){}
bool operator == (const GridCell &a) const {return x == a.x && y == a.y;}
};


Expand Down
29 changes: 29 additions & 0 deletions include/richdem/methods/upslope_cells.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#ifndef _richdem_upslope_cells_hpp_
#define _richdem_upslope_cells_hpp_

#include <richdem/common/Array2D.hpp>
#include <richdem/common/Array3D.hpp>
#include <richdem/methods/upslope_cells_functions.hpp>

namespace richdem {

template<class T, class U>
void init(
Array2D<T> &to_init,
const Array2D<U> &example,
const int &val
){
to_init.resize(example);
to_init.setAll(val);
to_init.setNoData(val);
}


// TODO: do we have to resize and initialize the results array?
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);}
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);}
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);}
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);}

}
#endif //_richdem_upslope_cells_
215 changes: 215 additions & 0 deletions include/richdem/methods/upslope_cells_functions.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
#ifndef _richdem_upslope_cells_functions_hpp_
#define _richdem_upslope_cells_functions_hpp_

#include <richdem/common/Array2D.hpp>
#include <richdem/common/Array3D.hpp>
#include <richdem/common/logger.hpp>
#include <richdem/common/ProgressBar.hpp>
#include <queue>

namespace richdem {

/**
* @brief Add all non-nodata cells to the return queue and sets the
* ``upslope_cells`` value to 2 there.
*
* @tparam T upslope cells dtype
* @tparam U mask dtype
* @param[in] mask The mask
* @param[out] upslope_cells grid for indicating upslope cells
* @return std::queue<GridCell>
*/
template<class T, class U>
std::queue<GridCell> queue_from_mask(
const Array2D<U> &mask,
Array2D<T> &upslope_cells
){
std::queue<GridCell> expansion;
// this cannot be parallelized, because it appends everything to the same queue
for (auto x=0;x<mask.width();x++){
for (auto y=0;y<mask.height();y++){
if(mask(x,y)!=mask.noData()){
upslope_cells(x,y)=2;
expansion.emplace(x,y);
}
}
}

return expansion;
}

/**
* @brief Draws a line between the points (x0,y0) and (x1,y1). Adds visited
* cells to the return queue and sets them to 2 in ``upslope_cells``.
*
* @tparam T upslope cells dtype
* @param[in] x0 x coordinate of first point
* @param[in] y0 y coordinate of first point
* @param[in] x1 x coordinate of second point
* @param[in] y1 y coordinate of second point
* @param[out] upslope_cells grid for indicating upslope cells
* @return std::queue<GridCell> A queue with gridcells that were visited
*/
template<class T>
std::queue<GridCell> queue_from_linepoints(
int x0,
int y0,
int x1,
int y1,
Array2D<T> &upslope_cells
){
std::queue<GridCell> expansion;

// if the slope>1, swap x and y coordinates.
// It works exatly the same, but points
// are drawn with swapped coordinates
bool swapxy = false;
if(std::abs(float(y0-y1)/float(x0-x1))>1){
std::cout << "swapped x and y" << std::endl;
std::swap(x0,y0);
std::swap(x1,y1);
swapxy= true;
}

if(x0>x1){
std::swap(x0,x1);
std::swap(y0,y1);
}

// modified Bresenham Line-Drawing Algorithm from
// https://www.geeksforgeeks.org/bresenhams-line-generation-algorithm/
int deltaerr = 2*(y1-y0);
int error = deltaerr - (x1-x0);

RDLOG_MISC<<"Line slope is "<<deltaerr;
int y=y0;
for(int x=x0;x<=x1;x++){
if (!swapxy){
expansion.emplace(x,y);
upslope_cells(x,y)=2;
} else {
expansion.emplace(y,x);
upslope_cells(y,x)=2;
}
error += deltaerr;
if (error>=0 && x!=x1) { //safeguard for segfault if we draw to the edge of the grid
// Draw the point above if we move to te next pixel
// the difference between a "solid" and non-solid line:
// o o X x x <--the X
// x x x 0 0
if(!swapxy){
expansion.emplace(x+1,y);
upslope_cells(x+1,y) = 2;
} else {
expansion.emplace(y,x+1);
upslope_cells(y,x+1) = 2;
}
y++;
error -= 2*(x1-x0);
}
}
return expansion;
}

//upslope_from_props
/**
* @brief Calculates uplsope cells for a given set of input cells, given a
* proportions matrix of flow. All cells that have flow into input cells will be added
*
* @param[in] &expansion queue with starting cells
* @param[in] &elevation DEM
* @param[out] &upslope_cells A grid of 1/2/NoData
*/
template<Topology topo, class T, class U>
void upslope_cells_props(
std::queue<GridCell> &expansion,
const Array3D<T> &props,
Array2D<U> &upslope_cells
){
//TODO: ALG NAME?
RDLOG_PROGRESS<<"Setting up the upslope_cells matrix..."<<std::flush;
// upslope_cells.resize(props.width(),props.height());
// upslope_cells.setAll(0);
// upslope_cells.setNoData(0);

static_assert(topo==Topology::D8 || topo==Topology::D4);
constexpr auto dx = get_dx_for_topology<topo>();
constexpr auto dy = get_dy_for_topology<topo>();
constexpr auto nmax = get_nmax_for_topology<topo>();

ProgressBar progress;

progress.start(props.size());
long int ccount=0;
while(expansion.size()>0){
GridCell c=expansion.front();
expansion.pop();

progress.update(ccount++);

for(int n=1;n<=8;n++)
if(!props.inGrid(c.x+dx[n],c.y+dy[n]))
continue;
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) {
expansion.emplace(c.x+dx[n],c.y+dy[n]);
upslope_cells(c.x+dx[n],c.y+dy[n])=1;
}
}
RDLOG_TIME_USE<<"Succeeded in "<<progress.stop();
RDLOG_MISC<<"Found "<<ccount<<" up-slope cells."; //TODO
}

//upslope_cells multiple flow implementation
/**
* @brief Calculates uplsope cells for a given set of input cells, assuming
* multiple flow. That is, all cells that are higher than the cell being
* processed will be added, regardless of whether the current cell is the lowest
* neighbour.
*
* @param[in] &expansion queue with starting cells
* @param[in] &elevation DEM
* @param[out] &upslope_cells A grid of 1/2/NoData
*/
template<Topology topo, class T, class U>
void upslope_cells_mflow(
std::queue<GridCell> &expansion,
const Array2D<T> &elevation,
Array2D<U> &upslope_cells
){
//TODO: ALG NAME?
RDLOG_PROGRESS<<"Setting up the upslope_cells matrix..."<<std::flush;
// upslope_cells.resize(elevation);
// upslope_cells.setAll(0);
// upslope_cells.setNoData(0);

static_assert(topo==Topology::D8 || topo==Topology::D4);
constexpr auto dx = get_dx_for_topology<topo>();
constexpr auto dy = get_dy_for_topology<topo>();
constexpr auto nmax = get_nmax_for_topology<topo>();

ProgressBar progress;

progress.start(elevation.size());
long int ccount=0;
while(expansion.size()>0){
GridCell c=expansion.front();
expansion.pop();

progress.update(ccount++);

for(int n=1;n<=8;n++)
if(!elevation.inGrid(c.x+dx[n],c.y+dy[n]))
continue;
else if(elevation.isNoData(c.x+dx[n],c.y+dy[n]))
continue;
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])) {
expansion.emplace(c.x+dx[n],c.y+dy[n]);
upslope_cells(c.x+dx[n],c.y+dy[n])=1;
}
}
RDLOG_TIME_USE<<"Succeeded in "<<progress.stop();
RDLOG_MISC<<"Found "<<ccount<<" up-slope cells."; //TODO
}

}
#endif
Loading