pgRouting
pgRouting extends the PostGIS / PostgreSQL geospatial database to provide geospatial routing functionality.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
trsp.c
Go to the documentation of this file.
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_driver.h"
33 
34 PGDLLEXPORT Datum turn_restrict_shortest_path_vertex(PG_FUNCTION_ARGS);
35 PGDLLEXPORT 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,
56  size_t *path_count) {
58 
59  PGR_DBG("Load edges");
60  pgr_edge_t *edges = NULL;
61  size_t total_tuples = 0;
62  pgr_get_edges(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  int v_max_id=0;
84  int v_min_id=INT_MAX;
85 
86  /* track if start and end are both in edge tuples */
87  int s_count = 0;
88  int t_count = 0;
89 
90  char *err_msg;
91  int ret = -1;
92  register int z;
93 
94  PGR_DBG("start turn_restrict_shortest_path\n");
95 
96  if (start_id == end_id) {
97  PGR_DBG("Starting vertex and Ending Vertex are equal");
98  *path = NULL;
99  return 0;
100  }
101 
102 
103  //defining min and max vertex id
104 
105  PGR_DBG("Total %ld edge tuples", total_tuples);
106 
107  for(z=0; z<total_tuples; z++) {
108  if(edges[z].source<v_min_id)
109  v_min_id=(int)edges[z].source;
110 
111  if(edges[z].source>v_max_id)
112  v_max_id=(int)edges[z].source;
113 
114  if(edges[z].target<v_min_id)
115  v_min_id=(int)edges[z].target;
116 
117  if(edges[z].target>v_max_id)
118  v_max_id=(int)edges[z].target;
119  //PGR_DBG("%i <-> %i", v_min_id, v_max_id);
120 
121  }
122 
123 //<<<<<<< HEAD
124  //::::::::::::::::::::::::::::::::::::
125  //:: reducing vertex id (renumbering)
126  //::::::::::::::::::::::::::::::::::::
127  for(z=0; z<total_tuples; z++) {
128  //check if edges[] contains source and target
129  if (dovertex) {
130  if(edges[z].source == start_id || edges[z].target == start_id)
131  ++s_count;
132  if(edges[z].source == end_id || edges[z].target == end_id)
133  ++t_count;
134  }
135  else {
136  if(edges[z].id == start_id)
137  ++s_count;
138  if(edges[z].id == end_id)
139  ++t_count;
140  }
141 
142  edges[z].source-=v_min_id;
143  edges[z].target-=v_min_id;
144  edges[z].cost = edges[z].cost;
145  //PGR_DBG("edgeID: %i SRc:%i - %i, cost: %f", edges[z].id,edges[z].source, edges[z].target,edges[z].cost);
146 
147  }
148 
149  PGR_DBG("Min vertex id: %i , Max vid: %i",v_min_id,v_max_id);
150  PGR_DBG("Total %ld edge tuples", total_tuples);
151 
152  if(s_count == 0) {
153  elog(ERROR, "Start id was not found.");
154  return -1;
155  }
156 
157  if(t_count == 0) {
158  elog(ERROR, "Target id was not found.");
159  return -1;
160  }
161 
162  if (dovertex) {
163  start_id -= v_min_id;
164  end_id -= v_min_id;
165  }
166 
167  if (dovertex) {
168  PGR_DBG("Calling trsp_node_wrapper\n");
169  ret = trsp_node_wrapper(edges, total_tuples,
170  restricts, total_restrict_tuples,
171  start_id, end_id,
172  directed, has_reverse_cost,
173  path, path_count, &err_msg);
174  }
175  else {
176  PGR_DBG("Calling trsp_edge_wrapper\n");
177  ret = trsp_edge_wrapper(edges, total_tuples,
178  restricts, total_restrict_tuples,
179  start_id, start_pos, end_id, end_pos,
180  directed, has_reverse_cost,
181  path, path_count, &err_msg);
182  }
183 
184  PGR_DBG("Message received from inside:");
185  PGR_DBG("%s",err_msg);
186 
187  //PGR_DBG("SIZE %i\n",*path_count);
188 
189  //::::::::::::::::::::::::::::::::
190  //:: restoring original vertex id
191  //::::::::::::::::::::::::::::::::
192  for(z=0;z<*path_count;z++) {
193  //PGR_DBG("vetex %i\n",(*path)[z].vertex_id);
194  if (z || (*path)[z].vertex_id != -1)
195  (*path)[z].vertex_id+=v_min_id;
196  }
197 
198  PGR_DBG("ret = %i\n", ret);
199 
200  PGR_DBG("*path_count = %ld\n", *path_count);
201 
202  if (ret < 0)
203  {
204  //elog(ERROR, "Error computing path: %s", err_msg);
205  ereport(ERROR, (errcode(ERRCODE_E_R_E_CONTAINING_SQL_NOT_PERMITTED),
206  errmsg("Error computing path: %s", err_msg)));
207  }
208 
209  pgr_SPI_finish();
210  return 0;
211 }
212 
213 
214 
216 PGDLLEXPORT Datum
218 {
219 
220  FuncCallContext *funcctx;
221  uint32_t call_cntr;
222  uint32_t max_calls;
223  TupleDesc tuple_desc;
225  char * sql;
226 
227 
228  // stuff done only on the first call of the function
229  if (SRF_IS_FIRSTCALL()) {
230  MemoryContext oldcontext;
231  size_t path_count = 0;
232 
233  int ret = -1;
234  if (ret == -1) {}; // to avoid warning set but not used
235 
236  int i;
237 
238  // create a function context for cross-call persistence
239  funcctx = SRF_FIRSTCALL_INIT();
240 
241  // switch to memory context appropriate for multiple function calls
242  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
243 
244  // verify that the first 5 args are not NULL
245  for (i=0; i<5; i++)
246  if(PG_ARGISNULL(i)) {
247  elog(ERROR, "turn_restrict_shortest_path(): Argument %i may not be NULL", i+1);
248  }
249 
250  if (PG_ARGISNULL(5))
251  sql = NULL;
252  else {
253  sql = pgr_text2char(PG_GETARG_TEXT_P(5));
254  if (strlen(sql) == 0)
255  sql = NULL;
256  }
257 
258  PGR_DBG("Calling compute_trsp");
259 
260 
261  ret =
262 
263  compute_trsp(pgr_text2char(PG_GETARG_TEXT_P(0)),
264  1, // do vertex
265  PG_GETARG_INT32(1),
266  0.5,
267  PG_GETARG_INT32(2),
268  0.5,
269  PG_GETARG_BOOL(3),
270  PG_GETARG_BOOL(4),
271  sql,
272  &path, &path_count);
273 #ifdef DEBUG
274  double total_cost = 0;
275  PGR_DBG("Ret is %i", ret);
276  if (ret >= 0)
277  {
278  int i;
279  for (i = 0; i < path_count; i++)
280  {
281  // PGR_DBG("Step %i vertex_id %i ", i, path[i].vertex_id);
282  // PGR_DBG(" edge_id %i ", path[i].edge_id);
283  // PGR_DBG(" cost %f ", path[i].cost);
284  total_cost+=path[i].cost;
285  }
286  }
287  PGR_DBG("Total cost is: %f",total_cost);
288 #endif
289 
290  // total number of tuples to be returned
291  funcctx->max_calls = (uint32_t)path_count;
292  funcctx->user_fctx = path;
293 
294  funcctx->tuple_desc =
295  BlessTupleDesc(RelationNameGetTupleDesc("pgr_costResult"));
296 
297  MemoryContextSwitchTo(oldcontext);
298  }
299 
300  // stuff done on every call of the function
301  funcctx = SRF_PERCALL_SETUP();
302 
303  call_cntr = funcctx->call_cntr;
304  max_calls = funcctx->max_calls;
305  tuple_desc = funcctx->tuple_desc;
306  path = (path_element_t*) funcctx->user_fctx;
307 
308  if (call_cntr < max_calls) // do when there is more left to send
309  {
310  HeapTuple tuple;
311  Datum result;
312  Datum *values;
313  bool* nulls;
314 
315  values = palloc(4 * sizeof(Datum));
316  nulls = palloc(4 * sizeof(bool));
317 
318  values[0] = Int32GetDatum(call_cntr);
319  nulls[0] = false;
320  values[1] = Int32GetDatum(path[call_cntr].vertex_id);
321  nulls[1] = false;
322  values[2] = Int32GetDatum(path[call_cntr].edge_id);
323  nulls[2] = false;
324  values[3] = Float8GetDatum(path[call_cntr].cost);
325  nulls[3] = false;
326 
327  tuple = heap_form_tuple(tuple_desc, values, nulls);
328 
329  // make the tuple into a datum
330  result = HeapTupleGetDatum(tuple);
331 
332  // clean up (this is not really necessary)
333  pfree(values);
334  pfree(nulls);
335 
336  SRF_RETURN_NEXT(funcctx, result);
337  }
338  else // do when there is no more left
339  {
340  PGR_DBG("Going to free path");
341  if (path) free(path);
342  SRF_RETURN_DONE(funcctx);
343  }
344 }
345 
347 PGDLLEXPORT Datum
349 {
350 
351  FuncCallContext *funcctx;
352  uint32_t call_cntr;
353  uint32_t max_calls;
354  TupleDesc tuple_desc;
356  char * sql;
357 
358  // stuff done only on the first call of the function
359  if (SRF_IS_FIRSTCALL()) {
360  MemoryContext oldcontext;
361  size_t path_count = 0;
362 #ifdef DEBUG
363  int ret = -1;
364 #endif
365  int i;
366  double s_pos;
367  double e_pos;
368 
369  // create a function context for cross-call persistence
370  funcctx = SRF_FIRSTCALL_INIT();
371 
372  // switch to memory context appropriate for multiple function calls
373  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
374 
375  // verify that the first 5 args are not NULL
376  for (i=0; i<7; i++) {
377  if(i==2 || i==4) continue;
378  if(PG_ARGISNULL(i)) {
379  elog(ERROR, "turn_restrict_shortest_path(): Argument %i may not be NULL", i+1);
380  }
381  }
382 
383  if (PG_ARGISNULL(2))
384  s_pos = 0.5;
385  else {
386  s_pos = PG_GETARG_FLOAT8(2);
387  if (s_pos < 0.0) s_pos = 0.5;
388  if (s_pos > 1.0) s_pos = 0.5;
389  }
390 
391  if (PG_ARGISNULL(4))
392  e_pos = 0.5;
393  else {
394  e_pos = PG_GETARG_FLOAT8(4);
395  if (e_pos < 0.0) e_pos = 0.5;
396  if (e_pos > 1.0) e_pos = 0.5;
397  }
398 
399  if (PG_ARGISNULL(7))
400  sql = NULL;
401  else {
402  sql = pgr_text2char(PG_GETARG_TEXT_P(7));
403  if (strlen(sql) == 0)
404  sql = NULL;
405  }
406 
407  PGR_DBG("Calling compute_trsp");
408 
409 #ifdef DEBUG
410  ret =
411 #endif
412  compute_trsp(pgr_text2char(PG_GETARG_TEXT_P(0)),
413  0, //sdo edge
414  PG_GETARG_INT32(1),
415  s_pos,
416  PG_GETARG_INT32(3),
417  e_pos,
418  PG_GETARG_BOOL(5),
419  PG_GETARG_BOOL(6),
420  sql,
421  &path, &path_count);
422 #ifdef DEBUG
423  double total_cost = 0;
424  PGR_DBG("Ret is %i", ret);
425  if (ret >= 0)
426  {
427  int i;
428  for (i = 0; i < path_count; i++)
429  {
430  // PGR_DBG("Step %i vertex_id %i ", i, path[i].vertex_id);
431  // PGR_DBG(" edge_id %i ", path[i].edge_id);
432  // PGR_DBG(" cost %f ", path[i].cost);
433  total_cost+=path[i].cost;
434  }
435  }
436  PGR_DBG("Total cost is: %f",total_cost);
437 #endif
438 
439  // total number of tuples to be returned
440  funcctx->max_calls = (uint32_t)path_count;
441  funcctx->user_fctx = path;
442 
443  funcctx->tuple_desc =
444  BlessTupleDesc(RelationNameGetTupleDesc("pgr_costResult"));
445 
446  MemoryContextSwitchTo(oldcontext);
447  }
448 
449  // stuff done on every call of the function
450  funcctx = SRF_PERCALL_SETUP();
451 
452  call_cntr = funcctx->call_cntr;
453  max_calls = funcctx->max_calls;
454  tuple_desc = funcctx->tuple_desc;
455  path = (path_element_t*) funcctx->user_fctx;
456 
457  if (call_cntr < max_calls) // do when there is more left to send
458  {
459  HeapTuple tuple;
460  Datum result;
461  Datum *values;
462  bool* nulls;
463 
464  values = palloc(4 * sizeof(Datum));
465  nulls = palloc(4 * sizeof(bool));
466 
467  values[0] = Int32GetDatum(call_cntr);
468  nulls[0] = false;
469  values[1] = Int32GetDatum(path[call_cntr].vertex_id);
470  nulls[1] = false;
471  values[2] = Int32GetDatum(path[call_cntr].edge_id);
472  nulls[2] = false;
473  values[3] = Float8GetDatum(path[call_cntr].cost);
474  nulls[3] = false;
475 
476  tuple = heap_form_tuple(tuple_desc, values, nulls);
477 
478  // make the tuple into a datum
479  result = HeapTupleGetDatum(tuple);
480 
481  // clean up (this is not really necessary)
482  pfree(values);
483  pfree(nulls);
484 
485  SRF_RETURN_NEXT(funcctx, result);
486  }
487  else // do when there is no more left
488  {
489  PGR_DBG("Going to free path");
490  if (path) free(path);
491  SRF_RETURN_DONE(funcctx);
492  }
493 }
int path_count
Definition: BDATester.cpp:51
int64_t source
Definition: pgr_types.h:129
int64_t target
Definition: pgr_types.h:130
#define PGR_DBG(...)
Definition: debug_macro.h:33
void pgr_get_edges(char *edges_sql, pgr_edge_t **edges, size_t *total_edges)
basic edge_sql
Definition: edges_input.c:535
static int compute_trsp(char *edges_sql, int dovertex, int start_id, double start_pos, int end_id, double end_pos, bool directed, bool has_reverse_cost, char *restrict_sql, path_element_t **path, size_t *path_count)
Definition: trsp.c:45
void pgr_SPI_finish(void)
int trsp_node_wrapper(edge_t *edges, size_t edge_count, restrict_t *restricts, size_t restrict_count, int start_vertex, int end_vertex, bool directed, bool has_reverse_cost, path_element_t **path, size_t *path_count, char **err_msg)
Definition: trsp_driver.cpp:34
double cost
Definition: pgr_types.h:131
void pgr_get_restriction_data(char *restrictions_sql, Restrict_t **restrictions, size_t *total_restrictions)
edge_astar_t * edges
Definition: BDATester.cpp:46
void pgr_SPI_connect(void)
PGDLLEXPORT Datum turn_restrict_shortest_path_vertex(PG_FUNCTION_ARGS)
Definition: trsp.c:217
path_element_t * path
Definition: BDATester.cpp:49
char * err_msg
Definition: BDATester.cpp:50
int trsp_edge_wrapper(edge_t *edges, size_t edge_count, restrict_t *restricts, size_t restrict_count, int start_edge, double start_pos, int end_edge, double end_pos, bool directed, bool has_reverse_cost, path_element_t **path, size_t *path_count, char **err_msg)
Definition: trsp_driver.cpp:84
char * pgr_text2char(text *in)
PG_FUNCTION_INFO_V1(turn_restrict_shortest_path_vertex)
PGDLLEXPORT Datum turn_restrict_shortest_path_edge(PG_FUNCTION_ARGS)
Definition: trsp.c:348
double cost
Definition: pgr_types.h:76