GRASS Programmer's Manual  6.5.svn(2014)-r66266
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
net.c
Go to the documentation of this file.
1 
20 #include <stdlib.h>
21 #include <string.h>
22 #include <fcntl.h>
23 #include <grass/gis.h>
24 #include <grass/dbmi.h>
25 #include <grass/Vect.h>
26 #include <grass/glocale.h>
27 
28 static int From_node; /* from node set in SP and used by clipper for first arc */
29 
30 static int clipper(dglGraph_s * pgraph,
31  dglSPClipInput_s * pargIn,
32  dglSPClipOutput_s * pargOut, void *pvarg)
33 { /* caller's pointer */
34  dglInt32_t cost;
35  dglInt32_t from;
36 
37  G_debug(3, "Net: clipper()");
38 
39  from = dglNodeGet_Id(pgraph, pargIn->pnNodeFrom);
40 
41  G_debug(3, " Edge = %d NodeFrom = %d NodeTo = %d edge cost = %d",
42  (int)dglEdgeGet_Id(pgraph, pargIn->pnEdge),
43  (int)from, (int)dglNodeGet_Id(pgraph, pargIn->pnNodeTo),
44  (int)pargOut->nEdgeCost);
45 
46  if (from != From_node) { /* do not clip first */
47  if (dglGet_NodeAttrSize(pgraph) > 0) {
48  memcpy(&cost, dglNodeGet_Attr(pgraph, pargIn->pnNodeFrom),
49  sizeof(cost));
50  if (cost == -1) { /* closed, cannot go from this node except it is 'from' node */
51  G_debug(3, " closed node");
52  return 1;
53  }
54  else {
55  G_debug(3, " EdgeCost += %d (node)", (int)cost);
56  pargOut->nEdgeCost += cost;
57  }
58  }
59  }
60  else {
61  G_debug(3, " don't clip first node");
62  }
63 
64  return 0;
65 }
66 
90 int
91 Vect_net_build_graph(struct Map_info *Map,
92  int ltype,
93  int afield,
94  int nfield,
95  const char *afcol,
96  const char *abcol,
97  const char *ncol, int geo, int algorithm)
98 {
99  int i, j, from, to, line, nlines, nnodes, ret, type, cat, skipped, cfound;
100  int dofw, dobw;
101  struct line_pnts *Points;
102  struct line_cats *Cats;
103  double dcost, bdcost, ll;
104  int cost, bcost;
105  dglGraph_s *gr;
106  dglInt32_t dgl_cost;
107  dglInt32_t opaqueset[16] =
108  { 360000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
109  struct field_info *Fi;
110  dbDriver *driver = NULL;
111  dbHandle handle;
112  dbString stmt;
113  dbColumn *Column;
114  dbCatValArray fvarr, bvarr;
115  int fctype = 0, bctype = 0, nrec;
116 
117  /* TODO int costs -> double (waiting for dglib) */
118  G_debug(1, "Vect_build_graph(): ltype = %d, afield = %d, nfield = %d",
119  ltype, afield, nfield);
120  G_debug(1, " afcol = %s, abcol = %s, ncol = %s", afcol, abcol, ncol);
121 
122  G_message(_("Building graph..."));
123 
124  Map->graph_line_type = ltype;
125 
126  Points = Vect_new_line_struct();
127  Cats = Vect_new_cats_struct();
128 
129  ll = 0;
130  if (G_projection() == 3)
131  ll = 1; /* LL */
132 
133  if (afcol == NULL && ll && !geo)
134  Map->cost_multip = 1000000;
135  else
136  Map->cost_multip = 1000;
137 
138  nlines = Vect_get_num_lines(Map);
139  nnodes = Vect_get_num_nodes(Map);
140 
141  gr = &(Map->graph);
142 
143  /* Allocate space for costs, later replace by functions reading costs from graph */
144  Map->edge_fcosts = (double *)G_malloc((nlines + 1) * sizeof(double));
145  Map->edge_bcosts = (double *)G_malloc((nlines + 1) * sizeof(double));
146  Map->node_costs = (double *)G_malloc((nnodes + 1) * sizeof(double));
147  /* Set to -1 initially */
148  for (i = 1; i <= nlines; i++) {
149  Map->edge_fcosts[i] = -1; /* forward */
150  Map->edge_bcosts[i] = -1; /* backward */
151  }
152  for (i = 1; i <= nnodes; i++) {
153  Map->node_costs[i] = 0;
154  }
155 
156  if (ncol != NULL)
157  dglInitialize(gr, (dglByte_t) 1, sizeof(dglInt32_t), (dglInt32_t) 0,
158  opaqueset);
159  else
160  dglInitialize(gr, (dglByte_t) 1, (dglInt32_t) 0, (dglInt32_t) 0,
161  opaqueset);
162 
163  if (gr == NULL)
164  G_fatal_error(_("Unable to build network graph"));
165 
166  db_init_handle(&handle);
167  db_init_string(&stmt);
168 
169  if (abcol != NULL && afcol == NULL)
170  G_fatal_error(_("Forward costs column not specified"));
171 
172  /* --- Add arcs --- */
173  /* Open db connection */
174  if (afcol != NULL) {
175  /* Get field info */
176  if (afield < 1)
177  G_fatal_error(_("Arc field < 1"));
178  Fi = Vect_get_field(Map, afield);
179  if (Fi == NULL)
180  G_fatal_error(_("Database connection not defined for layer %d"),
181  afield);
182 
183  /* Open database */
184  driver = db_start_driver_open_database(Fi->driver, Fi->database);
185  if (driver == NULL)
186  G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
187  Fi->database, Fi->driver);
188 
189  /* Load costs to array */
190  if (db_get_column(driver, Fi->table, afcol, &Column) != DB_OK)
191  G_fatal_error(_("Column <%s> not found in table <%s>"),
192  afcol, Fi->table);
193 
194  fctype = db_sqltype_to_Ctype(db_get_column_sqltype(Column));
195 
196  if (fctype != DB_C_TYPE_INT && fctype != DB_C_TYPE_DOUBLE)
197  G_fatal_error(_("Data type of column <%s> not supported (must be numeric)"),
198  afcol);
199 
200  db_CatValArray_init(&fvarr);
201  nrec =
202  db_select_CatValArray(driver, Fi->table, Fi->key, afcol, NULL,
203  &fvarr);
204  G_debug(1, "forward costs: nrec = %d", nrec);
205 
206  if (abcol != NULL) {
207  if (db_get_column(driver, Fi->table, abcol, &Column) != DB_OK)
208  G_fatal_error(_("Column <%s> not found in table <%s>"),
209  abcol, Fi->table);
210 
211  bctype = db_sqltype_to_Ctype(db_get_column_sqltype(Column));
212 
213  if (bctype != DB_C_TYPE_INT && bctype != DB_C_TYPE_DOUBLE)
214  G_fatal_error(_("Data type of column <%s> not supported (must be numeric)"),
215  abcol);
216 
217  db_CatValArray_init(&bvarr);
218  nrec =
219  db_select_CatValArray(driver, Fi->table, Fi->key, abcol, NULL,
220  &bvarr);
221  G_debug(1, "backward costs: nrec = %d", nrec);
222  }
223  }
224 
225  skipped = 0;
226 
227  G_message(_("Registering arcs..."));
228 
229  for (i = 1; i <= nlines; i++) {
230  G_percent(i, nlines, 1); /* must be before any continue */
231  dofw = dobw = 1;
232  Vect_get_line_nodes(Map, i, &from, &to);
233  type = Vect_read_line(Map, Points, Cats, i);
234  if (!(type & ltype & (GV_LINE | GV_BOUNDARY)))
235  continue;
236 
237  if (afcol != NULL) {
238  if (!(Vect_cat_get(Cats, afield, &cat))) {
239  G_debug(2,
240  "Category of field %d not attached to the line %d -> line skipped",
241  afield, i);
242  skipped += 2; /* Both directions */
243  continue;
244  }
245  else {
246  if (fctype == DB_C_TYPE_INT) {
247  ret = db_CatValArray_get_value_int(&fvarr, cat, &cost);
248  dcost = cost;
249  }
250  else { /* DB_C_TYPE_DOUBLE */
251  ret =
252  db_CatValArray_get_value_double(&fvarr, cat, &dcost);
253  }
254  if (ret != DB_OK) {
255  G_warning(_("Database record for line %d (cat = %d, "
256  "forward/both direction(s)) not found "
257  "(forward/both direction(s) of line skipped)"),
258  i, cat);
259  dofw = 0;
260  }
261 
262  if (abcol != NULL) {
263  if (bctype == DB_C_TYPE_INT) {
264  ret =
265  db_CatValArray_get_value_int(&bvarr, cat, &bcost);
266  bdcost = bcost;
267  }
268  else { /* DB_C_TYPE_DOUBLE */
269  ret =
271  &bdcost);
272  }
273  if (ret != DB_OK) {
274  G_warning(_("Database record for line %d (cat = %d, "
275  "backword direction) not found"
276  "(direction of line skipped)"), i, cat);
277  dobw = 0;
278  }
279  }
280  else {
281  if (dofw)
282  bdcost = dcost;
283  else
284  dobw = 0;
285  }
286  }
287  }
288  else {
289  if (ll) {
290  if (geo)
291  dcost = Vect_line_geodesic_length(Points);
292  else
293  dcost = Vect_line_length(Points);
294  }
295  else
296  dcost = Vect_line_length(Points);
297 
298  bdcost = dcost;
299  }
300  if (dofw && dcost != -1) {
301  cost = (dglInt32_t) Map->cost_multip * dcost;
302  G_debug(5, "Add arc %d from %d to %d cost = %d", i, from, to,
303  cost);
304  ret =
305  dglAddEdge(gr, (dglInt32_t) from, (dglInt32_t) to,
306  (dglInt32_t) cost, (dglInt32_t) i);
307  Map->edge_fcosts[i] = dcost;
308  if (ret < 0)
309  G_fatal_error("Cannot add network arc");
310  }
311 
312  G_debug(5, "bdcost = %f edge_bcosts = %f", bdcost,
313  Map->edge_bcosts[i]);
314  if (dobw && bdcost != -1) {
315  bcost = (dglInt32_t) Map->cost_multip * bdcost;
316  G_debug(5, "Add arc %d from %d to %d bcost = %d", -i, to, from,
317  bcost);
318  ret =
319  dglAddEdge(gr, (dglInt32_t) to, (dglInt32_t) from,
320  (dglInt32_t) bcost, (dglInt32_t) - i);
321  Map->edge_bcosts[i] = bdcost;
322  if (ret < 0)
323  G_fatal_error(_("Cannot add network arc"));
324  }
325  }
326 
327  if (afcol != NULL && skipped > 0)
328  G_debug(2, "%d lines missing category of field %d skipped", skipped,
329  afield);
330 
331  if (afcol != NULL) {
333  db_CatValArray_free(&fvarr);
334 
335  if (abcol != NULL) {
336  db_CatValArray_free(&bvarr);
337  }
338  }
339 
340  /* Set node attributes */
341  G_debug(2, "Register nodes");
342  if (ncol != NULL) {
343  G_debug(2, "Set nodes' costs");
344  if (nfield < 1)
345  G_fatal_error("Node field < 1");
346 
347  G_message(_("Setting node costs..."));
348 
349  Fi = Vect_get_field(Map, nfield);
350  if (Fi == NULL)
351  G_fatal_error(_("Database connection not defined for layer %d"),
352  nfield);
353 
354  driver = db_start_driver_open_database(Fi->driver, Fi->database);
355  if (driver == NULL)
356  G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
357  Fi->database, Fi->driver);
358 
359  /* Load costs to array */
360  if (db_get_column(driver, Fi->table, ncol, &Column) != DB_OK)
361  G_fatal_error(_("Column <%s> not found in table <%s>"),
362  ncol, Fi->table);
363 
364  fctype = db_sqltype_to_Ctype(db_get_column_sqltype(Column));
365 
366  if (fctype != DB_C_TYPE_INT && fctype != DB_C_TYPE_DOUBLE)
367  G_fatal_error(_("Data type of column <%s> not supported (must be numeric)"),
368  ncol);
369 
370  db_CatValArray_init(&fvarr);
371  nrec =
372  db_select_CatValArray(driver, Fi->table, Fi->key, ncol, NULL,
373  &fvarr);
374  G_debug(1, "node costs: nrec = %d", nrec);
375 
376  for (i = 1; i <= nnodes; i++) {
377  /* TODO: what happens if we set attributes of not existing node (skipped lines,
378  * nodes without lines) */
379 
380  nlines = Vect_get_node_n_lines(Map, i);
381  G_debug(2, " node = %d nlines = %d", i, nlines);
382  cfound = 0;
383  dcost = 0;
384  for (j = 0; j < nlines; j++) {
385  line = Vect_get_node_line(Map, i, j);
386  G_debug(2, " line (%d) = %d", j, line);
387  type = Vect_read_line(Map, NULL, Cats, abs(line));
388  if (!(type & GV_POINT))
389  continue;
390  if (Vect_cat_get(Cats, nfield, &cat)) { /* point with category of field found */
391  /* Set costs */
392  if (fctype == DB_C_TYPE_INT) {
393  ret =
394  db_CatValArray_get_value_int(&fvarr, cat, &cost);
395  dcost = cost;
396  }
397  else { /* DB_C_TYPE_DOUBLE */
398  ret =
400  &dcost);
401  }
402  if (ret != DB_OK) {
403  G_warning(_("Database record for node %d (cat = %d) not found "
404  "(cost set to 0)"), i, cat);
405  }
406  cfound = 1;
407  break;
408  }
409  }
410  if (!cfound) {
411  G_debug(2,
412  "Category of field %d not attached to any points in node %d"
413  "(costs set to 0)", nfield, i);
414  }
415  if (dcost == -1) { /* closed */
416  cost = -1;
417  }
418  else {
419  cost = (dglInt32_t) Map->cost_multip * dcost;
420  }
421  dgl_cost = cost;
422  G_debug(3, "Set node's cost to %d", cost);
423  dglNodeSet_Attr(gr, dglGetNode(gr, (dglInt32_t) i), &dgl_cost);
424  Map->node_costs[i] = dcost;
425  }
427  db_CatValArray_free(&fvarr);
428  }
429 
430  G_message(_("Flattening the graph..."));
431  ret = dglFlatten(gr);
432  if (ret < 0)
433  G_fatal_error(_("GngFlatten error"));
434 
435  /* init SP cache */
436  /* disable to debug dglib cache */
437  dglInitializeSPCache(gr, &(Map->spCache));
438 
439  G_message(_("Graph was built"));
440 
441  return 0;
442 }
443 
444 
463 int
464 Vect_net_shortest_path(struct Map_info *Map, int from, int to,
465  struct ilist *List, double *cost)
466 {
467  int i, line, *pclip, cArc, nRet;
468  dglSPReport_s *pSPReport;
469  dglInt32_t nDistance;
470  int use_cache = 1; /* set to 0 to disable dglib cache */
471 
472  G_debug(3, "Vect_net_shortest_path(): from = %d, to = %d", from, to);
473 
474  /* Note : if from == to dgl goes to nearest node and returns back (dgl feature) =>
475  * check here for from == to */
476 
477  if (List != NULL)
478  Vect_reset_list(List);
479 
480  /* Check if from and to are identical, otherwise dglib returns path to neares node and back! */
481  if (from == to) {
482  if (cost != NULL)
483  *cost = 0;
484  return 0;
485  }
486 
487  From_node = from;
488 
489  pclip = NULL;
490  if (List != NULL) {
491  if (use_cache) {
492  nRet =
493  dglShortestPath(&(Map->graph), &pSPReport, (dglInt32_t) from,
494  (dglInt32_t) to, clipper, pclip, &(Map->spCache));
495  }
496  else {
497  nRet =
498  dglShortestPath(&(Map->graph), &pSPReport, (dglInt32_t) from,
499  (dglInt32_t) to, clipper, pclip, NULL);
500  }
501  }
502  else {
503  if (use_cache) {
504  nRet =
505  dglShortestDistance(&(Map->graph), &nDistance, (dglInt32_t) from,
506  (dglInt32_t) to, clipper, pclip, &(Map->spCache));
507  }
508  else {
509  nRet =
510  dglShortestDistance(&(Map->graph), &nDistance, (dglInt32_t) from,
511  (dglInt32_t) to, clipper, pclip, NULL);
512  }
513  }
514 
515  if (nRet == 0) {
516  /* G_warning( "Destination node %d is unreachable from node %d\n" , to , from ); */
517  if (cost != NULL)
518  *cost = PORT_DOUBLE_MAX;
519  return -1;
520  }
521  else if (nRet < 0) {
522  G_warning(_("dglShortestPath error: %s"), dglStrerror(&(Map->graph)));
523  return -1;
524  }
525 
526  if (List != NULL) {
527  for (i = 0; i < pSPReport->cArc; i++) {
528  line = dglEdgeGet_Id(&(Map->graph), pSPReport->pArc[i].pnEdge);
529  G_debug(2, "From %ld to %ld - cost %ld user %d distance %ld", pSPReport->pArc[i].nFrom, pSPReport->pArc[i].nTo, dglEdgeGet_Cost(&(Map->graph), pSPReport->pArc[i].pnEdge) / Map->cost_multip, /* this is the cost from clip() */
530  line, pSPReport->pArc[i].nDistance);
531  Vect_list_append(List, line);
532  }
533  }
534 
535  if (cost != NULL) {
536  if (List != NULL)
537  *cost = (double)pSPReport->nDistance / Map->cost_multip;
538  else
539  *cost = (double)nDistance / Map->cost_multip;
540  }
541 
542  if (List != NULL) {
543  cArc = pSPReport->cArc;
544  dglFreeSPReport(&(Map->graph), pSPReport);
545  }
546  else
547  cArc = 0;
548 
549  return (cArc);
550 }
551 
564 int
565 Vect_net_get_line_cost(struct Map_info *Map, int line, int direction,
566  double *cost)
567 {
568  /* dglInt32_t *pEdge; */
569 
570  G_debug(5, "Vect_net_get_line_cost(): line = %d, dir = %d", line,
571  direction);
572 
573  if (direction == GV_FORWARD) {
574  /* V1 has no index by line-id -> array used */
575  /*
576  pEdge = dglGetEdge ( &(Map->graph), line );
577  if ( pEdge == NULL ) return 0;
578  *cost = (double) dglEdgeGet_Cost ( &(Map->graph), pEdge );
579  */
580  if (Map->edge_fcosts[line] == -1) {
581  *cost = -1;
582  return 0;
583  }
584  else
585  *cost = Map->edge_fcosts[line];
586  }
587  else if (direction == GV_BACKWARD) {
588  /*
589  pEdge = dglGetEdge ( &(Map->graph), -line );
590  if ( pEdge == NULL ) return 0;
591  *cost = (double) dglEdgeGet_Cost ( &(Map->graph), pEdge );
592  */
593  if (Map->edge_bcosts[line] == -1) {
594  *cost = -1;
595  return 0;
596  }
597  else
598  *cost = Map->edge_bcosts[line];
599  G_debug(5, "Vect_net_get_line_cost(): edge_bcosts = %f",
600  Map->edge_bcosts[line]);
601  }
602  else {
603  G_fatal_error(_("Wrong line direction in Vect_net_get_line_cost()"));
604  }
605 
606  return 1;
607 }
608 
618 int Vect_net_get_node_cost(struct Map_info *Map, int node, double *cost)
619 {
620  G_debug(3, "Vect_net_get_node_cost(): node = %d", node);
621 
622  *cost = Map->node_costs[node];
623 
624  G_debug(3, " -> cost = %f", *cost);
625 
626  return 1;
627 }
628 
647 int Vect_net_nearest_nodes(struct Map_info *Map,
648  double x, double y, double z,
649  int direction, double maxdist,
650  int *node1, int *node2, int *ln, double *costs1,
651  double *costs2, struct line_pnts *Points1,
652  struct line_pnts *Points2, double *distance)
653 {
654  int line, n1, n2, nnodes;
655  int npoints;
656  int segment; /* nearest line segment (first is 1) */
657  static struct line_pnts *Points = NULL;
658  double cx, cy, cz, c1, c2;
659  double along; /* distance along the line to nearest point */
660  double length;
661 
662  G_debug(3, "Vect_net_nearest_nodes() x = %f y = %f", x, y);
663 
664  /* Reset */
665  if (node1)
666  *node1 = 0;
667  if (node2)
668  *node2 = 0;
669  if (ln)
670  *ln = 0;
671  if (costs1)
672  *costs1 = PORT_DOUBLE_MAX;
673  if (costs2)
674  *costs2 = PORT_DOUBLE_MAX;
675  if (Points1)
676  Vect_reset_line(Points1);
677  if (Points2)
678  Vect_reset_line(Points2);
679  if (distance)
680  *distance = PORT_DOUBLE_MAX;
681 
682  if (!Points)
683  Points = Vect_new_line_struct();
684 
685  /* Find nearest line */
686  line = Vect_find_line(Map, x, y, z, Map->graph_line_type, maxdist, 0, 0);
687 
688  if (line < 1)
689  return 0;
690 
691  Vect_read_line(Map, Points, NULL, line);
692  npoints = Points->n_points;
693  Vect_get_line_nodes(Map, line, &n1, &n2);
694 
695  segment =
696  Vect_line_distance(Points, x, y, z, 0, &cx, &cy, &cz, distance, NULL,
697  &along);
698 
699  G_debug(4, "line = %d n1 = %d n2 = %d segment = %d", line, n1, n2,
700  segment);
701 
702  /* Check first or last point and return one node in that case */
703  G_debug(4, "cx = %f cy = %f first = %f %f last = %f %f", cx, cy,
704  Points->x[0], Points->y[0], Points->x[npoints - 1],
705  Points->y[npoints - 1]);
706 
707  if (Points->x[0] == cx && Points->y[0] == cy) {
708  if (node1)
709  *node1 = n1;
710  if (ln)
711  *ln = line;
712  if (costs1)
713  *costs1 = 0;
714  if (Points1) {
715  Vect_append_point(Points1, x, y, z);
716  Vect_append_point(Points1, cx, cy, cz);
717  }
718  G_debug(3, "first node nearest");
719  return 1;
720  }
721  if (Points->x[npoints - 1] == cx && Points->y[npoints - 1] == cy) {
722  if (node1)
723  *node1 = n2;
724  if (ln)
725  *ln = line;
726  if (costs1)
727  *costs1 = 0;
728  if (Points1) {
729  Vect_append_point(Points1, x, y, z);
730  Vect_append_point(Points1, cx, cy, cz);
731  }
732  G_debug(3, "last node nearest");
733  return 1;
734  }
735 
736  nnodes = 2;
737 
738  /* c1 - costs to get from/to the first vertex */
739  /* c2 - costs to get from/to the last vertex */
740  if (direction == GV_FORWARD) { /* from point to net */
741  Vect_net_get_line_cost(Map, line, GV_BACKWARD, &c1);
742  Vect_net_get_line_cost(Map, line, GV_FORWARD, &c2);
743  }
744  else {
745  Vect_net_get_line_cost(Map, line, GV_FORWARD, &c1);
746  Vect_net_get_line_cost(Map, line, GV_BACKWARD, &c2);
747  }
748 
749  if (c1 < 0)
750  nnodes--;
751  if (c2 < 0)
752  nnodes--;
753  if (nnodes == 0)
754  return 0; /* both directions closed */
755 
756  length = Vect_line_length(Points);
757 
758  if (ln)
759  *ln = line;
760 
761  if (nnodes == 1 && c1 < 0) { /* first direction is closed, return node2 as node1 */
762  if (node1)
763  *node1 = n2;
764 
765  if (costs1) { /* to node 2, i.e. forward */
766  *costs1 = c2 * (length - along) / length;
767  }
768 
769  if (Points1) { /* to node 2, i.e. forward */
770  int i;
771 
772  if (direction == GV_FORWARD) { /* from point to net */
773  Vect_append_point(Points1, x, y, z);
774  Vect_append_point(Points1, cx, cy, cz);
775  for (i = segment; i < npoints; i++)
776  Vect_append_point(Points1, Points->x[i], Points->y[i],
777  Points->z[i]);
778  }
779  else {
780  for (i = npoints - 1; i >= segment; i--)
781  Vect_append_point(Points1, Points->x[i], Points->y[i],
782  Points->z[i]);
783 
784  Vect_append_point(Points1, cx, cy, cz);
785  Vect_append_point(Points1, x, y, z);
786  }
787  }
788  }
789  else {
790  if (node1)
791  *node1 = n1;
792  if (node2)
793  *node2 = n2;
794 
795  if (costs1) { /* to node 1, i.e. backward */
796  *costs1 = c1 * along / length;
797  }
798 
799  if (costs2) { /* to node 2, i.e. forward */
800  *costs2 = c2 * (length - along) / length;
801  }
802 
803  if (Points1) { /* to node 1, i.e. backward */
804  int i;
805 
806  if (direction == GV_FORWARD) { /* from point to net */
807  Vect_append_point(Points1, x, y, z);
808  Vect_append_point(Points1, cx, cy, cz);
809  for (i = segment - 1; i >= 0; i--)
810  Vect_append_point(Points1, Points->x[i], Points->y[i],
811  Points->z[i]);
812  }
813  else {
814  for (i = 0; i < segment; i++)
815  Vect_append_point(Points1, Points->x[i], Points->y[i],
816  Points->z[i]);
817 
818  Vect_append_point(Points1, cx, cy, cz);
819  Vect_append_point(Points1, x, y, z);
820  }
821  }
822 
823  if (Points2) { /* to node 2, i.e. forward */
824  int i;
825 
826  if (direction == GV_FORWARD) { /* from point to net */
827  Vect_append_point(Points2, x, y, z);
828  Vect_append_point(Points2, cx, cy, cz);
829  for (i = segment; i < npoints; i++)
830  Vect_append_point(Points2, Points->x[i], Points->y[i],
831  Points->z[i]);
832  }
833  else {
834  for (i = npoints - 1; i >= segment; i--)
835  Vect_append_point(Points2, Points->x[i], Points->y[i],
836  Points->z[i]);
837 
838  Vect_append_point(Points2, cx, cy, cz);
839  Vect_append_point(Points2, x, y, z);
840  }
841  }
842  }
843 
844  return nnodes;
845 }
846 
865 int
867  double fx, double fy, double fz, double tx,
868  double ty, double tz, double fmax, double tmax,
869  double *costs, struct line_pnts *Points,
870  struct ilist *List, struct line_pnts *FPoints,
871  struct line_pnts *TPoints, double *fdist,
872  double *tdist)
873 {
874  return Vect_net_shortest_path_coor2 ( Map, fx, fy, fz, tx, ty, tz, fmax, tmax,
875  costs, Points, List, NULL, FPoints, TPoints, fdist, tdist );
876 }
877 
897 int
899  double fx, double fy, double fz, double tx,
900  double ty, double tz, double fmax, double tmax,
901  double *costs, struct line_pnts *Points,
902  struct ilist *List, struct ilist *NodesList,
903  struct line_pnts *FPoints,
904  struct line_pnts *TPoints, double *fdist,
905  double *tdist)
906 {
907  int fnode[2], tnode[2]; /* nearest nodes, *node[1] is 0 if only one was found */
908  double fcosts[2], tcosts[2], cur_cst; /* costs to nearest nodes on the network */
909  int nfnodes, ntnodes, fline, tline;
910  static struct line_pnts *APoints, *SPoints, *fPoints[2], *tPoints[2];
911  static struct ilist *LList;
912  static int first = 1;
913  int reachable, shortcut;
914  int i, j, fn = 0, tn = 0;
915 
916  /* from/to_point_node is set if from/to point projected to line
917  *falls exactly on node (shortcut -> fline == tline) */
918  int from_point_node = 0;
919  int to_point_node = 0;
920 
921  G_debug(3, "Vect_net_shortest_path_coor()");
922 
923  if (first) {
924  APoints = Vect_new_line_struct();
925  SPoints = Vect_new_line_struct();
926  fPoints[0] = Vect_new_line_struct();
927  fPoints[1] = Vect_new_line_struct();
928  tPoints[0] = Vect_new_line_struct();
929  tPoints[1] = Vect_new_line_struct();
930  LList = Vect_new_list();
931  first = 0;
932  }
933 
934  /* Reset */
935  if (costs)
936  *costs = PORT_DOUBLE_MAX;
937  if (Points)
938  Vect_reset_line(Points);
939  if (fdist)
940  *fdist = 0;
941  if (tdist)
942  *tdist = 0;
943  if (List)
944  List->n_values = 0;
945  if (FPoints)
946  Vect_reset_line(FPoints);
947  if (TPoints)
948  Vect_reset_line(TPoints);
949  if (NodesList != NULL)
950  Vect_reset_list(NodesList);
951 
952  /* Find nearest nodes */
953  fnode[0] = fnode[1] = tnode[0] = tnode[1] = 0;
954 
955  nfnodes =
956  Vect_net_nearest_nodes(Map, fx, fy, fz, GV_FORWARD, fmax, &(fnode[0]),
957  &(fnode[1]), &fline, &(fcosts[0]),
958  &(fcosts[1]), fPoints[0], fPoints[1], fdist);
959  if (nfnodes == 0)
960  return 0;
961 
962  if ( nfnodes == 1 && fPoints[0]->n_points < 3 ) {
963  from_point_node = fnode[0];
964  }
965 
966  ntnodes =
967  Vect_net_nearest_nodes(Map, tx, ty, tz, GV_BACKWARD, tmax,
968  &(tnode[0]), &(tnode[1]), &tline, &(tcosts[0]),
969  &(tcosts[1]), tPoints[0], tPoints[1], tdist);
970  if (ntnodes == 0)
971  return 0;
972 
973  if ( ntnodes == 1 && tPoints[0]->n_points < 3 ) {
974  to_point_node = tnode[0];
975  }
976 
977 
978  G_debug(3, "fline = %d tline = %d", fline, tline);
979 
980  reachable = shortcut = 0;
981  cur_cst = PORT_DOUBLE_MAX;
982 
983  /* It may happen, that 2 points are at the same line. */
984  /* TODO?: it could also happen that fline != tline but both points are on the same
985  * line if they fall on node but a different line was found. This case is correctly
986  * handled as normal non shortcut, but it could be added here. In that case
987  * NodesList collection must be changed */
988  if (fline == tline && (nfnodes > 1 || ntnodes > 1)) {
989  double len, flen, tlen, c, fseg, tseg;
990  double fcx, fcy, fcz, tcx, tcy, tcz;
991 
992  Vect_read_line(Map, APoints, NULL, fline);
993  len = Vect_line_length(APoints);
994 
995  /* distance along the line */
996  fseg =
997  Vect_line_distance(APoints, fx, fy, fz, 0, &fcx, &fcy, &fcz, NULL,
998  NULL, &flen);
999  tseg =
1000  Vect_line_distance(APoints, tx, ty, tz, 0, &tcx, &tcy, &tcz, NULL,
1001  NULL, &tlen);
1002 
1003  Vect_reset_line(SPoints);
1004  if (flen == tlen) {
1005  cur_cst = 0;
1006  reachable = shortcut = 1;
1007  }
1008  else if (flen < tlen) {
1009  Vect_net_get_line_cost(Map, fline, GV_FORWARD, &c);
1010  if (c >= 0) {
1011  cur_cst = c * (tlen - flen) / len;
1012 
1013  Vect_append_point(SPoints, fx, fy, fz);
1014  Vect_append_point(SPoints, fcx, fcy, fcz);
1015  for (i = fseg; i < tseg; i++)
1016  Vect_append_point(SPoints, APoints->x[i], APoints->y[i],
1017  APoints->z[i]);
1018 
1019  Vect_append_point(SPoints, tcx, tcy, tcz);
1020  Vect_append_point(SPoints, tx, ty, tz);
1021 
1022  reachable = shortcut = 1;
1023  }
1024  }
1025  else { /* flen > tlen */
1026  Vect_net_get_line_cost(Map, fline, GV_BACKWARD, &c);
1027  if (c >= 0) {
1028  cur_cst = c * (flen - tlen) / len;
1029 
1030  Vect_append_point(SPoints, fx, fy, fz);
1031  Vect_append_point(SPoints, fcx, fcy, fcz);
1032  for (i = fseg - 1; i >= tseg; i--)
1033  Vect_append_point(SPoints, APoints->x[i], APoints->y[i],
1034  APoints->z[i]);
1035 
1036  Vect_append_point(SPoints, tcx, tcy, tcz);
1037  Vect_append_point(SPoints, tx, ty, tz);
1038 
1039  reachable = shortcut = 1;
1040  }
1041  }
1042  }
1043 
1044  /* Find the shortest variant from maximum 4 */
1045  for (i = 0; i < nfnodes; i++) {
1046  for (j = 0; j < ntnodes; j++) {
1047  double ncst, cst;
1048  int ret;
1049 
1050  G_debug(3, "i = %d fnode = %d j = %d tnode = %d", i, fnode[i], j,
1051  tnode[j]);
1052 
1053  ret =
1054  Vect_net_shortest_path(Map, fnode[i], tnode[j], NULL, &ncst);
1055  if (ret == -1)
1056  continue; /* not reachable */
1057 
1058  cst = fcosts[i] + ncst + tcosts[j];
1059  if (reachable == 0 || cst < cur_cst) {
1060  cur_cst = cst;
1061  fn = i;
1062  tn = j;
1063  shortcut = 0;
1064  }
1065  reachable = 1;
1066  }
1067  }
1068 
1069  G_debug(3, "reachable = %d shortcut = %d cur_cst = %f", reachable,
1070  shortcut, cur_cst);
1071  if (reachable) {
1072  int ret;
1073 
1074  if (shortcut) {
1075  if (Points)
1076  Vect_append_points(Points, SPoints, GV_FORWARD);
1077  if (NodesList) {
1078  /* Check if from/to point projected to line falls on node and
1079  *add it to the list */
1080  if (from_point_node > 0)
1081  Vect_list_append(NodesList, from_point_node);
1082 
1083  if (to_point_node > 0)
1084  Vect_list_append(NodesList, to_point_node);
1085  }
1086  }
1087  else {
1088  if (NodesList) {
1089  /* it can happen that starting point falls on node but SP starts
1090  * form the other node, add it in that case,
1091  * similarly for to point below */
1092  if (from_point_node > 0 && from_point_node != fnode[fn]) {
1093  Vect_list_append(NodesList, from_point_node);
1094  }
1095 
1096  /* add starting net SP search node */
1097  Vect_list_append(NodesList, fnode[fn]);
1098  }
1099  ret =
1100  Vect_net_shortest_path(Map, fnode[fn], tnode[tn], LList,
1101  NULL);
1102  G_debug(3, "Number of lines %d", LList->n_values);
1103 
1104  if (Points)
1105  Vect_append_points(Points, fPoints[fn], GV_FORWARD);
1106 
1107  if (FPoints)
1108  Vect_append_points(FPoints, fPoints[fn], GV_FORWARD);
1109 
1110  for (i = 0; i < LList->n_values; i++) {
1111  int line;
1112 
1113  line = LList->value[i];
1114  G_debug(3, "i = %d line = %d", i, line);
1115 
1116  if (Points) {
1117  Vect_read_line(Map, APoints, NULL, abs(line));
1118 
1119  if (line > 0)
1120  Vect_append_points(Points, APoints, GV_FORWARD);
1121  else
1122  Vect_append_points(Points, APoints, GV_BACKWARD);
1123  }
1124  if (NodesList) {
1125  int node, node1, node2;
1126  Vect_get_line_nodes(Map, abs(line), &node1, &node2);
1127  /* add the second node, the first of first segmet was alread added */
1128  if (line > 0)
1129  node = node2;
1130  else
1131  node = node1;
1132 
1133  Vect_list_append(NodesList, node);
1134  }
1135 
1136  if (List)
1137  Vect_list_append(List, line);
1138  }
1139 
1140  if (Points)
1141  Vect_append_points(Points, tPoints[tn], GV_FORWARD);
1142 
1143  if (TPoints)
1144  Vect_append_points(TPoints, tPoints[tn], GV_FORWARD);
1145 
1146  if (NodesList) {
1147  if (to_point_node > 0 && to_point_node != tnode[tn]) {
1148  Vect_list_append(NodesList, to_point_node);
1149  }
1150  }
1151  }
1152 
1153  if (costs)
1154  *costs = cur_cst;
1155  }
1156 
1157  return reachable;
1158 }
dbDriver * db_start_driver_open_database(const char *drvname, const char *dbname)
Open driver/database connection.
Definition: db.c:28
int db_select_CatValArray(dbDriver *driver, const char *tab, const char *key, const char *col, const char *where, dbCatValArray *cvarr)
Select pairs key/value to array, values are sorted by key (must be integer)
dglInt32_t dglNodeGet_Id(dglGraph_s *pGraph, dglInt32_t *pnNode)
Definition: dglib/graph.c:213
int db_CatValArray_get_value_int(dbCatValArray *arr, int key, int *val)
Find value (integer) by key.
struct field_info * Vect_get_field(struct Map_info *Map, int field)
Get information about link to database.
Definition: field.c:404
int Vect_get_node_line(struct Map_info *Map, int node, int line)
Get line id for node line index.
Definition: level_two.c:316
int dglShortestPath(dglGraph_s *pGraph, dglSPReport_s **ppReport, dglInt32_t nStart, dglInt32_t nDestination, dglSPClip_fn fnClip, void *pvClipArg, dglSPCache_s *pCache)
Definition: dglib/graph.c:785
int Vect_net_shortest_path(struct Map_info *Map, int from, int to, struct ilist *List, double *cost)
Find shortest path.
Definition: net.c:464
unsigned char dglByte_t
Definition: type.h:36
int dglAddEdge(dglGraph_s *pGraph, dglInt32_t nHead, dglInt32_t nTail, dglInt32_t nCost, dglInt32_t nEdge)
Definition: dglib/graph.c:610
int Vect_get_line_nodes(struct Map_info *Map, int line, int *n1, int *n2)
Get line nodes.
Definition: level_two.c:247
dglInt32_t * pnEdge
Definition: graph.h:215
int db_close_database_shutdown_driver(dbDriver *driver)
Close driver/database connection.
Definition: db.c:62
struct line_pnts * Vect_new_line_struct()
Creates and initializes a struct line_pnts.
Definition: line.c:57
struct ilist * Vect_new_list(void)
Creates and initializes a struct ilist.
dglInt32_t * pnEdge
Definition: graph.h:96
dglInt32_t nDistance
Definition: graph.h:216
void db_CatValArray_free(dbCatValArray *arr)
Definition: value.c:348
int Vect_append_points(struct line_pnts *Points, struct line_pnts *APoints, int direction)
Appends points to the end of a line.
Definition: line.c:312
int Vect_reset_line(struct line_pnts *Points)
Reset line.
Definition: line.c:148
int dglShortestDistance(dglGraph_s *pGraph, dglInt32_t *pnDistance, dglInt32_t nStart, dglInt32_t nDestination, dglSPClip_fn fnClip, void *pvClipArg, dglSPCache_s *pCache)
Definition: dglib/graph.c:817
int Vect_net_get_line_cost(struct Map_info *Map, int line, int direction, double *cost)
Returns in cost for given direction in *cost.
Definition: net.c:565
int y
Definition: plot.c:34
int Vect_append_point(struct line_pnts *Points, double x, double y, double z)
Appends one point to the end of a line.
Definition: line.c:168
int dglGet_NodeAttrSize(dglGraph_s *pgraph)
Definition: dglib/graph.c:1231
int db_CatValArray_get_value_double(dbCatValArray *arr, int key, double *val)
Find value (double) by key.
dglInt32_t nTo
Definition: graph.h:214
dglInt32_t dglEdgeGet_Id(dglGraph_s *pGraph, dglInt32_t *pnEdge)
Definition: dglib/graph.c:438
int dglInitializeSPCache(dglGraph_s *pGraph, dglSPCache_s *pCache)
Definition: dglib/graph.c:1122
int db_sqltype_to_Ctype(int sqltype)
Definition: sqlCtype.c:9
int G_percent(long n, long d, int s)
Print percent complete messages.
Definition: percent.c:63
dglInt32_t * dglGetNode(dglGraph_s *pGraph, dglInt32_t nNodeId)
Definition: dglib/graph.c:155
int db_get_column_sqltype(dbColumn *column)
returns column sqltype for column (the function db_sqltype_name() returns sqltype description) ...
void G_message(const char *msg,...)
Print a message to stderr.
Definition: lib/gis/error.c:74
void dglNodeSet_Attr(dglGraph_s *pGraph, dglInt32_t *pnNode, dglInt32_t *pnAttr)
Definition: dglib/graph.c:275
int Vect_net_shortest_path_coor2(struct Map_info *Map, double fx, double fy, double fz, double tx, double ty, double tz, double fmax, double tmax, double *costs, struct line_pnts *Points, struct ilist *List, struct ilist *NodesList, struct line_pnts *FPoints, struct line_pnts *TPoints, double *fdist, double *tdist)
Find shortest path on network between 2 points given by coordinates.
Definition: net.c:898
dglSPArc_s * pArc
Definition: graph.h:229
int Vect_reset_list(struct ilist *list)
Reset ilist structure.
long dglInt32_t
Definition: type.h:37
int Vect_list_append(struct ilist *list, int val)
Append new item to the end of list if not yet present.
int Vect_net_build_graph(struct Map_info *Map, int ltype, int afield, int nfield, const char *afcol, const char *abcol, const char *ncol, int geo, int algorithm)
Build network graph.
Definition: net.c:91
dglInt32_t nFrom
Definition: graph.h:213
int Vect_net_shortest_path_coor(struct Map_info *Map, double fx, double fy, double fz, double tx, double ty, double tz, double fmax, double tmax, double *costs, struct line_pnts *Points, struct ilist *List, struct line_pnts *FPoints, struct line_pnts *TPoints, double *fdist, double *tdist)
Find shortest path on network between 2 points given by coordinates.
Definition: net.c:866
int first
Definition: form/open.c:25
dglInt32_t nEdgeCost
Definition: graph.h:104
int Vect_net_nearest_nodes(struct Map_info *Map, double x, double y, double z, int direction, double maxdist, int *node1, int *node2, int *ln, double *costs1, double *costs2, struct line_pnts *Points1, struct line_pnts *Points2, double *distance)
Find nearest node(s) on network.
Definition: net.c:647
int db_get_column(dbDriver *Driver, const char *tname, const char *cname, dbColumn **Column)
Get column structure by table and column name.
void db_CatValArray_init(dbCatValArray *arr)
Definition: value.c:335
dglInt32_t * dglNodeGet_Attr(dglGraph_s *pGraph, dglInt32_t *pnNode)
Definition: dglib/graph.c:255
struct line_cats * Vect_new_cats_struct()
Creates and initializes line_cats structure.
return NULL
Definition: dbfopen.c:1394
double Vect_line_length(struct line_pnts *Points)
Calculate line length, 3D-length in case of 3D vector line.
Definition: line.c:555
Definition: driver.h:25
G_warning("category support for [%s] in mapset [%s] %s", name, mapset, type)
int Vect_get_num_lines(struct Map_info *map)
Fetch number of features (points, lines, boundaries, centroids) in vector map.
Definition: level_two.c:69
dglInt32_t * pnNodeFrom
Definition: graph.h:95
dglInt32_t * pnNodeTo
Definition: graph.h:97
int Vect_net_get_node_cost(struct Map_info *Map, int node, double *cost)
Get cost of node.
Definition: net.c:618
int dglInitialize(dglGraph_s *pGraph, dglByte_t Version, dglInt32_t NodeAttrSize, dglInt32_t EdgeAttrSize, dglInt32_t *pOpaqueSet)
Definition: dglib/graph.c:53
tuple Map
Definition: render.py:1310
int G_debug(int level, const char *msg,...)
Print debugging message.
Definition: gis/debug.c:51
dglInt32_t dglEdgeGet_Cost(dglGraph_s *pGraph, dglInt32_t *pnEdge)
Definition: dglib/graph.c:418
void db_init_handle(dbHandle *handle)
Definition: handle.c:10
dglInt32_t cArc
Definition: graph.h:228
double Vect_line_geodesic_length(struct line_pnts *Points)
Calculate line length.
Definition: line.c:583
char * dglStrerror(dglGraph_s *pgraph)
Definition: dglib/graph.c:1160
void dglFreeSPReport(dglGraph_s *pgraph, dglSPReport_s *pSPReport)
Definition: dglib/graph.c:1106
CELL cat
Definition: g3dcats.c:90
int Vect_get_num_nodes(struct Map_info *map)
Get number of nodes in vector map.
Definition: level_two.c:29
int G_fatal_error(const char *msg,...)
Print a fatal error message to stderr.
int Vect_line_distance(struct line_pnts *points, double ux, double uy, double uz, int with_z, double *px, double *py, double *pz, double *dist, double *spdist, double *lpdist)
calculate line distance.
Definition: line.c:631
tuple fn
if textDict[&#39;border&#39;] != &#39;none&#39; and not rot: units = UnitConversion(self) borderWidth = units...
int G_projection(void)
query cartographic projection
Definition: proj1.c:33
int Vect_find_line(struct Map_info *map, double ux, double uy, double uz, int type, double maxdist, int with_z, int exclude)
Find the nearest line.
dglInt32_t nDistance
Definition: graph.h:227
void db_init_string(dbString *x)
Definition: string.c:11
int dglFlatten(dglGraph_s *pGraph)
Definition: dglib/graph.c:139
int Vect_read_line(struct Map_info *Map, struct line_pnts *line_p, struct line_cats *line_c, int line)
Read vector feature.
int Vect_cat_get(struct line_cats *Cats, int field, int *cat)
Get first found category of given field.
int Vect_get_node_n_lines(struct Map_info *Map, int node)
Get number of lines for node.
Definition: level_two.c:296