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;
}
Ejemplo n.º 4
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);
}
Ejemplo n.º 8
0
//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);
            }
        }
    }
}
Ejemplo n.º 9
0
// 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;
}
Ejemplo n.º 10
0
//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]);
            }
        }
    }
}
Ejemplo n.º 11
0
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;
}
Ejemplo n.º 12
0
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;
}
Ejemplo n.º 13
0
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;
}
Ejemplo n.º 14
0
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
    }
}
Ejemplo n.º 15
0
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;
}