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 1904 - (show annotations) (download) (as text)
Sun Mar 12 13:57:04 2017 UTC (8 years ago) by amb
File MIME type: text/x-csrc
File size: 19293 byte(s)
Merge the changes for version 3.2 into the branch.

1 /***************************************
2 OSM router using libroutino library.
3
4 Part of the Routino routing software.
5 ******************/ /******************
6 This file Copyright 2008-2016 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 '%s' that does not exist.\n",profiles);
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 char *defaultprofiles=FileName(ROUTINO_DATADIR,NULL,"profiles.xml");
223
224 if(access(defaultprofiles,F_OK))
225 {
226 fprintf(stderr,"Error: The '--profiles' option was not used and the files '%s' and '%s' do not exist.\n",profiles,defaultprofiles);
227 exit(EXIT_FAILURE);
228 }
229
230 free(profiles);
231 profiles=defaultprofiles;
232 }
233 }
234
235 if(!profilename)
236 {
237 fprintf(stderr,"Error: A profile name must be specified.\n");
238 exit(EXIT_FAILURE);
239 }
240
241 if(Routino_ParseXMLProfiles(profiles))
242 {
243 fprintf(stderr,"Error: Cannot read the profiles in the file '%s'.\n",profiles);
244 exit(EXIT_FAILURE);
245 }
246
247 profile=Routino_GetProfile(profilename);
248
249 if(!profile)
250 {
251 char **list=Routino_GetProfileNames();
252
253 fprintf(stderr,"Error: Cannot find a profile called '%s' in the file '%s'.\n",profilename,profiles);
254
255 fprintf(stderr,"Profiles available are: %s",*list++);
256 while(*list)
257 fprintf(stderr,", %s",*list++);
258 fprintf(stderr,"\n");
259
260 exit(EXIT_FAILURE);
261 }
262
263 /* Load in the selected translation */
264
265 if(translations)
266 {
267 if(access(translations,F_OK))
268 {
269 fprintf(stderr,"Error: The '--translations' option specifies a file that does not exist.\n");
270 exit(EXIT_FAILURE);
271 }
272 }
273 else
274 {
275 translations=FileName(dirname,prefix,"translations.xml");
276
277 if(access(translations,F_OK))
278 {
279 char *defaulttranslations=FileName(ROUTINO_DATADIR,NULL,"translations.xml");
280
281 if(access(defaulttranslations,F_OK))
282 {
283 fprintf(stderr,"Error: The '--translations' option was not used and the files '%s' and '%s' do not exist.\n",translations,defaulttranslations);
284 exit(EXIT_FAILURE);
285 }
286
287 free(translations);
288 translations=defaulttranslations;
289 }
290 }
291
292 if(Routino_ParseXMLTranslations(translations))
293 {
294 fprintf(stderr,"Error: Cannot read the translations in the file '%s'.\n",translations);
295 exit(EXIT_FAILURE);
296 }
297
298 if(language)
299 {
300 translation=Routino_GetTranslation(language);
301
302 if(!translation)
303 {
304 char **list1=Routino_GetTranslationLanguages();
305 char **list2=Routino_GetTranslationLanguageFullNames();
306
307 fprintf(stderr,"Warning: Cannot find a translation called '%s' in the file '%s'.\n",language,translations);
308
309 fprintf(stderr,"Languages available are: %s (%s)",*list1++,*list2++);
310 while(*list1)
311 fprintf(stderr,", %s (%s)",*list1++,*list2++);
312 fprintf(stderr,"\n");
313
314 exit(EXIT_FAILURE);
315 }
316 }
317 else
318 {
319 translation=Routino_GetTranslation(""); /* first in file */
320
321 if(!translation)
322 {
323 fprintf(stderr,"Warning: No translations in '%s'.\n",translations);
324 exit(EXIT_FAILURE);
325 }
326 }
327
328 /* Check the waypoints are valid */
329
330 for(waypoint=first_waypoint;waypoint<=last_waypoint;waypoint++)
331 if(point_used[waypoint]==1 || point_used[waypoint]==2)
332 print_usage(0,NULL,"All waypoints must have latitude and longitude.");
333 else if(point_used[waypoint]==3)
334 nwaypoints++;
335
336 if(first_waypoint>=last_waypoint)
337 {
338 fprintf(stderr,"Error: At least two waypoints must be specified.\n");
339 exit(EXIT_FAILURE);
340 }
341
342 waypoints=calloc(sizeof(Routino_Waypoint*),nwaypoints+2);
343
344 /* Load in the routing database */
345
346 database=Routino_LoadDatabase(dirname,prefix);
347
348 /* Check the profile is valid for use with this database */
349
350 if(Routino_ValidateProfile(database,profile)!=ROUTINO_ERROR_NONE)
351 {
352 fprintf(stderr,"Error: Profile is invalid or not compatible with database.\n");
353 exit(EXIT_FAILURE);
354 }
355
356 /* Loop through all waypoints */
357
358 nwaypoints=0;
359
360 for(waypoint=first_waypoint;waypoint<=last_waypoint;waypoint++)
361 {
362 int allow_destination=0;
363
364 if(point_used[waypoint]!=3)
365 continue;
366
367 if(waypoint==first_waypoint || (waypoint==last_waypoint && !loop))
368 allow_destination=1;
369
370 waypoints[nwaypoints]=Routino_FindWaypoint(database,profile,point_lat[waypoint],point_lon[waypoint],allow_destination);
371
372 if(!waypoints[nwaypoints])
373 {
374 fprintf(stderr,"Error: Cannot find node close to specified point %d.\n",waypoint);
375 exit(EXIT_FAILURE);
376 }
377
378 nwaypoints++;
379 }
380
381 /* Create the route */
382
383 routing_options=0;
384
385 if(quickest)
386 routing_options|=ROUTINO_ROUTE_QUICKEST;
387 else
388 routing_options|=ROUTINO_ROUTE_SHORTEST;
389
390 if(html ) routing_options|=ROUTINO_ROUTE_FILE_HTML;
391 if(gpx_track) routing_options|=ROUTINO_ROUTE_FILE_GPX_TRACK;
392 if(gpx_route) routing_options|=ROUTINO_ROUTE_FILE_GPX_ROUTE;
393 if(text ) routing_options|=ROUTINO_ROUTE_FILE_TEXT;
394 if(text_all ) routing_options|=ROUTINO_ROUTE_FILE_TEXT_ALL;
395
396 if(list_html) routing_options|=ROUTINO_ROUTE_LIST_HTML;
397 if(list_html_all) routing_options|=ROUTINO_ROUTE_LIST_HTML_ALL;
398 if(list_text) routing_options|=ROUTINO_ROUTE_LIST_TEXT;
399 if(list_text_all) routing_options|=ROUTINO_ROUTE_LIST_TEXT_ALL;
400
401 if(reverse) routing_options|=ROUTINO_ROUTE_REVERSE;
402 if(loop) routing_options|=ROUTINO_ROUTE_LOOP;
403
404 route=Routino_CalculateRoute(database,profile,translation,waypoints,nwaypoints,routing_options,NULL);
405
406 if(Routino_errno>=ROUTINO_ERROR_NO_ROUTE_1)
407 {
408 fprintf(stderr,"Error: Cannot find a route between specified waypoints.\n");
409 exit(EXIT_FAILURE);
410 }
411 else if(Routino_errno!=ROUTINO_ERROR_NONE)
412 {
413 fprintf(stderr,"Error: Internal error (%d).\n",Routino_errno);
414 exit(EXIT_FAILURE);
415 }
416
417 /* Print the list output */
418
419 if(list_html || list_html_all || list_text || list_text_all)
420 {
421 Routino_Output *list=route;
422 int first=1,last;
423
424 while(list)
425 {
426 last=list->next?0:1;
427
428 printf("----------------\n");
429 printf("Lon,Lat: %.5f, %.5f\n",(180.0/M_PI)*list->lon,(180.0/M_PI)*list->lat);
430
431 if(list_html || list_html_all || list_text || list_text_all)
432 printf("Dist,Time: %.3f km, %.1f minutes\n",list->dist,list->time);
433
434 if(list_text_all && !first)
435 printf("Speed: %.0f km/hr\n",list->speed);
436
437 printf("Point type: %d\n",list->type);
438
439 if((list_html || list_html_all || list_text) && !first && !last)
440 printf("Turn: %d degrees\n",list->turn);
441
442 if(((list_html || list_html_all || list_text) && !last) || (list_text_all && !first))
443 printf("Bearing: %d degrees\n",list->bearing);
444
445 if(((list_html || list_text) && !last) || (list_html_all && list->name) || (list_text_all && !first))
446 printf("Name: %s\n",list->name);
447
448 if(list_html || (list_html_all && list->name))
449 {
450 printf("Desc1: %s\n",list->desc1);
451 printf("Desc2: %s\n",list->desc2);
452
453 if(!last)
454 printf("Desc3: %s\n",list->desc3);
455 }
456
457 list=list->next;
458 first=0;
459 }
460 }
461
462 /* Tidy up and exit */
463
464 Routino_DeleteRoute(route);
465
466 Routino_UnloadDatabase(database);
467
468 Routino_FreeXMLProfiles();
469
470 Routino_FreeXMLTranslations();
471
472 for(waypoint=0;waypoint<nwaypoints;waypoint++)
473 free(waypoints[waypoint]);
474
475 free(waypoints);
476
477 exit(EXIT_SUCCESS);
478 }
479
480
481 /*++++++++++++++++++++++++++++++++++++++
482 Return a filename composed of the dirname, prefix and name.
483
484 char *FileName Returns a pointer to memory allocated to the filename.
485
486 const char *dirname The directory name.
487
488 const char *prefix The file prefix.
489
490 const char *name The main part of the name.
491 ++++++++++++++++++++++++++++++++++++++*/
492
493 static char *FileName(const char *dirname,const char *prefix, const char *name)
494 {
495 char *filename=(char*)malloc((dirname?strlen(dirname):0)+1+(prefix?strlen(prefix):0)+1+strlen(name)+1);
496
497 sprintf(filename,"%s%s%s%s%s",dirname?dirname:"",dirname?"/":"",prefix?prefix:"",prefix?"-":"",name);
498
499 return(filename);
500 }
501
502
503 /*++++++++++++++++++++++++++++++++++++++
504 Print out the usage information.
505
506 int detail The level of detail to use: -1 = just version number, 0 = low detail, 1 = full details.
507
508 const char *argerr The argument that gave the error (if there is one).
509
510 const char *err Other error message (if there is one).
511 ++++++++++++++++++++++++++++++++++++++*/
512
513 static void print_usage(int detail,const char *argerr,const char *err)
514 {
515 if(detail<0)
516 {
517 fprintf(stderr,
518 "Routino version " ROUTINO_VERSION " " ROUTINO_URL " "
519 "[Library version: %s, API version: %d]\n",
520 Routino_Version,Routino_APIVersion
521 );
522 }
523
524 if(detail>=0)
525 {
526 fprintf(stderr,
527 "Usage: router [--version]\n"
528 " [--help ]\n"
529 " [--dir=<dirname>] [--prefix=<name>]\n"
530 " [--profiles=<filename>] [--translations=<filename>]\n"
531 " [--language=<lang>]\n"
532 " [--output-html]\n"
533 " [--output-gpx-track] [--output-gpx-route]\n"
534 " [--output-text] [--output-text-all]\n"
535 " [--output-none] [--output-stdout]\n"
536 " [--list-html | --list-html-all |\n"
537 " --list-text | --list-text-all]\n"
538 " [--profile=<name>]\n"
539 " [--shortest | --quickest]\n"
540 " --lon1=<longitude> --lat1=<latitude>\n"
541 " --lon2=<longitude> --lon2=<latitude>\n"
542 " [ ... --lon99=<longitude> --lon99=<latitude>]\n"
543 " [--reverse] [--loop]\n");
544
545 if(argerr)
546 fprintf(stderr,
547 "\n"
548 "Error with command line parameter: %s\n",argerr);
549
550 if(err)
551 fprintf(stderr,
552 "\n"
553 "Error: %s\n",err);
554 }
555
556 if(detail==1)
557 fprintf(stderr,
558 "\n"
559 "--version Print the version of Routino.\n"
560 "\n"
561 "--help Prints this information.\n"
562 "\n"
563 "--dir=<dirname> The directory containing the routing database.\n"
564 "--prefix=<name> The filename prefix for the routing database.\n"
565 "--profiles=<filename> The name of the XML file containing the profiles\n"
566 " (defaults to 'profiles.xml' with '--dir' and\n"
567 " '--prefix' options or the file installed in\n"
568 " '" ROUTINO_DATADIR "').\n"
569 "--translations=<fname> The name of the XML file containing the translations\n"
570 " (defaults to 'translations.xml' with '--dir' and\n"
571 " '--prefix' options or the file installed in\n"
572 " '" ROUTINO_DATADIR "').\n"
573 "\n"
574 "--language=<lang> Use the translations for specified language.\n"
575 "--output-html Write an HTML description of the route.\n"
576 "--output-gpx-track Write a GPX track file with all route points.\n"
577 "--output-gpx-route Write a GPX route file with interesting junctions.\n"
578 "--output-text Write a plain text file with interesting junctions.\n"
579 "--output-text-all Write a plain text file with all route points.\n"
580 "--output-none Don't write any output files or read any translations.\n"
581 " (If no output option is given then all are written.)\n"
582 "--output-stdout Write to stdout instead of a file (requires exactly\n"
583 " one output format option, implies '--quiet').\n"
584 "\n"
585 "--list-html Create an HTML list of the route.\n"
586 "--list-html-all Create an HTML list of the route with all points.\n"
587 "--list-text Create a plain text list with interesting junctions.\n"
588 "--list-text-all Create a plain text list with all route points.\n"
589 "\n"
590 "--profile=<name> Select the loaded profile with this name.\n"
591 "\n"
592 "--shortest Find the shortest route between the waypoints.\n"
593 "--quickest Find the quickest route between the waypoints.\n"
594 "\n"
595 "--lon<n>=<longitude> Specify the longitude of the n'th waypoint.\n"
596 "--lat<n>=<latitude> Specify the latitude of the n'th waypoint.\n"
597 "\n"
598 "--reverse Find a route between the waypoints in reverse order.\n"
599 "--loop Find a route that returns to the first waypoint.\n"
600 "\n");
601
602 exit(!detail);
603 }