[GRASS-SVN] r71963 - in grass/trunk/raster: r.cost r.walk

svn_grass at osgeo.org svn_grass at osgeo.org
Wed Dec 20 14:09:39 PST 2017


Author: mmetz
Date: 2017-12-20 14:09:39 -0800 (Wed, 20 Dec 2017)
New Revision: 71963

Modified:
   grass/trunk/raster/r.cost/main.c
   grass/trunk/raster/r.cost/r.cost.html
   grass/trunk/raster/r.cost/stash.h
   grass/trunk/raster/r.walk/main.c
   grass/trunk/raster/r.walk/r.walk.html
   grass/trunk/raster/r.walk/stash.h
Log:
r.cost/r.walk: add bitmask encoded directions, use r.path instead of r.drain

Modified: grass/trunk/raster/r.cost/main.c
===================================================================
--- grass/trunk/raster/r.cost/main.c	2017-12-20 22:06:06 UTC (rev 71962)
+++ grass/trunk/raster/r.cost/main.c	2017-12-20 22:09:39 UTC (rev 71963)
@@ -79,8 +79,6 @@
 
 struct Cell_head window;
 
-struct start_pt *head_start_pt = NULL;
-
 struct rc
 {
     int r;
@@ -132,11 +130,12 @@
     long n_processed = 0;
     long total_cells;
     struct GModule *module;
-    struct Flag *flag2, *flag3, *flag4, *flag5;
+    struct Flag *flag2, *flag3, *flag4, *flag5, *flag6;
     struct Option *opt1, *opt2, *opt3, *opt4, *opt5, *opt6, *opt7, *opt8;
     struct Option *opt9, *opt10, *opt11, *opt12;
     struct cost *pres_cell;
-    struct start_pt *pres_start_pt = NULL;
+    struct start_pt *head_start_pt = NULL;
+    struct start_pt *next_start_pt;
     struct cc {
 	double cost_in, cost_out, nearest;
     } costs;
@@ -150,6 +149,7 @@
     double peak = 0.0;
     int dsize, nearest_size;
     double disk_mb, mem_mb, pq_mb;
+    int dir_bin;
 
     G_gisinit(argv[0]);
 
@@ -263,6 +263,11 @@
     flag5->key = 'i';
     flag5->description = _("Print info about disk space and memory requirements and exit");
 
+    flag6 = G_define_flag();
+    flag6->key = 'b';
+    flag6->description = _("Create bitmask encoded directions");
+    flag6->guisection = _("Optional outputs");
+
     /* Parse options */
     if (G_parser(argc, argv))
 	exit(EXIT_FAILURE);
@@ -300,6 +305,8 @@
 
     start_with_raster_vals = flag4->answer;
 
+    dir_bin = flag6->answer;
+
     {
 	int count = 0;
 
@@ -315,7 +322,8 @@
     }
 
     if (opt3->answers) {
-	if (!process_start_coords(opt3->answers, &head_start_pt, &pres_start_pt))
+	head_start_pt = process_start_coords(opt3->answers, head_start_pt);
+	if (!head_start_pt)
 	    G_fatal_error(_("No start points"));
     }
 
@@ -520,11 +528,14 @@
     }
 
     if (dir == 1) {
+	FCELL fnullval;
+
 	G_message(_("Initializing directional output..."));
+	Rast_set_f_null_value(&fnullval, 1);
 	for (row = 0; row < nrows; row++) {
 	    G_percent(row, nrows, 2);
 	    for (col = 0; col < ncols; col++) {
-		Segment_put(&dir_seg, &dnullval, row, col);
+		Segment_put(&dir_seg, &fnullval, row, col);
 	    }
 	}
 	G_percent(1, 1, 1);
@@ -540,7 +551,6 @@
 	struct line_pnts *Points;
 	struct line_cats *Cats;
 	struct bound_box box;
-	struct start_pt *new_start_pt;
 	int cat, type, npoints = 0;
 
 	Points = Vect_new_line_struct();
@@ -577,24 +587,15 @@
 	    col = (int)Rast_easting_to_col(Points->x[0], &window);
 	    row = (int)Rast_northing_to_row(Points->y[0], &window);
 
-	    new_start_pt =
+	    next_start_pt =
 		(struct start_pt *)(G_malloc(sizeof(struct start_pt)));
 
-	    new_start_pt->row = row;
-	    new_start_pt->col = col;
+	    next_start_pt->row = row;
+	    next_start_pt->col = col;
 	    Vect_cat_get(Cats, 1, &cat);
-	    new_start_pt->value = cat;
-	    new_start_pt->next = NULL;
-
-	    if (head_start_pt == NULL) {
-		head_start_pt = new_start_pt;
-		pres_start_pt = new_start_pt;
-		new_start_pt->next = NULL;
-	    }
-	    else {
-		pres_start_pt->next = new_start_pt;
-		pres_start_pt = new_start_pt;
-	    }
+	    next_start_pt->value = cat;
+	    next_start_pt->next = head_start_pt;
+	    head_start_pt = next_start_pt;
 	}
 
 	if (npoints < 1)
