Routino SVN Repository Browser

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

ViewVC logotype

Contents of /trunk/src/router+lib.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1795 - (show annotations) (download) (as text)
Thu Sep 3 18:12:28 2015 UTC (9 years, 6 months ago) by amb
File MIME type: text/x-csrc
File size: 18268 byte(s)
Add in an HTML-all linked list formats that includes the full set of
points and the HTML directions for the important ones.

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