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