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 1809 - (show annotations) (download) (as text)
Thu Sep 24 17:30:16 2015 UTC (9 years, 6 months ago) by amb
File MIME type: text/x-csrc
File size: 18965 byte(s)
Add the allow_destination options to the API.

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