[GRASS-SVN] r61064 - grass/trunk/vector/v.net.salesman
svn_grass at osgeo.org
svn_grass at osgeo.org
Sun Jun 29 08:24:46 PDT 2014
Author: turek
Date: 2014-06-29 08:24:46 -0700 (Sun, 29 Jun 2014)
New Revision: 61064
Modified:
grass/trunk/vector/v.net.salesman/main.c
grass/trunk/vector/v.net.salesman/v.net.salesman.html
Log:
v.net.salesman: added support for the turntable, guisections reorganized
Modified: grass/trunk/vector/v.net.salesman/main.c
===================================================================
--- grass/trunk/vector/v.net.salesman/main.c 2014-06-29 14:32:29 UTC (rev 61063)
+++ grass/trunk/vector/v.net.salesman/main.c 2014-06-29 15:24:46 UTC (rev 61064)
@@ -4,10 +4,11 @@
* MODULE: v.net.salesman
*
* AUTHOR(S): Radim Blazek, Markus Metz
+ * Stepan Turek <stepan.turek seznam.cz> (turns support)
*
* PURPOSE: Create a cycle connecting given nodes.
*
- * COPYRIGHT: (C) 2001-2011 by the GRASS Development Team
+ * COPYRIGHT: (C) 2001-2011,2014 by the GRASS Development Team
*
* This program is free software under the
* GNU General Public License (>=v2).
@@ -98,12 +99,12 @@
int main(int argc, char **argv)
{
int i, j, k, ret, city, city1;
- int nlines, type, ltype, afield, tfield, geo, cat;
+ int nlines, type, ltype, afield, nfield, tfield, tucfield, geo, cat;
int node, node1, node2, line;
- double **cost_cache; /* pointer to array of pointers to arrays of cached costs */
- struct Option *map, *output, *afield_opt, *tfield_opt, *afcol, *abcol,
- *seq, *type_opt, *term_opt;
- struct Flag *geo_f;
+ double **cost_cache; /* pointer to array of pointers to arrays of cached costs */
+ struct Option *map, *output, *afield_opt, *nfield_opt, *afcol, *abcol,
+ *seq, *type_opt, *term_opt, *tfield_opt, *tucfield_opt;
+ struct Flag *geo_f, *turntable_f;
struct GModule *module;
struct Map_info Map, Out;
struct ilist *TList; /* list of terminal nodes */
@@ -127,7 +128,8 @@
G_add_keyword(_("network"));
G_add_keyword(_("salesman"));
module->label =
- _("Creates a cycle connecting given nodes (Traveling salesman problem).");
+ _
+ ("Creates a cycle connecting given nodes (Traveling salesman problem).");
module->description =
_("Note that TSP is NP-hard, heuristic algorithm is used by "
"this module and created cycle may be sub optimal");
@@ -135,50 +137,76 @@
map = G_define_standard_option(G_OPT_V_INPUT);
output = G_define_standard_option(G_OPT_V_OUTPUT);
+ term_opt = G_define_standard_option(G_OPT_V_CATS);
+ term_opt->key = "ccats";
+ term_opt->required = YES;
+ term_opt->description = _("Categories of points ('cities') on nodes "
+ "(layer is specified by nlayer)");
+
+ afield_opt = G_define_standard_option(G_OPT_V_FIELD);
+ afield_opt->key = "alayer";
+ afield_opt->answer = "1";
+ afield_opt->required = YES;
+ afield_opt->label = _("Arc layer");
+
type_opt = G_define_standard_option(G_OPT_V_TYPE);
type_opt->options = "line,boundary";
type_opt->answer = "line,boundary";
+ type_opt->required = YES;
type_opt->description = _("Arc type");
- afield_opt = G_define_standard_option(G_OPT_V_FIELD);
- afield_opt->key = "alayer";
- afield_opt->label = _("Arc layer");
+ nfield_opt = G_define_standard_option(G_OPT_V_FIELD);
+ nfield_opt->key = "nlayer";
+ nfield_opt->answer = "2";
+ nfield_opt->required = YES;
+ nfield_opt->label = _("Node layer (used for cities)");
tfield_opt = G_define_standard_option(G_OPT_V_FIELD);
- tfield_opt->key = "nlayer";
- tfield_opt->answer = "2";
- tfield_opt->label = _("Node layer (used for cities)");
+ tfield_opt->key = "tlayer";
+ tfield_opt->answer = "3";
+ tfield_opt->label = _("Layer with turntable");
+ tfield_opt->description = _("Relevant only with -t flag.");
+ tfield_opt->guisection = _("Turntable");
+ tucfield_opt = G_define_standard_option(G_OPT_V_FIELD);
+ tucfield_opt->key = "tuclayer";
+ tucfield_opt->answer = "4";
+ tucfield_opt->label = _("Layer with unique categories used in turntable");
+ tucfield_opt->description = _("Relevant only with -t flag.");
+ tucfield_opt->guisection = _("Turntable");
+
afcol = G_define_option();
afcol->key = "afcolumn";
afcol->type = TYPE_STRING;
afcol->required = NO;
afcol->description =
_("Arc forward/both direction(s) cost column (number)");
+ afcol->guisection = _("Costs");
abcol = G_define_option();
abcol->key = "abcolumn";
abcol->type = TYPE_STRING;
abcol->required = NO;
- abcol->description = _("EXPERIMENTAL: Arc backward direction cost column (number)");
+ abcol->description =
+ _("EXPERIMENTAL: Arc backward direction cost column (number)");
+ abcol->guisection = _("Costs");
seq = G_define_standard_option(G_OPT_F_OUTPUT);
seq->key = "sequence";
seq->type = TYPE_STRING;
seq->required = NO;
- seq->description = _("Name for output file holding node sequence (\"-\" for stdout)");
+ seq->description =
+ _("Name for output file holding node sequence (\"-\" for stdout)");
- term_opt = G_define_standard_option(G_OPT_V_CATS);
- term_opt->key = "ccats";
- term_opt->required = YES;
- term_opt->description = _("Categories of points ('cities') on nodes "
- "(layer is specified by nlayer)");
-
geo_f = G_define_flag();
geo_f->key = 'g';
geo_f->description =
_("Use geodesic calculation for longitude-latitude locations");
+ turntable_f = G_define_flag();
+ turntable_f->key = 't';
+ turntable_f->description = _("Use turntable");
+
if (G_parser(argc, argv))
exit(EXIT_FAILURE);
@@ -186,7 +214,6 @@
Points = Vect_new_line_struct();
type = Vect_option_to_types(type_opt);
- afield = atoi(afield_opt->answer);
TList = Vect_new_list();
List = Vect_new_list();
@@ -194,9 +221,8 @@
StNodes = Vect_new_list();
Clist = Vect_new_cat_list();
- tfield = atoi(tfield_opt->answer);
Vect_str_to_cat_list(term_opt->answer, Clist);
-
+
dstr = G__getenv("DEBUG");
if (dstr != NULL)
@@ -223,27 +249,37 @@
if (Vect_open_old(&Map, map->answer, "") < 0)
G_fatal_error(_("Unable to open vector map <%s>"), map->answer);
+
+ afield = Vect_get_field_number(&Map, afield_opt->answer);
+ nfield = Vect_get_field_number(&Map, nfield_opt->answer);
+ tfield = Vect_get_field_number(&Map, tfield_opt->answer);
+ tucfield = Vect_get_field_number(&Map, tucfield_opt->answer);
+
nnodes = Vect_get_num_nodes(&Map);
nlines = Vect_get_num_lines(&Map);
/* Create list of terminals based on list of categories */
for (i = 1; i <= nlines; i++) {
-
+
ltype = Vect_get_line_type(&Map, i);
if (!(ltype & GV_POINT))
continue;
Vect_read_line(&Map, Points, Cats, i);
- if (!(Vect_cat_get(Cats, tfield, &cat)))
+
+ if (!(Vect_cat_get(Cats, nfield, &cat)))
continue;
if (Vect_cat_in_cat_list(cat, Clist)) {
- node = Vect_find_node(&Map, Points->x[0], Points->y[0], Points->z[0], 0, 0);
+ node =
+ Vect_find_node(&Map, Points->x[0], Points->y[0], Points->z[0],
+ 0, 0);
if (!node) {
G_warning(_("Point is not connected to the network"));
}
else
tsp_list_append(TList, node);
}
+
}
ncities = TList->n_values;
@@ -264,9 +300,9 @@
for (i = 0; i < ncities; i++) {
costs[i] = (COST *) G_malloc(ncities * sizeof(COST));
}
- cost_cache = (double **) G_malloc(ncities * sizeof(double *));
+ cost_cache = (double **)G_malloc(ncities * sizeof(double *));
for (i = 0; i < ncities; i++) {
- cost_cache[i] = (double *) G_malloc(ncities * sizeof(double));
+ cost_cache[i] = (double *)G_malloc(ncities * sizeof(double));
}
if (abcol->answer) {
bcosts = (COST **) G_malloc(ncities * sizeof(COST *));
@@ -280,8 +316,12 @@
cycle = (int *)G_malloc((ncities + 1) * sizeof(int)); /* + 1 is for output cycle */
/* Build graph */
- Vect_net_build_graph(&Map, type, afield, 0, afcol->answer, abcol->answer, NULL,
- geo, 0);
+ if (turntable_f->answer)
+ Vect_net_ttb_build_graph(&Map, type, afield, 0, tfield, tucfield,
+ afcol->answer, abcol->answer, NULL, geo, 0);
+ else
+ Vect_net_build_graph(&Map, type, afield, 0, afcol->answer,
+ abcol->answer, NULL, geo, 0);
/* Create sorted lists of costs */
/* for a large number of cities this will become very slow, can not be fixed */
@@ -294,33 +334,46 @@
if (i == j)
continue;
- ret =
- Vect_net_shortest_path(&Map, cities[i], cities[j], NULL,
- &cost);
+ if (turntable_f->answer)
+ ret =
+ Vect_net_ttb_shortest_path(&Map, cities[i], 0, cities[j],
+ 0, tucfield, NULL, &cost);
+ else
+ ret =
+ Vect_net_shortest_path(&Map, cities[i], cities[j], NULL,
+ &cost);
if (ret == -1) {
double coor_x, coor_y, coor_z;
int cat1, cat2;
-
- Vect_get_node_coor(&Map, cities[i], &coor_x, &coor_y, &coor_z);
- line = Vect_find_line(&Map, coor_x, coor_y, coor_z, GV_POINT, 0, 0, 0);
-
+
+ Vect_get_node_coor(&Map, cities[i], &coor_x, &coor_y,
+ &coor_z);
+ line =
+ Vect_find_line(&Map, coor_x, coor_y, coor_z, GV_POINT, 0,
+ 0, 0);
+
if (!line)
G_fatal_error(_("No point at node %d"), cities[i]);
Vect_read_line(&Map, Points, Cats, line);
- if (!(Vect_cat_get(Cats, tfield, &cat1)))
- G_fatal_error(_("No category for point at node %d"), cities[i]);
+ if (!(Vect_cat_get(Cats, nfield, &cat1)))
+ G_fatal_error(_("No category for point at node %d"),
+ cities[i]);
- Vect_get_node_coor(&Map, cities[j], &coor_x, &coor_y, &coor_z);
- line = Vect_find_line(&Map, coor_x, coor_y, coor_z, GV_POINT, 0, 0, 0);
-
+ Vect_get_node_coor(&Map, cities[j], &coor_x, &coor_y,
+ &coor_z);
+ line =
+ Vect_find_line(&Map, coor_x, coor_y, coor_z, GV_POINT, 0,
+ 0, 0);
+
if (!line)
G_fatal_error(_("No point at node %d"), cities[j]);
Vect_read_line(&Map, Points, Cats, line);
- if (!(Vect_cat_get(Cats, tfield, &cat2)))
- G_fatal_error(_("No category for point at node %d"), cities[j]);
+ if (!(Vect_cat_get(Cats, nfield, &cat2)))
+ G_fatal_error(_("No category for point at node %d"),
+ cities[j]);
G_fatal_error(_("Destination node [cat %d] is unreachable "
"from node [cat %d]"), cat1, cat2);
@@ -336,7 +389,7 @@
qsort((void *)costs[i], k, sizeof(COST), cmp);
}
G_percent(1, 1, 2);
-
+
if (bcosts) {
for (i = 0; i < ncities; i++) {
/* this should be fast, no need for G_percent() */
@@ -344,7 +397,7 @@
for (j = 0; j < ncities; j++) {
if (i == j)
continue;
-
+
bcosts[i][k].city = j;
bcosts[i][k].cost = cost_cache[j][i];
@@ -353,7 +406,7 @@
qsort((void *)bcosts[i], k, sizeof(COST), cmp);
}
}
-
+
if (debug_level >= 2) {
/* debug: print sorted */
for (i = 0; i < ncities; i++) {
@@ -375,8 +428,7 @@
city = i;
}
}
- G_debug(2, "biggest costs %d - %d", city,
- costs[city][ncities - 2].city);
+ G_debug(2, "biggest costs %d - %d", city, costs[city][ncities - 2].city);
/* add these 2 cities to array */
add_city(city, -1);
@@ -411,7 +463,7 @@
continue; /* only used */
/* directional costs k -> j */
tmpcost += bcosts[j][k].cost;
- break; /* first nearest */
+ break; /* first nearest */
}
}
@@ -443,7 +495,7 @@
/* get cost from directional cost cache */
tcost = cost_cache[city][cycle[j + 1]];
tmpcost += tcost;
-
+
/* tmpcost must always be > 0 */
G_debug(2, "? %d - %d cost = %f x %f", node1, node2, tmpcost,
@@ -456,7 +508,7 @@
}
add_city(city, city1);
}
-
+
/* TODO: optimize tour (some Lin-Kernighan method) */
if (debug_level >= 2) {
@@ -468,13 +520,20 @@
}
/* Create list of arcs */
- cycle[ncities] = cycle[0]; /* close the cycle */
+ cycle[ncities] = cycle[0]; /* close the cycle */
cost = 0.0;
for (i = 0; i < ncities; i++) {
node1 = cities[cycle[i]];
node2 = cities[cycle[i + 1]];
G_debug(2, " %d -> %d", node1, node2);
- ret = Vect_net_shortest_path(&Map, node1, node2, List, NULL);
+
+ if (turntable_f->answer)
+ ret =
+ Vect_net_ttb_shortest_path(&Map, node1, 0, node2, 0,
+ tucfield, List, NULL);
+ else
+ ret = Vect_net_shortest_path(&Map, node1, node2, List, NULL);
+
cost += cost_cache[cycle[i]][cycle[i + 1]];
for (j = 0; j < List->n_values; j++) {
line = abs(List->value[j]);
@@ -504,7 +563,7 @@
Vect_cat_get(Cats, afield, &cat);
G_debug(2, "%d. arc: cat %d", i + 1, cat);
}
-
+
seq2stdout = 0;
seqname = NULL;
if (seq->answer) {
@@ -518,8 +577,7 @@
fp = fopen(seqname, "w");
if (!fp)
- G_fatal_error(_("Unable to open file '%s' for writing"),
- seqname);
+ G_fatal_error(_("Unable to open file '%s' for writing"), seqname);
fprintf(fp, "sequence;category;cost_to_next\n");
}
@@ -528,27 +586,28 @@
k = 0;
/* this writes out only user-selected nodes, not all visited nodes */
- G_debug(2, "Nodes' categories (layer %d, %d nodes):", tfield,
- ncities);
+ G_debug(2, "Nodes' categories (layer %d, %d nodes):", nfield, ncities);
for (i = 0; i < ncities; i++) {
double coor_x, coor_y, coor_z;
-
+
node = cities[cycle[i]];
Vect_get_node_coor(&Map, node, &coor_x, &coor_y, &coor_z);
- line = Vect_find_line(&Map, coor_x, coor_y, coor_z, GV_POINT, 0, 0, 0);
-
+ line =
+ Vect_find_line(&Map, coor_x, coor_y, coor_z, GV_POINT, 0, 0, 0);
+
if (!line)
continue;
ltype = Vect_read_line(&Map, Points, Cats, line);
if (!(ltype & GV_POINT))
continue;
- if (!(Vect_cat_get(Cats, tfield, &cat)))
+ if (!(Vect_cat_get(Cats, nfield, &cat)))
continue;
Vect_write_line(&Out, ltype, Points, Cats);
k++;
if (fp) {
- fprintf(fp, "%d;%d;%.3f\n", k, cat, cost_cache[cycle[i]][cycle[i + 1]]);
+ fprintf(fp, "%d;%d;%.3f\n", k, cat,
+ cost_cache[cycle[i]][cycle[i + 1]]);
}
G_debug(2, "%d. node: cat %d", k, cat);
Modified: grass/trunk/vector/v.net.salesman/v.net.salesman.html
===================================================================
--- grass/trunk/vector/v.net.salesman/v.net.salesman.html 2014-06-29 14:32:29 UTC (rev 61063)
+++ grass/trunk/vector/v.net.salesman/v.net.salesman.html 2014-06-29 15:24:46 UTC (rev 61064)
@@ -20,8 +20,22 @@
<p>Points specified by category must be exactly on network nodes, and the
input vector map needs to be prepared with <em>v.net operation=connect</em>.
+<p>Application of flag <b>-t</b> enables a turntable support.
+This flag requires additional parameters <b>tlayer</b> and <b>tuclayer</b>
+that are otherwise ignored.
+ The turntable allows
+to model e.g. trafic code, where some turns may be prohibited.
+This means that the input layer is expanded by
+turntable with costs of every possible turn on any possible node
+(intersection) in both directions.
+ Turntable can be created by
+ the <em><a href="v.net.html">v.net</a></em> module.
+For more information about turns in the vector network analyses see
+<a href="http://grasswiki.osgeo.org/wiki/Turns_in_the_vector_network_analysis">wiki page</a>.
+
<h2>NOTES</h2>
Arcs can be closed using cost = -1.
+Turns support: The costs of turns on visiting nodes are not taken in account.
<h2>EXAMPLE</h2>
@@ -143,5 +157,13 @@
Markus Metz<br>
Documentation: Markus Neteler, Markus Metz
+<h3>TURNS SUPPORT</h3>
+The turns support was implemnented as part of GRASS GIS turns cost project at Czech Technical University in Prague, Czech Republic.
+Eliska Kyzlikova, Stepan Turek, Lukas Bocan and Viera Bejdova participated at the project.
+
+Implementation: Stepan Turek
+Documentation: Lukas Bocan
+Mentor: Martin Landa
+
<p><i>Last changed: $Date$</i>
More information about the grass-commit
mailing list