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