int do_cum(void) { int r, c, dr, dc; int r_nbr, c_nbr, ct_dir, np_side, edge; CELL is_swale, aspect, ele_nbr; DCELL value, valued; 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 }; int this_index, down_index, nbr_index; double *dist_to_nbr, *contour; double cell_size; G_message(_("SECTION 3: Accumulating Surface Flow with SFD.")); /* distances to neighbours, contour lengths */ dist_to_nbr = (double *)G_malloc(sides * sizeof(double)); contour = (double *)G_malloc(sides * sizeof(double)); cell_size = get_dist(dist_to_nbr, contour); if (bas_thres <= 0) threshold = 60; else threshold = bas_thres; for (killer = 1; killer <= do_points; killer++) { G_percent(killer, do_points, 1); this_index = astar_pts[killer]; aspect = asp[this_index]; seg_index_rc(alt_seg, this_index, &r, &c); if (aspect) { dr = r + asp_r[ABS(aspect)]; dc = c + asp_c[ABS(aspect)]; } /* skip user-defined depressions */ else dr = dc = -1; if (dr >= 0 && dr < nrows && dc >= 0 && dc < ncols) { /* if ((dr = astar_pts[killer].downr) > -1) { */ down_index = SEG_INDEX(wat_seg, dr, dc); value = wat[this_index]; if (fabs(value) >= threshold) FLAG_SET(swale, r, c); valued = wat[down_index]; edge = 0; np_side = -1; 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]; if (dr == r_nbr && dc == c_nbr) np_side = ct_dir; /* check that neighbour is within region */ if (r_nbr >= 0 && r_nbr < nrows && c_nbr >= 0 && c_nbr < ncols) { nbr_index = SEG_INDEX(wat_seg, r_nbr, c_nbr); ele_nbr = alt[nbr_index]; if (Rast_is_c_null_value(&ele_nbr)) edge = 1; } else edge = 1; if (edge) break; } /* do not distribute flow along edges, this causes artifacts */ if (edge) { is_swale = FLAG_GET(swale, r, c); if (is_swale && aspect > 0) { aspect = -1 * drain[r - r_nbr + 1][c - c_nbr + 1]; asp[this_index] = aspect; } if (valued > 0) wat[down_index] = -valued; continue; } if (value > 0) { if (valued > 0) valued += value; else valued -= value; } else { if (valued < 0) valued += value; else valued = value - valued; } wat[down_index] = valued; /* topographic wetness index ln(a / tan(beta)) and * stream power index a * tan(beta) */ if (atanb_flag) { sca[this_index] = fabs(wat[this_index]) * (cell_size / contour[np_side]); tanb[this_index] = get_slope_tci(alt[this_index], alt[down_index], dist_to_nbr[np_side]); } is_swale = FLAG_GET(swale, r, c); if (is_swale || fabs(valued) >= threshold) { FLAG_SET(swale, dr, dc); } else { if (er_flag && !is_swale) slope_length(r, c, dr, dc); } } } G_free(astar_pts); return 0; }
int do_cum_mfd(void) { int r, c, dr, dc; CELL is_swale; DCELL value, valued, tci_div, sum_contour, cell_size; int killer, threshold; /* MFD */ int mfd_cells, stream_cells, swale_cells, astar_not_set, is_null; double *dist_to_nbr, *contour, *weight, sum_weight, max_weight; int r_nbr, c_nbr, r_max, c_max, ct_dir, np_side; CELL ele, ele_nbr, aspect, is_worked; double prop, max_val; int workedon, edge, flat; 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 }; int this_index, down_index, nbr_index; G_message(_("SECTION 3a: Accumulating Surface Flow with MFD.")); G_debug(1, "MFD convergence factor set to %d.", c_fac); /* distances to neighbours, weights, contour lengths */ dist_to_nbr = (double *)G_malloc(sides * sizeof(double)); weight = (double *)G_malloc(sides * sizeof(double)); contour = (double *)G_malloc(sides * sizeof(double)); cell_size = get_dist(dist_to_nbr, contour); flag_clear_all(worked); workedon = 0; if (bas_thres <= 0) threshold = 60; else threshold = bas_thres; for (killer = 1; killer <= do_points; killer++) { G_percent(killer, do_points, 1); this_index = astar_pts[killer]; seg_index_rc(alt_seg, this_index, &r, &c); FLAG_SET(worked, r, c); aspect = asp[this_index]; if (aspect) { dr = r + asp_r[ABS(aspect)]; dc = c + asp_c[ABS(aspect)]; } else dr = dc = -1; if (dr >= 0 && dr < nrows && dc >= 0 && dc < ncols) { /* if ((dr = astar_pts[killer].downr) > -1) { */ value = wat[this_index]; down_index = SEG_INDEX(wat_seg, dr, dc); /* get weights */ max_weight = 0; sum_weight = 0; np_side = -1; mfd_cells = 0; astar_not_set = 1; ele = alt[this_index]; is_null = 0; edge = 0; /* 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; if (dr == r_nbr && dc == c_nbr) np_side = ct_dir; /* check that neighbour is within region */ if (r_nbr >= 0 && r_nbr < nrows && c_nbr >= 0 && c_nbr < ncols) { nbr_index = SEG_INDEX(wat_seg, r_nbr, c_nbr); valued = wat[nbr_index]; ele_nbr = alt[nbr_index]; is_worked = FLAG_GET(worked, r_nbr, c_nbr); if (is_worked == 0) { is_null = Rast_is_c_null_value(&ele_nbr); edge = is_null; if (!is_null && ele_nbr <= ele) { if (ele_nbr < ele) { weight[ct_dir] = mfd_pow(((ele - ele_nbr) / dist_to_nbr[ct_dir]), c_fac); } if (ele_nbr == 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; } if (value < 0 && valued > 0) wat[nbr_index] = -valued; } } } else edge = 1; if (edge) break; } /* do not distribute flow along edges, this causes artifacts */ if (edge) { 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; } /* set flow accumulation for neighbours */ max_val = -1; tci_div = sum_contour = 0.; 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 that neighbour is within region */ if (r_nbr >= 0 && r_nbr < nrows && c_nbr >= 0 && c_nbr < ncols && weight[ct_dir] > -0.5) { is_worked = FLAG_GET(worked, r_nbr, c_nbr); if (is_worked == 0) { nbr_index = SEG_INDEX(wat_seg, r_nbr, c_nbr); weight[ct_dir] = weight[ct_dir] / sum_weight; /* check everything adds up to 1.0 */ prop += weight[ct_dir]; if (atanb_flag) { sum_contour += contour[ct_dir]; tci_div += get_slope_tci(ele, alt[nbr_index], dist_to_nbr[ct_dir]) * weight[ct_dir]; } valued = wat[nbr_index]; if (value > 0) { if (valued > 0) valued += value * weight[ct_dir]; else valued -= value * weight[ct_dir]; } else { if (valued < 0) valued += value * weight[ct_dir]; else valued = value * weight[ct_dir] - valued; } wat[nbr_index] = valued; } else if (ct_dir == np_side) { /* check for consistency with A * path */ workedon++; } } } 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[down_index]; if (value > 0) { if (valued > 0) valued += value; else valued -= value; } else { if (valued < 0) valued += value; else valued = value - valued; } wat[down_index] = valued; if (atanb_flag) { sum_contour = contour[np_side]; tci_div = get_slope_tci(ele, alt[down_index], dist_to_nbr[np_side]); } } /* topographic wetness index ln(a / tan(beta)) and * stream power index a * tan(beta) */ if (atanb_flag) { sca[this_index] = fabs(wat[this_index]) * (cell_size / sum_contour); tanb[this_index] = tci_div; } } } if (workedon) G_warning(n_("MFD: A * path already processed when distributing flow: %d of %d cell", "MFD: A * path already processed when distributing flow: %d of %d cells", do_points), workedon, do_points); G_message(_("SECTION 3b: Adjusting drainage directions.")); for (killer = 1; killer <= do_points; killer++) { G_percent(killer, do_points, 1); this_index = astar_pts[killer]; seg_index_rc(alt_seg, this_index, &r, &c); FLAG_UNSET(worked, r, c); aspect = asp[this_index]; if (aspect) { dr = r + asp_r[ABS(aspect)]; dc = c + asp_c[ABS(aspect)]; } else dr = dc = -1; if (dr >= 0 && dr < nrows && dc >= 0 && dc < ncols) { /* if ((dr = astar_pts[killer].downr) > -1) { */ value = wat[this_index]; down_index = SEG_INDEX(wat_seg, dr, dc); r_max = dr; c_max = dc; /* get max flow accumulation */ max_val = -1; stream_cells = 0; swale_cells = 0; ele = alt[this_index]; is_null = 0; edge = 0; flat = 1; 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]; /* check that neighbour is within region */ if (r_nbr >= 0 && r_nbr < nrows && c_nbr >= 0 && c_nbr < ncols) { nbr_index = SEG_INDEX(wat_seg, r_nbr, c_nbr); /* check for swale or stream cells */ is_swale = FLAG_GET(swale, r_nbr, c_nbr); if (is_swale) swale_cells++; valued = wat[nbr_index]; ele_nbr = alt[nbr_index]; edge = Rast_is_c_null_value(&ele_nbr); if ((ABS(valued) + 0.5) >= threshold && ele_nbr > ele) stream_cells++; is_worked = !(FLAG_GET(worked, r_nbr, c_nbr)); if (is_worked == 0) { if (ele_nbr != ele) flat = 0; is_null = Rast_is_c_null_value(&ele_nbr); edge = is_null; if (!is_null && ABS(valued) > max_val) { max_val = ABS(valued); r_max = r_nbr; c_max = c_nbr; } } } else edge = 1; if (edge) break; } /* do not distribute flow along edges, this causes artifacts */ if (edge) { is_swale = FLAG_GET(swale, r, c); if (is_swale && aspect > 0) { aspect = -1 * drain[r - r_nbr + 1][c - c_nbr + 1]; asp[this_index] = aspect; } continue; } /* update asp */ if (dr != r_max || dc != c_max) { aspect = drain[r - r_max + 1][c - c_max + 1]; if (asp[this_index] < 0) aspect = -aspect; asp[this_index] = aspect; } is_swale = FLAG_GET(swale, r, c); /* start new stream */ value = ABS(value) + 0.5; if (!is_swale && (int)value >= threshold && stream_cells < 1 && swale_cells < 1 && !flat) { FLAG_SET(swale, r, c); is_swale = 1; } /* continue stream */ if (is_swale) { FLAG_SET(swale, r_max, c_max); } else { if (er_flag && !is_swale) slope_length(r, c, r_max, c_max); } } } G_free(astar_pts); flag_destroy(worked); G_free(dist_to_nbr); G_free(weight); return 0; }
/* * return 0 if nothing was modidied * return 1 if elevation was modified */ int do_flatarea(int index, CELL ele, CELL *alt_org, CELL *alt_new) { int upr, upc, r, c, ct_dir; CELL is_in_list, is_worked, this_in_list; int index_doer, index_up; int n_flat_cells = 0, counter; CELL ele_nbr, min_ele_diff; int uphill_order, downhill_order, max_uphill_order, max_downhill_order; int last_order; struct pq *up_pq = pq_create(); struct pq *down_pq = pq_create(); struct orders inc_order, *order_found, *nbr_order_found; struct RB_TREE *order_tree = rbtree_create(cmp_orders, sizeof(struct orders)); pq_add(index, down_pq); pq_add(index, up_pq); inc_order.downhill = -1; inc_order.uphill = 0; inc_order.index = index; inc_order.flag = 0; rbtree_insert(order_tree, &inc_order); n_flat_cells = 1; min_ele_diff = INT_MAX; max_uphill_order = max_downhill_order = 0; /* get uphill start points */ G_debug(2, "get uphill start points"); counter = 0; while (down_pq->size) { if ((index_doer = pq_drop(down_pq)) == -1) G_fatal_error("get start points: no more points in down queue"); seg_index_rc(alt_seg, index_doer, &r, &c); FLAG_SET(flat_done, r, c); /* 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]; /* check if r, c are within region */ if (upr >= 0 && upr < nrows && upc >= 0 && upc < ncols) { index_up = SEG_INDEX(alt_seg, upr, upc); is_in_list = FLAG_GET(in_list, upr, upc); is_worked = FLAG_GET(worked, upr, upc); ele_nbr = alt_org[index_up]; if (ele_nbr == ele && !is_worked) { inc_order.downhill = -1; inc_order.uphill = -1; inc_order.index = index_up; inc_order.flag = 0; /* not yet added to queue */ if ((order_found = rbtree_find(order_tree, &inc_order)) == NULL) { n_flat_cells++; /* add to down queue if not yet in there */ pq_add(index_up, down_pq); /* add to up queue if not yet in there */ if (is_in_list) { pq_add(index_up, up_pq); /* set uphill order to 0 */ inc_order.uphill = 0; counter++; } rbtree_insert(order_tree, &inc_order); } } } } } /* flat area too small, not worth the effort */ if (n_flat_cells < 5) { /* clean up */ pq_destroy(up_pq); pq_destroy(down_pq); rbtree_destroy(order_tree); return 0; } G_debug(2, "%d flat cells, %d cells in tree, %d start cells", n_flat_cells, (int)order_tree->count, counter); pq_destroy(down_pq); down_pq = pq_create(); /* got uphill start points, do uphill correction */ G_debug(2, "got uphill start points, do uphill correction"); counter = 0; uphill_order = 1; while (up_pq->size) { int is_in_down_queue = 0; if ((index_doer = pq_drop(up_pq)) == -1) G_fatal_error("uphill order: no more points in up queue"); seg_index_rc(alt_seg, index_doer, &r, &c); this_in_list = FLAG_GET(in_list, r, c); /* get uphill order for this point */ inc_order.index = index_doer; if ((order_found = rbtree_find(order_tree, &inc_order)) == NULL) G_fatal_error(_("flat cell escaped for uphill correction")); last_order = uphill_order - 1; uphill_order = order_found->uphill; if (last_order > uphill_order) G_warning(_("queue error: last uphill order %d > current uphill order %d"), last_order, uphill_order); /* debug */ if (uphill_order == -1) G_fatal_error(_("uphill order not set")); if (max_uphill_order < uphill_order) max_uphill_order = uphill_order; uphill_order++; counter++; /* 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]; /* check if r, c are within region */ if (upr >= 0 && upr < nrows && upc >= 0 && upc < ncols) { index_up = SEG_INDEX(alt_seg, upr, upc); is_in_list = FLAG_GET(in_list, upr, upc); is_worked = FLAG_GET(worked, upr, upc); ele_nbr = alt_org[index_up]; /* all cells that are in_list should have been added * previously as uphill start points */ if (ele_nbr == ele && !is_worked) { inc_order.index = index_up; if ((nbr_order_found = rbtree_find(order_tree, &inc_order)) == NULL) { G_fatal_error(_("flat cell escaped in uphill correction")); } /* not yet added to queue */ if (nbr_order_found->uphill == -1) { if (is_in_list) G_warning("cell should be in queue"); /* add to up queue */ pq_add(index_up, up_pq); /* set nbr uphill order = current uphill order + 1 */ nbr_order_found->uphill = uphill_order; } } /* add focus cell to down queue */ if (!this_in_list && !is_in_down_queue && ele_nbr != ele && !is_in_list && !is_worked) { pq_add(index_doer, down_pq); /* set downhill order to 0 */ order_found->downhill = 0; is_in_down_queue = 1; } if (ele_nbr > ele && min_ele_diff > ele_nbr - ele) min_ele_diff = ele_nbr - ele; } } } /* debug: all flags should be set to 0 */ pq_destroy(up_pq); up_pq = pq_create(); /* got downhill start points, do downhill correction */ G_debug(2, "got downhill start points, do downhill correction"); downhill_order = 1; while (down_pq->size) { if ((index_doer = pq_drop(down_pq)) == -1) G_fatal_error(_("downhill order: no more points in down queue")); seg_index_rc(alt_seg, index_doer, &r, &c); this_in_list = FLAG_GET(in_list, r, c); /* get downhill order for this point */ inc_order.index = index_doer; if ((order_found = rbtree_find(order_tree, &inc_order)) == NULL) G_fatal_error(_("flat cell escaped for downhill correction")); last_order = downhill_order - 1; downhill_order = order_found->downhill; if (last_order > downhill_order) G_warning(_("queue error: last downhill order %d > current downhill order %d"), last_order, downhill_order); /* debug */ if (downhill_order == -1) G_fatal_error(_("downhill order: downhill order not set")); if (max_downhill_order < downhill_order) max_downhill_order = downhill_order; downhill_order++; /* 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]; /* check if r, c are within region */ if (upr >= 0 && upr < nrows && upc >= 0 && upc < ncols) { index_up = SEG_INDEX(alt_seg, upr, upc); is_in_list = FLAG_GET(in_list, upr, upc); is_worked = FLAG_GET(worked, upr, upc); ele_nbr = alt_org[index_up]; if (ele_nbr == ele && !is_worked) { inc_order.index = index_up; if ((nbr_order_found = rbtree_find(order_tree, &inc_order)) == NULL) G_fatal_error(_("flat cell escaped in downhill correction")); /* not yet added to queue */ if (nbr_order_found->downhill == -1) { /* add to down queue */ pq_add(index_up, down_pq); /* set nbr downhill order = current downhill order + 1 */ nbr_order_found->downhill = downhill_order; /* add to up queue */ if (is_in_list) { pq_add(index_up, up_pq); /* set flag */ nbr_order_found->flag = 1; } } } } } } /* got uphill and downhill order, adjust ele */ /* increment: ele += uphill_order + max_downhill_order - downhill_order */ /* decrement: ele += uphill_order - max_uphill_order - downhill_order */ G_debug(2, "adjust ele"); while (up_pq->size) { if ((index_doer = pq_drop(up_pq)) == -1) G_fatal_error("no more points in up queue"); seg_index_rc(alt_seg, index_doer, &r, &c); this_in_list = FLAG_GET(in_list, r, c); /* get uphill and downhill order for this point */ inc_order.index = index_doer; if ((order_found = rbtree_find(order_tree, &inc_order)) == NULL) G_fatal_error(_("flat cell escaped for adjustment")); uphill_order = order_found->uphill; downhill_order = order_found->downhill; /* debug */ if (uphill_order == -1) G_fatal_error(_("adjustment: uphill order not set")); if (!this_in_list && downhill_order == -1) G_fatal_error(_("adjustment: downhill order not set")); /* increment */ if (this_in_list) { downhill_order = max_downhill_order; uphill_order = 0; } alt_new[index_doer] += (uphill_order + (double)(max_downhill_order - downhill_order) / 2.0 + 0.5) / 2.0 + 0.5; /* 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]; /* check if r, c are within region */ if (upr >= 0 && upr < nrows && upc >= 0 && upc < ncols) { index_up = SEG_INDEX(alt_seg, upr, upc); is_in_list = FLAG_GET(in_list, upr, upc); is_worked = FLAG_GET(worked, upr, upc); ele_nbr = alt_org[index_up]; if (ele_nbr == ele && !is_worked) { inc_order.index = index_up; if ((nbr_order_found = rbtree_find(order_tree, &inc_order)) == NULL) G_fatal_error(_("flat cell escaped in adjustment")); /* not yet added to queue */ if (nbr_order_found->flag == 0) { if (is_in_list) G_warning("adjustment: in_list cell should be in queue"); /* add to up queue */ pq_add(index_up, up_pq); nbr_order_found->flag = 1; } } } } } /* clean up */ pq_destroy(up_pq); pq_destroy(down_pq); rbtree_destroy(order_tree); return 1; }