void d8_flow_directions( const Array2D<T> &elevations, Array2D<U> &flowdirs ){ ProgressBar progress; std::cerr<<"A D8 Flow Directions"<<std::endl; std::cerr<<"C TODO"<<std::endl; std::cerr<<"p Setting up the flow directions matrix..."<<std::endl; flowdirs.resize(elevations); flowdirs.setAll(NO_FLOW); flowdirs.setNoData(FLOWDIR_NO_DATA); std::cerr<<"p Calculating D8 flow directions..."<<std::endl; progress.start( elevations.width()*elevations.height() ); #pragma omp parallel for for(int y=0;y<elevations.height();y++){ progress.update( y*elevations.width() ); for(int x=0;x<elevations.width();x++) if(elevations(x,y)==elevations.noData()) flowdirs(x,y) = flowdirs.noData(); else flowdirs(x,y) = d8_FlowDir(elevations,x,y); } std::cerr<<"t Succeeded in = "<<progress.stop()<<" s"<<std::endl; }
void Garbrecht_GradientTowardsLower(const Array2D<T> &elevations, const Array2D<d8_flowdir_t> &flowdirs, garbrecht_flat_type &flats, Array2D<int32_t> &inc1){ int loops = 0; int number_incremented = -1; std::cerr<<"Setting up the inc1 matrix..."<<std::endl; inc1.resize(elevations); inc1.setAll(0); while(number_incremented!=0){ number_incremented=0; for(int i=0;i<(int)flats.size();i++){ bool increment_elevation=true; int x=flats[i].x; int y=flats[i].y; for(int n=1;n<=8;n++){ if( elevations(x+dx[n],y+dy[n])<elevations(x,y) && flowdirs(x+dx[n],y+dy[n])!=NO_FLOW && !flowdirs.isNoData(x+dx[n],y+dy[n]) ){ increment_elevation=false; break; } else if(inc1(x+dx[n],y+dy[n])<loops && elevations(x+dx[n],y+dy[n])==elevations(x,y) ){ increment_elevation=false; break; } } if(increment_elevation){ inc1(x,y)++; number_incremented++; } } loops++; } }
void Garbrecht_GradientAwayFromHigher(const Array2D<T> &elevations, const Array2D<d8_flowdir_t> &flowdirs, garbrecht_flat_type &flats, Array2D<int32_t> &inc2){ int loops = 0; int number_incremented = 0; std::cerr<<"Setting up the inc2 matrix..."<<std::endl; inc2.resize(elevations); inc2.setAll(0); while(number_incremented<(int)flats.size()){ for(int i=0;i<(int)flats.size();i++){ int x=flats[i].x; int y=flats[i].y; if(inc2(x,y)>0){ inc2(x,y)++; continue; } } for(int i=0;i<(int)flats.size();i++){ bool has_higher=false,has_lower=false; int x=flats[i].x; int y=flats[i].y; if(inc2(x,y)>0) continue; for(int n=1;n<=8;n++){ if( !has_higher && (elevations(x+dx[n],y+dy[n])>elevations(x,y) || inc2(x+dx[n],y+dy[n])==2) ) has_higher=true; else if( !has_lower && elevations(x+dx[n],y+dy[n])<elevations(x,y) ) has_lower=true; } if(has_higher && !has_lower){ inc2(x,y)++; number_incremented++; } } loops++; } }
void dinf_flow_directions(const Array2D<T> &elevations, Array2D<float> &flowdirs){ ProgressBar progress; std::cerr<<"\nA Dinf Flow Directions"<<std::endl; std::cerr<<"C Tarboton, D.G. 1997. A new method for the determination of flow directions and upslope areas in grid digital elevation models. Water Resources Research. Vol. 33. pp 309-319."<<std::endl; std::cerr<<"p Setting up the Dinf flow directions matrix..."<<std::endl; flowdirs.resize(elevations); flowdirs.setNoData(dinf_NO_DATA); flowdirs.setAll(NO_FLOW); std::cerr<<"p Calculating Dinf flow directions..."<<std::endl; progress.start( elevations.size() ); #pragma omp parallel for for(int y=0;y<elevations.height();y++){ progress.update( y*elevations.width() ); for(int x=0;x<elevations.width();x++) if(elevations(x,y)==elevations.noData()) flowdirs(x,y) = flowdirs.noData(); else flowdirs(x,y) = dinf_FlowDir(elevations,x,y); } std::cerr<<"t Succeeded in = "<<progress.stop()<<" s"<<std::endl; }
void Zhou2015Labels( Array2D<elev_t> &dem, Array2D<label_t> &labels, std::vector<std::map<label_t, elev_t> > &my_graph, uint8_t edge, bool flipH, bool flipV ){ std::queue<GridCellZ<elev_t> > traceQueue; std::queue<GridCellZ<elev_t> > depressionQue; label_t current_label = 2; labels.setAll(0); GridCellZ_pq<elev_t> priorityQueue; for(int32_t x=0;x<dem.width();x++){ const int height = dem.height()-1; priorityQueue.emplace(x,0, dem(x,0 )); priorityQueue.emplace(x,height,dem(x,height)); } for(int32_t y=1;y<dem.height()-1;y++){ const int width = dem.width()-1; priorityQueue.emplace(0, y,dem(0, y)); priorityQueue.emplace(width,y,dem(width,y)); } while (!priorityQueue.empty()){ GridCellZ<elev_t> c = priorityQueue.top(); priorityQueue.pop(); auto my_label = labels(c.x,c.y) = GetNewLabelZhou(c.x,c.y,current_label,edge,dem,labels); for(int n=1;n<=8;n++){ int nx = c.x+dx[n]; int ny = c.y+dy[n]; if (!dem.inGrid(nx,ny)) continue; WatershedsMeet(my_label,labels(nx,ny),dem(c.x,c.y),dem(nx,ny),my_graph); if(labels(nx,ny)!=0) continue; labels(nx,ny) = labels(c.x,c.y); if(dem(nx,ny)<=c.z){ //Depression cell dem(nx,ny) = c.z; depressionQue.emplace(nx,ny,c.z); ProcessPit_onepass(dem,labels,depressionQue,traceQueue,priorityQueue,my_graph); } else { //Slope cell traceQueue.emplace(nx,ny,dem(nx,ny)); } ProcessTraceQue_onepass(dem,labels,traceQueue,priorityQueue,my_graph); } } //Connect the DEM's outside edges to Special Watershed 1. This requires //knowing whether the tile has been flipped toe snure that we connect the //correct edges. if( ((edge & GRID_TOP) && !flipV) || ((edge & GRID_BOTTOM) && flipV) ) for(int32_t x=0;x<labels.width();x++) WatershedsMeet(labels(x,0),(label_t)1,dem(x,0),dem(x,0),my_graph); if( ((edge & GRID_BOTTOM) && !flipV) || ((edge & GRID_TOP) && flipV) ){ int bottom_row = labels.height()-1; for(int32_t x=0;x<labels.width();x++) WatershedsMeet(labels(x,bottom_row),(label_t)1,dem(x,bottom_row),dem(x,bottom_row),my_graph); } if( ((edge & GRID_LEFT) && !flipH) || ((edge & GRID_RIGHT) && flipH) ) for(int32_t y=0;y<labels.height();y++) WatershedsMeet(labels(0,y),(label_t)1,dem(0,y),dem(0,y),my_graph); if( ((edge & GRID_RIGHT) && !flipH) || ((edge & GRID_LEFT) && flipH) ){ int right_col = labels.width()-1; for(int32_t y=0;y<labels.height();y++) WatershedsMeet(labels(right_col,y),(label_t)1,dem(right_col,y),dem(right_col,y),my_graph); } my_graph.resize(current_label); }
void dinf_upslope_area( const Array2D<T> &flowdirs, Array2D<U> &area ){ Array2D<int8_t> dependency; std::queue<GridCell> sources; ProgressBar progress; std::cerr<<"\nA D-infinity Upslope Area"<<std::endl; std::cerr<<"C Tarboton, D.G. 1997. A new method for the determination of flow directions and upslope areas in grid digital elevation models. Water Resources Research. Vol. 33. pp 309-319."<<std::endl; std::cerr<<"p Setting up the dependency matrix..."<<std::endl; dependency.resize(flowdirs); dependency.setAll(0); std::cerr<<"p Setting up the area matrix..."<<std::endl; area.resize(flowdirs); area.setAll(0); area.setNoData(dinf_NO_DATA); bool has_cells_without_flow_directions=false; std::cerr<<"p Calculating dependency matrix & setting noData() cells..."<<std::endl; progress.start( flowdirs.size() ); /////////////////////// //Calculate the number of "dependencies" each cell has. That is, count the //number of cells which flow into each cell. #pragma omp parallel for reduction(|:has_cells_without_flow_directions) for(int y=0;y<flowdirs.height();y++){ progress.update( y*flowdirs.width() ); for(int x=0;x<flowdirs.width();x++){ //If the flow direction of the cell is NoData, mark its area as NoData if(flowdirs.isNoData(x,y)){ area(x,y) = area.noData(); dependency(x,y) = 9; //TODO: This is an unnecessary safety precaution. This prevents the cell from ever being enqueued (an unnecessary safe guard? TODO) continue; //Only necessary if there are bugs below (TODO) } //If the cell has no flow direction, note that so we can warn the user if(flowdirs(x,y)==NO_FLOW){ has_cells_without_flow_directions=true; continue; } //TODO: More explanation of what's going on here int n_high, n_low; int nhx,nhy,nlx,nly; where_do_i_flow(flowdirs(x,y),n_high,n_low); nhx=x+dinf_dx[n_high]; nhy=y+dinf_dy[n_high]; if(n_low!=-1){ nlx = x+dinf_dx[n_low]; nly = y+dinf_dy[n_low]; } if( n_low!=-1 && flowdirs.inGrid(nlx,nly) && flowdirs(nlx,nly)!=flowdirs.noData() ) dependency(nlx,nly)++; if( flowdirs.inGrid(nhx,nhy) && flowdirs(nhx,nhy)!=flowdirs.noData() ) dependency(nhx,nhy)++; } } std::cerr<<"t Succeeded in = "<<progress.stop()<<" s"<<std::endl; if(has_cells_without_flow_directions) std::cerr<<"W \033[91mNot all cells had defined flow directions! This implies that there will be digital dams!\033[39m"<<std::endl; /////////////////////// //Find those cells which have no dependencies. These are the places to start //the flow accumulation calculation. std::cerr<<"p Locating source cells..."<<std::endl; progress.start( flowdirs.size() ); for(int y=0;y<flowdirs.height();y++){ progress.update( y*flowdirs.width() ); for(int x=0;x<flowdirs.width();x++) if(flowdirs(x,y)==flowdirs.noData()) continue; else if(flowdirs(x,y)==NO_FLOW) continue; else if(dependency(x,y)==0) sources.emplace(x,y); } std::cerr<<"t Source cells located in = "<<progress.stop()<<" s"<<std::endl; /////////////////////// //Calculate the flow accumulation by "pouring" a cell's flow accumulation //value into the cells below it, as indicated by the D-infinite flow routing //method. std::cerr<<"p Calculating up-slope areas..."<<std::endl; progress.start( flowdirs.numDataCells() ); long int ccount=0; while(sources.size()>0){ auto c = sources.front(); sources.pop(); progress.update(ccount++); if(flowdirs.isNoData(c.x,c.y)) //TODO: This line shouldn't be necessary since NoData's do not get added below continue; area(c.x,c.y)+=1; if(flowdirs(c.x,c.y)==NO_FLOW) continue; int n_high,n_low,nhx,nhy,nlx,nly; where_do_i_flow(flowdirs(c.x,c.y),n_high,n_low); nhx = c.x+dinf_dx[n_high]; nhy = c.y+dinf_dy[n_high]; float phigh,plow; area_proportion(flowdirs(c.x,c.y), n_high, n_low, phigh, plow); if(flowdirs.inGrid(nhx,nhy) && flowdirs(nhx,nhy)!=flowdirs.noData()) area(nhx,nhy)+=area(c.x,c.y)*phigh; if(n_low!=-1){ nlx = c.x+dinf_dx[n_low]; nly = c.y+dinf_dy[n_low]; if(flowdirs.inGrid(nlx,nly) && flowdirs(nlx,nly)!=flowdirs.noData()){ area(nlx,nly)+=area(c.x,c.y)*plow; if((--dependency(nlx,nly))==0) sources.emplace(nlx,nly); } } if( flowdirs.inGrid(nhx,nhy) && flowdirs(nhx,nhy)!=flowdirs.noData() && (--dependency(nhx,nhy))==0) sources.emplace(nhx,nhy); } std::cerr<<"p Succeeded in = "<<progress.stop()<<" s"<<std::endl; }