GRASS 8 Programmer's Manual  8.5.0dev(2025)-c070206eb1
net_analyze.c
Go to the documentation of this file.
1 /*!
2  * \file lib/vector/Vlib/net_analyze.c
3  *
4  * \brief Vector library - related fns for vector network analyses
5  *
6  * Higher level functions for reading/writing/manipulating vectors.
7  *
8  * (C) 2001-2009, 2014 by the GRASS Development Team
9  *
10  * This program is free software under the GNU General Public License
11  * (>=v2). Read the file COPYING that comes with GRASS for details.
12  *
13  * \author Radim Blazek
14  * \author Stepan Turek stepan.turek seznam.cz (turns support)
15  */
16 
17 #include <grass/dbmi.h>
18 #include <grass/vector.h>
19 #include <grass/glocale.h>
20 
21 static int
22  From_node; /* from node set in SP and used by clipper for first arc */
23 
24 static int clipper(dglGraph_s *pgraph, dglSPClipInput_s *pargIn,
25  dglSPClipOutput_s *pargOut, void *pvarg UNUSED)
26 { /* caller's pointer */
27  dglInt32_t cost;
28  dglInt32_t from;
29 
30  G_debug(3, "Net: clipper()");
31 
32  from = dglNodeGet_Id(pgraph, pargIn->pnNodeFrom);
33 
34  G_debug(3, " Edge = %d NodeFrom = %d NodeTo = %d edge cost = %d",
35  (int)dglEdgeGet_Id(pgraph, pargIn->pnEdge), (int)from,
36  (int)dglNodeGet_Id(pgraph, pargIn->pnNodeTo),
37  (int)pargOut->nEdgeCost);
38 
39  if (from != From_node) { /* do not clip first */
40  if (dglGet_NodeAttrSize(pgraph) > 0) {
41  memcpy(&cost, dglNodeGet_Attr(pgraph, pargIn->pnNodeFrom),
42  sizeof(cost));
43  if (cost == -1) { /* closed, cannot go from this node except it is
44  'from' node */
45  G_debug(3, " closed node");
46  return 1;
47  }
48  else {
49  G_debug(3, " EdgeCost += %d (node)", (int)cost);
50  pargOut->nEdgeCost += cost;
51  }
52  }
53  }
54  else {
55  G_debug(3, " don't clip first node");
56  }
57 
58  return 0;
59 }
60 
61 /*!
62  \brief Converts shortest path result, which is calculated by DGLib on
63  newtwork without turntable, into output format.
64  */
65 static int convert_dgl_shortest_path_result(struct Map_info *Map,
66  dglSPReport_s *pSPReport,
67  struct ilist *List)
68 {
69  int i, line;
70 
71  Vect_reset_list(List);
72 
73  for (i = 0; i < pSPReport->cArc; i++) {
74  line = dglEdgeGet_Id(&(Map->dgraph.graph_s), pSPReport->pArc[i].pnEdge);
75  G_debug(
76  2, "From %ld to %ld - cost %ld user %d distance %ld",
77  pSPReport->pArc[i].nFrom, pSPReport->pArc[i].nTo,
78  dglEdgeGet_Cost(&(Map->dgraph.graph_s), pSPReport->pArc[i].pnEdge) /
79  Map->dgraph.cost_multip, /* this is the cost from clip() */
80  line, pSPReport->pArc[i].nDistance);
81  Vect_list_append(List, line);
82  }
83 
84  return 0;
85 }
86 
87 /*!
88  \brief Converts shortest path result, which is calculated by DGLib on
89  newtwork with turntable, into output format.
90  */
91 static int ttb_convert_dgl_shortest_path_result(struct Map_info *Map,
92  dglSPReport_s *pSPReport,
93  int tucfield,
94  struct ilist *List)
95 {
96  int i, line_id, type, tucfield_idx;
97  int line_ucat;
98 
99  Vect_reset_list(List);
100 
101  tucfield_idx = Vect_cidx_get_field_index(Map, tucfield);
102 
103  for (i = 0; i < pSPReport->cArc; i++) {
104  dglEdgeGet_Id(&(Map->dgraph.graph_s), pSPReport->pArc[i].pnEdge);
105 
106  line_ucat = dglNodeGet_Id(
107  &(Map->dgraph.graph_s),
108  dglEdgeGet_Head(&(Map->dgraph.graph_s), pSPReport->pArc[i].pnEdge));
109 
110  /* get standard ucat numbers (DGLib does not like negative node numbers)
111  */
112  if (line_ucat % 2 == 1)
113  line_ucat = ((line_ucat - 1) / -2);
114  else
115  line_ucat = (line_ucat) / 2;
116 
117  /* skip virtual nodes */
118  if (Vect_cidx_find_next(Map, tucfield_idx, abs(line_ucat), GV_LINE, 0,
119  &type, &line_id) == -1)
120  continue;
121 
122  if (line_ucat < 0)
123  line_id *= -1;
124 
125  G_debug(
126  2, "From %ld to %ld - cost %ld user %d distance %ld",
127  pSPReport->pArc[i].nFrom, pSPReport->pArc[i].nTo,
128  dglEdgeGet_Cost(&(Map->dgraph.graph_s), pSPReport->pArc[i].pnEdge) /
129  Map->dgraph.cost_multip, /* this is the cost from clip() */
130  line_ucat, pSPReport->pArc[i].nDistance);
131 
132  Vect_list_append(List, line_id);
133  }
134 
135  return 0;
136 }
137 
138 /*!
139  \brief Finds shortest path on network using DGLib
140 
141 
142  \param Map vector map with build DGLib graph (see Vect_net_ttb_build_graph
143  and Vect_net_build_graph) \param from from node id in build the network
144  \param to to node in build the network
145  \param UseTtb the graph is build with/without turntable
146  \param tucfield layer with unique cats for turntable (relevant only when
147  UseTtb = 1)
148  */
149 static int find_shortest_path(struct Map_info *Map, int from, int to,
150  struct ilist *List, double *cost, int UseTtb,
151  int tucfield)
152 {
153  int *pclip, cArc, nRet;
154  dglSPReport_s *pSPReport;
155  dglInt32_t nDistance;
156  int use_cache = 1; /* set to 0 to disable dglib cache */
157 
158  G_debug(3, "find_shortest_path(): from = %d, to = %d", from, to);
159 
160  /* Note : if from == to dgl goes to nearest node and returns back (dgl
161  * feature) => check here for from == to */
162 
163  if (List != NULL)
164  Vect_reset_list(List);
165 
166  /* Check if from and to are identical, otherwise dglib returns path to
167  * nearest node and back! */
168  if (from == to) {
169  if (cost != NULL)
170  *cost = 0;
171  return 0;
172  }
173 
174  From_node = from;
175  pclip = NULL;
176  if (List != NULL) {
177  if (use_cache) {
178  nRet = dglShortestPath(&(Map->dgraph.graph_s), &pSPReport,
179  (dglInt32_t)from, (dglInt32_t)to, clipper,
180  pclip, &(Map->dgraph.spCache));
181  }
182  else {
183  nRet = dglShortestPath(&(Map->dgraph.graph_s), &pSPReport,
184  (dglInt32_t)from, (dglInt32_t)to, clipper,
185  pclip, NULL);
186  }
187  }
188  else {
189  if (use_cache) {
190  nRet = dglShortestDistance(&(Map->dgraph.graph_s), &nDistance,
191  (dglInt32_t)from, (dglInt32_t)to,
192  clipper, pclip, &(Map->dgraph.spCache));
193  }
194  else {
195  nRet = dglShortestDistance(&(Map->dgraph.graph_s), &nDistance,
196  (dglInt32_t)from, (dglInt32_t)to,
197  clipper, pclip, NULL);
198  }
199  }
200 
201  if (nRet == 0) {
202  /* G_warning("Destination node %d is unreachable from node %d\n" , to ,
203  * from); */
204  if (cost != NULL)
205  *cost = PORT_DOUBLE_MAX;
206  return -1;
207  }
208  else if (nRet < 0) {
209  G_warning(_("dglShortestPath error: %s"),
210  dglStrerror(&(Map->dgraph.graph_s)));
211  return -1;
212  }
213 
214  if (List != NULL) {
215  if (UseTtb)
216  ttb_convert_dgl_shortest_path_result(Map, pSPReport, tucfield,
217  List);
218  else
219  convert_dgl_shortest_path_result(Map, pSPReport, List);
220  }
221 
222  if (cost != NULL) {
223  if (List != NULL)
224  *cost = (double)pSPReport->nDistance / Map->dgraph.cost_multip;
225  else
226  *cost = (double)nDistance / Map->dgraph.cost_multip;
227  }
228 
229  if (List != NULL) {
230  cArc = pSPReport->cArc;
231  dglFreeSPReport(&(Map->dgraph.graph_s), pSPReport);
232  }
233  else
234  cArc = 0;
235 
236  return cArc;
237 }
238 
239 /*!
240  \brief Find shortest path on network.
241 
242  Costs for 'from' and 'to' nodes are not considered (SP found even if
243  'from' or 'to' are 'closed' (costs = -1) and costs of these
244  nodes are not added to SP costs result.
245 
246  \param Map vector map with build graph (see Vect_net_ttb_build_graph and
247  Vect_net_build_graph) \param from start of the path \param from_type if 0 -
248  node id (intersection), if 1 - line unique cat \param to end of the path
249  \param to_type if 0 - node id (intersection), if 1 - line unique cat
250  \param tucfield field with unique categories used in the turntable
251  \param[out] List list of line ids (path)
252  \param[out] cost costs value
253 
254  \return number of segments
255  \return 0 is correct for from = to, or List == NULL ? sum of costs is better
256  return value, \return -1 : destination unreachable
257 
258  */
259 int Vect_net_ttb_shortest_path(struct Map_info *Map, int from, int from_type,
260  int to, int to_type, int tucfield,
261  struct ilist *List, double *cost)
262 {
263  double x, y, z;
264  struct bound_box box;
265  struct boxlist *box_List;
266  struct line_cats *Cats;
267  int f, t;
268  int i_line, line, type, cfound;
269 
270  box_List = Vect_new_boxlist(0);
271  Cats = Vect_new_cats_struct();
272 
273  if (from_type ==
274  0) { /* TODO duplicite code with to_type, move into function */
275  /* select points at node */
276  Vect_get_node_coor(Map, from, &x, &y, &z);
277  box.E = box.W = x;
278  box.N = box.S = y;
279  box.T = box.B = z;
280  Vect_select_lines_by_box(Map, &box, GV_POINT, box_List);
281 
282  cfound = 0;
283 
284  for (i_line = 0; i_line < box_List->n_values; i_line++) {
285  line = box_List->id[i_line];
286 
287  type = Vect_read_line(Map, NULL, Cats, line);
288  if (!(type & GV_POINT))
289  continue;
290  if (Vect_cat_get(Cats, tucfield, &f)) {
291  ++cfound;
292  break;
293  }
294  }
295  if (!cfound)
296  G_fatal_error(_("Unable to find point with defined unique category "
297  "for node <%d>."),
298  from);
299  else if (cfound > 1)
300  G_warning(_("There exists more than one point on node <%d> with "
301  "unique category in field <%d>.\n"
302  "The unique category layer may not be valid."),
303  tucfield, from);
304 
305  G_debug(2, "from node = %d, unique cat = %d ", from, f);
306  f = f * 2;
307  }
308  else {
309  if (from < 0)
310  f = from * -2 + 1;
311  else
312  f = from * 2;
313  G_debug(2, "from edge unique cat = %d", from);
314  }
315 
316  if (to_type == 0) {
317  /* select points at node */
318  Vect_get_node_coor(Map, to, &x, &y, &z);
319  box.E = box.W = x;
320  box.N = box.S = y;
321  box.T = box.B = z;
322  Vect_select_lines_by_box(Map, &box, GV_POINT, box_List);
323 
324  cfound = 0;
325 
326  for (i_line = 0; i_line < box_List->n_values; i_line++) {
327  line = box_List->id[i_line];
328  type = Vect_read_line(Map, NULL, Cats, line);
329  if (!(type & GV_POINT))
330  continue;
331  if (Vect_cat_get(Cats, tucfield, &t)) {
332  cfound = 1;
333  break;
334  }
335  }
336  if (!cfound)
337  G_fatal_error(_("Unable to find point with defined unique category "
338  "for node <%d>."),
339  to);
340  else if (cfound > 1)
341  G_warning(_("There exists more than one point on node <%d> with "
342  "unique category in field <%d>.\n"
343  "The unique category layer may not be valid."),
344  tucfield, to);
345 
346  G_debug(2, "to node = %d, unique cat = %d ", to, t);
347  t = t * 2 + 1;
348  }
349  else {
350  if (to < 0)
351  t = to * -2 + 1;
352  else
353  t = to * 2;
354  G_debug(2, "to edge unique cat = %d", to);
355  }
356 
357  Vect_destroy_boxlist(box_List);
359 
360  return find_shortest_path(Map, f, t, List, cost, 1, tucfield);
361 }
362 
363 /*!
364  \brief Find shortest path.
365 
366  Costs for 'from' and 'to' nodes are not considered (SP found even if
367  'from' or 'to' are 'closed' (costs = -1) and costs of these
368  nodes are not added to SP costs result.
369 
370  \param Map vector map with build graph (see Vect_net_ttb_build_graph and
371  Vect_net_build_graph) \param from from node \param to to node \param[out]
372  List list of line ids (path) \param[out] cost costs value
373 
374  \return number of segments
375  \return 0 is correct for from = to, or List == NULL ? sum of costs is better
376  return value, \return -1 : destination unreachable
377 
378  */
379 int Vect_net_shortest_path(struct Map_info *Map, int from, int to,
380  struct ilist *List, double *cost)
381 {
382  return find_shortest_path(Map, from, to, List, cost, 0, -1);
383 }
384 
385 /*!
386  \brief Get graph structure
387 
388  Graph is built by Vect_net_build_graph().
389 
390  Returns NULL when graph is not built.
391 
392  \param Map pointer to Map_info struct
393 
394  \return pointer to dglGraph_s struct or NULL
395  */
397 {
398  return &(Map->dgraph.graph_s);
399 }
400 
401 /*!
402  \brief Returns in cost for given direction in *cost.
403 
404  cost is set to -1 if closed.
405 
406  \param Map vector map with build graph (see Vect_net_ttb_build_graph and
407  Vect_net_build_graph) \param line line id \param direction direction
408  (GV_FORWARD, GV_BACKWARD) \param[out] cost
409 
410  \return 1 OK
411  \return 0 does not exist (was not inserted)
412  */
413 int Vect_net_get_line_cost(struct Map_info *Map, int line, int direction,
414  double *cost)
415 {
416  /* dglInt32_t *pEdge; */
417 
418  G_debug(5, "Vect_net_get_line_cost(): line = %d, dir = %d", line,
419  direction);
420 
421  if (direction == GV_FORWARD) {
422  /* V1 has no index by line-id -> array used */
423  /*
424  pEdge = dglGetEdge(&(Map->dgraph.graph_s), line);
425  if (pEdge == NULL)
426  return 0;
427  *cost = (double) dglEdgeGet_Cost(&(Map->dgraph.graph_s), pEdge);
428  */
429  if (Map->dgraph.edge_fcosts[line] == -1) {
430  *cost = -1;
431  return 0;
432  }
433  else
434  *cost = Map->dgraph.edge_fcosts[line];
435  }
436  else if (direction == GV_BACKWARD) {
437  /*
438  pEdge = dglGetEdge(&(Map->dgraph.graph_s), -line);
439  if (pEdge == NULL)
440  return 0;
441  *cost = (double) dglEdgeGet_Cost(&(Map->dgraph.graph_s), pEdge);
442  */
443  if (Map->dgraph.edge_bcosts[line] == -1) {
444  *cost = -1;
445  return 0;
446  }
447  else
448  *cost = Map->dgraph.edge_bcosts[line];
449  G_debug(5, "Vect_net_get_line_cost(): edge_bcosts = %f",
450  Map->dgraph.edge_bcosts[line]);
451  }
452  else {
453  G_fatal_error(_("Wrong line direction in Vect_net_get_line_cost()"));
454  }
455 
456  return 1;
457 }
458 
459 /*!
460  \brief Get cost of node
461 
462  \param Map vector map with build graph (see Vect_net_ttb_build_graph and
463  Vect_net_build_graph) \param node node id \param[out] cost costs value
464 
465  \return 1
466  */
467 int Vect_net_get_node_cost(struct Map_info *Map, int node, double *cost)
468 {
469  G_debug(3, "Vect_net_get_node_cost(): node = %d", node);
470 
471  *cost = Map->dgraph.node_costs[node];
472 
473  G_debug(3, " -> cost = %f", *cost);
474 
475  return 1;
476 }
477 
478 /*!
479  \brief Find nearest node(s) on network.
480 
481  \param Map vector map with build graph (see Vect_net_ttb_build_graph and
482  Vect_net_build_graph)
483  \param x,y,z point coordinates (z coordinate NOT USED!)
484  \param direction (GV_FORWARD - from point to net, GV_BACKWARD - from net
485  to point)
486  \param maxdist maximum distance to the network
487  \param[out] node1 pointer where to store the node number (or NULL)
488  \param[out] node2 pointer where to store the node number (or NULL)
489  \param[out] ln pointer where to store the nearest line number (or NULL)
490  \param[out] costs1 pointer where to store costs on nearest line to node1 (not
491  costs from x,y,z to the line) (or NULL)
492  \param[out] costs2 pointer where to store costs on nearest line to node2
493  (not costs from x,y,z to the line) (or NULL)
494  \param[out] Points1 pointer to structure where to store vertices on nearest
495  line to node1 (or NULL)
496  \param[out] Points2 pointer to structure where to store vertices on nearest
497  line to node2 (or NULL)
498  \param[out] pointer where to distance to the line (or NULL)
499  \param[out] distance
500 
501  \return number of nodes found (0,1,2)
502  */
503 int Vect_net_nearest_nodes(struct Map_info *Map, double x, double y, double z,
504  int direction, double maxdist, int *node1,
505  int *node2, int *ln, double *costs1, double *costs2,
506  struct line_pnts *Points1, struct line_pnts *Points2,
507  double *distance)
508 {
509  int line, n1, n2, nnodes;
510  int npoints;
511  int segment; /* nearest line segment (first is 1) */
512  static struct line_pnts *Points = NULL;
513  double cx, cy, cz, c1, c2;
514  double along; /* distance along the line to nearest point */
515  double length;
516 
517  G_debug(3, "Vect_net_nearest_nodes() x = %f y = %f", x, y);
518 
519  /* Reset */
520  if (node1)
521  *node1 = 0;
522  if (node2)
523  *node2 = 0;
524  if (ln)
525  *ln = 0;
526  if (costs1)
527  *costs1 = PORT_DOUBLE_MAX;
528  if (costs2)
529  *costs2 = PORT_DOUBLE_MAX;
530  if (Points1)
531  Vect_reset_line(Points1);
532  if (Points2)
533  Vect_reset_line(Points2);
534  if (distance)
535  *distance = PORT_DOUBLE_MAX;
536 
537  if (!Points)
538  Points = Vect_new_line_struct();
539 
540  /* Find nearest line */
541  line = Vect_find_line(Map, x, y, z, Map->dgraph.line_type, maxdist, 0, 0);
542 
543  if (line < 1)
544  return 0;
545 
546  Vect_read_line(Map, Points, NULL, line);
547  npoints = Points->n_points;
548  Vect_get_line_nodes(Map, line, &n1, &n2);
549 
550  segment = Vect_line_distance(Points, x, y, z, 0, &cx, &cy, &cz, distance,
551  NULL, &along);
552 
553  G_debug(4, "line = %d n1 = %d n2 = %d segment = %d", line, n1, n2, segment);
554 
555  /* Check first or last point and return one node in that case */
556  G_debug(4, "cx = %f cy = %f first = %f %f last = %f %f", cx, cy,
557  Points->x[0], Points->y[0], Points->x[npoints - 1],
558  Points->y[npoints - 1]);
559 
560  if (Points->x[0] == cx && Points->y[0] == cy) {
561  if (node1)
562  *node1 = n1;
563  if (ln)
564  *ln = line;
565  if (costs1)
566  *costs1 = 0;
567  if (Points1) {
568  Vect_append_point(Points1, x, y, z);
569  Vect_append_point(Points1, cx, cy, cz);
570  }
571  G_debug(3, "first node nearest");
572  return 1;
573  }
574  if (Points->x[npoints - 1] == cx && Points->y[npoints - 1] == cy) {
575  if (node1)
576  *node1 = n2;
577  if (ln)
578  *ln = line;
579  if (costs1)
580  *costs1 = 0;
581  if (Points1) {
582  Vect_append_point(Points1, x, y, z);
583  Vect_append_point(Points1, cx, cy, cz);
584  }
585  G_debug(3, "last node nearest");
586  return 1;
587  }
588 
589  nnodes = 2;
590 
591  /* c1 - costs to get from/to the first vertex */
592  /* c2 - costs to get from/to the last vertex */
593  if (direction == GV_FORWARD) { /* from point to net */
594  Vect_net_get_line_cost(Map, line, GV_BACKWARD, &c1);
595  Vect_net_get_line_cost(Map, line, GV_FORWARD, &c2);
596  }
597  else {
598  Vect_net_get_line_cost(Map, line, GV_FORWARD, &c1);
599  Vect_net_get_line_cost(Map, line, GV_BACKWARD, &c2);
600  }
601 
602  if (c1 < 0)
603  nnodes--;
604  if (c2 < 0)
605  nnodes--;
606  if (nnodes == 0)
607  return 0; /* both directions closed */
608 
609  length = Vect_line_length(Points);
610 
611  if (ln)
612  *ln = line;
613 
614  if (nnodes == 1 &&
615  c1 < 0) { /* first direction is closed, return node2 as node1 */
616  if (node1)
617  *node1 = n2;
618 
619  if (costs1) { /* to node 2, i.e. forward */
620  *costs1 = c2 * (length - along) / length;
621  }
622 
623  if (Points1) { /* to node 2, i.e. forward */
624  int i;
625 
626  if (direction == GV_FORWARD) { /* from point to net */
627  Vect_append_point(Points1, x, y, z);
628  Vect_append_point(Points1, cx, cy, cz);
629  for (i = segment; i < npoints; i++)
630  Vect_append_point(Points1, Points->x[i], Points->y[i],
631  Points->z[i]);
632  }
633  else {
634  for (i = npoints - 1; i >= segment; i--)
635  Vect_append_point(Points1, Points->x[i], Points->y[i],
636  Points->z[i]);
637 
638  Vect_append_point(Points1, cx, cy, cz);
639  Vect_append_point(Points1, x, y, z);
640  }
641  }
642  }
643  else {
644  if (node1)
645  *node1 = n1;
646  if (node2)
647  *node2 = n2;
648 
649  if (costs1) { /* to node 1, i.e. backward */
650  *costs1 = c1 * along / length;
651  }
652 
653  if (costs2) { /* to node 2, i.e. forward */
654  *costs2 = c2 * (length - along) / length;
655  }
656 
657  if (Points1) { /* to node 1, i.e. backward */
658  int i;
659 
660  if (direction == GV_FORWARD) { /* from point to net */
661  Vect_append_point(Points1, x, y, z);
662  Vect_append_point(Points1, cx, cy, cz);
663  for (i = segment - 1; i >= 0; i--)
664  Vect_append_point(Points1, Points->x[i], Points->y[i],
665  Points->z[i]);
666  }
667  else {
668  for (i = 0; i < segment; i++)
669  Vect_append_point(Points1, Points->x[i], Points->y[i],
670  Points->z[i]);
671 
672  Vect_append_point(Points1, cx, cy, cz);
673  Vect_append_point(Points1, x, y, z);
674  }
675  }
676 
677  if (Points2) { /* to node 2, i.e. forward */
678  int i;
679 
680  if (direction == GV_FORWARD) { /* from point to net */
681  Vect_append_point(Points2, x, y, z);
682  Vect_append_point(Points2, cx, cy, cz);
683  for (i = segment; i < npoints; i++)
684  Vect_append_point(Points2, Points->x[i], Points->y[i],
685  Points->z[i]);
686  }
687  else {
688  for (i = npoints - 1; i >= segment; i--)
689  Vect_append_point(Points2, Points->x[i], Points->y[i],
690  Points->z[i]);
691 
692  Vect_append_point(Points2, cx, cy, cz);
693  Vect_append_point(Points2, x, y, z);
694  }
695  }
696  }
697 
698  return nnodes;
699 }
700 
701 /*!
702  \brief Find shortest path on network between 2 points given by coordinates.
703 
704  \param Map vector map with build graph (see Vect_net_ttb_build_graph and
705  Vect_net_build_graph) \param fx,fy,fz from point x coordinate (z ignored)
706  \param tx,ty,tz to point x coordinate (z ignored)
707  \param fmax maximum distance to the network from 'from'
708  \param tmax maximum distance to the network from 'to'
709  \param UseTtb the graph is build with/without turntable
710  \param tucfield field with unique categories used in the turntable
711  \param costs pointer where to store costs on the network (or NULL)
712  \param Points pointer to the structure where to store vertices of shortest
713  path (or NULL) \param List pointer to the structure where list of lines on
714  the network is stored (or NULL) \param NodesList pointer to the structure
715  where list of nodes on the network is stored (or NULL) \param FPoints pointer
716  to the structure where to store line from 'from' to first network node (or
717  NULL) \param TPoints pointer to the structure where to store line from last
718  network node to 'to' (or NULL) \param fdist distance from 'from' to the net
719  (or NULL) \param tdist distance from 'to' to the net (or NULL)
720 
721  \return 1 OK, 0 not reachable
722  */
723 static int
724 find_shortest_path_coor(struct Map_info *Map, double fx, double fy, double fz,
725  double tx, double ty, double tz, double fmax,
726  double tmax, int UseTtb, int tucfield, double *costs,
727  struct line_pnts *Points, struct ilist *List,
728  struct ilist *NodesList, struct line_pnts *FPoints,
729  struct line_pnts *TPoints, double *fdist, double *tdist)
730 {
731  int fnode[2],
732  tnode[2]; /* nearest nodes, *node[1] is 0 if only one was found */
733  double fcosts[2], tcosts[2],
734  cur_cst; /* costs to nearest nodes on the network */
735  int nfnodes, ntnodes, fline, tline;
736  static struct line_pnts *APoints, *SPoints, *fPoints[2], *tPoints[2];
737  static struct ilist *LList;
738  static int first = 1;
739  int reachable, shortcut;
740  int i, j, fn = 0, tn = 0;
741 
742  /* from/to_point_node is set if from/to point projected to line
743  *falls exactly on node (shortcut -> fline == tline) */
744  int from_point_node = 0;
745  int to_point_node = 0;
746 
747  G_debug(3, "Vect_net_shortest_path_coor()");
748 
749  if (first) {
750  APoints = Vect_new_line_struct();
751  SPoints = Vect_new_line_struct();
752  fPoints[0] = Vect_new_line_struct();
753  fPoints[1] = Vect_new_line_struct();
754  tPoints[0] = Vect_new_line_struct();
755  tPoints[1] = Vect_new_line_struct();
756  LList = Vect_new_list();
757  first = 0;
758  }
759 
760  /* Reset */
761  if (costs)
762  *costs = PORT_DOUBLE_MAX;
763  if (Points)
764  Vect_reset_line(Points);
765  if (fdist)
766  *fdist = 0;
767  if (tdist)
768  *tdist = 0;
769  if (List)
770  List->n_values = 0;
771  if (FPoints)
772  Vect_reset_line(FPoints);
773  if (TPoints)
774  Vect_reset_line(TPoints);
775  if (NodesList != NULL)
776  Vect_reset_list(NodesList);
777 
778  /* Find nearest nodes */
779  fnode[0] = fnode[1] = tnode[0] = tnode[1] = 0;
780 
781  nfnodes = Vect_net_nearest_nodes(
782  Map, fx, fy, fz, GV_FORWARD, fmax, &(fnode[0]), &(fnode[1]), &fline,
783  &(fcosts[0]), &(fcosts[1]), fPoints[0], fPoints[1], fdist);
784  if (nfnodes == 0)
785  return 0;
786 
787  if (nfnodes == 1 && fPoints[0]->n_points < 3) {
788  from_point_node = fnode[0];
789  }
790 
791  ntnodes = Vect_net_nearest_nodes(
792  Map, tx, ty, tz, GV_BACKWARD, tmax, &(tnode[0]), &(tnode[1]), &tline,
793  &(tcosts[0]), &(tcosts[1]), tPoints[0], tPoints[1], tdist);
794  if (ntnodes == 0)
795  return 0;
796 
797  if (ntnodes == 1 && tPoints[0]->n_points < 3) {
798  to_point_node = tnode[0];
799  }
800 
801  G_debug(3, "fline = %d tline = %d", fline, tline);
802 
803  reachable = shortcut = 0;
804  cur_cst = PORT_DOUBLE_MAX;
805 
806  /* It may happen, that 2 points are at the same line. */
807  /* TODO?: it could also happen that fline != tline but both points are on
808  * the same line if they fall on node but a different line was found. This
809  * case is correctly handled as normal non shortcut, but it could be added
810  * here. In that case NodesList collection must be changed */
811  if (fline == tline && (nfnodes > 1 || ntnodes > 1)) {
812  double len, flen, tlen, c, fseg, tseg;
813  double fcx, fcy, fcz, tcx, tcy, tcz;
814 
815  Vect_read_line(Map, APoints, NULL, fline);
816  len = Vect_line_length(APoints);
817 
818  /* distance along the line */
819  fseg = Vect_line_distance(APoints, fx, fy, fz, 0, &fcx, &fcy, &fcz,
820  NULL, NULL, &flen);
821  tseg = Vect_line_distance(APoints, tx, ty, tz, 0, &tcx, &tcy, &tcz,
822  NULL, NULL, &tlen);
823 
824  Vect_reset_line(SPoints);
825  if (flen == tlen) {
826  cur_cst = 0;
827 
828  Vect_append_point(SPoints, fx, fy, fz);
829  Vect_append_point(SPoints, fcx, fcy, fcz);
830  Vect_append_point(SPoints, tx, ty, tz);
831 
832  reachable = shortcut = 1;
833  }
834  else if (flen < tlen) {
835  Vect_net_get_line_cost(Map, fline, GV_FORWARD, &c);
836  if (c >= 0) {
837  cur_cst = c * (tlen - flen) / len;
838 
839  Vect_append_point(SPoints, fx, fy, fz);
840  Vect_append_point(SPoints, fcx, fcy, fcz);
841  for (i = fseg; i < tseg; i++)
842  Vect_append_point(SPoints, APoints->x[i], APoints->y[i],
843  APoints->z[i]);
844 
845  Vect_append_point(SPoints, tcx, tcy, tcz);
846  Vect_append_point(SPoints, tx, ty, tz);
847 
848  reachable = shortcut = 1;
849  }
850  }
851  else { /* flen > tlen */
852  Vect_net_get_line_cost(Map, fline, GV_BACKWARD, &c);
853  if (c >= 0) {
854  cur_cst = c * (flen - tlen) / len;
855 
856  Vect_append_point(SPoints, fx, fy, fz);
857  Vect_append_point(SPoints, fcx, fcy, fcz);
858  for (i = fseg - 1; i >= tseg; i--)
859  Vect_append_point(SPoints, APoints->x[i], APoints->y[i],
860  APoints->z[i]);
861 
862  Vect_append_point(SPoints, tcx, tcy, tcz);
863  Vect_append_point(SPoints, tx, ty, tz);
864 
865  reachable = shortcut = 1;
866  }
867  }
868  }
869 
870  /* Find the shortest variant from maximum 4 */
871  for (i = 0; i < nfnodes; i++) {
872  for (j = 0; j < ntnodes; j++) {
873  double ncst, cst;
874  int ret;
875 
876  G_debug(3, "i = %d fnode = %d j = %d tnode = %d", i, fnode[i], j,
877  tnode[j]);
878 
879  if (UseTtb)
880  ret = Vect_net_ttb_shortest_path(Map, fnode[i], 0, tnode[j], 0,
881  tucfield, NULL, &ncst);
882  else
883  ret = Vect_net_shortest_path(Map, fnode[i], tnode[j], NULL,
884  &ncst);
885  if (ret == -1)
886  continue; /* not reachable */
887 
888  cst = fcosts[i] + ncst + tcosts[j];
889  if (reachable == 0 || cst < cur_cst) {
890  cur_cst = cst;
891  fn = i;
892  tn = j;
893  shortcut = 0;
894  }
895  reachable = 1;
896  }
897  }
898 
899  G_debug(3, "reachable = %d shortcut = %d cur_cst = %f", reachable, shortcut,
900  cur_cst);
901  if (reachable) {
902  if (shortcut) {
903  if (Points)
904  Vect_append_points(Points, SPoints, GV_FORWARD);
905  if (NodesList) {
906  /* Check if from/to point projected to line falls on node and
907  *add it to the list */
908  if (from_point_node > 0)
909  Vect_list_append(NodesList, from_point_node);
910 
911  if (to_point_node > 0)
912  Vect_list_append(NodesList, to_point_node);
913  }
914  }
915  else {
916  if (NodesList) {
917  /* it can happen that starting point falls on node but SP starts
918  * form the other node, add it in that case,
919  * similarly for to point below */
920  if (from_point_node > 0 && from_point_node != fnode[fn]) {
921  Vect_list_append(NodesList, from_point_node);
922  }
923 
924  /* add starting net SP search node */
925  Vect_list_append(NodesList, fnode[fn]);
926  }
927 
928  if (UseTtb)
929  Vect_net_ttb_shortest_path(Map, fnode[fn], 0, tnode[tn], 0,
930  tucfield, LList, NULL);
931  else
932  Vect_net_shortest_path(Map, fnode[fn], tnode[tn], LList, NULL);
933 
934  G_debug(3, "Number of lines %d", LList->n_values);
935 
936  if (Points)
937  Vect_append_points(Points, fPoints[fn], GV_FORWARD);
938 
939  if (FPoints)
940  Vect_append_points(FPoints, fPoints[fn], GV_FORWARD);
941 
942  for (i = 0; i < LList->n_values; i++) {
943  int line;
944 
945  line = LList->value[i];
946  G_debug(3, "i = %d line = %d", i, line);
947 
948  if (Points) {
949  Vect_read_line(Map, APoints, NULL, abs(line));
950 
951  if (line > 0)
952  Vect_append_points(Points, APoints, GV_FORWARD);
953  else
954  Vect_append_points(Points, APoints, GV_BACKWARD);
955  Points->n_points--;
956  }
957  if (NodesList) {
958  int node, node1, node2;
959 
960  Vect_get_line_nodes(Map, abs(line), &node1, &node2);
961  /* add the second node, the first of first segmet was
962  * already added */
963  if (line > 0)
964  node = node2;
965  else
966  node = node1;
967 
968  Vect_list_append(NodesList, node);
969  }
970 
971  if (List)
972  Vect_list_append(List, line);
973  }
974 
975  if (Points) {
976  if (LList->n_values)
977  Points->n_points++;
978  Vect_append_points(Points, tPoints[tn], GV_FORWARD);
979  }
980 
981  if (TPoints)
982  Vect_append_points(TPoints, tPoints[tn], GV_FORWARD);
983 
984  if (NodesList) {
985  if (to_point_node > 0 && to_point_node != tnode[tn]) {
986  Vect_list_append(NodesList, to_point_node);
987  }
988  }
989  }
990 
991  if (costs)
992  *costs = cur_cst;
993  if (Points)
994  Vect_line_prune(Points);
995  }
996 
997  return reachable;
998 }
999 
1000 /*!
1001  \brief Find shortest path on network between 2 points given by coordinates.
1002 
1003  \param Map vector map with build graph (see Vect_net_ttb_build_graph and
1004  Vect_net_build_graph) \param fx,fy,fz from point x coordinate (z ignored)
1005  \param tx,ty,tz to point x coordinate (z ignored)
1006  \param fmax maximum distance to the network from 'from'
1007  \param tmax maximum distance to the network from 'to'
1008  \param costs pointer where to store costs on the network (or NULL)
1009  \param Points pointer to the structure where to store vertices of shortest
1010  path (or NULL) \param List pointer to the structure where list of lines on
1011  the network is stored (or NULL) \param NodesList pointer to the structure
1012  where list of nodes on the network is stored (or NULL) \param FPoints pointer
1013  to the structure where to store line from 'from' to first network node (or
1014  NULL) \param TPoints pointer to the structure where to store line from last
1015  network node to 'to' (or NULL) \param fdist distance from 'from' to the net
1016  (or NULL) \param tdist distance from 'to' to the net (or NULL)
1017 
1018  \return 1 OK, 0 not reachable
1019  */
1020 int Vect_net_shortest_path_coor(struct Map_info *Map, double fx, double fy,
1021  double fz, double tx, double ty, double tz,
1022  double fmax, double tmax, double *costs,
1023  struct line_pnts *Points, struct ilist *List,
1024  struct ilist *NodesList,
1025  struct line_pnts *FPoints,
1026  struct line_pnts *TPoints, double *fdist,
1027  double *tdist)
1028 {
1029  return find_shortest_path_coor(Map, fx, fy, fz, tx, ty, tz, fmax, tmax, 0,
1030  0, costs, Points, List, NodesList, FPoints,
1031  TPoints, fdist, tdist);
1032 }
1033 
1034 /*!
1035  \brief Find shortest path on network with turntable between 2 points given by
1036  coordinates.
1037 
1038  \param Map vector map with build graph (see Vect_net_ttb_build_graph and
1039  Vect_net_build_graph) \param fx,fy,fz from point x coordinate (z ignored)
1040  \param tx,ty,tz to point x coordinate (z ignored)
1041  \param fmax maximum distance to the network from 'from'
1042  \param tmax maximum distance to the network from 'to'
1043  \param tucfield field with unique categories used in the turntable
1044  \param costs pointer where to store costs on the network (or NULL)
1045  \param Points pointer to the structure where to store vertices of shortest
1046  path (or NULL) \param List pointer to the structure where list of lines on
1047  the network is stored (or NULL) \param NodesList pointer to the structure
1048  where list of nodes on the network is stored (or NULL) \param FPoints pointer
1049  to the structure where to store line from 'from' to first network node (or
1050  NULL) \param TPoints pointer to the structure where to store line from last
1051  network node to 'to' (or NULL) \param fdist distance from 'from' to the net
1052  (or NULL) \param tdist distance from 'to' to the net (or NULL)
1053 
1054  \return 1 OK, 0 not reachable
1055  */
1056 int Vect_net_ttb_shortest_path_coor(struct Map_info *Map, double fx, double fy,
1057  double fz, double tx, double ty, double tz,
1058  double fmax, double tmax, int tucfield,
1059  double *costs, struct line_pnts *Points,
1060  struct ilist *List, struct ilist *NodesList,
1061  struct line_pnts *FPoints,
1062  struct line_pnts *TPoints, double *fdist,
1063  double *tdist)
1064 {
1065  return find_shortest_path_coor(Map, fx, fy, fz, tx, ty, tz, fmax, tmax, 1,
1066  tucfield, costs, Points, List, NodesList,
1067  FPoints, TPoints, fdist, tdist);
1068 }
#define NULL
Definition: ccmath.h:32
Main header of GRASS DataBase Management Interface.
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
void G_warning(const char *,...) __attribute__((format(printf
int G_debug(int, const char *,...) __attribute__((format(printf
int Vect_get_line_nodes(struct Map_info *, int, int *, int *)
Get line nodes.
Definition: level_two.c:304
int Vect_get_node_coor(struct Map_info *, int, double *, double *, double *)
Get node coordinates.
Definition: level_two.c:274
double Vect_line_length(const struct line_pnts *)
Calculate line length, 3D-length in case of 3D vector line.
Definition: line.c:575
int Vect_cidx_get_field_index(struct Map_info *, int)
Get layer index for given layer number.
Definition: Vlib/cindex.c:115
int Vect_cidx_find_next(struct Map_info *, int, int, int, int, int *, int *)
Find next line/area id for given category, start_index and type_mask.
Definition: Vlib/cindex.c:327
struct boxlist * Vect_new_boxlist(int)
Creates and initializes a struct boxlist.
int Vect_cat_get(const struct line_cats *, int, int *)
Get first found category of given field.
void Vect_destroy_boxlist(struct boxlist *)
Frees all memory associated with a struct boxlist, including the struct itself.
void Vect_destroy_cats_struct(struct line_cats *)
Frees all memory associated with line_cats structure, including the struct itself.
int Vect_list_append(struct ilist *, int)
Append new item to the end of list if not yet present.
int Vect_read_line(struct Map_info *, struct line_pnts *, struct line_cats *, int)
Read vector feature (topological level required)
int Vect_line_distance(const struct line_pnts *, double, double, double, int, double *, double *, double *, double *, double *, double *)
Calculate distance of point to line.
Definition: line.c:648
struct ilist * Vect_new_list(void)
Creates and initializes a struct ilist.
int Vect_find_line(struct Map_info *, double, double, double, int, double, int, int)
Find the nearest line.
struct line_pnts * Vect_new_line_struct(void)
Creates and initializes a line_pnts structure.
Definition: line.c:45
int Vect_select_lines_by_box(struct Map_info *, const struct bound_box *, int, struct boxlist *)
Select lines with bounding boxes by box.
Definition: sindex.c:32
void Vect_reset_line(struct line_pnts *)
Reset line.
Definition: line.c:129
int Vect_line_prune(struct line_pnts *)
Remove duplicate points, i.e. zero length segments.
Definition: line.c:279
struct line_cats * Vect_new_cats_struct(void)
Creates and initializes line_cats structure.
int Vect_reset_list(struct ilist *)
Reset ilist structure.
int Vect_append_point(struct line_pnts *, double, double, double)
Appends one point to the end of a line.
Definition: line.c:148
int Vect_append_points(struct line_pnts *, const struct line_pnts *, int)
Appends points to the end of a line.
Definition: line.c:335
#define GV_LINE
Definition: dig_defines.h:184
#define GV_POINT
Feature types used in memory on run time (may change)
Definition: dig_defines.h:183
#define PORT_DOUBLE_MAX
Limits for portable types.
Definition: dig_defines.h:66
#define GV_FORWARD
Line direction indicator forward/backward.
Definition: dig_defines.h:179
#define GV_BACKWARD
Definition: dig_defines.h:180
#define UNUSED
A macro for an attribute, if attached to a variable, indicating that the variable is not used.
Definition: gis.h:46
#define _(str)
Definition: glocale.h:10
int Vect_net_shortest_path(struct Map_info *Map, int from, int to, struct ilist *List, double *cost)
Find shortest path.
Definition: net_analyze.c:379
int Vect_net_ttb_shortest_path_coor(struct Map_info *Map, double fx, double fy, double fz, double tx, double ty, double tz, double fmax, double tmax, int tucfield, 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 with turntable between 2 points given by coordinates.
Definition: net_analyze.c:1056
dglGraph_s * Vect_net_get_graph(struct Map_info *Map)
Get graph structure.
Definition: net_analyze.c:396
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 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_analyze.c:1020
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_analyze.c:413
int Vect_net_ttb_shortest_path(struct Map_info *Map, int from, int from_type, int to, int to_type, int tucfield, struct ilist *List, double *cost)
Find shortest path on network.
Definition: net_analyze.c:259
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_analyze.c:503
int Vect_net_get_node_cost(struct Map_info *Map, int node, double *cost)
Get cost of node.
Definition: net_analyze.c:467
double t
Definition: r_raster.c:39
dglSPCache_s spCache
Shortest path cache.
Definition: dig_structs.h:1216
int line_type
Line type used to build the graph.
Definition: dig_structs.h:1208
int cost_multip
Edge and node costs multiplicator.
Definition: dig_structs.h:1234
double * edge_fcosts
Forward costs used for graph.
Definition: dig_structs.h:1222
double * node_costs
Node costs used for graph.
Definition: dig_structs.h:1230
dglGraph_s graph_s
Graph structure.
Definition: dig_structs.h:1212
double * edge_bcosts
backward costs used for graph
Definition: dig_structs.h:1226
Vector map info.
Definition: dig_structs.h:1243
struct Graph_info dgraph
Graph info (built for network analysis)
Definition: dig_structs.h:1383
dglInt32_t nDistance
Definition: graph.h:196
dglInt32_t nTo
Definition: graph.h:194
dglInt32_t * pnEdge
Definition: graph.h:195
dglInt32_t nFrom
Definition: graph.h:193
dglInt32_t * pnNodeTo
Definition: graph.h:90
dglInt32_t * pnNodeFrom
Definition: graph.h:88
dglInt32_t * pnEdge
Definition: graph.h:89
dglInt32_t nEdgeCost
Definition: graph.h:96
dglInt32_t nDistance
Definition: graph.h:205
dglInt32_t cArc
Definition: graph.h:206
dglSPArc_s * pArc
Definition: graph.h:207
Bounding box.
Definition: dig_structs.h:64
double W
West.
Definition: dig_structs.h:80
double T
Top.
Definition: dig_structs.h:84
double S
South.
Definition: dig_structs.h:72
double N
North.
Definition: dig_structs.h:68
double E
East.
Definition: dig_structs.h:76
double B
Bottom.
Definition: dig_structs.h:88
List of bounding boxes with id.
Definition: dig_structs.h:1723
int * id
Array of ids.
Definition: dig_structs.h:1727
int n_values
Number of items in the list.
Definition: dig_structs.h:1739
List of integers.
Definition: gis.h:715
int n_values
Number of values in the list.
Definition: gis.h:723
int * value
Array of values.
Definition: gis.h:719
Feature category info.
Definition: dig_structs.h:1677
Feature geometry info - coordinates.
Definition: dig_structs.h:1651
double * y
Array of Y coordinates.
Definition: dig_structs.h:1659
double * x
Array of X coordinates.
Definition: dig_structs.h:1655
int n_points
Number of points.
Definition: dig_structs.h:1667
double * z
Array of Z coordinates.
Definition: dig_structs.h:1663
long dglInt32_t
Definition: type.h:36
void dglFreeSPReport(dglGraph_s *pgraph, dglSPReport_s *pSPReport)
int dglGet_NodeAttrSize(dglGraph_s *pgraph)
int dglShortestPath(dglGraph_s *pGraph, dglSPReport_s **ppReport, dglInt32_t nStart, dglInt32_t nDestination, dglSPClip_fn fnClip, void *pvClipArg, dglSPCache_s *pCache)
char * dglStrerror(dglGraph_s *pgraph)
dglInt32_t dglEdgeGet_Id(dglGraph_s *pGraph, dglInt32_t *pnEdge)
dglInt32_t * dglEdgeGet_Head(dglGraph_s *pGraph, dglInt32_t *pnEdge)
dglInt32_t * dglNodeGet_Attr(dglGraph_s *pGraph, dglInt32_t *pnNode)
int dglShortestDistance(dglGraph_s *pGraph, dglInt32_t *pnDistance, dglInt32_t nStart, dglInt32_t nDestination, dglSPClip_fn fnClip, void *pvClipArg, dglSPCache_s *pCache)
dglInt32_t dglEdgeGet_Cost(dglGraph_s *pGraph, dglInt32_t *pnEdge)
dglInt32_t dglNodeGet_Id(dglGraph_s *pGraph, dglInt32_t *pnNode)
#define x