@@ -714,26 +715,24 @@
 	    G_fatal_error(_("No start points"));
     }
 
-    /*  Insert start points into min heap
-     */
+    /*  Insert start points into min heap */
     if (head_start_pt) {
-	struct start_pt *top_start_pt = NULL;
 
-	top_start_pt = head_start_pt;
-	while (top_start_pt != NULL) {
+	next_start_pt = head_start_pt;
+	while (next_start_pt != NULL) {
 	    value = &zero;
-	    if (top_start_pt->row < 0 || top_start_pt->row >= nrows
-		|| top_start_pt->col < 0 || top_start_pt->col >= ncols)
+	    if (next_start_pt->row < 0 || next_start_pt->row >= nrows
+		|| next_start_pt->col < 0 || next_start_pt->col >= ncols)
 		G_fatal_error(_("Specified starting location outside database window"));
-	    insert(zero, top_start_pt->row, top_start_pt->col);
-	    Segment_get(&cost_seg, &costs, top_start_pt->row,
-			top_start_pt->col);
+	    insert(zero, next_start_pt->row, next_start_pt->col);
+	    Segment_get(&cost_seg, &costs, next_start_pt->row,
+			next_start_pt->col);
 	    costs.cost_out = *value;
-	    costs.nearest = top_start_pt->value;
+	    costs.nearest = next_start_pt->value;
 
-	    Segment_put(&cost_seg, &costs, top_start_pt->row,
-			top_start_pt->col);
-	    top_start_pt = top_start_pt->next;
+	    Segment_put(&cost_seg, &costs, next_start_pt->row,
+			next_start_pt->col);
+	    next_start_pt = next_start_pt->next;
 	}
     }
 
@@ -819,7 +818,7 @@
 	 * 202.5 225   270  315   337.5
 	 *       247.5      292.5
 	 * 
-	 * X = present cell, directions for neighbors:
+	 * X = current cell:
 	 * 
 	 *       292.5      247.5 
 	 * 337.5 315   270  225    202.5
@@ -828,75 +827,134 @@
 	 *        67.5      112.5
 	 */
 
+	/* drainage directions bitmask encoded CW from North
+	 * drainage directions are set for each neighbor and must be 
+	 * read as from neighbor to current cell
+	 * 
+	 * bit positions, zero-based, from neighbor to current cell
+	 * 
+	 *     X = neighbor                X = current cell
+	 * 
+	 *      15       8                   11      12 
+	 *    14 6   7   0  9              10 2   3   4 13
+	 *       5   X   1                    1   X   5
+	 *    13 4   3   2 10               9 0   7   6 14
+	 *      12      11                    8      15
+	 */
+
 	for (neighbor = 1; neighbor <= total_reviewed; neighbor++) {
 	    switch (neighbor) {
 	    case 1:
+		row = pres_cell->row;
 		col = pres_cell->col - 1;
 		cur_dir = 360.0;
+		if (dir_bin)
+		    cur_dir = 1;
 		break;
 	    case 2:
+		row = pres_cell->row;
 		col = pres_cell->col + 1;
 		cur_dir = 180.0;
+		if (dir_bin)
+		    cur_dir = 5;
 		break;
 	    case 3:
 		row = pres_cell->row - 1;
 		col = pres_cell->col;
 		cur_dir = 270.0;
+		if (dir_bin)
+		    cur_dir = 3;
 		break;
 	    case 4:
 		row = pres_cell->row + 1;
+		col = pres_cell->col;
 		cur_dir = 90.0;
+		if (dir_bin)
+		    cur_dir = 7;
 		break;
 	    case 5:
 		row = pres_cell->row - 1;
 		col = pres_cell->col - 1;
 		cur_dir = 315.0;
+		if (dir_bin)
+		    cur_dir = 2;
 		break;
 	    case 6:
+		row = pres_cell->row - 1;
 		col = pres_cell->col + 1;
 		cur_dir = 225.0;
+		if (dir_bin)
+		    cur_dir = 4;
 		break;
 	    case 7:
 		row = pres_cell->row + 1;
+		col = pres_cell->col + 1;
 		cur_dir = 135.0;
+		if (dir_bin)
+		    cur_dir = 6;
 		break;
 	    case 8:
+		row = pres_cell->row + 1;
 		col = pres_cell->col - 1;
 		cur_dir = 45.0;
+		if (dir_bin)
+		    cur_dir = 0;
 		break;
 	    case 9:
 		row = pres_cell->row - 2;
 		col = pres_cell->col - 1;
 		cur_dir = 292.5;
+		if (dir_bin)
+		    cur_dir = 11;
 		break;
 	    case 10:
+		row = pres_cell->row - 2;
 		col = pres_cell->col + 1;
 		cur_dir = 247.5;
+		if (dir_bin)
+		    cur_dir = 12;
 		break;
 	    case 11:
 		row = pres_cell->row + 2;
+		col = pres_cell->col + 1;
 		cur_dir = 112.5;
+		if (dir_bin)
+		    cur_dir = 15;
 		break;
 	    case 12:
+		row = pres_cell->row + 2;
 		col = pres_cell->col - 1;
 		cur_dir = 67.5;
+		if (dir_bin)
+		    cur_dir = 8;
 		break;
 	    case 13:
 		row = pres_cell->row - 1;
 		col = pres_cell->col - 2;
 		cur_dir = 337.5;
+		if (dir_bin)
+		    cur_dir = 10;
 		break;
 	    case 14:
+		row = pres_cell->row - 1;
 		col = pres_cell->col + 2;
 		cur_dir = 202.5;
+		if (dir_bin)
+		    cur_dir = 13;
 		break;
 	    case 15:
 		row = pres_cell->row + 1;
+		col = pres_cell->col + 2;
 		cur_dir = 157.5;
+		if (dir_bin)
+		    cur_dir = 14;
 		break;
 	    case 16:
+		row = pres_cell->row + 1;
 		col = pres_cell->col - 2;
 		cur_dir = 22.5;
+		if (dir_bin)
+		    cur_dir = 9;
 		break;
 	    }
 
@@ -1005,6 +1063,8 @@
 		Segment_put(&cost_seg, &costs, row, col);
 		insert(min_cost, row, col);
 		if (dir == 1) {
+		    if (dir_bin)
+			cur_dir = (1 << (int)cur_dir);
 		    Segment_put(&dir_seg, &cur_dir, row, col);
 		}
 	    }
@@ -1015,9 +1075,28 @@
 		Segment_put(&cost_seg, &costs, row, col);
 		insert(min_cost, row, col);
 		if (dir == 1) {
+		    if (dir_bin)
+			cur_dir = (1 << (int)cur_dir);
 		    Segment_put(&dir_seg, &cur_dir, row, col);
 		}
 	    }
