static int sift_up(GW_LARGE_INT start, HEAP_PNT child_p) { GW_LARGE_INT parent, child; HEAP_PNT heap_p; child = start; while (child > 1) { parent = GET_PARENT(child); seg_get(&search_heap, (char *)&heap_p, 0, parent); /* push parent point down if child is smaller */ if (heap_cmp(&child_p, &heap_p)) { seg_put(&search_heap, (char *)&heap_p, 0, child); child = parent; } else /* no more sifting up, found slot for child */ break; } /* add child to heap */ seg_put(&search_heap, (char *)&child_p, 0, child); return 0; }
/* * drop item from heap * returns heap size */ HEAP_PNT heap_drop(void) { GW_LARGE_INT child, childr, parent; GW_LARGE_INT i; HEAP_PNT child_p, childr_p, last_p, root_p; seg_get(&search_heap, (char *)&last_p, 0, heap_size); seg_get(&search_heap, (char *)&root_p, 0, 1); if (heap_size == 1) { heap_size = 0; return root_p; } parent = 1; while ((child = GET_CHILD(parent)) < heap_size) { seg_get(&search_heap, (char *)&child_p, 0, child); if (child < heap_size) { childr = child + 1; i = child + 8; while (childr < heap_size && childr < i) { seg_get(&search_heap, (char *)&childr_p, 0, childr); if (heap_cmp(&childr_p, &child_p)) { child = childr; child_p = childr_p; } childr++; } } if (heap_cmp(&last_p, &child_p)) { break; } /* move hole down */ seg_put(&search_heap, (char *)&child_p, 0, parent); parent = child; } /* fill hole */ if (parent < heap_size) { seg_put(&search_heap, (char *)&last_p, 0, parent); } /* the actual drop */ heap_size--; return root_p; }
/* drop point routine for min heap */ HEAP_PNT drop_pt(void) { int child, childr, parent; int i; HEAP_PNT child_p, childr_p, last_p, root_p; seg_get(&search_heap, (char *)&last_p, 0, heap_size); seg_get(&search_heap, (char *)&root_p, 0, 1); /* sift down: move hole back towards bottom of heap */ parent = 1; while ((child = GET_CHILD(parent)) < heap_size) { /* select child with lower ele, if both are equal, older child * older child is older startpoint for flow path, important */ seg_get(&search_heap, (char *)&child_p, 0, child); if (child < heap_size) { childr = child + 1; i = child + 4; while (childr < i && childr < heap_size) { seg_get(&search_heap, (char *)&childr_p, 0, childr); if (cmp_pnt(&childr_p, &child_p)) { child = childr; child_p = childr_p; } childr++; } } if (cmp_pnt(&last_p, &child_p)) { break; } /* move hole down */ seg_put(&search_heap, (char *)&child_p, 0, parent); parent = child; } seg_put(&search_heap, (char *)&last_p, 0, parent); /* the actual drop */ heap_size--; return root_p; }
int init_search(int depr_fd) { int r, c, r_nbr, c_nbr, ct_dir; CELL *depr_buf, ele_value; int nextdr[8] = { 1, -1, 0, 0, -1, 1, 1, -1 }; int nextdc[8] = { 0, 0, -1, 1, 1, -1, 1, -1 }; char asp_value, is_null; WAT_ALT wa; ASP_FLAG af, af_nbr; GW_LARGE_INT n_depr_cells = 0; nxt_avail_pt = heap_size = 0; /* load edge cells and real depressions to A* heap */ if (depr_fd >= 0) depr_buf = Rast_allocate_buf(CELL_TYPE); else depr_buf = NULL; G_message(_("Initializing A* search...")); for (r = 0; r < nrows; r++) { G_percent(r, nrows, 2); if (depr_fd >= 0) { Rast_get_row(depr_fd, depr_buf, r, CELL_TYPE); } for (c = 0; c < ncols; c++) { seg_get(&aspflag, (char *)&af, r, c); is_null = FLAG_GET(af.flag, NULLFLAG); if (is_null) continue; asp_value = 0; if (r == 0 || r == nrows - 1 || c == 0 || c == ncols - 1) { if (r == 0 && c == 0) asp_value = -7; else if (r == 0 && c == ncols - 1) asp_value = -5; else if (r == nrows - 1 && c == 0) asp_value = -1; else if (r == nrows - 1 && c == ncols - 1) asp_value = -3; else if (r == 0) asp_value = -2; else if (c == 0) asp_value = -4; else if (r == nrows - 1) asp_value = -6; else if (c == ncols - 1) asp_value = -8; seg_get(&watalt, (char *)&wa, r, c); ele_value = wa.ele; heap_add(r, c, ele_value); FLAG_SET(af.flag, INLISTFLAG); FLAG_SET(af.flag, EDGEFLAG); af.asp = asp_value; seg_put(&aspflag, (char *)&af, r, c); continue; } /* any neighbour NULL ? */ 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]; seg_get(&aspflag, (char *)&af_nbr, r_nbr, c_nbr); is_null = FLAG_GET(af_nbr.flag, NULLFLAG); if (is_null) { asp_value = -1 * drain[r - r_nbr + 1][c - c_nbr + 1]; seg_get(&watalt, (char *)&wa, r, c); ele_value = wa.ele; heap_add(r, c, ele_value); FLAG_SET(af.flag, INLISTFLAG); FLAG_SET(af.flag, EDGEFLAG); af.asp = asp_value; seg_put(&aspflag, (char *)&af, r, c); break; } } if (asp_value) /* some neighbour was NULL, point added to list */ continue; /* real depression ? */ if (depr_fd >= 0) { if (!Rast_is_c_null_value(&depr_buf[c]) && depr_buf[c] != 0) { seg_get(&watalt, (char *)&wa, r, c); ele_value = wa.ele; heap_add(r, c, ele_value); FLAG_SET(af.flag, INLISTFLAG); FLAG_SET(af.flag, DEPRFLAG); af.asp = asp_value; seg_put(&aspflag, (char *)&af, r, c); n_depr_cells++; } } } } G_percent(nrows, nrows, 2); /* finish it */ if (depr_fd >= 0) { Rast_close(depr_fd); G_free(depr_buf); } G_debug(1, "%lld edge cells", heap_size - n_depr_cells); if (n_depr_cells) G_debug(1, "%lld cells in depressions", n_depr_cells); return 1; }
int do_astar(void) { int r, c, r_nbr, c_nbr, ct_dir; GW_LARGE_INT first_cum, count; int nextdr[8] = { 1, -1, 0, 0, -1, 1, 1, -1 }; int nextdc[8] = { 0, 0, -1, 1, 1, -1, 1, -1 }; CELL ele_val, ele_up, ele_nbr[8]; WAT_ALT wa; ASP_FLAG af; char 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]; struct Cell_head window; int skip_diag; count = 0; first_cum = n_points; G_message(_("A* Search...")); Rast_get_window(&window); 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); } ew_res = window.ew_res; ns_res = window.ns_res; while (heap_size > 0) { G_percent(count++, n_points, 1); if (count > n_points) G_fatal_error(_("%lld surplus points"), heap_size); if (heap_size > n_points) G_fatal_error (_("Too many points in heap %lld, should be %lld"), heap_size, n_points); heap_p = heap_drop(); r = heap_p.pnt.r; c = heap_p.pnt.c; ele_val = heap_p.ele; 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]; slope[ct_dir] = ele_nbr[ct_dir] = 0; skip_diag = 0; /* check that neighbour is within region */ if (r_nbr < 0 || r_nbr >= nrows || c_nbr < 0 || c_nbr >= ncols) continue; seg_get(&aspflag, (char *)&af, r_nbr, c_nbr); is_in_list = FLAG_GET(af.flag, INLISTFLAG); is_worked = FLAG_GET(af.flag, WORKEDFLAG); if (!is_worked) { seg_get(&watalt, (char *)&wa, r_nbr, c_nbr); ele_nbr[ct_dir] = wa.ele; slope[ct_dir] = get_slope(ele_val, ele_nbr[ct_dir], dist_to_nbr[ct_dir]); } /* avoid diagonal flow direction bias */ 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_slope(ele_nbr[nbr_ew[ct_dir]], ele_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_slope(ele_nbr[nbr_ns[ct_dir]], ele_nbr[ct_dir], ns_res)) skip_diag = 1; } } } if (!skip_diag) { if (is_in_list == 0) { ele_up = ele_nbr[ct_dir]; af.asp = drain[r_nbr - r + 1][c_nbr - c + 1]; heap_add(r_nbr, c_nbr, ele_up); FLAG_SET(af.flag, INLISTFLAG); seg_put(&aspflag, (char *)&af, r_nbr, c_nbr); } else if (is_in_list && is_worked == 0) { if (FLAG_GET(af.flag, EDGEFLAG)) { /* neighbour is edge in list, not yet worked */ if (af.asp < 0) { /* adjust flow direction for edge cell */ af.asp = drain[r_nbr - r + 1][c_nbr - c + 1]; seg_put(&aspflag, (char *)&af, r_nbr, c_nbr); } } else if (FLAG_GET(af.flag, DEPRFLAG)) { G_debug(3, "real depression"); /* neighbour is inside real depression, not yet worked */ if (af.asp == 0 && ele_val <= ele_nbr[ct_dir]) { af.asp = drain[r_nbr - r + 1][c_nbr - c + 1]; FLAG_UNSET(af.flag, DEPRFLAG); seg_put(&aspflag, (char *)&af, r_nbr, c_nbr); } } } } } /* end neighbours */ /* add astar points to sorted list for flow accumulation and stream extraction */ first_cum--; seg_put(&astar_pts, (char *)&heap_p.pnt, 0, first_cum); seg_get(&aspflag, (char *)&af, r, c); FLAG_SET(af.flag, WORKEDFLAG); seg_put(&aspflag, (char *)&af, r, c); } /* end A* search */ G_percent(n_points, n_points, 1); /* finish it */ return 1; }
int init_vars(int argc, char *argv[]) { int r, c; int ele_fd, wat_fd, fd = -1; int seg_rows, seg_cols, num_cseg_total, num_open_segs, num_open_array_segs; double memory_divisor, heap_mem, seg_factor, disk_space; /* int page_block, num_cseg; */ int max_bytes; CELL *buf, alt_value, *alt_value_buf, block_value; char asp_value; DCELL wat_value; DCELL dvalue; WAT_ALT wa, *wabuf; ASP_FLAG af, af_nbr, *afbuf; char MASK_flag; void *elebuf, *ptr, *watbuf, *watptr; int ele_map_type, wat_map_type; size_t ele_size, wat_size; int ct_dir, r_nbr, c_nbr; G_gisinit(argv[0]); /* input */ ele_flag = pit_flag = run_flag = ril_flag = 0; /* output */ wat_flag = asp_flag = bas_flag = seg_flag = haf_flag = tci_flag = 0; bas_thres = 0; /* shed, unused */ arm_flag = dis_flag = 0; /* RUSLE */ ob_flag = st_flag = sl_flag = sg_flag = ls_flag = er_flag = 0; nxt_avail_pt = 0; /* dep_flag = 0; */ max_length = d_zero = 0.0; d_one = 1.0; ril_value = -1.0; /* dep_slope = 0.0; */ max_bytes = 0; sides = 8; mfd = 1; c_fac = 5; abs_acc = 0; ele_scale = 1; segs_mb = 300; /* scan options */ for (r = 1; r < argc; r++) { if (sscanf(argv[r], "elevation=%s", ele_name) == 1) ele_flag++; else if (sscanf(argv[r], "accumulation=%s", wat_name) == 1) wat_flag++; else if (sscanf(argv[r], "tci=%s", tci_name) == 1) tci_flag++; else if (sscanf(argv[r], "drainage=%s", asp_name) == 1) asp_flag++; else if (sscanf(argv[r], "depression=%s", pit_name) == 1) pit_flag++; else if (sscanf(argv[r], "threshold=%d", &bas_thres) == 1) ; else if (sscanf(argv[r], "max_slope_length=%lf", &max_length) == 1) ; else if (sscanf(argv[r], "basin=%s", bas_name) == 1) bas_flag++; else if (sscanf(argv[r], "stream=%s", seg_name) == 1) seg_flag++; else if (sscanf(argv[r], "half_basin=%s", haf_name) == 1) haf_flag++; else if (sscanf(argv[r], "flow=%s", run_name) == 1) run_flag++; else if (sscanf(argv[r], "ar=%s", arm_name) == 1) arm_flag++; /* slope length else if (sscanf(argv[r], "slope_length=%s", sl_name) == 1) sl_flag++; */ else if (sscanf(argv[r], "slope_steepness=%s", sg_name) == 1) sg_flag++; else if (sscanf(argv[r], "length_slope=%s", ls_name) == 1) ls_flag++; else if (sscanf(argv[r], "blocking=%s", ob_name) == 1) ob_flag++; else if (sscanf(argv[r], "memory=%lf", &segs_mb) == 1) ; else if (sscanf(argv[r], "disturbed_land=%s", ril_name) == 1) { if (sscanf(ril_name, "%lf", &ril_value) == 0) { ril_value = -1.0; ril_flag++; } } /* slope deposition else if (sscanf (argv[r], "sd=%[^\n]", dep_name) == 1) dep_flag++; */ else if (sscanf(argv[r], "-%d", &sides) == 1) { if (sides != 4) usage(argv[0]); } else if (sscanf(argv[r], "convergence=%d", &c_fac) == 1) ; else if (strcmp(argv[r], "-s") == 0) mfd = 0; else if (strcmp(argv[r], "-a") == 0) abs_acc = 1; else usage(argv[0]); } /* check options */ if (mfd == 1 && (c_fac < 1 || c_fac > 10)) { G_fatal_error("Convergence factor must be between 1 and 10."); } if ((ele_flag != 1) || ((arm_flag == 1) && ((bas_thres <= 0) || ((haf_flag != 1) && (bas_flag != 1)))) || ((bas_thres <= 0) && ((bas_flag == 1) || (seg_flag == 1) || (haf_flag == 1) || (sl_flag == 1) || (sg_flag == 1) || (ls_flag == 1))) ) usage(argv[0]); tot_parts = 4; if (sl_flag || sg_flag || ls_flag) er_flag = 1; /* do RUSLE */ if (er_flag) tot_parts++; /* define basins */ if (seg_flag || bas_flag || haf_flag) tot_parts++; G_message(_n("SECTION 1 beginning: Initiating Variables. %d section total.", "SECTION 1 beginning: Initiating Variables. %d sections total.", tot_parts), tot_parts); this_mapset = G_mapset(); /* for sd factor if (dep_flag) { if (sscanf (dep_name, "%lf", &dep_slope) != 1) { dep_flag = -1; } } */ G_get_set_window(&window); nrows = Rast_window_rows(); ncols = Rast_window_cols(); if (max_length <= d_zero) max_length = 10 * nrows * window.ns_res + 10 * ncols * window.ew_res; if (window.ew_res < window.ns_res) half_res = .5 * window.ew_res; else half_res = .5 * window.ns_res; diag = sqrt(window.ew_res * window.ew_res + window.ns_res * window.ns_res); if (sides == 4) diag *= 0.5; /* Segment rows and cols: 64 */ seg_rows = SROW; seg_cols = SCOL; /* seg_factor * <size in bytes> = segment size in KB */ seg_factor = seg_rows * seg_rows / 1024.; if (segs_mb < 3.0) { segs_mb = 3; G_warning(_("Maximum memory to be used was smaller than 3 MB," " set to 3 MB.")); } /* balance segment files */ /* elevation + accumulation: * 2 */ memory_divisor = sizeof(WAT_ALT) * 2; disk_space = sizeof(WAT_ALT); /* aspect and flags: * 4 */ memory_divisor += sizeof(ASP_FLAG) * 4; disk_space += sizeof(ASP_FLAG); /* astar_points: / 16 */ /* ideally only a few but large segments */ memory_divisor += sizeof(POINT) / 16.; disk_space += sizeof(POINT); /* heap points: / 4 */ memory_divisor += sizeof(HEAP_PNT) / 4.; disk_space += sizeof(HEAP_PNT); /* TCI: as is */ if (tci_flag) { memory_divisor += sizeof(double); disk_space += sizeof(double); } /* RUSLE */ if (er_flag) { /* r_h */ memory_divisor += 4; disk_space += 4; /* s_l */ memory_divisor += 8; disk_space += 8; /* s_g */ if (sg_flag) { memory_divisor += 8; disk_space += 8; } /* l_s */ if (ls_flag) { memory_divisor += 8; disk_space += 8; } /* ril */ if (ril_flag) { memory_divisor += 8; disk_space += 8; } } /* KB -> MB */ memory_divisor = memory_divisor * seg_factor / 1024.; disk_space = disk_space * seg_factor / 1024.; num_open_segs = segs_mb / memory_divisor; heap_mem = num_open_segs * seg_factor * sizeof(HEAP_PNT) / (4. * 1024.); G_debug(1, "segs MB: %.0f", segs_mb); G_debug(1, "region rows: %d", nrows); G_debug(1, "seg rows: %d", seg_rows); G_debug(1, "region cols: %d", ncols); G_debug(1, "seg cols: %d", seg_cols); num_cseg_total = nrows / SROW + 1; G_debug(1, " row segments:\t%d", num_cseg_total); num_cseg_total = ncols / SCOL + 1; G_debug(1, "column segments:\t%d", num_cseg_total); num_cseg_total = (ncols / seg_cols + 1) * (nrows / seg_rows + 1); G_debug(1, " total segments:\t%d", num_cseg_total); G_debug(1, " open segments:\t%d", num_open_segs); /* nonsense to have more segments open than exist */ if (num_open_segs > num_cseg_total) num_open_segs = num_cseg_total; G_debug(1, " open segments after adjusting:\t%d", num_open_segs); disk_space *= num_cseg_total; if (disk_space < 1024.0) G_verbose_message(_("Will need up to %.2f MB of disk space"), disk_space); else G_verbose_message(_("Will need up to %.2f GB (%.0f MB) of disk space"), disk_space / 1024.0, disk_space); if (er_flag) { cseg_open(&r_h, seg_rows, seg_cols, num_open_segs); cseg_read_cell(&r_h, ele_name, ""); } /* read elevation input and mark NULL/masked cells */ /* scattered access: alt, watalt, bitflags, asp */ seg_open(&watalt, nrows, ncols, seg_rows, seg_cols, num_open_segs * 2, sizeof(WAT_ALT)); seg_open(&aspflag, nrows, ncols, seg_rows, seg_cols, num_open_segs * 4, sizeof(ASP_FLAG)); if (tci_flag) dseg_open(&tci, seg_rows, seg_cols, num_open_segs); /* open elevation input */ ele_fd = Rast_open_old(ele_name, ""); ele_map_type = Rast_get_map_type(ele_fd); ele_size = Rast_cell_size(ele_map_type); elebuf = Rast_allocate_buf(ele_map_type); afbuf = G_malloc(ncols * sizeof(ASP_FLAG)); if (ele_map_type == FCELL_TYPE || ele_map_type == DCELL_TYPE) ele_scale = 1000; /* should be enough to do the trick */ /* initial flow accumulation */ if (run_flag) { wat_fd = Rast_open_old(run_name, ""); wat_map_type = Rast_get_map_type(ele_fd); wat_size = Rast_cell_size(ele_map_type); watbuf = Rast_allocate_buf(ele_map_type); } else { watbuf = watptr = NULL; wat_fd = wat_size = wat_map_type = -1; } wabuf = G_malloc(ncols * sizeof(WAT_ALT)); alt_value_buf = Rast_allocate_buf(CELL_TYPE); /* read elevation input and mark NULL/masked cells */ G_message("SECTION 1a: Mark masked and NULL cells"); MASK_flag = 0; do_points = (GW_LARGE_INT) nrows * ncols; for (r = 0; r < nrows; r++) { G_percent(r, nrows, 1); Rast_get_row(ele_fd, elebuf, r, ele_map_type); ptr = elebuf; if (run_flag) { Rast_get_row(wat_fd, watbuf, r, wat_map_type); watptr = watbuf; } for (c = 0; c < ncols; c++) { afbuf[c].flag = 0; afbuf[c].asp = 0; /* check for masked and NULL cells */ if (Rast_is_null_value(ptr, ele_map_type)) { FLAG_SET(afbuf[c].flag, NULLFLAG); FLAG_SET(afbuf[c].flag, INLISTFLAG); FLAG_SET(afbuf[c].flag, WORKEDFLAG); Rast_set_c_null_value(&alt_value, 1); /* flow accumulation */ Rast_set_d_null_value(&wat_value, 1); do_points--; } else { if (ele_map_type == CELL_TYPE) { alt_value = *((CELL *)ptr); } else if (ele_map_type == FCELL_TYPE) { dvalue = *((FCELL *)ptr); dvalue *= ele_scale; alt_value = ele_round(dvalue); } else if (ele_map_type == DCELL_TYPE) { dvalue = *((DCELL *)ptr); dvalue *= ele_scale; alt_value = ele_round(dvalue); } /* flow accumulation */ if (run_flag) { if (Rast_is_null_value(watptr, wat_map_type)) { wat_value = 0; /* ok ? */ } else { if (wat_map_type == CELL_TYPE) { wat_value = *((CELL *)watptr); } else if (wat_map_type == FCELL_TYPE) { wat_value = *((FCELL *)watptr); } else if (wat_map_type == DCELL_TYPE) { wat_value = *((DCELL *)watptr); } } } else { wat_value = 1; } } wabuf[c].wat = wat_value; wabuf[c].ele = alt_value; alt_value_buf[c] = alt_value; ptr = G_incr_void_ptr(ptr, ele_size); if (run_flag) { watptr = G_incr_void_ptr(watptr, wat_size); } } seg_put_row(&watalt, (char *) wabuf, r); seg_put_row(&aspflag, (char *)afbuf, r); if (er_flag) { cseg_put_row(&r_h, alt_value_buf, r); } } G_percent(nrows, nrows, 1); /* finish it */ Rast_close(ele_fd); G_free(wabuf); G_free(afbuf); if (run_flag) { Rast_close(wat_fd); G_free(watbuf); } MASK_flag = (do_points < nrows * ncols); /* do RUSLE */ if (er_flag) { if (ob_flag) { fd = Rast_open_old(ob_name, ""); buf = Rast_allocate_c_buf(); for (r = 0; r < nrows; r++) { G_percent(r, nrows, 1); Rast_get_c_row(fd, buf, r); for (c = 0; c < ncols; c++) { block_value = buf[c]; if (!Rast_is_c_null_value(&block_value) && block_value) { seg_get(&aspflag, (char *)&af, r, c); FLAG_SET(af.flag, RUSLEBLOCKFLAG); seg_put(&aspflag, (char *)&af, r, c); } } } G_percent(nrows, nrows, 1); /* finish it */ Rast_close(fd); G_free(buf); } if (ril_flag) { dseg_open(&ril, seg_rows, seg_cols, num_open_segs); dseg_read_cell(&ril, ril_name, ""); } /* dseg_open(&slp, SROW, SCOL, num_open_segs); */ dseg_open(&s_l, seg_rows, seg_cols, num_open_segs); if (sg_flag) dseg_open(&s_g, seg_rows, seg_cols, num_open_segs); if (ls_flag) dseg_open(&l_s, seg_rows, seg_cols, num_open_segs); } G_debug(1, "open segments for A* points"); /* columns per segment */ seg_cols = seg_rows * seg_rows; num_cseg_total = do_points / seg_cols; if (do_points % seg_cols > 0) num_cseg_total++; /* no need to have more segments open than exist */ num_open_array_segs = num_open_segs / 16.; if (num_open_array_segs > num_cseg_total) num_open_array_segs = num_cseg_total; if (num_open_array_segs < 1) num_open_array_segs = 1; seg_open(&astar_pts, 1, do_points, 1, seg_cols, num_open_array_segs, sizeof(POINT)); /* one-based d-ary search_heap with astar_pts */ G_debug(1, "open segments for A* search heap"); G_debug(1, "heap memory %.2f MB", heap_mem); /* columns per segment */ /* larger is faster */ seg_cols = seg_rows * seg_rows; num_cseg_total = do_points / seg_cols; if (do_points % seg_cols > 0) num_cseg_total++; /* no need to have more segments open than exist */ num_open_array_segs = (1 << 20) * heap_mem / (seg_cols * sizeof(HEAP_PNT)); if (num_open_array_segs > num_cseg_total) num_open_array_segs = num_cseg_total; if (num_open_array_segs < 2) num_open_array_segs = 2; G_debug(1, "A* search heap open segments %d, total %d", num_open_array_segs, num_cseg_total); /* the search heap will not hold more than 5% of all points at any given time ? */ /* chances are good that the heap will fit into one large segment */ seg_open(&search_heap, 1, do_points + 1, 1, seg_cols, num_open_array_segs, sizeof(HEAP_PNT)); G_message(_("SECTION 1b: Determining Offmap Flow.")); /* heap is empty */ heap_size = 0; if (pit_flag) { buf = Rast_allocate_c_buf(); fd = Rast_open_old(pit_name, ""); } else buf = NULL; first_astar = first_cum = -1; for (r = 0; r < nrows; r++) { G_percent(r, nrows, 1); if (pit_flag) Rast_get_c_row(fd, buf, r); for (c = 0; c < ncols; c++) { seg_get(&aspflag, (char *)&af, r, c); if (!FLAG_GET(af.flag, NULLFLAG)) { if (er_flag) dseg_put(&s_l, &half_res, r, c); asp_value = af.asp; if (r == 0 || c == 0 || r == nrows - 1 || c == ncols - 1) { /* dseg_get(&wat, &wat_value, r, c); */ seg_get(&watalt, (char *)&wa, r, c); wat_value = wa.wat; if (wat_value > 0) { wat_value = -wat_value; /* dseg_put(&wat, &wat_value, r, c); */ wa.wat = wat_value; seg_put(&watalt, (char *)&wa, r, c); } if (r == 0) asp_value = -2; else if (c == 0) asp_value = -4; else if (r == nrows - 1) asp_value = -6; else if (c == ncols - 1) asp_value = -8; /* cseg_get(&alt, &alt_value, r, c); */ alt_value = wa.ele; add_pt(r, c, alt_value); FLAG_SET(af.flag, INLISTFLAG); FLAG_SET(af.flag, EDGEFLAG); af.asp = asp_value; seg_put(&aspflag, (char *)&af, r, c); } else { seg_get(&watalt, (char *)&wa, r, c); 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]; seg_get(&aspflag, (char *)&af_nbr, r_nbr, c_nbr); if (FLAG_GET(af_nbr.flag, NULLFLAG)) { af.asp = -1 * drain[r - r_nbr + 1][c - c_nbr + 1]; add_pt(r, c, wa.ele); FLAG_SET(af.flag, INLISTFLAG); FLAG_SET(af.flag, EDGEFLAG); seg_put(&aspflag, (char *)&af, r, c); wat_value = wa.wat; if (wat_value > 0) { wa.wat = -wat_value; seg_put(&watalt, (char *)&wa, r, c); } break; } } } /* real depression ? */ if (pit_flag && asp_value == 0) { if (!Rast_is_c_null_value(&buf[c]) && buf[c] != 0) { seg_get(&watalt, (char *)&wa, r, c); add_pt(r, c, wa.ele); FLAG_SET(af.flag, INLISTFLAG); FLAG_SET(af.flag, EDGEFLAG); seg_put(&aspflag, (char *)&af, r, c); wat_value = wa.wat; if (wat_value > 0) { wa.wat = -wat_value; seg_put(&watalt, (char *)&wa, r, c); } } } } /* end non-NULL cell */ } /* end column */ } G_percent(r, nrows, 1); /* finish it */ return 0; }
int thin_seg(int stream_id) { int thinned = 0; int r, c, r_nbr, c_nbr, last_r, last_c; CELL curr_stream, no_stream = 0; 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 }; ASP_FLAG af; r = stream_node[stream_id].r; c = stream_node[stream_id].c; cseg_get(&stream, &curr_stream, r, c); seg_get(&aspflag, (char *)&af, r, c); if (af.asp > 0) { /* get downstream point */ last_r = r + asp_r[(int)af.asp]; last_c = c + asp_c[(int)af.asp]; cseg_get(&stream, &curr_stream, last_r, last_c); if (curr_stream != stream_id) return thinned; /* get next downstream point */ seg_get(&aspflag, (char *)&af, last_r, last_c); while (af.asp > 0) { r_nbr = last_r + asp_r[(int)af.asp]; c_nbr = last_c + asp_c[(int)af.asp]; if (r_nbr == last_r && c_nbr == last_c) return thinned; if (r_nbr < 0 || r_nbr >= nrows || c_nbr < 0 || c_nbr >= ncols) return thinned; cseg_get(&stream, &curr_stream, r_nbr, c_nbr); if (curr_stream != stream_id) return thinned; if (abs(r_nbr - r) < 2 && abs(c_nbr - c) < 2) { /* eliminate last point */ cseg_put(&stream, &no_stream, last_r, last_c); FLAG_UNSET(af.flag, STREAMFLAG); seg_put(&aspflag, (char *)&af, last_r, last_c); /* update start point */ seg_get(&aspflag, (char *)&af, r, c); af.asp = drain[r - r_nbr + 1][c - c_nbr + 1]; seg_put(&aspflag, (char *)&af, r, c); thinned = 1; } else { /* nothing to eliminate, continue from last point */ r = last_r; c = last_c; } last_r = r_nbr; last_c = c_nbr; seg_get(&aspflag, (char *)&af, last_r, last_c); } } return thinned; }
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; }