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 1758 - (show annotations) (download) (as text)
Thu Jul 30 18:36:07 2015 UTC (9 years, 8 months ago) by amb
File MIME type: text/x-csrc
File size: 15560 byte(s)
Add the ability to request a linked list output representing the route
when using the routino library.

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