+	    else if (dir && dir_bin && old_min_cost == min_cost) {
+		FCELL old_dir;
+		int dir_inv[16] = { 4, 5, 6, 7, 0, 1, 2, 3,
+		                   12, 13, 14, 15, 8, 9, 10, 11 };
+		int dir_fwd;
+
+		/* this can create circular paths:
+		 * set only if current cell does not point to neighbor
+                 * does not avoid longer circular paths */
+		Segment_get(&dir_seg, &old_dir, pres_cell->row, pres_cell->col);
+		dir_fwd = (1 << dir_inv[(int)cur_dir]);
+		if (!((int)old_dir & dir_fwd)) {
+		    Segment_get(&dir_seg, &old_dir, row, col);
+		    cur_dir = ((1 << (int)cur_dir) | (int)old_dir);
+		    Segment_put(&dir_seg, &cur_dir, row, col);
+		}
+	    }
 	}
 
 	if (stop_pnts && time_to_stop(pres_cell->row, pres_cell->col))
@@ -1220,17 +1299,14 @@
     exit(EXIT_SUCCESS);
 }
 
-int
-process_start_coords(char **answers, struct start_pt **points,
-		struct start_pt **top_start_pt)
+struct start_pt *
+process_start_coords(char **answers, struct start_pt *top_start_pt)
 {
     int col, row;
     double east, north;
     struct start_pt *new_start_pt;
     int point_no = 0;
 
-    *points = NULL;
-
     if (!answers)
 	return (0);
 
@@ -1255,19 +1331,11 @@
 	new_start_pt->row = row;
 	new_start_pt->col = col;
 	new_start_pt->value = ++point_no;
-	new_start_pt->next = NULL;
+	new_start_pt->next = top_start_pt;
+	top_start_pt = new_start_pt;
+    }
 
