graph.c 6.3 KB

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