int bseg_write_cellfile(BSEG * bseg, char *map_name) { int map_fd; int row, nrows; int col, ncols; CELL *buffer; CELL value; map_fd = G_open_cell_new(map_name); if (map_fd < 0) { G_warning("%s(): unable to open new map layer [%s]", me, map_name); return -1; } nrows = G_window_rows(); ncols = G_window_cols(); buffer = G_allocate_cell_buf(); for (row = 0; row < nrows; row++) { for (col = 0; col < ncols; col++) { bseg_get(bseg, &value, row, col); buffer[col] = value; } if (G_put_raster_row(map_fd, buffer, CELL_TYPE) < 0) { G_free(buffer); G_unopen_cell(map_fd); G_warning("%s(): unable to write new map layer [%s], row %d", me, map_name, row); return -2; } } G_free(buffer); G_close_cell(map_fd); return 0; }
int slope_length(int r, int c, int dr, int dc) { CELL top_alt, bot_alt, ridge; char asp_value; double res, top_ls, bot_ls; WAT_ALT wa; if (sides == 8) { if (r == dr) res = window.ns_res; else if (c == dc) res = window.ew_res; else res = diag; } else { /* sides == 4 */ bseg_get(&asp, &asp_value, dr, dc); if (r == dr) { if (asp_value == 2 || asp_value == 6) res = window.ns_res; else /* asp_value == 4, 8, -2, -4, -6, or -8 */ res = diag; /* how can res be diag with sides == 4??? */ } else { /* c == dc */ if (asp_value == 4 || asp_value == 8) res = window.ew_res; else /* asp_value == 2, 6, -2, -4, -6, or -8 */ res = diag; } } dseg_get(&s_l, &top_ls, r, c); if (top_ls == half_res) top_ls = res; else top_ls += res; dseg_put(&s_l, &top_ls, r, c); seg_get(&watalt, (char *) &wa, r, c); top_alt = wa.ele; seg_get(&watalt, (char *) &wa, dr, dc); bot_alt = wa.ele; if (top_alt > bot_alt) { dseg_get(&s_l, &bot_ls, dr, dc); if (top_ls > bot_ls) { bot_ls = top_ls + res; dseg_put(&s_l, &bot_ls, dr, dc); cseg_get(&r_h, &ridge, r, c); cseg_put(&r_h, &ridge, dr, dc); } } return 0; }
int find_con_slow(int r, int c, double *d1, double *d2, DCELL * con1, DCELL * con2) { int ct, low_ct, node_ct; int rr, cc, dor, doc; double dd, shortest; DCELL value; char mask_value; G_set_d_null_value(con1, 1); G_set_d_null_value(con2, 1); *d1 = *d2 = 1.0; shortest = nrows * ncols; for (rr = minr; rr <= maxr; rr++) { for (cc = minc; cc <= maxc; cc++) { /* FLAG_UNSET (seen, rr, cc); */ bseg_put(&bseen, &off, rr, cc); } } minr = nrows; minc = ncols; maxr = maxc = -1; /* set_seen_slow (r,c); */ bseg_put(&bseen, &on, r, c); if (r < minr) minr = r; if (r > maxr) maxr = r; if (c < minc) minc = c; if (c > maxc) maxc = c; node_ct = 0; zero = addpts_slow(zero, r, c, r, c, &node_ct); low_ct = 0; while (1) { ct = low_ct++; if (node_ct <= ct) return 1; rr = zero[ct].r; cc = zero[ct].c; dor = ABS(rr - r); doc = ABS(cc - c); bseg_get(&bmask, &mask_value, rr, cc); if (!mask_value && rr >= 0 && cc >= 0 && rr < nrows && cc < ncols && zero[ct].d < shortest) { dseg_get(&con, rr, cc, &value); if (G_is_d_null_value(&value)) zero = addpts_slow(zero, r, c, rr, cc, &node_ct); else if (G_is_d_null_value(con1)) { *con1 = value; *d1 = MIN(dor, doc) * 1.414 + ABS(dor - doc); shortest = *d1 * 2.0 * i_val_l_f; } else if (*con1 == value) { dd = MIN(dor, doc) * 1.414 + ABS(dor - doc); if (dd < *d1) { *d1 = dd; shortest = dd * 2.0 * i_val_l_f; } } else if (G_is_d_null_value(con2)) { *con2 = value; *d2 = MIN(dor, doc) * 1.414 + ABS(dor - doc); shortest = *d2; } else { dd = MIN(dor, doc) * 1.414 + ABS(dor - doc); shortest = MIN(shortest, dd); } } } }
int do_cum(void) { int r, c, dr, dc; char asp_val, asp_val_down; char is_swale, this_flag_value, flag_value; DCELL value, valued; POINT point; int killer, threshold; int asp_r[9] = { 0, -1, -1, -1, 0, 1, 1, 1, 0 }; int asp_c[9] = { 0, 1, 0, -1, -1, -1, 0, 1, 1 }; WAT_ALT wa, wadown; G_message(_("SECTION 3: Accumulating Surface Flow with SFD.")); if (bas_thres <= 0) threshold = 60; else threshold = bas_thres; for (killer = 0; killer < do_points; killer++) { G_percent(killer, do_points, 1); seg_get(&astar_pts, (char *)&point, 0, killer); r = point.r; c = point.c; bseg_get(&asp, &asp_val, r, c); if (asp_val) { dr = r + asp_r[ABS(asp_val)]; dc = c + asp_c[ABS(asp_val)]; } /* skip user-defined depressions */ else dr = dc = -1; bseg_get(&bitflags, &this_flag_value, r, c); FLAG_UNSET(this_flag_value, WORKEDFLAG); if (dr >= 0 && dr < nrows && dc >= 0 && dc < ncols) { /* TODO: do not distribute flow along edges, this causes artifacts */ seg_get(&watalt, (char *)&wa, r, c); value = wa.wat; is_swale = FLAG_GET(this_flag_value, SWALEFLAG); if (fabs(value) >= threshold && !is_swale) { is_swale = 1; FLAG_SET(this_flag_value, SWALEFLAG); } seg_get(&watalt, (char *)&wadown, dr, dc); valued = wadown.wat; if (value > 0) { if (valued > 0) valued += value; else valued -= value; } else { if (valued < 0) valued += value; else valued = value - valued; } wadown.wat = valued; seg_put(&watalt, (char *)&wadown, dr, dc); /* update asp for depression */ if (is_swale || fabs(valued) >= threshold) { bseg_get(&bitflags, &flag_value, dr, dc); FLAG_SET(flag_value, SWALEFLAG); bseg_put(&bitflags, &flag_value, dr, dc); is_swale = 1; } else { if (er_flag && !is_swale && !FLAG_GET(this_flag_value, RUSLEBLOCKFLAG)) slope_length(r, c, dr, dc); } } bseg_put(&bitflags, &this_flag_value, r, c); } G_percent(do_points, do_points, 1); /* finish it */ seg_close(&astar_pts); return 0; }
int do_cum_mfd(void) { int r, c, dr, dc; DCELL value, valued, *wat_nbr; POINT point; WAT_ALT wa; int killer, threshold; /* MFD */ int mfd_cells, stream_cells, swale_cells, astar_not_set, is_null; double *dist_to_nbr, *weight, sum_weight, max_weight; int r_nbr, c_nbr, r_max, c_max, ct_dir, np_side, max_side; double dx, dy; CELL ele, *ele_nbr; char asp_val, asp_val_down; double prop, max_acc; int workedon, edge, is_swale, flat; char *flag_nbr, this_flag_value, flag_value; int asp_r[9] = { 0, -1, -1, -1, 0, 1, 1, 1, 0 }; int asp_c[9] = { 0, 1, 0, -1, -1, -1, 0, 1, 1 }; G_message(_("SECTION 3: Accumulating Surface Flow with MFD.")); G_debug(1, "MFD convergence factor set to %d.", c_fac); /* distances to neighbours */ dist_to_nbr = (double *)G_malloc(sides * sizeof(double)); weight = (double *)G_malloc(sides * sizeof(double)); for (ct_dir = 0; ct_dir < sides; ct_dir++) { /* get r, c (r_nbr, c_nbr) for neighbours */ r_nbr = nextdr[ct_dir]; c_nbr = nextdc[ct_dir]; /* account for rare cases when ns_res != ew_res */ dy = ABS(r_nbr) * window.ns_res; dx = ABS(c_nbr) * window.ew_res; if (ct_dir < 4) dist_to_nbr[ct_dir] = dx + dy; else dist_to_nbr[ct_dir] = sqrt(dx * dx + dy * dy); } flag_nbr = (char *)G_malloc(sides * sizeof(char)); wat_nbr = (DCELL *)G_malloc(sides * sizeof(DCELL)); ele_nbr = (CELL *)G_malloc(sides * sizeof(CELL)); workedon = 0; if (bas_thres <= 0) threshold = 60; else threshold = bas_thres; for (killer = 0; killer < do_points; killer++) { G_percent(killer, do_points, 1); seg_get(&astar_pts, (char *)&point, 0, killer); r = point.r; c = point.c; bseg_get(&asp, &asp_val, r, c); if (asp_val) { dr = r + asp_r[ABS(asp_val)]; dc = c + asp_c[ABS(asp_val)]; } /* skip user-defined depressions */ else dr = dc = -1; /* WORKEDFLAG has been set during A* Search * reversed meaning here: 0 = done, 1 = not yet done */ bseg_get(&bitflags, &this_flag_value, r, c); FLAG_UNSET(this_flag_value, WORKEDFLAG); if (dr >= 0 && dr < nrows && dc >= 0 && dc < ncols) { r_max = dr; c_max = dc; seg_get(&watalt, (char *)&wa, r, c); value = wa.wat; /* get weights */ max_weight = 0; sum_weight = 0; np_side = -1; mfd_cells = 0; stream_cells = 0; swale_cells = 0; astar_not_set = 1; ele = wa.ele; is_null = 0; edge = 0; flat = 1; /* this loop is needed to get the sum of weights */ for (ct_dir = 0; ct_dir < sides; ct_dir++) { /* get r, c (r_nbr, c_nbr) for neighbours */ r_nbr = r + nextdr[ct_dir]; c_nbr = c + nextdc[ct_dir]; weight[ct_dir] = -1; wat_nbr[ct_dir] = 0; ele_nbr[ct_dir] = 0; /* check if neighbour is within region */ if (r_nbr >= 0 && r_nbr < nrows && c_nbr >= 0 && c_nbr < ncols) { if (dr == r_nbr && dc == c_nbr) np_side = ct_dir; bseg_get(&bitflags, &flag_nbr[ct_dir], r_nbr, c_nbr); seg_get(&watalt, (char *)&wa, r_nbr, c_nbr); wat_nbr[ct_dir] = wa.wat; ele_nbr[ct_dir] = wa.ele; /* check for swale or stream cells */ is_swale = FLAG_GET(flag_nbr[ct_dir], SWALEFLAG); if (is_swale) swale_cells++; if ((ABS(wat_nbr[ct_dir]) + 0.5) >= threshold && ct_dir != np_side && ele_nbr[ct_dir] > ele) stream_cells++; if (FLAG_GET(flag_nbr[ct_dir], WORKEDFLAG)) { if (ele_nbr[ct_dir] != ele) flat = 0; edge = is_null = FLAG_GET(flag_nbr[ct_dir], NULLFLAG); if (!is_null && ele_nbr[ct_dir] <= ele) { if (ele_nbr[ct_dir] < ele) { weight[ct_dir] = mfd_pow(((ele - ele_nbr[ct_dir]) / dist_to_nbr[ct_dir]), c_fac); } if (ele_nbr[ct_dir] == ele) { weight[ct_dir] = mfd_pow((0.5 / dist_to_nbr[ct_dir]), c_fac); } sum_weight += weight[ct_dir]; mfd_cells++; if (weight[ct_dir] > max_weight) { max_weight = weight[ct_dir]; } if (dr == r_nbr && dc == c_nbr) { astar_not_set = 0; } } } } else edge = 1; if (edge) break; } /* do not continue streams along edges, this causes artifacts */ if (edge) { is_swale = FLAG_GET(this_flag_value, SWALEFLAG); if (is_swale && asp_val > 0) { asp_val = -1 * drain[r - r_nbr + 1][c - c_nbr + 1]; bseg_put(&asp, &asp_val, r, c); } bseg_put(&bitflags, &this_flag_value, r, c); continue; } /* honour A * path * mfd_cells == 0: fine, SFD along A * path * mfd_cells == 1 && astar_not_set == 0: fine, SFD along A * path * mfd_cells > 0 && astar_not_set == 1: A * path not included, add to mfd_cells */ /* MFD, A * path not included, add to mfd_cells */ if (mfd_cells > 0 && astar_not_set == 1) { mfd_cells++; sum_weight += max_weight; weight[np_side] = max_weight; max_side = np_side; } /* set flow accumulation for neighbours */ max_acc = -1; max_side = np_side; if (mfd_cells > 1) { prop = 0.0; for (ct_dir = 0; ct_dir < sides; ct_dir++) { r_nbr = r + nextdr[ct_dir]; c_nbr = c + nextdc[ct_dir]; /* check if neighbour is within region */ if (r_nbr >= 0 && r_nbr < nrows && c_nbr >= 0 && c_nbr < ncols && weight[ct_dir] > -0.5) { if (FLAG_GET(flag_nbr[ct_dir], WORKEDFLAG)) { weight[ct_dir] = weight[ct_dir] / sum_weight; /* check everything adds up to 1.0 */ prop += weight[ct_dir]; if (value > 0) { if (wat_nbr[ct_dir] > 0) wat_nbr[ct_dir] += value * weight[ct_dir]; else wat_nbr[ct_dir] -= value * weight[ct_dir]; } else { if (wat_nbr[ct_dir] < 0) wat_nbr[ct_dir] += value * weight[ct_dir]; else wat_nbr[ct_dir] = value * weight[ct_dir] - wat_nbr[ct_dir]; } valued = wat_nbr[ct_dir]; wa.wat = valued; wa.ele = ele_nbr[ct_dir]; seg_put(&watalt, (char *)&wa, r_nbr, c_nbr); /* get main drainage direction */ if (ABS(wat_nbr[ct_dir]) >= max_acc) { max_acc = ABS(wat_nbr[ct_dir]); r_max = r_nbr; c_max = c_nbr; max_side = ct_dir; } } else if (ct_dir == np_side) { /* check for consistency with A * path */ workedon++; } } } /* adjust main drainage direction to A* path if possible */ /*if (fabs(wat_nbr[np_side]) >= max_acc) { max_acc = fabs(wat_nbr[np_side]); r_max = dr; c_max = dc; } */ if (ABS(prop - 1.0) > 5E-6f) { G_warning(_("MFD: cumulative proportion of flow distribution not 1.0 but %f"), prop); } } /* SFD-like accumulation */ else { valued = wat_nbr[np_side]; if (value > 0) { if (valued > 0) valued += value; else valued -= value; } else { if (valued < 0) valued += value; else valued = value - valued; } wa.wat = valued; wa.ele = ele_nbr[np_side]; seg_put(&watalt, (char *)&wa, dr, dc); } /* update asp */ if (dr != r_max || dc != c_max) { if (asp_val < 0) { asp_val = -1 * drain[r - r_max + 1][c - c_max + 1]; } else asp_val = drain[r - r_max + 1][c - c_max + 1]; bseg_put(&asp, &asp_val, r, c); } is_swale = FLAG_GET(this_flag_value, SWALEFLAG); /* start new stream */ value = ABS(value) + 0.5; if (!is_swale && (int)value >= threshold && stream_cells < 1 && swale_cells < 1 && !flat) { FLAG_SET(this_flag_value, SWALEFLAG); is_swale = 1; } /* continue stream */ if (is_swale) { flag_value = flag_nbr[max_side]; FLAG_SET(flag_value, SWALEFLAG); bseg_put(&bitflags, &flag_value, r_max, c_max); } else { if (er_flag && !is_swale && !FLAG_GET(this_flag_value, RUSLEBLOCKFLAG)) slope_length(r, c, r_max, c_max); } } bseg_put(&bitflags, &this_flag_value, r, c); } G_percent(do_points, do_points, 1); /* finish it */ if (workedon) G_warning(_("MFD: A * path already processed when distributing flow: %d of %d cells"), workedon, do_points); seg_close(&astar_pts); G_free(dist_to_nbr); G_free(weight); G_free(wat_nbr); G_free(ele_nbr); G_free(flag_nbr); return 0; }
int do_astar(void) { int doer, count; int upr, upc, r = -1, c = -1, ct_dir; CELL alt_val, alt_nbr[8]; WAT_ALT wa; char asp_val; char flag_value, is_in_list, is_worked; HEAP_PNT heap_p; /* sides * |7|1|4| * |2| |3| * |5|0|6| */ int nbr_ew[8] = { 0, 1, 2, 3, 1, 0, 0, 1 }; int nbr_ns[8] = { 0, 1, 2, 3, 3, 2, 3, 2 }; double dx, dy, dist_to_nbr[8], ew_res, ns_res; double slope[8]; int skip_diag; int count_edge = 0, count_diag = 0, count_edge_sink = 0, count_diag_sink = 0; G_message(_("SECTION 2: A* Search.")); for (ct_dir = 0; ct_dir < sides; ct_dir++) { /* get r, c (upr, upc) for neighbours */ upr = nextdr[ct_dir]; upc = nextdc[ct_dir]; /* account for rare cases when ns_res != ew_res */ dy = ABS(upr) * window.ns_res; dx = ABS(upc) * window.ew_res; if (ct_dir < 4) dist_to_nbr[ct_dir] = dx + dy; else dist_to_nbr[ct_dir] = sqrt(dx * dx + dy * dy); } ew_res = window.ew_res; ns_res = window.ns_res; if (heap_size == 0) G_fatal_error(_("No seeds for A* Search")); G_debug(1, "heap size %d, points %d", heap_size, do_points); count = 0; doer = do_points - 1; /* A* Search: search uphill, get downhill paths */ while (heap_size > 0) { G_percent(count++, do_points, 1); heap_p = drop_pt(); r = heap_p.pnt.r; c = heap_p.pnt.c; G_debug(3, "heap size %d, r %d, c %d", heap_size, r, c); alt_val = heap_p.ele; /* check all neighbours, breadth first search */ for (ct_dir = 0; ct_dir < sides; ct_dir++) { /* get r, c (upr, upc) for this neighbour */ upr = r + nextdr[ct_dir]; upc = c + nextdc[ct_dir]; slope[ct_dir] = alt_nbr[ct_dir] = 0; /* check if upr, upc are within region */ if (upr >= 0 && upr < nrows && upc >= 0 && upc < ncols) { bseg_get(&bitflags, &flag_value, upr, upc); is_in_list = FLAG_GET(flag_value, INLISTFLAG); is_worked = FLAG_GET(flag_value, WORKEDFLAG); skip_diag = 0; /* avoid diagonal flow direction bias */ if (!is_worked) { seg_get(&watalt, (char *)&wa, upr, upc); alt_nbr[ct_dir] = wa.ele; slope[ct_dir] = get_slope2(alt_val, alt_nbr[ct_dir], dist_to_nbr[ct_dir]); } if (!is_in_list) { if (ct_dir > 3 && slope[ct_dir] > 0) { if (slope[nbr_ew[ct_dir]] > 0) { /* slope to ew nbr > slope to center */ if (slope[ct_dir] < get_slope2(alt_nbr[nbr_ew[ct_dir]], alt_nbr[ct_dir], ew_res)) skip_diag = 1; } if (!skip_diag && slope[nbr_ns[ct_dir]] > 0) { /* slope to ns nbr > slope to center */ if (slope[ct_dir] < get_slope2(alt_nbr[nbr_ns[ct_dir]], alt_nbr[ct_dir], ns_res)) skip_diag = 1; } } } /* add neighbour as new point if not in the list */ if (is_in_list == 0 && skip_diag == 0) { /* set flow direction */ asp_val = drain[upr - r + 1][upc - c + 1]; add_pt(upr, upc, alt_nbr[ct_dir]); bseg_put(&asp, &asp_val, upr, upc); FLAG_SET(flag_value, INLISTFLAG); bseg_put(&bitflags, &flag_value, upr, upc); if (alt_nbr[ct_dir] < alt_val) { if (ct_dir < 4) count_edge_sink++; else count_diag_sink++; } /* includes flat areas */ else { if (ct_dir < 4) count_edge++; else count_diag++; } } else if (is_in_list && is_worked == 0 && FLAG_GET(flag_value, EDGEFLAG)) { /* neighbour is edge in list, not yet worked */ bseg_get(&asp, &asp_val, upr, upc); if (asp_val < 0) { /* adjust flow direction for edge cell */ asp_val = drain[upr - r + 1][upc - c + 1]; bseg_put(&asp, &asp_val, upr, upc); seg_get(&watalt, (char *)&wa, r, c); if (wa.wat > 0) { wa.wat = -wa.wat; seg_put(&watalt, (char *)&wa, r, c); } } /* neighbour is inside real depression, not yet worked */ else if (asp_val == 0) { asp_val = drain[upr - r + 1][upc - c + 1]; bseg_put(&asp, &asp_val, upr, upc); } } } } /* add astar points to sorted list for flow accumulation */ seg_put(&astar_pts, (char *)&heap_p.pnt, 0, doer); doer--; bseg_get(&bitflags, &flag_value, r, c); FLAG_SET(flag_value, WORKEDFLAG); bseg_put(&bitflags, &flag_value, r, c); } if (doer != -1) G_fatal_error(_("bug in A* Search: doer %d heap size %d count %d"), doer, heap_size, count); seg_close(&search_heap); G_percent(count, do_points, 1); /* finish it */ G_debug(1, "edge direction: %d (%.2f%%)", count_edge, (double) 100. * count_edge / (count_edge + count_diag)); G_debug(1, "diag direction: %d (%.2f%%)", count_diag, (double) 100. * count_diag / (count_edge + count_diag)); G_debug(1, "edge out of depression: %d (%.2f%%)", count_edge_sink, (double) 100. * count_edge_sink / (count_edge_sink + count_diag_sink)); G_debug(1, "diag out of depression: %d (%.2f%%)", count_diag_sink, (double) 100. * count_diag_sink / (count_edge_sink + count_diag_sink)); return 0; }