GRASS 8 Programmer's Manual 8.6.0dev(2026)-1d1e47ad9d
Loading...
Searching...
No Matches
timetables.c
Go to the documentation of this file.
1/*!
2 \file vector/neta/timetables.c
3
4 \brief Network Analysis library - timetables
5
6 Shortest path using timetables.
7
8 (C) 2009-2010 by Daniel Bundala, and the GRASS Development Team
9
10 This program is free software under the GNU General Public License
11 (>=v2). Read the file COPYING that comes with GRASS for details.
12
13 \author Daniel Bundala (Google Summer of Code 2009)
14 */
15
16#include <stdio.h>
17#include <stdlib.h>
18#include <grass/gis.h>
19#include <grass/vector.h>
20#include <grass/dbmi.h>
21#include <grass/glocale.h>
22#include <grass/dgl/graph.h>
23#include <grass/neta.h>
24
25/*!
26 \brief Get number of distinct elements
27
28 \param driver DB driver
29 \param sql SQl string
30 \param[out] lengths list of lengths
31 \param[out] ids list of ids
32
33 \return number of distinct elements
34 \return -1 on failure
35 */
37 int **ids)
38{
39 int count, last, cur, result, index, more;
41 dbTable *table;
43 dbValue *value;
44
46 G_warning(_("Unable to open select cursor: %s"), db_get_string(sql));
47 return -1;
48 }
49 /*TODO: check column types */
50
51 count = last = 0;
52 /*count number of distinct routes */
54 column = db_get_table_column(table, 0);
55 while (db_fetch(&cursor, DB_NEXT, &more) == DB_OK && more) {
57 cur = db_get_value_int(value);
58 if (count == 0 || cur != last) {
59 last = cur;
60 count++;
61 }
62 }
63 result = count;
65
66 *lengths = (int *)G_calloc(count, sizeof(int));
67 *ids = (int *)G_calloc(count, sizeof(int));
68 if (!*lengths || !*ids) {
69 G_warning(_("Out of memory"));
70 return -1;
71 }
73 G_warning(_("Unable to open select cursor: %s"), db_get_string(sql));
74 return -1;
75 }
76 count = index = 0;
77 /*calculate the lengths of the routes */
79 column = db_get_table_column(table, 0);
80 while (db_fetch(&cursor, DB_NEXT, &more) == DB_OK && more) {
82 cur = db_get_value_int(value);
83 if (count != 0 && cur != last)
84 index++;
85 if (count == 0 || cur != last)
86 (*ids)[index] = cur;
87 (*lengths)[index]++;
88 last = cur;
89 count++;
90 }
92 return result;
93}
94
95static int cmp_int(const void *a, const void *b)
96{
97 return *(int *)a - *(int *)b;
98}
99
100/*!
101 \brief Initialises timetable from a database
102
103 \param In pointer to Map_info structure
104 \param route_layer layer number of routes
105 \param walk_layer layer number of walkers
106 \param route_id id of route
107 \param times list of timestamps
108 \param to_stop ?
109 \param walk_length walk length as string
110 \param timetable pointer to neta_timetable
111 \param route_ids list of route ids
112 \param stop_ids list of stop ids
113
114 \return 0 on success
115 \return non-zero value on failure
116 */
118 int walk_layer, char *route_id, char *times,
119 char *to_stop, char *walk_length,
121 int **stop_ids)
122{
123 int more, i, stop, route, time, *stop_pnt, stop1, stop2;
126 dbTable *table;
128 dbValue *value;
129 char buf[2000];
130
132 struct field_info *Fi;
133
135 if (Fi == NULL)
136 G_fatal_error(_("Database connection not defined for layer %d"),
138
139 driver = db_start_driver_open_database(Fi->driver, Fi->database);
140 if (driver == NULL)
141 G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
142 Fi->database, Fi->driver);
143
145 snprintf(buf, sizeof(buf), "select %s from %s order by %s", route_id,
146 Fi->table, route_id);
147 db_set_string(&sql, buf);
148 timetable->routes =
149 NetA_init_distinct(driver, &sql, &(timetable->route_length), route_ids);
150 if (timetable->routes < 0)
151 return 1;
152
153 snprintf(buf, sizeof(buf), "select %s from %s order by %s", Fi->key,
154 Fi->table, Fi->key);
155 db_set_string(&sql, buf);
156 timetable->stops =
157 NetA_init_distinct(driver, &sql, &(timetable->stop_length), stop_ids);
158 if (timetable->stops < 0)
159 return 1;
160
161 timetable->route_stops = (int **)G_calloc(timetable->routes, sizeof(int *));
162 timetable->route_times = (int **)G_calloc(timetable->routes, sizeof(int *));
163 timetable->stop_routes = (int **)G_calloc(timetable->stops, sizeof(int *));
164 timetable->stop_times = (int **)G_calloc(timetable->stops, sizeof(int *));
165 timetable->walk_length = (int *)G_calloc(timetable->stops, sizeof(int));
166 timetable->walk_stops = (int **)G_calloc(timetable->stops, sizeof(int *));
167 timetable->walk_times = (int **)G_calloc(timetable->stops, sizeof(int *));
168 if (!timetable->route_stops || !timetable->route_times ||
169 !timetable->stop_routes || !timetable->stop_times ||
170 !timetable->walk_length) {
171 G_warning(_("Out of memory"));
172 return 2;
173 }
174
175 for (i = 0; i < timetable->routes; i++) {
176 timetable->route_stops[i] =
177 (int *)G_calloc(timetable->route_length[i], sizeof(int));
178 timetable->route_times[i] =
179 (int *)G_calloc(timetable->route_length[i], sizeof(int));
180 if (!timetable->route_stops[i] || !timetable->route_times[i]) {
181 G_warning(_("Out of memory"));
182 return 2;
183 }
184
185 timetable->route_length[i] = 0;
186 }
187
188 for (i = 0; i < timetable->stops; i++) {
189 timetable->stop_routes[i] =
190 (int *)G_calloc(timetable->stop_length[i], sizeof(int));
191 timetable->stop_times[i] =
192 (int *)G_calloc(timetable->stop_length[i], sizeof(int));
193 if (!timetable->stop_routes[i] || !timetable->stop_times[i]) {
194 G_warning(_("Out of memory"));
195 return 2;
196 }
197 timetable->walk_length[i] = 0;
198 timetable->stop_length[i] = 0;
199 }
200
201 snprintf(buf, sizeof(buf), "select %s, %s, %s from %s order by %s", Fi->key,
202 route_id, times, Fi->table, times);
203 db_set_string(&sql, buf);
204
206 G_warning(_("Unable to open select cursor: %s"), db_get_string(&sql));
207 return 1;
208 }
209
214 while (db_fetch(&cursor, DB_NEXT, &more) == DB_OK && more) {
216 stop = db_get_value_int(value);
218 route = db_get_value_int(value);
220 time = db_get_value_int(value);
221 stop = (int *)bsearch(&stop, *stop_ids, timetable->stops, sizeof(int),
222 cmp_int) -
223 (*stop_ids);
224 route = (int *)bsearch(&route, *route_ids, timetable->routes,
225 sizeof(int), cmp_int) -
226 (*route_ids);
227
228 timetable->stop_routes[stop][timetable->stop_length[stop]] = route;
229 timetable->stop_times[stop][timetable->stop_length[stop]++] = time;
230
231 timetable->route_stops[route][timetable->route_length[route]] = stop;
232 timetable->route_times[route][timetable->route_length[route]++] = time;
233 }
235
236 if (walk_layer != -1) {
237
239 snprintf(buf, sizeof(buf), "select %s, %s, %s from %s", Fi->key,
240 to_stop, walk_length, Fi->table);
241 db_set_string(&sql, buf);
242
244 DB_OK) {
245 G_warning(_("Unable to open select cursor: %s"),
247 return 1;
248 }
249
253 while (db_fetch(&cursor, DB_NEXT, &more) == DB_OK && more) {
255 stop = db_get_value_int(value);
256 stop_pnt = (int *)bsearch(&stop, *stop_ids, timetable->stops,
257 sizeof(int), cmp_int);
258 if (stop_pnt) {
260 stop = db_get_value_int(value);
261 stop_pnt = (int *)bsearch(&stop, *stop_ids, timetable->stops,
262 sizeof(int), cmp_int);
263 if (stop_pnt) {
264 stop = stop_pnt - (*stop_ids);
265 timetable->walk_length[stop]++;
266 }
267 }
268 }
270
271 for (i = 0; i < timetable->stops; i++) {
272 timetable->walk_stops[i] =
273 (int *)G_calloc(timetable->walk_length[i], sizeof(int));
274 timetable->walk_times[i] =
275 (int *)G_calloc(timetable->walk_length[i], sizeof(int));
276 if (!timetable->walk_stops[i] || !timetable->walk_times[i]) {
277 G_warning(_("Out of memory"));
278 return 2;
279 }
280 timetable->walk_length[i] = 0;
281 }
282
284 DB_OK) {
285 G_warning(_("Unable to open select cursor: %s"),
287 return 1;
288 }
289
294 while (db_fetch(&cursor, DB_NEXT, &more) == DB_OK && more) {
296 stop = db_get_value_int(value);
297 stop_pnt = (int *)bsearch(&stop, *stop_ids, timetable->stops,
298 sizeof(int), cmp_int);
299 if (stop_pnt) {
300 stop2 = stop_pnt - (*stop_ids);
302 stop = db_get_value_int(value);
303 stop_pnt = (int *)bsearch(&stop, *stop_ids, timetable->stops,
304 sizeof(int), cmp_int);
305 if (stop_pnt) {
306 stop1 = stop_pnt - (*stop_ids);
308 time = db_get_value_int(value);
310 ->walk_stops[stop1][timetable->walk_length[stop1]] =
311 stop2;
313 ->walk_times[stop1][timetable->walk_length[stop1]++] =
314 time;
315 }
316 }
317 }
319 }
322
323 return 0;
324}
325
326typedef struct {
327 int v;
328 int conns;
329} neta_heap_data;
330
331static neta_heap_data *new_heap_data(int conns, int v)
332{
333 neta_heap_data *d = (neta_heap_data *)G_calloc(1, sizeof(neta_heap_data));
334 d->v = v;
335 d->conns = conns;
336 return d;
337}
338
339/*!
340 \brief Update Dijkstra structures
341
342 \param old_conns old connection
343 \param new_conns new connection
344 \param to old 'to' node
345 \param new_dst new 'to' node
346 \param v ?
347 \param route id of route
348 \param rows ? (unused)
349 \param update ?
350 \param[out] result pointer to neta_timetable_result structure
351 \param heap ?
352 */
354 int v, int route, int rows UNUSED, int update,
356{
357 if (result->dst[new_conns][to] == -1 ||
358 result->dst[new_conns][to] > new_dst) {
359 result->dst[new_conns][to] = new_dst;
360 result->prev_stop[new_conns][to] = v;
361 result->prev_route[new_conns][to] = route;
362 result->prev_conn[new_conns][to] = old_conns;
363 if (update) {
365
366 heap_data.pv = (void *)new_heap_data(new_conns, to);
368 }
369 }
370}
371
372/*!
373 \brief Computes the earliest arrival time.
374
375 Computes the earliest arrival time to to_stop from from_stop
376 starting at start_time, or -1 if no path exists
377
378 \param timetable pointer to neta_timetable structure
379 \param from_stop 'from' node
380 \param to_stop 'to' stop
381 \param start_time start timestamp
382 \param min_change ?
383 \param max_changes ?
384 \param walking_change ?
385 \param[out] result pointer to neta_timetable_result
386
387 \return ?
388 \return -1 on error
389 */
391 int to_stop, int start_time, int min_change,
393 neta_timetable_result *result)
394{
395 int i, j;
397
398 int opt_conns, rows = 1;
399
400 if (max_changes != -1)
401 rows = max_changes + 2;
402
403 result->rows = rows;
404 result->dst = (int **)G_calloc(rows, sizeof(int *));
405 result->prev_stop = (int **)G_calloc(rows, sizeof(int *));
406 result->prev_route = (int **)G_calloc(rows, sizeof(int *));
407 result->prev_conn = (int **)G_calloc(rows, sizeof(int *));
408
409 if (!result->dst || !result->prev_stop || !result->prev_route ||
410 !result->prev_conn) {
411 G_warning(_("Out of memory"));
412 return -1;
413 }
414
415 for (i = 0; i < rows; i++) {
416 result->dst[i] = (int *)G_calloc(timetable->stops, sizeof(int));
417 result->prev_stop[i] = (int *)G_calloc(timetable->stops, sizeof(int));
418 result->prev_route[i] = (int *)G_calloc(timetable->stops, sizeof(int));
419 result->prev_conn[i] = (int *)G_calloc(timetable->stops, sizeof(int));
420 if (!result->dst[i] || !result->prev_stop[i] ||
421 !result->prev_route[i] || !result->prev_conn[i]) {
422 G_warning(_("Out of memory"));
423 return -1;
424 }
425 }
426
427 if (from_stop == to_stop) {
428 result->dst[0][to_stop] = start_time;
429 result->prev_route[0][to_stop] = result->prev_stop[0][to_stop] = -1;
430 result->routes = 0;
431 return start_time;
432 }
433
434 result->routes = -1;
435 if (walking_change > 1)
436 walking_change = 1;
437 if (walking_change < 0 || max_changes == -1)
438 walking_change = 0;
440
441 for (i = 0; i < rows; i++)
442 for (j = 0; j < timetable->stops; j++)
443 result->dst[i][j] = result->prev_stop[i][j] =
444 result->prev_route[i][j] = -1;
445
446 result->dst[0][from_stop] = start_time - min_change;
447 result->prev_stop[0][from_stop] = result->prev_route[0][from_stop] = -1;
449
450 heap_data.pv = (void *)new_heap_data(0, from_stop);
452
453 while (1) {
454 dglInt32_t v, dist, conns;
456 int new_conns, walk_conns, update;
457
459 break;
460 v = ((neta_heap_data *)(heap_node.value.pv))->v;
461 conns = ((neta_heap_data *)(heap_node.value.pv))->conns;
462 dist = heap_node.key;
463
464 if (dist > result->dst[conns][v])
465 continue;
466 if (v == to_stop)
467 break;
468 new_conns = (max_changes == -1) ? 0 : (conns + 1);
469 walk_conns = conns + walking_change;
470
471 /*walking */
472 if (walk_conns < rows) {
473 /* update = (max_changes == -1 || walk_conns <=
474 * max_changes); */
475 update = 1;
476 for (i = 0; i < timetable->walk_length[v]; i++) {
477 int to = timetable->walk_stops[v][i];
478 int new_dst = dist + timetable->walk_times[v][i];
479
480 NetA_update_dijkstra(conns, walk_conns, to, new_dst, v, -2,
481 rows, update, result, &heap);
482 }
483 }
484
485 if (new_conns >= rows)
486 continue;
487 /*process all routes arriving after dist+min_change */
488 for (i = 0; i < timetable->stop_length[v]; i++)
489 if (timetable->stop_times[v][i] >= dist + min_change) {
490 int route = timetable->stop_routes[v][i];
491
492 /*find the index of v on the route */
493 for (j = 0; j < timetable->route_length[route]; j++)
494 if (timetable->route_stops[route][j] == v)
495 break;
496 j++;
497 for (; j < timetable->route_length[route]; j++) {
498 int to = timetable->route_stops[route][j];
499
501 timetable->route_times[route][j], v,
502 route, rows, 1, result, &heap);
503 }
504 }
505 }
507 opt_conns = -1;
508 for (i = 0; i < rows; i++)
509 if (result->dst[i][to_stop] != -1 &&
510 (opt_conns == -1 ||
511 result->dst[opt_conns][to_stop] > result->dst[i][to_stop]))
512 opt_conns = i;
513 result->routes = opt_conns;
514
515 if (opt_conns != -1)
516 return result->dst[opt_conns][to_stop];
517 return -1;
518}
519
520/*!
521 \brief Get time
522
523 Get time when route "route" arrives at stop "stop" or -1.
524
525 \param timetable pointer to neta_timetable structure
526 \param stop 'stop' node id
527 \param route route id
528
529 \return time
530 \return -1 if not found
531 */
533 int route)
534{
535 int i;
536
537 for (i = 0; i < timetable->route_length[route]; i++)
538 if (timetable->route_stops[route][i] == stop)
539 return timetable->route_times[route][i];
540 return -1;
541}
542
543/*!
544 \brief Free neta_timetable_result structure
545
546 \param result pointer to neta_timetable_result structure
547 */
549{
550 int i;
551
552 for (i = 0; i < result->rows; i++) {
553 G_free(result->dst[i]);
554 G_free(result->prev_stop[i]);
555 G_free(result->prev_route[i]);
556 }
557 G_free(result->dst);
558 G_free(result->prev_stop);
559 G_free(result->prev_route);
560}
#define NULL
Definition ccmath.h:32
Main header of GRASS DataBase Management Interface.
#define DB_SEQUENTIAL
Definition dbmi.h:123
#define DB_OK
Definition dbmi.h:71
#define DB_NEXT
Definition dbmi.h:114
dbColumn * db_get_table_column(dbTable *, int)
Returns column structure for given table and column number.
dbValue * db_get_column_value(dbColumn *)
Returns column value for given column structure.
int db_close_database_shutdown_driver(dbDriver *)
Close driver/database connection.
Definition db.c:61
char * db_get_string(const dbString *)
Get string.
Definition string.c:140
dbTable * db_get_cursor_table(dbCursor *)
Get table allocated by cursor.
Definition cursor.c:67
int db_set_string(dbString *, const char *)
Inserts string to dbString (enlarge string)
Definition string.c:41
int db_get_value_int(dbValue *)
Get integer value.
Definition value.c:38
void db_init_string(dbString *)
Initialize dbString.
Definition string.c:25
int db_close_cursor(dbCursor *)
Close cursor.
Definition c_close_cur.c:27
int db_open_select_cursor(dbDriver *, dbString *, dbCursor *, int)
Open select cursor.
dbDriver * db_start_driver_open_database(const char *, const char *)
Open driver/database connection.
Definition db.c:28
int db_fetch(dbCursor *, int, int *)
Fetch data from open cursor.
Definition c_fetch.c:28
void G_free(void *)
Free allocated memory.
Definition gis/alloc.c:147
#define G_calloc(m, n)
Definition defs/gis.h:140
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
void G_warning(const char *,...) __attribute__((format(printf
struct field_info * Vect_get_field(struct Map_info *, int)
Get information about link to database (by layer number)
Definition field.c:510
void Vect_destroy_field_info(struct field_info *)
Free a struct field_info and all memory associated with it.
Definition field.c:628
#define UNUSED
A macro for an attribute, if attached to a variable, indicating that the variable is not used.
Definition gis.h:46
#define _(str)
Definition glocale.h:10
void dglHeapInit(dglHeap_s *pheap)
Definition heap.c:27
int dglHeapInsertMin(dglHeap_s *pheap, long key, unsigned char flags, dglHeapData_u value)
Definition heap.c:50
void dglHeapFree(dglHeap_s *pheap, dglHeapCancelItem_fn pfnCancelItem)
Definition heap.c:35
int dglHeapExtractMin(dglHeap_s *pheap, dglHeapNode_s *pnoderet)
Definition heap.c:76
int count
double b
Definition r_raster.c:39
Vector map info.
Layer (old: field) information.
char * table
Name of DB table.
int NetA_init_timetable_from_db(struct Map_info *In, int route_layer, int walk_layer, char *route_id, char *times, char *to_stop, char *walk_length, neta_timetable *timetable, int **route_ids, int **stop_ids)
Initialises timetable from a database.
Definition timetables.c:117
int NetA_init_distinct(dbDriver *driver, dbString *sql, int **lengths, int **ids)
Get number of distinct elements.
Definition timetables.c:36
void NetA_timetable_result_release(neta_timetable_result *result)
Free neta_timetable_result structure.
Definition timetables.c:548
void NetA_update_dijkstra(int old_conns, int new_conns, int to, int new_dst, int v, int route, int rows, int update, neta_timetable_result *result, dglHeap_s *heap)
Update Dijkstra structures.
Definition timetables.c:353
int NetA_timetable_get_route_time(neta_timetable *timetable, int stop, int route)
Get time.
Definition timetables.c:532
int NetA_timetable_shortest_path(neta_timetable *timetable, int from_stop, int to_stop, int start_time, int min_change, int max_changes, int walking_change, neta_timetable_result *result)
Computes the earliest arrival time.
Definition timetables.c:390
long dglInt32_t
Definition type.h:36