Routino SVN Repository Browser

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

ViewVC logotype

Contents of /branches/destination-access/src/router+lib.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1829 - (show annotations) (download) (as text)
Sat Oct 17 14:17:17 2015 UTC (9 years, 5 months ago) by amb
File MIME type: text/x-csrc
File size: 19098 byte(s)
Merge trunk back into routino-destination branch after completing the
loop and reverse changes.

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