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