Example #1
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);
	    }
	}
    }
}
Example #2
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;
}
Example #3
0
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;
}
Example #4
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;
}