-	if (*points == NULL) {
-	    *points = new_start_pt;
-	    *top_start_pt = new_start_pt;
-	    new_start_pt->next = NULL;
-	}
-	else {
-	    (*top_start_pt)->next = new_start_pt;
-	    *top_start_pt = new_start_pt;
-	}
-    }
-    return (point_no > 0);
+    return top_start_pt;
 }
 
 int process_stop_coords(char **answers)

Modified: grass/trunk/raster/r.cost/r.cost.html
===================================================================
--- grass/trunk/raster/r.cost/r.cost.html	2017-12-20 22:06:06 UTC (rev 71962)
+++ grass/trunk/raster/r.cost/r.cost.html	2017-12-20 22:09:39 UTC (rev 71963)
@@ -102,21 +102,10 @@
 
 <h2>NOTES</h2>
 
-Sometimes, when the differences among integer cell category values in the
-<em>r.cost</em> cumulative cost surface output are small, this
-cumulative cost output cannot accurately be used as input to <em><a href="r.drain.html">r.drain</a></em>
-(<em><a href="r.drain.html">r.drain</a></em> will output bad
-results). This problem can be circumvented by making the differences
-between cell category values in the cumulative cost output bigger. It
-is recommended that, if the output from <em>r.cost</em> is to be used
-as input to <em><a href="r.drain.html">r.drain</a></em>, the user
-multiply the input cost surface map to <em>r.cost</em> by the value
-of the map's cell resolution, before running <em>r.cost</em>. This
-can be done using <em><a href="r.mapcalc.html">r.mapcalc</a></em>. The map 
-resolution can be found using <em><a href="g.region.html">g.region</a></em>.
-This problem doesn't arise with floating point maps.
+Paths from any point to the nearest starting point of <em>r.cost</em> 
+can be extracted with <em><a href="r.path.html">r.path</a></em> by 
+using the direction output map of <em>r.cost</em>.
 
-
 <h3>Algorithm notes</h3>
 
 The fundamental approach to calculating minimum travel cost is as
@@ -202,9 +191,9 @@
 <h3>Output analysis</h3>
 
 The output map can be viewed, for example, as an elevation model in which
-the starting location(s) is/are the lowest point(s). Outputs from  <em>r.cost</em>
-can be used as inputs to <em><a href="r.drain.html">r.drain</a></em> with
-the direction flag <b>-d</b>, in order to trace the least-cost path given by this 
+the starting location(s) is/are the lowest point(s). Outputs from <em>r.cost</em>
+can be used as inputs to <em><a href="r.path.html">r.path</a></em> , 
+in order to trace the least-cost path given by this 
 model between any given cell and the <em>r.cost</em> starting location(s). The 
 two programs, when used together, generate least-cost paths or corridors between any 
 two map locations (cells).
@@ -231,10 +220,11 @@
 <a name="move"></a>
 <h2>Movement Direction</h2>
 The movement direction surface is created to record the sequence of
-movements that created the cost accumulation surface. Without it 
-<em><a href="r.drain.html">r.drain</a></em> would not correctly create a path from an end point 
-back to the start point. The direction of each cell points towards 
-the next cell. The directions are recorded as degrees CCW from East:
+movements that created the cost accumulation surface. This movement 
+direction surface can be used by <em><a href="r.path.html">r.path</a></em> 
+to recover a path from an end point back to the start point. 
+The direction of each cell points towards the next cell. 
+The directions are recorded as degrees CCW from East:
 
 <div class="code"><pre>
        112.5      67.5         i.e. a cell with the value 135 
@@ -256,26 +246,26 @@
 
 
 <h3>Find the minimum cost path</h3>
-Once <em>r.cost</em> computes the cumulative cost map, <em><a href="r.drain.html">r.drain</a></em>
-can be used to find the minimum cost path. Make sure to use the <b>-d</b> flag
-and the movement direction raster map when running r.drain to ensure
-the path is computed according to the proper movement directions.
+Once <em>r.cost</em> computes the cumulative cost map and an associated 
+movement direction map, <em><a href="r.path.html">r.path</a></em>
+can be used to find the minimum cost path.
 
 <h2>SEE ALSO</h2>
 
 <em>
-<a href="r.drain.html">r.drain</a>,
 <a href="r.walk.html">r.walk</a>,
+<a href="r.path.html">r.path</a>,
 <a href="r.in.ascii.html">r.in.ascii</a>,
 <a href="r.mapcalc.html">r.mapcalc</a>,
 <a href="r.out.ascii.html">r.out.ascii</a>
 </em>
 
