int markPits(T& elevDEM, linearpart<float>& flowDir, std::vector<std::vector<node>>&islands, SparsePartition<short>& inc) { int nx = flowDir.getnx(); int ny = flowDir.getny(); int numPits = 0; //There are pits remaining - set direction to no data for (auto& island : islands) { for (node flat : island) { bool skip = false; for (int k=1; k<=8; k++) { if (dontCross(k, flat.x, flat.y, flowDir)==0) { int jn = flat.y + d2[k]; int in = flat.x + d1[k]; if (!flowDir.hasAccess(in, jn)) continue; auto elevDiff = elevDEM.getData(flat.x, flat.y) - elevDEM.getData(in, jn); float flow = flowDir.getData(in, jn); // Adjacent cell drains and is equal or lower in elevation so this is a low boundary if (elevDiff >= 0 && flow == -1) { skip = true; break; } else if (flow == -1) { // If neighbor is in flat // FIXME: check if this is correct if (inc.getData(in,jn) >= 0){ // && inc.getData(in,jn)<st) { skip = true; break; } } } } // mark pit if (!skip) { numPits++; flowDir.setToNodata(flat.x, flat.y); } } } return numPits; }
void flowTowardsLower(T& elev, linearpart<float>& flowDir, std::vector<std::vector<node>>&islands, SparsePartition<short>& inc) { long nx = flowDir.getnx(); long ny = flowDir.getny(); std::vector<node> lowBoundaries; // Find low boundaries. for(auto& island : islands) { for(node flat : island) { float flatElev = elev.getData(flat.x, flat.y); for (int k = 1; k <= 8; k++) { if (dontCross(k, flat.x, flat.y, flowDir) == 0) { int in = flat.x + d1[k]; int jn = flat.y + d2[k]; if (!flowDir.hasAccess(in, jn)) continue; auto elevDiff = flatElev - elev.getData(in,jn); float flow = flowDir.getData(in, jn); bool edgeDrain = flowDir.isNodata(in, jn); // Adjacent cell drains and is equal or lower in elevation so this is a low boundary if ((elevDiff >= 0 && flow >= 0.0) || edgeDrain) { lowBoundaries.push_back(flat); inc.setData(flat.x, flat.y, -1); // No need to check the other neighbors break; } } } } } size_t numInc = propagateIncrements(flowDir, inc, lowBoundaries); // Not all grid cells were resolved - pits remain // Remaining grid cells are unresolvable pits if (numInc > 0) { markPits(elev, flowDir, islands, inc); } }
//Checks if cells cross int dontCross(int k, int i, int j, linearpart<float>& flowDir) { long in1, jn1, in2, jn2; int n1, c1, n2, c2; switch(k) { case 2: n1=1; c1=4; n2=3; c2=8; break; case 4: n1=3; c1=6; n2=5; c2=2; break; case 6: n1=7; c1=4; n2=5; c2=8; break; case 8: n1=1; c1=6; n2=7; c2=2; break; default: return 0; } in1=i+d1[n1]; jn1=j+d2[n1]; in2=i+d1[n2]; jn2=j+d2[n2]; if (flowDir.getData(in1,jn1) == c1 || flowDir.getData(in2,jn2) == c2) { return 1; } return 0; }
void setFlow2(int i, int j, linearpart<short>& flowDir, T& elev, SparsePartition<int>& inc) { /* This function sets directions based upon secondary elevations for assignment of flow directions across flats according to Garbrecht and Martz scheme. There are two possibilities: A. The neighbor is outside the flat set B. The neighbor is in the flat set. In the case of A the input elevations are used and if a draining neighbor is found it is selected. Case B requires slope to be positive. Remaining flats are removed by iterating this process */ int nx = flowDir.getnx(); int ny = flowDir.getny(); const short order[8]= {1,3,5,7,2,4,6,8}; float slopeMax = 0; for (short k : order) { int in = i+d1[k]; int jn = j+d2[k]; if (!flowDir.hasAccess(in, jn)) continue; if (inc.getData(in, jn) > 0) { // Neighbor is in flat float slope = fact[j][k]*(inc.getData(i, j) - inc.getData(in, jn)); if (slope > slopeMax) { flowDir.setData(i, j, k); slopeMax = slope; } } else { // Neighbor is not in flat auto ed = elev.getData(i, j) - elev.getData(in, jn); if (ed >= 0) { // Found a way out - this is outlet flowDir.setData(i, j, k); break; } } } }
void flowFromHigher(T& elev, linearpart<float>& flowDir, std::vector<std::vector<node>>&islands, SparsePartition<short>& inc) { long nx = flowDir.getnx(); long ny = flowDir.getny(); // Find high boundaries for (auto& island : islands) { std::vector<node> highBoundaries; for (node flat : island) { float flatElev = elev.getData(flat.x, flat.y); bool highBoundary = false; for (int k = 1; k <= 8; k++) { if (dontCross(k, flat.x, flat.y, flowDir) == 0) { int in = flat.x + d1[k]; int jn = flat.y + d2[k]; if (!flowDir.hasAccess(in, jn)) continue; auto elevDiff = flatElev - elev.getData(in, jn); if (elevDiff < 0) { // Adjacent cell has higher elevation so this is a high boundary highBoundary = true; break; } } } if (highBoundary) { inc.setData(flat.x, flat.y, -1); highBoundaries.push_back(flat); } } propagateIncrements(flowDir, inc, highBoundaries); } }
size_t propagateIncrements(linearpart<float>& flowDir, SparsePartition<short>& inc, std::vector<node>& queue) { size_t numInc = 0; int st = 1; std::vector<node> newFlats; while (!queue.empty()) { for(node flat : queue) { // Duplicate. already set if (inc.getData(flat.x, flat.y) > 0) continue; for (int k = 1; k <= 8; k++) { if (dontCross(k, flat.x, flat.y, flowDir) == 0) { int in = flat.x + d1[k]; int jn = flat.y + d2[k]; if (!flowDir.isInPartition(in, jn)) continue; float flow = flowDir.getData(in, jn); if (flow == -1 && inc.getData(in, jn) == 0) { newFlats.push_back(node(in, jn)); inc.setData(in, jn, -1); } } } numInc++; inc.setData(flat.x, flat.y, st); } queue.clear(); queue.swap(newFlats); st++; } return numInc; }
void SET2(int I, int J, float *DXX, float DD, linearpart<float>& elevDEM, linearpart<float>& flowDir, linearpart<float>& slope) { double dxA = elevDEM.getdxA(); double dyA = elevDEM.getdyA(); float SK[9]; float ANGLE[9]; float SMAX; float tempFloat; int K; int KD; int ID1[] = {0, 1, 2, 2, 1, 1, 2, 2, 1}; int ID2[] = {0, 2, 1, 1, 2, 2, 1, 1, 2}; int I1[] = {0, 0, -1, -1, 0, 0, 1, 1, 0}; int I2[] = {0, -1, -1, -1, -1, 1, 1, 1, 1}; int J1[] = {0, 1, 0, 0, -1, -1, 0, 0, 1}; int J2[] = {0, 1, 1, -1, -1, -1, -1, 1, 1}; float ANGC[] = {0, 0., 1., 1., 2., 2., 3., 3., 4.}; float ANGF[] = {0, 1., -1., 1., -1., 1., -1., 1., -1.}; for (K = 1; K <= 8; K++) { VSLOPE( elevDEM.getData(J, I, tempFloat), //felevg.d[J][I], elevDEM.getData(J + J1[K], I + I1[K], tempFloat), //[felevg.d[J+J1[K]][I+I1[K]], elevDEM.getData(J + J2[K], I + I2[K], tempFloat), //felevg.d[J+J2[K]][I+I2[K]], DXX[ID1[K]], DXX[ID2[K]], DD, &SK[K], &ANGLE[K] ); } tempFloat = -1; SMAX = 0.; KD = 0; flowDir.setData(J, I, tempFloat); //USE -1 TO INDICATE DIRECTION NOT YET SET for (K = 1; K <= 8; K++) { if (SK[K] > SMAX) { SMAX = SK[K]; KD = K; } } if (KD > 0) { tempFloat = (float) (ANGC[KD]*(PI / 2) + ANGF[KD] * ANGLE[KD]); flowDir.setData(J, I, tempFloat); //set to angle } slope.setData(J, I, SMAX); }
//Set positive flowdirections of elevDEM void setFlow(int i, int j, linearpart<short>& flowDir, linearpart<float>& elevDEM) { int in,jn; int amax=0; float smax=0; float elev = elevDEM.getData(i, j); // fixme: return instead of checking isNodata for (short k=1; k<=8 && !flowDir.isNodata(i,j); k+=2) { in=i+d1[k]; jn=j+d2[k]; float slope = fact[j][k] * (elev - elevDEM.getData(in,jn)); if (slope > smax) { smax=slope; short dirnb=flowDir.getData(in,jn); if (dirnb > 0 && abs(dirnb-k) == 4) { flowDir.setToNodata(i,j); } else { flowDir.setData(i,j,k); } } } for (short k=2; k<=8 && !flowDir.isNodata(i,j); k+=2) { in=i+d1[k]; jn=j+d2[k]; float slope = fact[j][k] * (elev - elevDEM.getData(in,jn)); if (slope > smax && !cellsCross(k,i,j,flowDir)) { smax = slope; short dirnb = flowDir.getData(in,jn); if (dirnb > 0 && abs(dirnb-k) == 4) { flowDir.setToNodata(i,j); } else { flowDir.setData(i,j,k); } } } }
// Sets only flowDir only where there is a positive slope // Returns number of cells which are flat int setPosDir(linearpart<float>& elevDEM, linearpart<short>& flowDir) { double dxA = elevDEM.getdxA(); double dyA = elevDEM.getdyA(); int nx = elevDEM.getnx(); int ny = elevDEM.getny(); int numFlat = 0; double tempdxc, tempdyc; fact = new double*[ny]; // initialize 2d array by Nazmus 2/16 for(int m = 0; m<ny; m++) fact[m] = new double[9]; for (int m = 0; m<ny; m++) { for (int k = 1; k <= 8; k++) { elevDEM.getdxdyc(m, tempdxc, tempdyc); fact[m][k] = (double) (1./sqrt(d1[k]*d1[k]*tempdxc*tempdxc + d2[k]*d2[k]*tempdyc*tempdyc)); } } for (int j = 0; j < ny; j++) { for (int i=0; i < nx; i++) { //FlowDir is nodata if it is on the border OR elevDEM has no data if (elevDEM.isNodata(i,j) || !elevDEM.hasAccess(i-1,j) || !elevDEM.hasAccess(i+1,j) || !elevDEM.hasAccess(i,j-1) || !elevDEM.hasAccess(i,j+1)) { //do nothing continue; } //Check if cell is "contaminated" (neighbors have no data) // set flowDir to noData if contaminated bool contaminated = false; for (int k=1; k<=8; k++) { int in=i+d1[k]; int jn=j+d2[k]; if (elevDEM.isNodata(in,jn)) { contaminated = true; break; } } if (contaminated) { flowDir.setToNodata(i,j); } else { // If cell is not contaminated, flowDir.setData(i, j, 0); setFlow(i,j, flowDir, elevDEM); if (flowDir.getData(i,j) == 0) { numFlat++; } } } } return numFlat; }
//Calculate the slope information of flowDir to slope void calcSlope(linearpart<short>& flowDir, linearpart<float>& elevDEM, linearpart<float>& slope) { int nx = elevDEM.getnx(); int ny = elevDEM.getny(); for (int j=0; j < ny; j++) { for (int i=0; i < nx; i++) { // If i,j is on the border or flowDir has no data, set slope(i,j) to slopeNoData if (flowDir.isNodata(i,j) || !flowDir.hasAccess(i-1,j) || !flowDir.hasAccess(i+1,j) || !flowDir.hasAccess(i,j-1) || !flowDir.hasAccess(i,j+1)) { slope.setToNodata(i, j); } else { short flowDirection = flowDir.getData(i,j); int in = i + d1[flowDirection]; int jn = j + d2[flowDirection]; float elevDiff = elevDEM.getData(i,j) - elevDEM.getData(in,jn); slope.setData(i,j, elevDiff*fact[j][flowDirection]); } } } }
long resolveFlats_parallel(T& elev, SparsePartition<short>& inc, linearpart<float>& flowDir, std::vector<std::vector<node>>&islands, linearpart<float>& orelevDir) { long nx = flowDir.getnx(); long ny = flowDir.getny(); int rank; MPI_Comm_rank(MCW, &rank); int numFlatsChanged = 0, totalNumFlatsChanged = 0; flowTowardsLower(elev, flowDir, islands, inc); do { inc.share(); numFlatsChanged = propagateBorderIncrements(flowDir, inc); MPI_Allreduce(&numFlatsChanged, &totalNumFlatsChanged, 1, MPI_INT, MPI_SUM, MCW); if (rank == 0) { printf("PRL: Lower gradient processed %d flats this iteration\n", totalNumFlatsChanged); } } while(totalNumFlatsChanged > 0); // Not all grid cells were resolved - pits remain // Remaining grid cells are unresolvable pits markPits(elev, flowDir, islands, inc); // Drain flats away from higher adjacent terrain SparsePartition<short> higherGradient(nx, ny, 0); flowFromHigher(elev, flowDir, islands, higherGradient); do { higherGradient.share(); numFlatsChanged = propagateBorderIncrements(flowDir, higherGradient); MPI_Allreduce(&numFlatsChanged, &totalNumFlatsChanged, 1, MPI_INT, MPI_SUM, MCW); if (rank == 0) { printf("PRL: Higher gradient processed %d flats this iteration\n", totalNumFlatsChanged); } } while(totalNumFlatsChanged > 0); // High flow must be inverted before it is combined // // higherFlowMax has to be greater than all of the increments // higherFlowMax can be maximum value of the data type (e.g. 65535) but it will cause overflow problems if more than one iteration is needed short higherFlowMax = 0; for (auto& island : islands) { for (auto& flat : island) { short val = higherGradient.getData(flat.x, flat.y); if (val > higherFlowMax) higherFlowMax = val; } } // FIXME: Is this needed? would it affect directions at the border? short globalHigherFlowmax = 0; MPI_Allreduce(&higherFlowMax, &globalHigherFlowmax, 1, MPI_SHORT, MPI_MAX, MCW); for (auto& island : islands) { for (auto flat : island) { inc.addToData(flat.x, flat.y, globalHigherFlowmax - higherGradient.getData(flat.x, flat.y)); } } inc.share(); if (rank==0) { fprintf(stderr,"\nPRL: Setting directions\n"); fflush(stderr); } uint64_t localFlatsRemaining = 0, globalFlatsRemaining = 0; double tempdxc, tempdyc; for (auto& island : islands) { for (node flat : island) { //setFlow2(flat.x, flat.y, flowDir, elev, inc); orelevDir.getdxdyc(flat.y, tempdxc, tempdyc); float DXX[3] = {0, tempdxc, tempdyc}; //tardemlib.cpp ln 1291 float DD = sqrt(tempdxc * tempdxc + tempdyc * tempdyc); //tardemlib.cpp ln 1293 SET2(flat.y, flat.x, DXX, DD, elev, inc, flowDir); if (flowDir.getData(flat.x, flat.y) == -1) { localFlatsRemaining++; } } } flowDir.share(); MPI_Allreduce(&localFlatsRemaining, &globalFlatsRemaining, 1, MPI_UINT64_T, MPI_SUM, MCW); auto hasFlowDirection = [&](const node& n) { return flowDir.getData(n.x, n.y) != -1; }; auto isEmpty = [&](const std::vector<node>& i) { return i.empty(); }; // Remove flats which have flow direction set for (auto& island : islands) { island.erase(std::remove_if(island.begin(), island.end(), hasFlowDirection), island.end()); } // Remove empty islands islands.erase(std::remove_if(islands.begin(), islands.end(), isEmpty), islands.end()); return globalFlatsRemaining; }
long resolveFlats(T& elevDEM, SparsePartition<short>& inc, linearpart<float>& flowDir, std::vector<std::vector<node>>&islands, linearpart<float>& orelevDir) { long nx = flowDir.getnx(); long ny = flowDir.getny(); int rank; MPI_Comm_rank(MCW, &rank); if (rank==0) { fprintf(stderr,"Resolving flats\n"); fflush(stderr); } flowTowardsLower(elevDEM, flowDir, islands, inc); // Drain flats away from higher adjacent terrain SparsePartition<short> s(nx, ny, 0); flowFromHigher(elevDEM, flowDir, islands, s); // High flow must be inverted before it is combined // // higherFlowMax has to be greater than all of the increments // higherFlowMax can be maximum value of the data type but it will cause overflow problems if more than one iteration is needed short higherFlowMax = 0; for (auto& island : islands) { for (node flat : island) { short val = s.getData(flat.x, flat.y); if (val > higherFlowMax) higherFlowMax = val; } } for (auto& island : islands) { for (auto flat : island) { inc.addToData(flat.x, flat.y, higherFlowMax - s.getData(flat.x, flat.y)); } } if (rank==0) { fprintf(stderr,"Setting directions\n"); fflush(stderr); } long flatsRemaining = 0; double tempdxc, tempdyc; for (auto& island : islands) { for (node flat : island) { //setFlow2(flat.x, flat.y, flowDir, elevDEM, inc); orelevDir.getdxdyc(flat.y, tempdxc, tempdyc); float DXX[3] = {0, tempdxc, tempdyc}; //tardemlib.cpp ln 1291 float DD = sqrt(tempdxc * tempdxc + tempdyc * tempdyc); //tardemlib.cpp ln 1293 SET2(flat.y, flat.x, DXX, DD, elevDEM, inc, flowDir); if (flowDir.getData(flat.x, flat.y) == -1) { flatsRemaining++; } } } auto hasFlowDirection = [&](const node& n) { return flowDir.getData(n.x, n.y) != -1; }; auto isEmpty = [&](const std::vector<node>& i) { return i.empty(); }; // Remove flats which have flow direction set for (auto& island : islands) { island.erase(std::remove_if(island.begin(), island.end(), hasFlowDirection), island.end()); } // Remove empty islands islands.erase(std::remove_if(islands.begin(), islands.end(), isEmpty), islands.end()); return flatsRemaining; }
long setPosDirDinf(linearpart<float>& elevDEM, linearpart<float>& flowDir, linearpart<float>& slope, int useflowfile) { double dxA = elevDEM.getdxA(); double dyA = elevDEM.getdyA(); long nx = elevDEM.getnx(); long ny = elevDEM.getny(); float tempFloat; double tempdxc, tempdyc; int i, j, k, in, jn, con; long numFlat = 0; tempFloat = 0; for (j = 0; j < ny; j++) { for (i = 0; i < nx; i++) { //FlowDir is nodata if it is on the border OR elevDEM has no data if (elevDEM.isNodata(i, j) || !elevDEM.hasAccess(i - 1, j) || !elevDEM.hasAccess(i + 1, j) || !elevDEM.hasAccess(i, j - 1) || !elevDEM.hasAccess(i, j + 1)) { //do nothing } else { //Check if cell is "contaminated" (neighbors have no data) // set flowDir to noData if contaminated con = 0; for (k = 1; k <= 8 && con != -1; k++) { in = i + d1[k]; jn = j + d2[k]; if (elevDEM.isNodata(in, jn)) con = -1; } if (con == -1) flowDir.setToNodata(i, j); //If cell is not contaminated, else { tempFloat = -1.; flowDir.setData(i, j, tempFloat); //set to -1 elevDEM.getdxdyc(j, tempdxc, tempdyc); float DXX[3] = {0, tempdxc, tempdyc}; //tardemlib.cpp ln 1291 float DD = sqrt(tempdxc * tempdxc + tempdyc * tempdyc); //tardemlib.cpp ln 1293 SET2(j, i, DXX, DD, elevDEM, flowDir, slope); //i=y in function form old code j is x switched on purpose // Use SET2 from serial code here modified to get what it has as felevg.d from elevDEM partition // Modify to return 0 if there is a 0 slope. Modify SET2 to output flowDIR as no data (do nothing // if verified initialization to nodata) and // slope as 0 if a positive slope is not found //setFlow( i,j, flowDir, elevDEM, area, useflowfile); if (flowDir.getData(i, j, tempFloat) == -1) numFlat++; } } } } return numFlat; }
void SET2(int I, int J, float *DXX, float DD, T& elevDEM, SparsePartition<short>& elev2, linearpart<float>& flowDir) { float SK[9]; float ANGLE[9]; float SMAX = 0.0; float tempFloat; short tempShort, tempShort1, tempShort2; int K; int KD = 0; int ID1[] = {0, 1, 2, 2, 1, 1, 2, 2, 1}; int ID2[] = {0, 2, 1, 1, 2, 2, 1, 1, 2}; int I1[] = {0, 0, -1, -1, 0, 0, 1, 1, 0}; int I2[] = {0, -1, -1, -1, -1, 1, 1, 1, 1}; int J1[] = {0, 1, 0, 0, -1, -1, 0, 0, 1}; int J2[] = {0, 1, 1, -1, -1, -1, -1, 1, 1}; float ANGC[] = {0, 0., 1., 1., 2., 2., 3., 3., 4.}; float ANGF[] = {0, 1., -1., 1., -1., 1., -1., 1., -1.}; bool diagOutFound = false; for (K = 1; K <= 8; K++) { tempShort1 = elev2.getData(J + J1[K], I + I1[K]); tempShort2 = elev2.getData(J + J2[K], I + I2[K]); if (tempShort1 <= 0 && tempShort2 <= 0) { //Both E1 and E2 are outside the flat get slope and angle float a = elevDEM.getData(J, I); float b = elevDEM.getData(J + J1[K], I + I1[K]); float c = elevDEM.getData(J + J2[K], I + I2[K]); VSLOPE( a, //E0 b, //E1 c, //E2 DXX[ID1[K]], //dx or dy depending on ID1 DXX[ID2[K]], //dx or dy depending on ID2 DD, //Hypotenuse &SK[K], //Slope Returned &ANGLE[K]//Angle Returned ); if (SK[K] >= 0.0) // Found an outlet { if (b > a) // Outlet found had better be a diagonal, because it is not an edge { if (!diagOutFound) { diagOutFound = true; KD = K; } } else { // Here it is an adjacent outlet KD = K; break; } } } else if (tempShort1 <= 0 && tempShort2 > 0) {//E1 is outside of the flat and E2 is inside the flat. Use DEM elevations. tempShort2/E2 is in the artificial grid float a = elevDEM.getData(J, I); float b = elevDEM.getData(J + J1[K], I + I1[K]); if (a >= b) { ANGLE[K] = 0.0; SK[K] = 0.0; KD = K; break; } short a1 = elev2.getData(J, I); short c1 = elev2.getData(J + J2[K], I + I2[K]); short b1 = max(a1, c1); VSLOPE( (float) a1, //felevg.d[J][I], (float) b1, //[felevg.d[J+J1[K]][I+I1[K]], (float) c1, //felevg.d[J+J2[K]][I+I2[K]], DXX[ID1[K]], //dx or dy DXX[ID2[K]], //dx or dy DD, //Hypotenuse &SK[K], //Slope Returned &ANGLE[K]//Angle Reutnred ); if (SK[K] > SMAX) { SMAX = SK[K]; KD = K; } } else if (tempShort1 > 0 && tempShort2 <= 0) {//E2 is out side of the flat and E1 is inside the flat, use DEM elevations float a = elevDEM.getData(J, I); //float b=elevDEM->getData(J+J1[K],I+I1[K],tempFloat); float c = elevDEM.getData(J + J2[K], I + I2[K]); if (a >= c) { if (!diagOutFound) { ANGLE[K] = (float) atan2(DXX[ID2[K]], DXX[ID1[K]]); SK[K] = 0.0; KD = K; diagOutFound = true; } } else { short a1 = elev2.getData(J, I); short b1 = elev2.getData(J + J1[K], I + I1[K]); short c1 = max(a1, b1); VSLOPE( (float) a1, //felevg.d[J][I], (float) b1, //[felevg.d[J+J1[K]][I+I1[K]], (float) c1, //felevg.d[J+J2[K]][I+I2[K]], DXX[ID1[K]], //dx or dy DXX[ID2[K]], //dx or dy DD, //Hypotenuse &SK[K], //Slope Returned &ANGLE[K]//Angle Reutnred ); if (SK[K] > SMAX) { SMAX = SK[K]; KD = K; } } } else {//Both E1 and E2 are in the flat. Use artificial elevation to get slope and angle short a, b, c; a = elev2.getData(J, I); b = elev2.getData(J + J1[K], I + I1[K]); c = elev2.getData(J + J2[K], I + I2[K]); VSLOPE( (float) a, //felevg.d[J][I], (float) b, //[felevg.d[J+J1[K]][I+I1[K]], (float) c, //felevg.d[J+J2[K]][I+I2[K]], DXX[ID1[K]], //dx or dy DXX[ID2[K]], //dx or dy DD, //Hypotenuse &SK[K], //Slope Returned &ANGLE[K]//Angle Reutnred ); if (SK[K] > SMAX) { SMAX = SK[K]; KD = K; } } } //USE -1 TO INDICATE DIRECTION NOT YET SET, // but only for non pit grid cells. Pits will have flowDir as no data if (!flowDir.isNodata(J, I)) { tempFloat = -1; flowDir.setData(J, I, tempFloat); } if (KD > 0)//We have a flow direction. Calculate the Angle and save/write it. { tempFloat = (float) (ANGC[KD]*(PI / 2) + ANGF[KD] * ANGLE[KD]); //Calculate the Angle if (tempFloat >= 0.0)//Make sure the angle is positive flowDir.setData(J, I, tempFloat); //set the angle in the flowPartition } }
size_t propagateBorderIncrements(linearpart<float>& flowDir, SparsePartition<short>& inc) { int nx = flowDir.getnx(); int ny = flowDir.getny(); struct pnode { int x; int y; int inc; bool operator<(const struct pnode& b) const { return inc < b.inc; } }; std::vector<pnode> queue; // Find the starting nodes at the edge of the raster // // FIXME: oob access for (auto y : {-1, ny}) { for(int x = 0; x < nx; x++) { int st = inc.getData(x, y); if (st == 0) continue; auto jn = y == -1 ? 0 : ny - 1; for (auto in : {x-1, x, x+1}) { if (!flowDir.isInPartition(in, jn)) continue; float flow = flowDir.getData(in, jn); auto neighSt = inc.getData(in, jn); if (flow == -1 && (neighSt == 0 || neighSt > st + 1 || -neighSt > st + 1)) { queue.push_back({in, jn, st + 1}); // Here we set a negative increment if it's still pending // // Another flat might be neighboring the same cell with a lower increment, // which has to override the higher increment (that hasn't been set yet but is in the queue). inc.setData(in, jn, -(st + 1)); } } } } size_t numChanged = 0; // Sort queue by lowest increment std::sort(queue.begin(), queue.end()); std::vector<pnode> newFlats; while (!queue.empty()) { for(pnode flat : queue) { // Skip if the increment was already set and it is lower auto st = inc.getData(flat.x, flat.y); if (st > 0 && st <= flat.inc) { continue; } for (int k = 1; k <= 8; k++) { if (dontCross(k, flat.x, flat.y, flowDir) == 0) { int in = flat.x + d1[k]; int jn = flat.y + d2[k]; if (!flowDir.isInPartition(in, jn)) continue; float flow = flowDir.getData(in, jn); auto neighInc = inc.getData(in, jn); if (flow == -1 && (neighInc == 0 || neighInc > flat.inc + 1 || -neighInc > flat.inc + 1)) { newFlats.push_back({in, jn, flat.inc + 1}); inc.setData(in, jn, -(flat.inc + 1)); } } } inc.setData(flat.x, flat.y, flat.inc); numChanged++; } std::sort(newFlats.begin(), newFlats.end()); queue.clear(); queue.swap(newFlats); } return numChanged; }