pgRouting  2.2
pgRouting extends the PostGIS / PostgreSQL geospatial database to provide geospatial routing functionality.
 All Classes Functions Variables Pages
trsp.c
1 /*PGR-GNU*****************************************************************
2 
3 Copyright (c) 2015 pgRouting developers
4 Mail: project@pgrouting.org
5 
6 ------
7 
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12 
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 
22 ********************************************************************PGR-GNU*/
23 #include "postgres.h"
24 #include "executor/spi.h"
25 #include "funcapi.h"
26 #include "catalog/pg_type.h"
27 #if PGSQL_VERSION > 92
28 #include "access/htup_details.h"
29 #endif
30 
31 #include "fmgr.h"
32 #include "trsp.h"
33 
34 Datum turn_restrict_shortest_path_vertex(PG_FUNCTION_ARGS);
35 Datum turn_restrict_shortest_path_edge(PG_FUNCTION_ARGS);
36 
37 // #define DEBUG
38 #include "../../common/src/debug_macro.h"
39 #include "../../common/src/pgr_types.h"
40 #include "../../common/src/postgres_connection.h"
41 #include "../../common/src/edges_input.h"
42 #include "../../common/src/restrictions_input.h"
43 
44 
45 static int compute_trsp(
46  char* edges_sql,
47  int dovertex,
48  int start_id,
49  double start_pos,
50  int end_id,
51  double end_pos,
52  bool directed,
53  bool has_reverse_cost,
54  char *restrict_sql,
55  path_element_t **path,
56  size_t *path_count) {
57  pgr_SPI_connect();
58 
59  PGR_DBG("Load edges");
60  pgr_edge_t *edges = NULL;
61  size_t total_tuples = 0;
62  pgr_get_data_5_columns(edges_sql, &edges, &total_tuples);
63  PGR_DBG("Total %ld edges", total_tuples);
64 
65  PGR_DBG("Load restrictions");
66  restrict_t *restricts = NULL;
67  size_t total_restrict_tuples = 0;
68  if (restrict_sql == NULL) {
69  PGR_DBG("Sql for restrictions is null.");
70  } else {
71  pgr_get_restriction_data(restrict_sql, &restricts, &total_restrict_tuples);
72  }
73 #ifdef DEBUG
74  int t1;
75  for (t1=0; t1<total_restrict_tuples; t1++) {
76  PGR_DBG("restricts: %.2f, %ld, %ld, %ld, %ld, %ld, %ld", restricts[t1].to_cost,
77  restricts[t1].target_id, restricts[t1].via[0], restricts[t1].via[1], restricts[t1].via[2], restricts[t1].via[3], restricts[t1].via[4]);
78  }
79 #endif
80  PGR_DBG("Total %ld restriction", total_restrict_tuples);
81 
82 
83 
84  int v_max_id=0;
85  int v_min_id=INT_MAX;
86 
87  /* track if start and end are both in edge tuples */
88  int s_count = 0;
89  int t_count = 0;
90 
91  char *err_msg;
92  int ret = -1;
93  register int z;
94 
95  PGR_DBG("start turn_restrict_shortest_path\n");
96 
97  if (start_id == end_id) {
98  PGR_DBG("Starting vertex and Ending Vertex are equal");
99  *path = NULL;
100  return 0;
101  }
102 
103 
104  //defining min and max vertex id
105 
106  PGR_DBG("Total %i edge tuples", total_tuples);
107 
108  for(z=0; z<total_tuples; z++) {
109  if(edges[z].source<v_min_id)
110  v_min_id=(int)edges[z].source;
111 
112  if(edges[z].source>v_max_id)
113  v_max_id=(int)edges[z].source;
114 
115  if(edges[z].target<v_min_id)
116  v_min_id=(int)edges[z].target;
117 
118  if(edges[z].target>v_max_id)
119  v_max_id=(int)edges[z].target;
120 
121  //PGR_DBG("%i <-> %i", v_min_id, v_max_id);
122 
123  }
124 
125  //::::::::::::::::::::::::::::::::::::
126  //:: reducing vertex id (renumbering)
127  //::::::::::::::::::::::::::::::::::::
128  for(z=0; z<total_tuples; z++) {
129  //check if edges[] contains source and target
130  if (dovertex) {
131  if(edges[z].source == start_id || edges[z].target == start_id)
132  ++s_count;
133  if(edges[z].source == end_id || edges[z].target == end_id)
134  ++t_count;
135  }
136  else {
137  if(edges[z].id == start_id)
138  ++s_count;
139  if(edges[z].id == end_id)
140  ++t_count;
141  }
142 
143  edges[z].source-=v_min_id;
144  edges[z].target-=v_min_id;
145  edges[z].cost = edges[z].cost;
146  //PGR_DBG("edgeID: %i SRc:%i - %i, cost: %f", edges[z].id,edges[z].source, edges[z].target,edges[z].cost);
147 
148  }
149 
150  PGR_DBG("Min vertex id: %i , Max vid: %i",v_min_id,v_max_id);
151  PGR_DBG("Total %ld edge tuples", total_tuples);
152 
153  if(s_count == 0) {
154  elog(ERROR, "Start id was not found.");
155  return -1;
156  }
157 
158  if(t_count == 0) {
159  elog(ERROR, "Target id was not found.");
160  return -1;
161  }
162 
163  if (dovertex) {
164  start_id -= v_min_id;
165  end_id -= v_min_id;
166  }
167 
168 
169  if (dovertex) {
170  PGR_DBG("Calling trsp_node_wrapper\n");
171  ret = trsp_node_wrapper(edges, total_tuples,
172  restricts, total_restrict_tuples,
173  start_id, end_id,
174  directed, has_reverse_cost,
175  path, path_count, &err_msg);
176  }
177  else {
178  PGR_DBG("Calling trsp_edge_wrapper\n");
179  ret = trsp_edge_wrapper(edges, total_tuples,
180  restricts, total_restrict_tuples,
181  start_id, start_pos, end_id, end_pos,
182  directed, has_reverse_cost,
183  path, path_count, &err_msg);
184  }
185 
186  PGR_DBG("Message received from inside:");
187  PGR_DBG("%s",err_msg);
188 
189  //PGR_DBG("SIZE %i\n",*path_count);
190 
191  //::::::::::::::::::::::::::::::::
192  //:: restoring original vertex id
193  //::::::::::::::::::::::::::::::::
194  for(z=0;z<*path_count;z++) {
195  //PGR_DBG("vetex %i\n",(*path)[z].vertex_id);
196  if (z || (*path)[z].vertex_id != -1)
197  (*path)[z].vertex_id+=v_min_id;
198  }
199 
200  PGR_DBG("ret = %i\n", ret);
201 
202  PGR_DBG("*path_count = %i\n", *path_count);
203 
204  if (ret < 0)
205  {
206  //elog(ERROR, "Error computing path: %s", err_msg);
207  ereport(ERROR, (errcode(ERRCODE_E_R_E_CONTAINING_SQL_NOT_PERMITTED),
208  errmsg("Error computing path: %s", err_msg)));
209  }
210 
211  pgr_SPI_finish();
212  return 0;
213 }
214 
215 
216 
217 PG_FUNCTION_INFO_V1(turn_restrict_shortest_path_vertex);
218  Datum
219 turn_restrict_shortest_path_vertex(PG_FUNCTION_ARGS)
220 {
221 
222  FuncCallContext *funcctx;
223  uint32_t call_cntr;
224  uint32_t max_calls;
225  TupleDesc tuple_desc;
226  path_element_t *path;
227  char * sql;
228 
229 
230  // stuff done only on the first call of the function
231  if (SRF_IS_FIRSTCALL()) {
232  MemoryContext oldcontext;
233  size_t path_count = 0;
234 
235  int ret = -1;
236  if (ret == -1) {}; // to avoid warning set but not used
237 
238  int i;
239 
240  // create a function context for cross-call persistence
241  funcctx = SRF_FIRSTCALL_INIT();
242 
243  // switch to memory context appropriate for multiple function calls
244  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
245 
246  // verify that the first 5 args are not NULL
247  for (i=0; i<5; i++)
248  if(PG_ARGISNULL(i)) {
249  elog(ERROR, "turn_restrict_shortest_path(): Argument %i may not be NULL", i+1);
250  }
251 
252  if (PG_ARGISNULL(5))
253  sql = NULL;
254  else {
255  sql = pgr_text2char(PG_GETARG_TEXT_P(5));
256  if (strlen(sql) == 0)
257  sql = NULL;
258  }
259 
260  PGR_DBG("Calling compute_trsp");
261 
262 
263  ret =
264 
265  compute_trsp(pgr_text2char(PG_GETARG_TEXT_P(0)),
266  1, // do vertex
267  PG_GETARG_INT32(1),
268  0.5,
269  PG_GETARG_INT32(2),
270  0.5,
271  PG_GETARG_BOOL(3),
272  PG_GETARG_BOOL(4),
273  sql,
274  &path, &path_count);
275 #ifdef DEBUG
276  double total_cost = 0;
277  PGR_DBG("Ret is %i", ret);
278  if (ret >= 0)
279  {
280  int i;
281  for (i = 0; i < path_count; i++)
282  {
283  // PGR_DBG("Step %i vertex_id %i ", i, path[i].vertex_id);
284  // PGR_DBG(" edge_id %i ", path[i].edge_id);
285  // PGR_DBG(" cost %f ", path[i].cost);
286  total_cost+=path[i].cost;
287  }
288  }
289  PGR_DBG("Total cost is: %f",total_cost);
290 #endif
291 
292  // total number of tuples to be returned
293  funcctx->max_calls = (uint32_t)path_count;
294  funcctx->user_fctx = path;
295 
296  funcctx->tuple_desc =
297  BlessTupleDesc(RelationNameGetTupleDesc("pgr_costResult"));
298 
299  MemoryContextSwitchTo(oldcontext);
300  }
301 
302  // stuff done on every call of the function
303  funcctx = SRF_PERCALL_SETUP();
304 
305  call_cntr = funcctx->call_cntr;
306  max_calls = funcctx->max_calls;
307  tuple_desc = funcctx->tuple_desc;
308  path = (path_element_t*) funcctx->user_fctx;
309 
310  if (call_cntr < max_calls) // do when there is more left to send
311  {
312  HeapTuple tuple;
313  Datum result;
314  Datum *values;
315  char* nulls;
316 
317  values = palloc(4 * sizeof(Datum));
318  nulls = palloc(4 * sizeof(char));
319 
320  values[0] = Int32GetDatum(call_cntr);
321  nulls[0] = ' ';
322  values[1] = Int32GetDatum(path[call_cntr].vertex_id);
323  nulls[1] = ' ';
324  values[2] = Int32GetDatum(path[call_cntr].edge_id);
325  nulls[2] = ' ';
326  values[3] = Float8GetDatum(path[call_cntr].cost);
327  nulls[3] = ' ';
328 
329  tuple = heap_formtuple(tuple_desc, values, nulls);
330 
331  // make the tuple into a datum
332  result = HeapTupleGetDatum(tuple);
333 
334  // clean up (this is not really necessary)
335  pfree(values);
336  pfree(nulls);
337 
338  SRF_RETURN_NEXT(funcctx, result);
339  }
340  else // do when there is no more left
341  {
342  PGR_DBG("Going to free path");
343  if (path) free(path);
344  SRF_RETURN_DONE(funcctx);
345  }
346 }
347 
348 PG_FUNCTION_INFO_V1(turn_restrict_shortest_path_edge);
349  Datum
350 turn_restrict_shortest_path_edge(PG_FUNCTION_ARGS)
351 {
352 
353  FuncCallContext *funcctx;
354  uint32_t call_cntr;
355  uint32_t max_calls;
356  TupleDesc tuple_desc;
357  path_element_t *path;
358  char * sql;
359 
360  // stuff done only on the first call of the function
361  if (SRF_IS_FIRSTCALL()) {
362  MemoryContext oldcontext;
363  size_t path_count = 0;
364 #ifdef DEBUG
365  int ret = -1;
366 #endif
367  int i;
368  double s_pos;
369  double e_pos;
370 
371  // create a function context for cross-call persistence
372  funcctx = SRF_FIRSTCALL_INIT();
373 
374  // switch to memory context appropriate for multiple function calls
375  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
376 
377  // verify that the first 5 args are not NULL
378  for (i=0; i<7; i++) {
379  if(i==2 || i==4) continue;
380  if(PG_ARGISNULL(i)) {
381  elog(ERROR, "turn_restrict_shortest_path(): Argument %i may not be NULL", i+1);
382  }
383  }
384 
385  if (PG_ARGISNULL(2))
386  s_pos = 0.5;
387  else {
388  s_pos = PG_GETARG_FLOAT8(2);
389  if (s_pos < 0.0) s_pos = 0.5;
390  if (s_pos > 1.0) s_pos = 0.5;
391  }
392 
393  if (PG_ARGISNULL(4))
394  e_pos = 0.5;
395  else {
396  e_pos = PG_GETARG_FLOAT8(4);
397  if (e_pos < 0.0) e_pos = 0.5;
398  if (e_pos > 1.0) e_pos = 0.5;
399  }
400 
401  if (PG_ARGISNULL(7))
402  sql = NULL;
403  else {
404  sql = pgr_text2char(PG_GETARG_TEXT_P(7));
405  if (strlen(sql) == 0)
406  sql = NULL;
407  }
408 
409  PGR_DBG("Calling compute_trsp");
410 
411 #ifdef DEBUG
412  ret =
413 #endif
414  compute_trsp(pgr_text2char(PG_GETARG_TEXT_P(0)),
415  0, //sdo edge
416  PG_GETARG_INT32(1),
417  s_pos,
418  PG_GETARG_INT32(3),
419  e_pos,
420  PG_GETARG_BOOL(5),
421  PG_GETARG_BOOL(6),
422  sql,
423  &path, &path_count);
424 #ifdef DEBUG
425  double total_cost = 0;
426  PGR_DBG("Ret is %i", ret);
427  if (ret >= 0)
428  {
429  int i;
430  for (i = 0; i < path_count; i++)
431  {
432  // PGR_DBG("Step %i vertex_id %i ", i, path[i].vertex_id);
433  // PGR_DBG(" edge_id %i ", path[i].edge_id);
434  // PGR_DBG(" cost %f ", path[i].cost);
435  total_cost+=path[i].cost;
436  }
437  }
438  PGR_DBG("Total cost is: %f",total_cost);
439 #endif
440 
441  // total number of tuples to be returned
442  funcctx->max_calls = (uint32_t)path_count;
443  funcctx->user_fctx = path;
444 
445  funcctx->tuple_desc =
446  BlessTupleDesc(RelationNameGetTupleDesc("pgr_costResult"));
447 
448  MemoryContextSwitchTo(oldcontext);
449  }
450 
451  // stuff done on every call of the function
452  funcctx = SRF_PERCALL_SETUP();
453 
454  call_cntr = funcctx->call_cntr;
455  max_calls = funcctx->max_calls;
456  tuple_desc = funcctx->tuple_desc;
457  path = (path_element_t*) funcctx->user_fctx;
458 
459  if (call_cntr < max_calls) // do when there is more left to send
460  {
461  HeapTuple tuple;
462  Datum result;
463  Datum *values;
464  char* nulls;
465 
466  values = palloc(4 * sizeof(Datum));
467  nulls = palloc(4 * sizeof(char));
468 
469  values[0] = Int32GetDatum(call_cntr);
470  nulls[0] = ' ';
471  values[1] = Int32GetDatum(path[call_cntr].vertex_id);
472  nulls[1] = ' ';
473  values[2] = Int32GetDatum(path[call_cntr].edge_id);
474  nulls[2] = ' ';
475  values[3] = Float8GetDatum(path[call_cntr].cost);
476  nulls[3] = ' ';
477 
478  tuple = heap_formtuple(tuple_desc, values, nulls);
479 
480  // make the tuple into a datum
481  result = HeapTupleGetDatum(tuple);
482 
483  // clean up (this is not really necessary)
484  pfree(values);
485  pfree(nulls);
486 
487  SRF_RETURN_NEXT(funcctx, result);
488  }
489  else // do when there is no more left
490  {
491  PGR_DBG("Going to free path");
492  if (path) free(path);
493  SRF_RETURN_DONE(funcctx);
494  }
495 }