-<h2>AUTHOR</h2>
+<h2>AUTHORS</h2>
 
 Antony Awaida, Intelligent Engineering Systems Laboratory, M.I.T.<br>
 James Westervelt, U.S.Army Construction Engineering Research Laboratory<br>
 Updated for Grass 5 by Pierre de Mouveaux (pmx at audiovu.com) 
+Markus Metz
 
 <p>
 <i>Last changed: $Date$</i>

Modified: grass/trunk/raster/r.cost/stash.h
===================================================================
--- grass/trunk/raster/r.cost/stash.h	2017-12-20 22:06:06 UTC (rev 71962)
+++ grass/trunk/raster/r.cost/stash.h	2017-12-20 22:09:39 UTC (rev 71963)
@@ -28,7 +28,7 @@
     struct start_pt *next;
 };
 
-int process_start_coords(char **, struct start_pt **, struct start_pt **);
+struct start_pt *process_start_coords(char **, struct start_pt *);
 int process_stop_coords(char **answers);
 int time_to_stop(int, int);
 

Modified: grass/trunk/raster/r.walk/main.c
===================================================================
--- grass/trunk/raster/r.walk/main.c	2017-12-20 22:06:06 UTC (rev 71962)
+++ grass/trunk/raster/r.walk/main.c	2017-12-20 22:09:39 UTC (rev 71963)
@@ -36,7 +36,7 @@
  *               License (>=v2). Read the file COPYING that comes with GRASS
  *               for details.
  *
- *****************************************************************************/
+ ***************************************************************************/
 
 /*********************************************************************
  *
@@ -113,8 +113,6 @@
 
 struct Cell_head window;
 
-struct start_pt *head_start_pt = NULL;
-
 struct rc
 {
     int r;
@@ -168,11 +166,12 @@
     long n_processed = 0;
     long total_cells;
     struct GModule *module;
-    struct Flag *flag2, *flag3, *flag4, *flag5;
+    struct Flag *flag2, *flag3, *flag4, *flag5, *flag6;
     struct Option *opt1, *opt2, *opt3, *opt4, *opt5, *opt6, *opt7, *opt8;
     struct Option *opt9, *opt10, *opt11, *opt12, *opt13, *opt14, *opt15;
     struct cost *pres_cell;
-    struct start_pt *pres_start_pt = NULL;
+    struct start_pt *head_start_pt = NULL;
+    struct start_pt *next_start_pt;
     struct cc {
 	double dtm;		/* elevation model */
 	double cost_in;		/* friction costs */
@@ -186,6 +185,7 @@
     double peak = 0.0;
     int dtm_dsize, cost_dsize;
     double disk_mb, mem_mb, pq_mb;
+    int dir_bin;
 
     /* Definition for dimension and region check */
     struct Cell_head dtm_cellhd, cost_cellhd;
@@ -330,6 +330,11 @@
     flag5->key = 'i';
     flag5->description = _("Print info about disk space and memory requirements and exit");
 
+    flag6 = G_define_flag();
+    flag6->key = 'b';
+    flag6->description = _("Create bitmask encoded directions");
+    flag6->guisection = _("Optional outputs");
+
     /* Parse options */
     if (G_parser(argc, argv))
 	exit(EXIT_FAILURE);
@@ -361,6 +366,8 @@
 
     start_with_raster_vals = flag4->answer;
 
+    dir_bin = flag6->answer;
+
     {
 	int count = 0;
 
@@ -376,7 +383,8 @@
     }
 
     if (opt3->answers) {
-	if (!process_start_coords(opt3->answers, &head_start_pt, &pres_start_pt))
+	head_start_pt = process_start_coords(opt3->answers, head_start_pt);
+	if (!head_start_pt)
 	    G_fatal_error(_("No start points"));
     }
 
@@ -660,17 +668,19 @@
     }
 
     if (dir == 1) {
+	FCELL fnullval;
+
 	G_message(_("Initializing directional output..."));
+	Rast_set_f_null_value(&fnullval, 1);
 	for (row = 0; row < nrows; row++) {
 	    G_percent(row, nrows, 2);
 	    for (col = 0; col < ncols; col++) {
-		Segment_put(&dir_seg, &dnullval, row, col);
+		Segment_put(&dir_seg, &fnullval, row, col);
 	    }
 	}
 	G_percent(1, 1, 1);
     }
-
-    /*   Scan the existing cum_cost_layer searching for starting points.
+    /*   Scan the start_points layer searching for starting points.
      *   Create a heap of starting points ordered by increasing costs.
      */
     init_heap();
@@ -681,7 +691,6 @@
 	struct line_pnts *Points;
 	struct line_cats *Cats;
 	struct bound_box box;
