Routino SVN Repository Browser

Check out the latest version of Routino: svn co http://routino.org/svn/trunk routino

ViewVC logotype

Contents of /branches/libroutino/src/router+lib.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1774 - (show annotations) (download) (as text)
Mon Aug 10 19:00:17 2015 UTC (9 years, 8 months ago) by amb
File MIME type: text/x-csrc
File size: 17311 byte(s)
Use 'use_stdout' instead of 'stdout' as a variable name (patch from
Oliver Eichler).

1 /***************************************
2 OSM router using libroutino library.
3
4 Part of the Routino routing software.
5 ******************/ /******************
6 This file Copyright 2008-2015 Andrew M. Bishop
7
8 This program is free software: you can redistribute it and/or modify
9 it under the terms of the GNU Affero General Public License as published by
10 the Free Software Foundation, either version 3 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 Affero General Public License for more details.
17
18 You should have received a copy of the GNU Affero General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 ***************************************/
21
22
23 #include <unistd.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include <ctype.h>
28
29 #include "routino.h"
30
31
32 /*+ The maximum number of waypoints +*/
33 #define NWAYPOINTS 99
34
35
36 /* Local functions */
37
38 static char *FileName(const char *dirname,const char *prefix, const char *name);
39 static void print_usage(int detail,const char *argerr,const char *err);
40
41
42 /*++++++++++++++++++++++++++++++++++++++
43 The main program for the router.
44 ++++++++++++++++++++++++++++++++++++++*/
45
46 int main(int argc,char** argv)
47 {
48 Routino_Database *database;
49 Routino_Profile *profile;
50 Routino_Translation *translation;
51 Routino_Waypoint **waypoints;
52 Routino_Output *route;
53 int point_used[NWAYPOINTS+1]={0};
54 double point_lon[NWAYPOINTS+1],point_lat[NWAYPOINTS+1];
55 char *dirname=NULL,*prefix=NULL;
56 char *profiles=NULL,*profilename="motorcar";
57 char *translations=NULL,*language="en";
58 int reverse=0,loop=0;
59 int quickest=0;
60 int html=0,gpx_track=0,gpx_route=0,text=0,text_all=0,none=0,use_stdout=0;
61 int list_html=0,list_text=0,list_text_all=0;
62 int arg;
63 int first_waypoint=NWAYPOINTS,last_waypoint=1,inc_dec_waypoint,waypoint,nwaypoints=0;
64 int routing_options;
65
66 /* Check the libroutino API version */
67
68 if(Routino_CheckAPIVersion()!=ROUTINO_ERROR_NONE)
69 {
70 fprintf(stderr,"Error: Executable version (%d) and library version (%d) do not match.\n",ROUTINO_API_VERSION,Routino_APIVersion);
71 exit(EXIT_FAILURE);
72 }
73
74 /* Parse the command line arguments */
75
76 if(argc<2)
77 print_usage(0,NULL,NULL);
78
79 /* Get the non-routing, general program options */
80
81 for(arg=1;arg<argc;arg++)
82 {
83 if(!strcmp(argv[arg],"--help"))
84 print_usage(1,NULL,NULL);
85 else if(!strncmp(argv[arg],"--dir=",6))
86 dirname=&argv[arg][6];
87 else if(!strncmp(argv[arg],"--prefix=",9))
88 prefix=&argv[arg][9];
89 else if(!strncmp(argv[arg],"--profiles=",11))
90 profiles=&argv[arg][11];
91 else if(!strncmp(argv[arg],"--translations=",15))
92 translations=&argv[arg][15];
93 else if(!strcmp(argv[arg],"--reverse"))
94 reverse=1;
95 else if(!strcmp(argv[arg],"--loop"))
96 loop=1;
97 else if(!strcmp(argv[arg],"--output-html"))
98 html=1;
99 else if(!strcmp(argv[arg],"--output-gpx-track"))
100 gpx_track=1;
101 else if(!strcmp(argv[arg],"--output-gpx-route"))
102 gpx_route=1;
103 else if(!strcmp(argv[arg],"--output-text"))
104 text=1;
105 else if(!strcmp(argv[arg],"--output-text-all"))
106 text_all=1;
107 else if(!strcmp(argv[arg],"--output-none"))
108 none=1;
109 else if(!strcmp(argv[arg],"--output-stdout"))
110 use_stdout=1;
111 else if(!strcmp(argv[arg],"--list-html"))
112 list_html=1;
113 else if(!strcmp(argv[arg],"--list-text"))
114 list_text=1;
115 else if(!strcmp(argv[arg],"--list-text-all"))
116 list_text_all=1;
117 else if(!strncmp(argv[arg],"--profile=",10))
118 profilename=&argv[arg][10];
119 else if(!strncmp(argv[arg],"--language=",11))
120 language=&argv[arg][11];
121 else if(!strcmp(argv[arg],"--shortest"))
122 quickest=0;
123 else if(!strcmp(argv[arg],"--quickest"))
124 quickest=1;
125 else if(!strncmp(argv[arg],"--lon",5) && isdigit(argv[arg][5]))
126 {
127 int point;
128 char *p=&argv[arg][6];
129
130 while(isdigit(*p)) p++;
131 if(*p++!='=')
132 print_usage(0,argv[arg],NULL);
133
134 point=atoi(&argv[arg][5]);
135 if(point>NWAYPOINTS || point_used[point]&1)
136 print_usage(0,argv[arg],NULL);
137
138 point_lon[point]=atof(p);
139 point_used[point]+=1;
140
141 if(point<first_waypoint)
142 first_waypoint=point;
143 if(point>last_waypoint)
144 last_waypoint=point;
145 }
146 else if(!strncmp(argv[arg],"--lat",5) && isdigit(argv[arg][5]))
147 {
148 int point;
149 char *p=&argv[arg][6];
150
151 while(isdigit(*p)) p++;
152 if(*p++!='=')
153 print_usage(0,argv[arg],NULL);
154
155 point=atoi(&argv[arg][5]);
156 if(point>NWAYPOINTS || point_used[point]&2)
157 print_usage(0,argv[arg],NULL);
158
159 point_lat[point]=atof(p);
160 point_used[point]+=2;
161
162 if(point<first_waypoint)
163 first_waypoint=point;
164 if(point>last_waypoint)
165 last_waypoint=point;
166 }
167 else
168 print_usage(0,argv[arg],NULL);
169
170 argv[arg]=NULL;
171 }
172
173 /* Check the specified command line options */
174
175 if(use_stdout && (html+gpx_track+gpx_route+text+text_all)!=1)
176 {
177 fprintf(stderr,"Error: The '--output-stdout' option requires exactly one other output option (but not '--output-none').\n");
178 exit(EXIT_FAILURE);
179 }
180
181 if(html==0 && gpx_track==0 && gpx_route==0 && text==0 && text_all==0 && none==0)
182 html=gpx_track=gpx_route=text=text_all=1;
183
184 /* Load in the selected profiles */
185
186 if(profiles)
187 {
188 if(access(profiles,F_OK))
189 {
190 fprintf(stderr,"Error: The '--profiles' option specifies a file that does not exist.\n");
191 exit(EXIT_FAILURE);
192 }
193 }
194 else
195 {
196 profiles=FileName(dirname,prefix,"profiles.xml");
197
198 if(access(profiles,F_OK))
199 {
200 free(profiles);
201
202 profiles=FileName(ROUTINO_DATADIR,NULL,"profiles.xml");
203
204 if(access(profiles,F_OK))
205 {
206 fprintf(stderr,"Error: The '--profiles' option was not used and the default 'profiles.xml' does not exist.\n");
207 exit(EXIT_FAILURE);
208 }
209 }
210 }
211
212 if(!profilename)
213 {
214 fprintf(stderr,"Error: A profile name must be specified.\n");
215 exit(EXIT_FAILURE);
216 }
217
218 if(Routino_ParseXMLProfiles(profiles))
219 {
220 fprintf(stderr,"Error: Cannot read the profiles in the file '%s'.\n",profiles);
221 exit(EXIT_FAILURE);
222 }
223
224 profile=Routino_GetProfile(profilename);
225
226 if(!profile)
227 {
228 char **list=Routino_GetProfileNames();
229
230 fprintf(stderr,"Error: Cannot find a profile called '%s' in '%s'.\n",profilename,profiles);
231
232 fprintf(stderr,"Profiles available are: %s",*list++);
233 while(*list)
234 fprintf(stderr,", %s",*list++);
235 fprintf(stderr,"\n");
236
237 exit(EXIT_FAILURE);
238 }
239
240 /* Load in the selected translation */
241
242 if(translations)
243 {
244 if(access(translations,F_OK))
245 {
246 fprintf(stderr,"Error: The '--translations' option specifies a file that does not exist.\n");
247 exit(EXIT_FAILURE);
248 }
249 }
250 else
251 {
252 translations=FileName(dirname,prefix,"translations.xml");
253
254 if(access(translations,F_OK))
255 {
256 free(translations);
257
258 translations=FileName(ROUTINO_DATADIR,NULL,"translations.xml");
259
260 if(access(translations,F_OK))
261 {
262 fprintf(stderr,"Error: The '--translations' option was not used and the default 'translations.xml' does not exist.\n");
263 exit(EXIT_FAILURE);
264 }
265 }
266 }
267
268 if(Routino_ParseXMLTranslations(translations))
269 {
270 fprintf(stderr,"Error: Cannot read the translations in the file '%s'.\n",translations);
271 exit(EXIT_FAILURE);
272 }
273
274 if(language)
275 {
276 translation=Routino_GetTranslation(language);
277
278 if(!translation)
279 {
280 char **list=Routino_GetTranslationLanguages();
281
282 fprintf(stderr,"Warning: Cannot find a translation called '%s' in '%s'.\n",language,translations);
283
284 fprintf(stderr,"Languages available are: %s",*list++);
285 while(*list)
286 fprintf(stderr,", %s",*list++);
287 fprintf(stderr,"\n");
288
289 exit(EXIT_FAILURE);
290 }
291 }
292 else
293 {
294 translation=Routino_GetTranslation(""); /* first in file */
295
296 if(!translation)
297 {
298 fprintf(stderr,"Warning: No translations in '%s'.\n",translations);
299 exit(EXIT_FAILURE);
300 }
301 }
302
303 /* Check the waypoints are valid */
304
305 for(waypoint=first_waypoint;waypoint<=last_waypoint;waypoint++)
306 if(point_used[waypoint]==1 || point_used[waypoint]==2)
307 print_usage(0,NULL,"All waypoints must have latitude and longitude.");
308 else if(point_used[waypoint]==3)
309 nwaypoints++;
310
311 if(first_waypoint>=last_waypoint)
312 {
313 fprintf(stderr,"Error: At least two waypoints must be specified.\n");
314 exit(EXIT_FAILURE);
315 }
316
317 waypoints=calloc(sizeof(Routino_Waypoint*),nwaypoints+2);
318
319 /* Load in the routing database */
320
321 database=Routino_LoadDatabase(dirname,prefix);
322
323 /* Check the profile is valid for use with this database */
324
325 Routino_ValidateProfile(database,profile);
326
327 /* Check for reverse direction */
328
329 if(reverse)
330 {
331 int temp;
332
333 temp=first_waypoint;
334 first_waypoint=last_waypoint;
335 last_waypoint=temp;
336
337 last_waypoint--;
338
339 inc_dec_waypoint=-1;
340 }
341 else
342 {
343 last_waypoint++;
344
345 inc_dec_waypoint=1;
346 }
347
348 /* Loop through all waypoints */
349
350 nwaypoints=0;
351
352 for(waypoint=first_waypoint;waypoint!=last_waypoint;waypoint+=inc_dec_waypoint)
353 if(point_used[waypoint]==3)
354 {
355 waypoints[nwaypoints]=Routino_FindWaypoint(database,profile,point_lat[waypoint],point_lon[waypoint]);
356
357 if(!waypoints[nwaypoints])
358 {
359 fprintf(stderr,"Error: Cannot find node close to specified point %d.\n",waypoint);
360 exit(EXIT_FAILURE);
361 }
362
363 nwaypoints++;
364 }
365
366 if(loop)
367 waypoints[nwaypoints++]=waypoints[0];
368
369 /* Create the route */
370
371 routing_options=0;
372
373 if(quickest)
374 routing_options|=ROUTINO_ROUTE_QUICKEST;
375 else
376 routing_options|=ROUTINO_ROUTE_SHORTEST;
377
378 if(html ) routing_options|=ROUTINO_ROUTE_FILE_HTML;
379 if(gpx_track) routing_options|=ROUTINO_ROUTE_FILE_GPX_TRACK;
380 if(gpx_route) routing_options|=ROUTINO_ROUTE_FILE_GPX_ROUTE;
381 if(text ) routing_options|=ROUTINO_ROUTE_FILE_TEXT;
382 if(text_all ) routing_options|=ROUTINO_ROUTE_FILE_TEXT_ALL;
383
384 if(list_html) routing_options|=ROUTINO_ROUTE_LIST_HTML;
385 if(list_text) routing_options|=ROUTINO_ROUTE_LIST_TEXT;
386 if(list_text_all) routing_options|=ROUTINO_ROUTE_LIST_TEXT_ALL;
387
388 route=Routino_CalculateRoute(database,profile,translation,waypoints,nwaypoints,routing_options,NULL);
389
390 if(Routino_errno>=ROUTINO_ERROR_NO_ROUTE_1)
391 {
392 fprintf(stderr,"Error: Cannot find a route between specified waypoints.\n");
393 exit(EXIT_FAILURE);
394 }
395 else if(Routino_errno!=ROUTINO_ERROR_NONE)
396 {
397 fprintf(stderr,"Error: Internal error (%d).\n",Routino_errno);
398 exit(EXIT_FAILURE);
399 }
400
401 /* Print the list output */
402
403 if(list_html || list_text || list_text_all)
404 {
405 Routino_Output *list=route;
406 int first=1,last;
407
408 while(list)
409 {
410 last=list->next?0:1;
411
412 printf("----------------\n");
413 printf("Lon,Lat: %.5f, %.5f\n",list->lon,list->lat);
414
415 if((list_html && !last) || list_text || list_text_all)
416 printf("Dist,Time: %.3f km, %.1f minutes\n",list->dist,list->time);
417
418 if(list_text_all && !first)
419 printf("Speed: %.0f km/hr\n",list->speed);
420
421 printf("Point type: %d\n",list->type);
422
423 if((list_text || list_html) && !first && !last)
424 printf("Turn: %d degrees\n",list->turn);
425
426 if(((list_text || list_html) && !last) || (list_text_all && !first))
427 printf("Bearing: %d degrees\n",list->bearing);
428
429 if(((list_text || list_html) && !last) || (list_text_all && !first))
430 printf("Name: %s\n",list->name);
431
432 if(list_html)
433 {
434 printf("Desc1: %s\n",list->desc1);
435 printf("Desc2: %s\n",list->desc2);
436
437 if(!last)
438 printf("Desc3: %s\n",list->desc3);
439 }
440
441 list=list->next;
442 first=0;
443 }
444 }
445
446 /* Tidy up and exit */
447
448 Routino_DeleteRoute(route);
449
450 Routino_UnloadDatabase(database);
451
452 Routino_FreeXMLProfiles();
453
454 Routino_FreeXMLTranslations();
455
456 for(waypoint=0;waypoint<nwaypoints;waypoint++)
457 free(waypoints[waypoint]);
458
459 free(waypoints);
460
461 exit(EXIT_SUCCESS);
462 }
463
464
465 /*++++++++++++++++++++++++++++++++++++++
466 Return a filename composed of the dirname, prefix and name.
467
468 char *FileName Returns a pointer to memory allocated to the filename.
469
470 const char *dirname The directory name.
471
472 const char *prefix The file prefix.
473
474 const char *name The main part of the name.
475 ++++++++++++++++++++++++++++++++++++++*/
476
477 static char *FileName(const char *dirname,const char *prefix, const char *name)
478 {
479 char *filename=(char*)malloc((dirname?strlen(dirname):0)+1+(prefix?strlen(prefix):0)+1+strlen(name)+1);
480
481 sprintf(filename,"%s%s%s%s%s",dirname?dirname:"",dirname?"/":"",prefix?prefix:"",prefix?"-":"",name);
482
483 return(filename);
484 }
485
486
487 /*++++++++++++++++++++++++++++++++++++++
488 Print out the usage information.
489
490 int detail The level of detail to use - 0 = low, 1 = high.
491
492 const char *argerr The argument that gave the error (if there is one).
493
494 const char *err Other error message (if there is one).
495 ++++++++++++++++++++++++++++++++++++++*/
496
497 static void print_usage(int detail,const char *argerr,const char *err)
498 {
499 fprintf(stderr,
500 "Usage: router [--help ]\n"
501 " [--dir=<dirname>] [--prefix=<name>]\n"
502 " [--profiles=<filename>] [--translations=<filename>]\n"
503 " [--language=<lang>]\n"
504 " [--output-html]\n"
505 " [--output-gpx-track] [--output-gpx-route]\n"
506 " [--output-text] [--output-text-all]\n"
507 " [--output-none] [--output-stdout]\n"
508 " [--profile=<name>]\n"
509 " [--shortest | --quickest]\n"
510 " --lon1=<longitude> --lat1=<latitude>\n"
511 " --lon2=<longitude> --lon2=<latitude>\n"
512 " [ ... --lon99=<longitude> --lon99=<latitude>]\n"
513 " [--reverse] [--loop]\n");
514
515 if(argerr)
516 fprintf(stderr,
517 "\n"
518 "Error with command line parameter: %s\n",argerr);
519
520 if(err)
521 fprintf(stderr,
522 "\n"
523 "Error: %s\n",err);
524
525 if(detail)
526 fprintf(stderr,
527 "\n"
528 "--help Prints this information.\n"
529 "\n"
530 "--dir=<dirname> The directory containing the routing database.\n"
531 "--prefix=<name> The filename prefix for the routing database.\n"
532 "--profiles=<filename> The name of the XML file containing the profiles\n"
533 " (defaults to 'profiles.xml' with '--dir' and\n"
534 " '--prefix' options or the file installed in\n"
535 " '" ROUTINO_DATADIR "').\n"
536 "--translations=<fname> The name of the XML file containing the translations\n"
537 " (defaults to 'translations.xml' with '--dir' and\n"
538 " '--prefix' options or the file installed in\n"
539 " '" ROUTINO_DATADIR "').\n"
540 "\n"
541 "--language=<lang> Use the translations for specified language.\n"
542 "--output-html Write an HTML description of the route.\n"
543 "--output-gpx-track Write a GPX track file with all route points.\n"
544 "--output-gpx-route Write a GPX route file with interesting junctions.\n"
545 "--output-text Write a plain text file with interesting junctions.\n"
546 "--output-text-all Write a plain test file with all route points.\n"
547 "--output-none Don't write any output files or read any translations.\n"
548 " (If no output option is given then all are written.)\n"
549 "--output-stdout Write to stdout instead of a file (requires exactly\n"
550 " one output format option, implies '--quiet').\n"
551 "\n"
552 "--profile=<name> Select the loaded profile with this name.\n"
553 "\n"
554 "--shortest Find the shortest route between the waypoints.\n"
555 "--quickest Find the quickest route between the waypoints.\n"
556 "\n"
557 "--lon<n>=<longitude> Specify the longitude of the n'th waypoint.\n"
558 "--lat<n>=<latitude> Specify the latitude of the n'th waypoint.\n"
559 "\n"
560 "--reverse Find a route between the waypoints in reverse order.\n"
561 "--loop Find a route that returns to the first waypoint.\n"
562 "\n");
563
564 exit(!detail);
565 }