graph.c 6.3 KB

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