-	struct start_pt *new_start_pt;
 	int cat, type, npoints = 0;
 
 	Points = Vect_new_line_struct();
@@ -718,24 +727,15 @@
 	    col = (int)Rast_easting_to_col(Points->x[0], &window);
 	    row = (int)Rast_northing_to_row(Points->y[0], &window);
 
-	    new_start_pt =
+	    next_start_pt =
 		(struct start_pt *)(G_malloc(sizeof(struct start_pt)));
 
-	    new_start_pt->row = row;
-	    new_start_pt->col = col;
+	    next_start_pt->row = row;
+	    next_start_pt->col = col;
 	    Vect_cat_get(Cats, 1, &cat);
-	    new_start_pt->value = cat;
-	    new_start_pt->next = NULL;
-
-	    if (head_start_pt == NULL) {
-		head_start_pt = new_start_pt;
-		pres_start_pt = new_start_pt;
-		new_start_pt->next = NULL;
-	    }
-	    else {
-		pres_start_pt->next = new_start_pt;
-		pres_start_pt = new_start_pt;
-	    }
+	    next_start_pt->value = cat;
+	    next_start_pt->next = head_start_pt;
+	    head_start_pt = next_start_pt;
 	}
 
 	if (npoints < 1)
@@ -826,9 +826,9 @@
 
 		    Segment_get(&cost_seg, &costs, row, col);
 
+		    cellval = Rast_get_d_value(ptr2, data_type2);
 		    if (start_with_raster_vals == 1) {
-			cellval = Rast_get_d_value(ptr2, data_type2);
-			insert(cellval, row, col);
+                        insert(cellval, row, col);
 			costs.cost_out = cellval;
 			Segment_put(&cost_seg, &costs, row, col);
 		    }
@@ -852,24 +852,22 @@
 	    G_fatal_error(_("No start points"));
     }
 
