graph.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. /*!
  2. \file lib/vector/Vlib/graph.c
  3. \brief Vector library - graph manipulation
  4. Higher level functions for reading/writing/manipulating vectors.
  5. \todo Vect_graph_free ( dglGraph_s *graph )
  6. (C) 2001-2009 by the GRASS Development Team
  7. This program is free software under the GNU General Public License
  8. (>=v2). Read the file COPYING that comes with GRASS for details.
  9. \author Radim Blazek
  10. */
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <grass/dbmi.h>
  14. #include <grass/vector.h>
  15. #include <grass/glocale.h>
  16. static int From_node; /* from node set in SP and used by clipper for first arc */
  17. static int clipper(dglGraph_s * pgraph,
  18. dglSPClipInput_s * pargIn,
  19. dglSPClipOutput_s * pargOut, void *pvarg)
  20. { /* caller's pointer */
  21. dglInt32_t cost;
  22. dglInt32_t from;
  23. G_debug(3, "Net: clipper()");
  24. from = dglNodeGet_Id(pgraph, pargIn->pnNodeFrom);
  25. G_debug(3, " Edge = %d NodeFrom = %d NodeTo = %d edge cost = %d",
  26. (int)dglEdgeGet_Id(pgraph, pargIn->pnEdge),
  27. (int)from, (int)dglNodeGet_Id(pgraph, pargIn->pnNodeTo),
  28. (int)pargOut->nEdgeCost);
  29. if (from != From_node) { /* do not clip first */
  30. if (dglGet_NodeAttrSize(pgraph) > 0) {
  31. memcpy(&cost, dglNodeGet_Attr(pgraph, pargIn->pnNodeFrom),
  32. sizeof(cost));
  33. if (cost == -1) { /* closed, cannot go from this node except it is 'from' node */
  34. G_debug(3, " closed node");
  35. return 1;
  36. }
  37. else {
  38. G_debug(3, " EdgeCost += %d (node)", (int)cost);
  39. pargOut->nEdgeCost += cost;
  40. }
  41. }
  42. }
  43. else {
  44. G_debug(3, " don't clip first node");
  45. }
  46. return 0;
  47. }
  48. /*!
  49. \brief Initialize graph structure
  50. \param graph poiter to graph structure
  51. \param nodes_costs use node costs
  52. \return void
  53. */
  54. void Vect_graph_init(dglGraph_s * graph, int nodes_costs)
  55. {
  56. dglInt32_t opaqueset[16] =
  57. { 360000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  58. G_debug(3, "Vect_graph_init()");
  59. if (nodes_costs)
  60. dglInitialize(graph, (dglByte_t) 1, sizeof(dglInt32_t),
  61. (dglInt32_t) 0, opaqueset);
  62. else
  63. dglInitialize(graph, (dglByte_t) 1, (dglInt32_t) 0, (dglInt32_t) 0,
  64. opaqueset);
  65. }
  66. /*!
  67. \brief Build network graph.
  68. Internal format for edge costs is integer, costs are multiplied
  69. before conversion to int by 1000. Costs -1 for infinity i.e. arc
  70. or node is closed and cannot be traversed.
  71. \param graph poiter to graph structure
  72. \return void
  73. */
  74. void Vect_graph_build(dglGraph_s * graph)
  75. {
  76. int ret;
  77. G_debug(3, "Vect_graph_build()");
  78. ret = dglFlatten(graph);
  79. if (ret < 0)
  80. G_fatal_error(_("GngFlatten error"));
  81. }
  82. /*!
  83. \brief Add edge to graph.
  84. Internal format for edge costs is integer, costs are multiplied
  85. before conversion to int by 1000. Costs -1 for infinity i.e. arc
  86. or node is closed and cannot be traversed.
  87. \param graph poiter to graph structure
  88. \param from from node
  89. \param to to node
  90. \param costs costs value
  91. \param id edge id
  92. \return void
  93. */
  94. void
  95. Vect_graph_add_edge(dglGraph_s * graph, int from, int to, double costs, int id)
  96. {
  97. int ret;
  98. dglInt32_t dglcosts;
  99. G_debug(3, "Vect_add_edge() from = %d to = %d, costs = %f, id = %d", from,
  100. to, costs, id);
  101. dglcosts = (dglInt32_t) costs *1000;
  102. ret =
  103. dglAddEdge(graph, (dglInt32_t) from, (dglInt32_t) to, dglcosts,
  104. (dglInt32_t) id);
  105. if (ret < 0)
  106. G_fatal_error(_("Unable to add network arc"));
  107. }
  108. /*!
  109. \brief Set node costs
  110. Internal format for edge costs is integer, costs are multiplied
  111. before conversion to int by 1000. Costs -1 for infinity i.e. arc
  112. or node is closed and cannot be traversed.
  113. \param graph poiter to graph structure
  114. \param node node id
  115. \param costs costs value
  116. \return void
  117. */
  118. void Vect_graph_set_node_costs(dglGraph_s * graph, int node, double costs)
  119. {
  120. dglInt32_t dglcosts;
  121. /* TODO: Not tested! */
  122. G_debug(3, "Vect_graph_set_node_costs()");
  123. dglcosts = (dglInt32_t) costs *1000;
  124. dglNodeSet_Attr(graph, dglGetNode(graph, (dglInt32_t) node), &dglcosts);
  125. }
  126. /*!
  127. \brief Find shortest path.
  128. Costs for 'from' and 'to' nodes are not considered (SP found even if
  129. 'from' or 'to' are 'closed' (costs = -1) and costs of these
  130. nodes are not added to SP costs result.
  131. \param graph pointer to graph structure
  132. \param from from node
  133. \param to to node
  134. \param List list of line ids
  135. \param cost costs value
  136. \return number of segments
  137. \return 0 is correct for from = to, or List == NULL ), ? sum of costs is better return value,
  138. \return -1 destination unreachable
  139. */
  140. int
  141. Vect_graph_shortest_path(dglGraph_s * graph, int from, int to, struct ilist *List,
  142. double *cost)
  143. {
  144. int i, line, *pclip, cArc, nRet;
  145. dglSPReport_s *pSPReport;
  146. dglInt32_t nDistance;
  147. G_debug(3, "Vect_graph_shortest_path(): from = %d, to = %d", from, to);
  148. /* Note : if from == to dgl goes to nearest node and returns back (dgl feature) =>
  149. * check here for from == to */
  150. if (List != NULL)
  151. Vect_reset_list(List);
  152. /* Check if from and to are identical, otherwise dglib returns path to neares node and back! */
  153. if (from == to) {
  154. if (cost != NULL)
  155. *cost = 0;
  156. return 0;
  157. }
  158. From_node = from;
  159. pclip = NULL;
  160. if (List != NULL) {
  161. nRet =
  162. dglShortestPath(graph, &pSPReport, (dglInt32_t) from,
  163. (dglInt32_t) to, clipper, pclip, NULL);
  164. }
  165. else {
  166. nRet =
  167. dglShortestDistance(graph, &nDistance, (dglInt32_t) from,
  168. (dglInt32_t) to, clipper, pclip, NULL);
  169. }
  170. if (nRet == 0) {
  171. if (cost != NULL)
  172. *cost = PORT_DOUBLE_MAX;
  173. return -1;
  174. }
  175. else if (nRet < 0) {
  176. G_warning(_("dglShortestPath error: %s"), dglStrerror(graph));
  177. return -1;
  178. }
  179. if (List != NULL) {
  180. for (i = 0; i < pSPReport->cArc; i++) {
  181. line = dglEdgeGet_Id(graph, pSPReport->pArc[i].pnEdge);
  182. G_debug(2, "From %ld to %ld - cost %ld user %d distance %ld",
  183. pSPReport->pArc[i].nFrom, pSPReport->pArc[i].nTo,
  184. /* this is the cost from clip() */
  185. dglEdgeGet_Cost(graph, pSPReport->pArc[i].pnEdge) / 1000,
  186. line, pSPReport->pArc[i].nDistance);
  187. Vect_list_append(List, line);
  188. }
  189. }
  190. if (cost != NULL) {
  191. if (List != NULL)
  192. *cost = (double)pSPReport->nDistance / 1000;
  193. else
  194. *cost = (double)nDistance / 1000;
  195. }
  196. if (List != NULL) {
  197. cArc = pSPReport->cArc;
  198. dglFreeSPReport(graph, pSPReport);
  199. }
  200. else
  201. cArc = 0;
  202. return (cArc);
  203. }