-    /*  Insert start points into min heap
-     */
+    /*  Insert start points into min heap */
     if (head_start_pt) {
-	struct start_pt *top_start_pt = NULL;
 
-	top_start_pt = head_start_pt;
-	while (top_start_pt != NULL) {
+	next_start_pt = head_start_pt;
+	while (next_start_pt != NULL) {
 	    value = &zero;
-	    if (top_start_pt->row < 0 || top_start_pt->row >= nrows
-		|| top_start_pt->col < 0 || top_start_pt->col >= ncols)
+	    if (next_start_pt->row < 0 || next_start_pt->row >= nrows
+		|| next_start_pt->col < 0 || next_start_pt->col >= ncols)
 		G_fatal_error(_("Specified starting location outside database window"));
-	    insert(zero, top_start_pt->row, top_start_pt->col);
-	    Segment_get(&cost_seg, &costs, top_start_pt->row,
-			top_start_pt->col);
+	    insert(zero, next_start_pt->row, next_start_pt->col);
+	    Segment_get(&cost_seg, &costs, next_start_pt->row,
+			next_start_pt->col);
 	    costs.cost_out = *value;
-	    Segment_put(&cost_seg, &costs, top_start_pt->row,
-			top_start_pt->col);
-	    top_start_pt = top_start_pt->next;
+	    Segment_put(&cost_seg, &costs, next_start_pt->row,
+			next_start_pt->col);
+	    next_start_pt = next_start_pt->next;
 	}
     }
 
@@ -973,7 +971,7 @@
 	 * 202.5 225   270  315   337.5
 	 *       247.5      292.5
 	 * 
-	 * X = present cell, directions for neighbors:
+	 * X = current cell:
 	 * 
 	 *       292.5      247.5 
 	 * 337.5 315   270  225    202.5
@@ -982,75 +980,134 @@
 	 *        67.5      112.5
 	 */
 
+	/* drainage directions bitmask encoded CW from North
+	 * drainage directions are set for each neighbor and must be 
+	 * read as from neighbor to current cell
+	 * 
+	 * bit positions, zero-based, from neighbor to current cell
+	 * 
+	 *     X = neighbor                X = current cell
+	 * 
+	 *      15       8                   11      12 
+	 *    14 6   7   0  9              10 2   3   4 13
+	 *       5   X   1                    1   X   5
+	 *    13 4   3   2 10               9 0   7   6 14
+	 *      12      11                    8      15
+	 */
+
 	for (neighbor = 1; neighbor <= total_reviewed; neighbor++) {
 	    switch (neighbor) {
 	    case 1:
+		row = pres_cell->row;
 		col = pres_cell->col - 1;
 		cur_dir = 360.0;
+		if (dir_bin)
+		    cur_dir = 1;
 		break;
 	    case 2:
+		row = pres_cell->row;
 		col = pres_cell->col + 1;
 		cur_dir = 180.0;
+		if (dir_bin)
+		    cur_dir = 5;
 		break;
 	    case 3:
 		row = pres_cell->row - 1;
 		col = pres_cell->col;
 		cur_dir = 270.0;
+		if (dir_bin)
+		    cur_dir = 3;
 		break;
 	    case 4:
 		row = pres_cell->row + 1;
+		col = pres_cell->col;
 		cur_dir = 90.0;
+		if (dir_bin)
+		    cur_dir = 7;
 		break;
 	    case 5:
 		row = pres_cell->row - 1;
 		col = pres_cell->col - 1;
 		cur_dir = 315.0;
+		if (dir_bin)
+		    cur_dir = 2;
 		break;
 	    case 6:
+		row = pres_cell->row - 1;
 		col = pres_cell->col + 1;
 		cur_dir = 225.0;
+		if (dir_bin)
+		    cur_dir = 4;
 		break;
 	    case 7:
 		row = pres_cell->row + 1;
+		col = pres_cell->col + 1;
 		cur_dir = 135.0;
+		if (dir_bin)
+		    cur_dir = 6;
 		break;
 	    case 8:
+		row = pres_cell->row + 1;
 		col = pres_cell->col - 1;
 		cur_dir = 45.0;
+		if (dir_bin)
+		    cur_dir = 0;
 		break;
 	    case 9:
 		row = pres_cell->row - 2;
 		col = pres_cell->col - 1;
 		cur_dir = 292.5;
+		if (dir_bin)
+		    cur_dir = 11;
 		break;
 	    case 10:
+		row = pres_cell->row - 2;
 		col = pres_cell->col + 1;
 		cur_dir = 247.5;
+		if (dir_bin)
+		    cur_dir = 12;
 		break;
 	    case 11:
 		row = pres_cell->row + 2;
+		col = pres_cell->col + 1;
 		cur_dir = 112.5;
+		if (dir_bin)
+		    cur_dir = 15;
 		break;
 	    case 12:
+		row = pres_cell->row + 2;
 		col = pres_cell->col - 1;
 		cur_dir = 67.5;
+		if (dir_bin)
+		    cur_dir = 8;
 		break;
 	    case 13:
 		row = pres_cell->row - 1;
 		col = pres_cell->col - 2;
 		cur_dir = 337.5;
+		if (dir_bin)
+		    cur_dir = 10;
 		break;
 	    case 14:
+		row = pres_cell->row - 1;
 		col = pres_cell->col + 2;
 		cur_dir = 202.5;
+		if (dir_bin)
+		    cur_dir = 13;
 		break;
 	    case 15:
 		row = pres_cell->row + 1;
+		col = pres_cell->col + 2;
 		cur_dir = 157.5;
+		if (dir_bin)
+		    cur_dir = 14;
 		break;
 	    case 16:
+		row = pres_cell->row + 1;
 		col = pres_cell->col - 2;
 		cur_dir = 22.5;
+		if (dir_bin)
+		    cur_dir = 9;
 		break;
 	    }
 
@@ -1358,6 +1415,8 @@
 		Segment_put(&cost_seg, &costs, row, col);
 		insert(min_cost, row, col);
 		if (dir == 1) {
+		    if (dir_bin)
+			cur_dir = (1 << (int)cur_dir);
 		    Segment_put(&dir_seg, &cur_dir, row, col);
 		}
 	    }
@@ -1367,9 +1426,28 @@
 		Segment_put(&cost_seg, &costs, row, col);
 		insert(min_cost, row, col);
 		if (dir == 1) {
+		    if (dir_bin)
+			cur_dir = (1 << (int)cur_dir);
 		    Segment_put(&dir_seg, &cur_dir, row, col);
 		}
 	    }
+	    else if (dir && dir_bin && old_min_cost == min_cost) {
+		FCELL old_dir;
+		int dir_inv[16] = { 4, 5, 6, 7, 0, 1, 2, 3,
+		                   12, 13, 14, 15, 8, 9, 10, 11 };
+		int dir_fwd;
+
+		/* this can create circular paths:
+		 * set only if current cell does not point to neighbor
+                 * does not avoid longer circular paths */
+		Segment_get(&dir_seg, &old_dir, pres_cell->row, pres_cell->col);
+		dir_fwd = (1 << dir_inv[(int)cur_dir]);
+		if (!((int)old_dir & dir_fwd)) {
+		    Segment_get(&dir_seg, &old_dir, row, col);
+		    cur_dir = ((1 << (int)cur_dir) | (int)old_dir);
+		    Segment_put(&dir_seg, &cur_dir, row, col);
+		}
+	    }
 	}
 
 	if (stop_pnts && time_to_stop(pres_cell->row, pres_cell->col))
@@ -1506,17 +1584,14 @@
     exit(EXIT_SUCCESS);
 }
 
-int
-process_start_coords(char **answers, struct start_pt **points,
-		struct start_pt **top_start_pt)
+struct start_pt *
+process_start_coords(char **answers, struct start_pt *top_start_pt)
 {
     int col, row;
     double east, north;
     struct start_pt *new_start_pt;
     int point_no = 0;
 
-    *points = NULL;
-
     if (!answers)
 	return (0);
 
@@ -1541,19 +1616,11 @@
 	new_start_pt->row = row;
 	new_start_pt->col = col;
 	new_start_pt->value = ++point_no;
-	new_start_pt->next = NULL;
+	new_start_pt->next = top_start_pt;
+	top_start_pt = new_start_pt;
+    }
 
-	if (*points == NULL) {
-	    *points = new_start_pt;
-	    *top_start_pt = new_start_pt;
-	    new_start_pt->next = NULL;
-	}
-	else {
-	    (*top_start_pt)->next = new_start_pt;
-	    *top_start_pt = new_start_pt;
-	}
-    }
-    return (point_no > 0);
+    return top_start_pt;
 }
 
 int process_stop_coords(char **answers)

Modified: grass/trunk/raster/r.walk/r.walk.html
===================================================================
--- grass/trunk/raster/r.walk/r.walk.html	2017-12-20 22:06:06 UTC (rev 71962)
+++ grass/trunk/raster/r.walk/r.walk.html	2017-12-20 22:09:39 UTC (rev 71963)
@@ -92,11 +92,14 @@
 
 <a name="move"></a>
 <h2>Movement Direction</h2>
-<p>The movement direction surface is created to record the sequence of
-movements that created the cost accumulation surface. Without it 
-<em><a href="r.drain.html">r.drain</a></em> would not correctly create a path from an end point 
-back to the start point. The direction of each cell points towards 
-the next cell. The directions are recorded as degrees CCW from East:
+<p>
+The movement direction surface is created to record the sequence of
+movements that created the cost accumulation surface. This movement 
+direction surface can be used by <em><a href="r.path.html">r.path</a></em> 
+to recover a path from an end point back to the start point. 
+The direction of each cell points towards the next cell. 
+The directions are recorded as degrees CCW from East:
+
 <div class="code"><pre>
        112.5      67.5         i.e. a cell with the value 135 
 157.5  135   90   45   22.5    means the next cell is to the north-west
@@ -108,12 +111,9 @@
 <p>
 Once <em>r.walk</em> computes the cumulative cost map as a linear
 combination of friction cost (from friction map) and the altitude and
-distance covered (from the digital elevation
-model), <em><a href="r.drain.html">r.drain</a></em> can be used to
-find the minimum cost path. Make sure to use the <b>-d</b> flag and
-the movement direction raster map when
-running <em><a href="r.drain.html">r.drain</a></em> to ensure the path
-is computed according to the proper movement directions.
+distance covered (from the digital elevation model), the associated 
+movement direction map can be used by <em><a href="r.path.html">r.path</a></em> 
+to find the minimum cost path.
 
 <p>
 <em>r.walk</em>, like most all GRASS raster programs, is also made to 
@@ -167,7 +167,7 @@
 
 <em>
 <a href="r.cost.html">r.cost</a>,
-<a href="r.drain.html">r.drain</a>,
+<a href="r.path.html">r.path</a>,
 <a href="r.in.ascii.html">r.in.ascii</a>,
 <a href="r.mapcalc.html">r.mapcalc</a>,
 <a href="r.out.ascii.html">r.out.ascii</a>

Modified: grass/trunk/raster/r.walk/stash.h
===================================================================
--- grass/trunk/raster/r.walk/stash.h	2017-12-20 22:06:06 UTC (rev 71962)
+++ grass/trunk/raster/r.walk/stash.h	2017-12-20 22:09:39 UTC (rev 71963)
@@ -28,7 +28,7 @@
     struct start_pt *next;
 };
 
-int process_start_coords(char **, struct start_pt **, struct start_pt **);
+struct start_pt *process_start_coords(char **, struct start_pt *);
 int process_stop_coords(char **answers);
 int time_to_stop(int, int);
 



More information about the grass-commit mailing list