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.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 488 - (show annotations) (download) (as text)
Wed Sep 15 17:41:28 2010 UTC (14 years, 6 months ago) by amb
File MIME type: text/x-csrc
File size: 20748 byte(s)
Usage message has wrong option name.

1 /***************************************
2 $Header: /home/amb/CVS/routino/src/router.c,v 1.87 2010-09-15 17:41:28 amb Exp $
3
4 OSM router.
5
6 Part of the Routino routing software.
7 ******************/ /******************
8 This file Copyright 2008-2010 Andrew M. Bishop
9
10 This program is free software: you can redistribute it and/or modify
11 it under the terms of the GNU Affero General Public License as published by
12 the Free Software Foundation, either version 3 of the License, or
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU Affero General Public License for more details.
19
20 You should have received a copy of the GNU Affero General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 ***************************************/
23
24
25 #include <stdio.h>
26 #include <string.h>
27 #include <stdlib.h>
28 #include <ctype.h>
29
30 #include "types.h"
31 #include "nodes.h"
32 #include "segments.h"
33 #include "ways.h"
34
35 #include "files.h"
36 #include "functions.h"
37 #include "translations.h"
38 #include "profiles.h"
39
40
41 /*+ The maximum distance from the specified point to search for a node or segment (in km). +*/
42 #define MAXSEARCH 1
43
44
45 /*+ A set of waypoint latitudes and longitudes. +*/
46 static double point_lon[NWAYPOINTS+1],point_lat[NWAYPOINTS+1];
47
48 /*+ The option not to print any progress information. +*/
49 int option_quiet=0;
50
51 /*+ The options to select the format of the output. +*/
52 int option_html=0,option_gpx_track=0,option_gpx_route=0,option_text=0,option_text_all=0,option_none=0;
53
54 /*+ The option to calculate the quickest route insted of the shortest. +*/
55 int option_quickest=0;
56
57
58 /* Local functions */
59
60 static void print_usage(int detail);
61
62
63 /*++++++++++++++++++++++++++++++++++++++
64 The main program for the router.
65 ++++++++++++++++++++++++++++++++++++++*/
66
67 int main(int argc,char** argv)
68 {
69 Nodes *OSMNodes;
70 Segments *OSMSegments;
71 Ways *OSMWays;
72 Results *results[NWAYPOINTS+1]={NULL};
73 int point_used[NWAYPOINTS+1]={0};
74 int help_profile=0,help_profile_xml=0,help_profile_json=0,help_profile_pl=0;
75 char *dirname=NULL,*prefix=NULL;
76 char *profiles=NULL,*profilename=NULL;
77 char *translations=NULL,*language=NULL;
78 int exactnodes=0;
79 Transport transport=Transport_None;
80 Profile *profile=NULL;
81 index_t start=NO_NODE,finish=NO_NODE;
82 int arg,point;
83
84 /* Parse the command line arguments */
85
86 if(argc<2)
87 print_usage(0);
88
89 /* Get the non-routing, general program options */
90
91 for(arg=1;arg<argc;arg++)
92 {
93 if(!strcmp(argv[arg],"--help"))
94 print_usage(1);
95 else if(!strcmp(argv[arg],"--help-profile"))
96 help_profile=1;
97 else if(!strcmp(argv[arg],"--help-profile-xml"))
98 help_profile_xml=1;
99 else if(!strcmp(argv[arg],"--help-profile-json"))
100 help_profile_json=1;
101 else if(!strcmp(argv[arg],"--help-profile-perl"))
102 help_profile_pl=1;
103 else if(!strncmp(argv[arg],"--dir=",6))
104 dirname=&argv[arg][6];
105 else if(!strncmp(argv[arg],"--prefix=",9))
106 prefix=&argv[arg][9];
107 else if(!strncmp(argv[arg],"--profiles=",11))
108 profiles=&argv[arg][11];
109 else if(!strncmp(argv[arg],"--translations=",15))
110 translations=&argv[arg][15];
111 else if(!strcmp(argv[arg],"--exact-nodes-only"))
112 exactnodes=1;
113 else if(!strcmp(argv[arg],"--quiet"))
114 option_quiet=1;
115 else if(!strcmp(argv[arg],"--output-html"))
116 option_html=1;
117 else if(!strcmp(argv[arg],"--output-gpx-track"))
118 option_gpx_track=1;
119 else if(!strcmp(argv[arg],"--output-gpx-route"))
120 option_gpx_route=1;
121 else if(!strcmp(argv[arg],"--output-text"))
122 option_text=1;
123 else if(!strcmp(argv[arg],"--output-text-all"))
124 option_text_all=1;
125 else if(!strcmp(argv[arg],"--output-none"))
126 option_none=1;
127 else if(!strncmp(argv[arg],"--profile=",10))
128 profilename=&argv[arg][10];
129 else if(!strncmp(argv[arg],"--language=",11))
130 language=&argv[arg][11];
131 else if(!strncmp(argv[arg],"--transport=",12))
132 {
133 transport=TransportType(&argv[arg][12]);
134
135 if(transport==Transport_None)
136 print_usage(0);
137 }
138 else
139 continue;
140
141 argv[arg]=NULL;
142 }
143
144 /* Load in the profiles */
145
146 if(transport==Transport_None)
147 transport=Transport_Motorcar;
148
149 if(profiles)
150 {
151 if(!ExistsFile(profiles))
152 {
153 fprintf(stderr,"Error: The '--profiles' option specifies a file that does not exist.\n");
154 return(1);
155 }
156 }
157 else
158 {
159 if(ExistsFile(FileName(dirname,prefix,"profiles.xml")))
160 profiles=FileName(dirname,prefix,"profiles.xml");
161 else if(ExistsFile(FileName(DATADIR,NULL,"tagging.xml")))
162 profiles=FileName(DATADIR,NULL,"profiles.xml");
163 else
164 {
165 fprintf(stderr,"Error: The '--profiles' option was not used and the default 'profiles.xml' does not exist.\n");
166 return(1);
167 }
168 }
169
170 if(ParseXMLProfiles(profiles))
171 {
172 fprintf(stderr,"Error: Cannot read the profiles in the file '%s'.\n",profiles);
173 return(1);
174 }
175
176 if(profilename)
177 {
178 profile=GetProfile(profilename);
179
180 if(!profile)
181 {
182 fprintf(stderr,"Error: Cannot find a profile called '%s' in '%s'.\n",profilename,profiles);
183 return(1);
184 }
185 }
186 else
187 profile=GetProfile(TransportName(transport));
188
189 if(!profile)
190 {
191 profile=(Profile*)calloc(1,sizeof(Profile));
192 profile->transport=transport;
193 }
194
195 /* Parse the other command line arguments */
196
197 for(arg=1;arg<argc;arg++)
198 {
199 if(!argv[arg])
200 continue;
201 else if(!strcmp(argv[arg],"--shortest"))
202 option_quickest=0;
203 else if(!strcmp(argv[arg],"--quickest"))
204 option_quickest=1;
205 else if(isdigit(argv[arg][0]) ||
206 ((argv[arg][0]=='-' || argv[arg][0]=='+') && isdigit(argv[arg][1])))
207 {
208 for(point=1;point<=NWAYPOINTS;point++)
209 if(point_used[point]!=3)
210 {
211 if(point_used[point]==0)
212 {
213 point_lon[point]=degrees_to_radians(atof(argv[arg]));
214 point_used[point]=1;
215 }
216 else /* if(point_used[point]==1) */
217 {
218 point_lat[point]=degrees_to_radians(atof(argv[arg]));
219 point_used[point]=3;
220 }
221 break;
222 }
223 }
224 else if(!strncmp(argv[arg],"--lon",5) && isdigit(argv[arg][5]))
225 {
226 char *p=&argv[arg][6];
227 while(isdigit(*p)) p++;
228 if(*p++!='=')
229 print_usage(0);
230
231 point=atoi(&argv[arg][5]);
232 if(point>NWAYPOINTS || point_used[point]&1)
233 print_usage(0);
234
235 point_lon[point]=degrees_to_radians(atof(p));
236 point_used[point]+=1;
237 }
238 else if(!strncmp(argv[arg],"--lat",5) && isdigit(argv[arg][5]))
239 {
240 char *p=&argv[arg][6];
241 while(isdigit(*p)) p++;
242 if(*p++!='=')
243 print_usage(0);
244
245 point=atoi(&argv[arg][5]);
246 if(point>NWAYPOINTS || point_used[point]&2)
247 print_usage(0);
248
249 point_lat[point]=degrees_to_radians(atof(p));
250 point_used[point]+=2;
251 }
252 else if(!strncmp(argv[arg],"--transport=",12))
253 ; /* Done this already */
254 else if(!strncmp(argv[arg],"--highway-",10))
255 {
256 Highway highway;
257 char *equal=strchr(argv[arg],'=');
258 char *string;
259
260 if(!equal)
261 print_usage(0);
262
263 string=strcpy((char*)malloc(strlen(argv[arg])),argv[arg]+10);
264 string[equal-argv[arg]-10]=0;
265
266 highway=HighwayType(string);
267
268 if(highway==Way_Count)
269 print_usage(0);
270
271 profile->highway[highway]=atof(equal+1);
272
273 free(string);
274 }
275 else if(!strncmp(argv[arg],"--speed-",8))
276 {
277 Highway highway;
278 char *equal=strchr(argv[arg],'=');
279 char *string;
280
281 if(!equal)
282 print_usage(0);
283
284 string=strcpy((char*)malloc(strlen(argv[arg])),argv[arg]+8);
285 string[equal-argv[arg]-8]=0;
286
287 highway=HighwayType(string);
288
289 if(highway==Way_Count)
290 print_usage(0);
291
292 profile->speed[highway]=kph_to_speed(atof(equal+1));
293
294 free(string);
295 }
296 else if(!strncmp(argv[arg],"--property-",11))
297 {
298 Property property;
299 char *equal=strchr(argv[arg],'=');
300 char *string;
301
302 if(!equal)
303 print_usage(0);
304
305 string=strcpy((char*)malloc(strlen(argv[arg])),argv[arg]+11);
306 string[equal-argv[arg]-11]=0;
307
308 property=PropertyType(string);
309
310 if(property==Way_Count)
311 print_usage(0);
312
313 profile->props_yes[property]=atof(equal+1);
314
315 free(string);
316 }
317 else if(!strncmp(argv[arg],"--oneway=",9))
318 profile->oneway=!!atoi(&argv[arg][9]);
319 else if(!strncmp(argv[arg],"--weight=",9))
320 profile->weight=tonnes_to_weight(atof(&argv[arg][9]));
321 else if(!strncmp(argv[arg],"--height=",9))
322 profile->height=metres_to_height(atof(&argv[arg][9]));
323 else if(!strncmp(argv[arg],"--width=",8))
324 profile->width=metres_to_width(atof(&argv[arg][8]));
325 else if(!strncmp(argv[arg],"--length=",9))
326 profile->length=metres_to_length(atof(&argv[arg][9]));
327 else
328 print_usage(0);
329 }
330
331 for(point=1;point<=NWAYPOINTS;point++)
332 if(point_used[point]==1 || point_used[point]==2)
333 print_usage(0);
334
335 if(help_profile)
336 {
337 PrintProfile(profile);
338
339 return(0);
340 }
341 else if(help_profile_xml)
342 {
343 PrintProfilesXML();
344
345 return(0);
346 }
347 else if(help_profile_json)
348 {
349 PrintProfilesJSON();
350
351 return(0);
352 }
353 else if(help_profile_pl)
354 {
355 PrintProfilesPerl();
356
357 return(0);
358 }
359
360 /* Load in the translations */
361
362 if(option_html==0 && option_gpx_track==0 && option_gpx_route==0 && option_text==0 && option_text_all==0 && option_none==0)
363 option_html=option_gpx_track=option_gpx_route=option_text=option_text_all=1;
364
365 if(option_html || option_gpx_route || option_gpx_track)
366 {
367 if(translations)
368 {
369 if(!ExistsFile(translations))
370 {
371 fprintf(stderr,"Error: The '--translations' option specifies a file that does not exist.\n");
372 return(1);
373 }
374 }
375 else
376 {
377 if(ExistsFile(FileName(dirname,prefix,"translations.xml")))
378 translations=FileName(dirname,prefix,"translations.xml");
379 else if(ExistsFile(FileName(DATADIR,NULL,"translations.xml")))
380 translations=FileName(DATADIR,NULL,"translations.xml");
381 else
382 {
383 fprintf(stderr,"Error: The '--translations' option was not used and the default 'translations.xml' does not exist.\n");
384 return(1);
385 }
386 }
387
388 if(ParseXMLTranslations(translations,language))
389 {
390 fprintf(stderr,"Error: Cannot read the translations in the file '%s'.\n",translations);
391 return(1);
392 }
393 }
394
395 /* Load in the data - Note: No error checking because Load*List() will call exit() in case of an error. */
396
397 OSMNodes=LoadNodeList(FileName(dirname,prefix,"nodes.mem"));
398
399 OSMSegments=LoadSegmentList(FileName(dirname,prefix,"segments.mem"));
400
401 OSMWays=LoadWayList(FileName(dirname,prefix,"ways.mem"));
402
403 if(UpdateProfile(profile,OSMWays))
404 {
405 fprintf(stderr,"Error: Profile is invalid or not compatible with database.\n");
406 return(1);
407 }
408
409 /* Loop through all pairs of points */
410
411 for(point=1;point<=NWAYPOINTS;point++)
412 {
413 Results *begin,*end;
414 distance_t distmax=km_to_distance(MAXSEARCH);
415 distance_t distmin;
416 index_t segment=NO_SEGMENT;
417 index_t node1,node2;
418
419 if(point_used[point]!=3)
420 continue;
421
422 /* Find the closest point */
423
424 start=finish;
425
426 if(exactnodes)
427 {
428 finish=FindClosestNode(OSMNodes,OSMSegments,OSMWays,point_lat[point],point_lon[point],distmax,profile,&distmin);
429 }
430 else
431 {
432 distance_t dist1,dist2;
433
434 segment=FindClosestSegment(OSMNodes,OSMSegments,OSMWays,point_lat[point],point_lon[point],distmax,profile,&distmin,&node1,&node2,&dist1,&dist2);
435
436 if(segment!=NO_SEGMENT)
437 finish=CreateFakes(OSMNodes,point,LookupSegment(OSMSegments,segment,1),node1,node2,dist1,dist2);
438 else
439 finish=NO_NODE;
440 }
441
442 if(finish==NO_NODE)
443 {
444 fprintf(stderr,"Error: Cannot find node close to specified point %d.\n",point);
445 return(1);
446 }
447
448 if(!option_quiet)
449 {
450 double lat,lon;
451
452 if(IsFakeNode(finish))
453 GetFakeLatLong(finish,&lat,&lon);
454 else
455 GetLatLong(OSMNodes,finish,&lat,&lon);
456
457 if(IsFakeNode(finish))
458 printf("Point %d is segment %d (node %d -> %d): %3.6f %4.6f = %2.3f km\n",point,segment,node1,node2,
459 radians_to_degrees(lon),radians_to_degrees(lat),distance_to_km(distmin));
460 else
461 printf("Point %d is node %d: %3.6f %4.6f = %2.3f km\n",point,finish,
462 radians_to_degrees(lon),radians_to_degrees(lat),distance_to_km(distmin));
463 }
464
465 if(start==NO_NODE)
466 continue;
467
468 if(start==finish)
469 continue;
470
471 /* Calculate the beginning of the route */
472
473 if(!IsFakeNode(start) && IsSuperNode(OSMNodes,start))
474 {
475 Result *result;
476
477 begin=NewResultsList(1);
478
479 begin->start=start;
480
481 result=InsertResult(begin,start);
482
483 ZeroResult(result);
484 }
485 else
486 {
487 begin=FindStartRoutes(OSMNodes,OSMSegments,OSMWays,start,profile);
488
489 if(!begin)
490 {
491 fprintf(stderr,"Error: Cannot find initial section of route compatible with profile.\n");
492 return(1);
493 }
494 }
495
496 if(FindResult(begin,finish))
497 {
498 FixForwardRoute(begin,finish);
499
500 results[point]=begin;
501
502 if(!option_quiet)
503 {
504 printf("\rRouted: Super-Nodes Checked = %d\n",begin->number);
505 fflush(stdout);
506 }
507 }
508 else
509 {
510 Results *superresults;
511
512 /* Calculate the end of the route */
513
514 if(!IsFakeNode(finish) && IsSuperNode(OSMNodes,finish))
515 {
516 Result *result;
517
518 end=NewResultsList(1);
519
520 end->finish=finish;
521
522 result=InsertResult(end,finish);
523
524 ZeroResult(result);
525 }
526 else
527 {
528 end=FindFinishRoutes(OSMNodes,OSMSegments,OSMWays,finish,profile);
529
530 if(!end)
531 {
532 fprintf(stderr,"Error: Cannot find final section of route compatible with profile.\n");
533 return(1);
534 }
535 }
536
537 /* Calculate the middle of the route */
538
539 superresults=FindMiddleRoute(OSMNodes,OSMSegments,OSMWays,begin,end,profile);
540
541 FreeResultsList(begin);
542 FreeResultsList(end);
543
544 if(!superresults)
545 {
546 fprintf(stderr,"Error: Cannot find route compatible with profile.\n");
547 return(1);
548 }
549
550 results[point]=CombineRoutes(superresults,OSMNodes,OSMSegments,OSMWays,profile);
551
552 FreeResultsList(superresults);
553 }
554 }
555
556 /* Print out the combined route */
557
558 if(!option_none)
559 PrintRoute(results,NWAYPOINTS,OSMNodes,OSMSegments,OSMWays,profile);
560
561 return(0);
562 }
563
564
565 /*++++++++++++++++++++++++++++++++++++++
566 Print out the usage information.
567
568 int detail The level of detail to use - 0 = low, 1 = high.
569 ++++++++++++++++++++++++++++++++++++++*/
570
571 static void print_usage(int detail)
572 {
573 fprintf(stderr,
574 "Usage: router [--help | --help-profile | --help-profile-xml |\n"
575 " --help-profile-json | --help-profile-perl ]\n"
576 " [--dir=<dirname>] [--prefix=<name>]\n"
577 " [--profiles=<filename>] [--translations=<filename>]\n"
578 " [--exact-nodes-only]\n"
579 " [--quiet]\n"
580 " [--language=<lang>]\n"
581 " [--output-html]\n"
582 " [--output-gpx-track] [--output-gpx-route]\n"
583 " [--output-text] [--output-text-all]\n"
584 " [--output-none]\n"
585 " [--profile=<name>]\n"
586 " [--transport=<transport>]\n"
587 " [--shortest | --quickest]\n"
588 " --lon1=<longitude> --lat1=<latitude>\n"
589 " --lon2=<longitude> --lon2=<latitude>\n"
590 " [ ... --lon99=<longitude> --lon99=<latitude>]\n"
591 " [--highway-<highway>=<preference> ...]\n"
592 " [--speed-<highway>=<speed> ...]\n"
593 " [--property-<property>=<preference> ...]\n"
594 " [--oneway=(0|1)]\n"
595 " [--weight=<weight>]\n"
596 " [--height=<height>] [--width=<width>] [--length=<length>]\n");
597
598 if(detail)
599 fprintf(stderr,
600 "\n"
601 "--help Prints this information.\n"
602 "--help-profile Prints the information about the selected profile.\n"
603 "--help-profile-xml Prints all loaded profiles in XML format.\n"
604 "--help-profile-json Prints all loaded profiles in JSON format.\n"
605 "--help-profile-perl Prints all loaded profiles in Perl format.\n"
606 "\n"
607 "--dir=<dirname> The directory containing the routing database.\n"
608 "--prefix=<name> The filename prefix for the routing database.\n"
609 "--profiles=<filename> The name of the XML file containing the profiles\n"
610 " (defaults to 'profiles.xml' with '--dir' and\n"
611 " '--prefix' options or the file installed in\n"
612 " '" DATADIR "').\n"
613 "--translations=<fname> The name of the XML file containing the translations\n"
614 " (defaults to 'translations.xml' with '--dir' and\n"
615 " '--prefix' options or the file installed in\n"
616 " '" DATADIR "').\n"
617 "\n"
618 "--exact-nodes-only Only route between nodes (don't find closest segment).\n"
619 "\n"
620 "--quiet Don't print any screen output when running.\n"
621 "--language=<lang> Use the translations for specified language.\n"
622 "--output-html Write an HTML description of the route.\n"
623 "--output-gpx-track Write a GPX track file with all route points.\n"
624 "--output-gpx-route Write a GPX route file with interesting junctions.\n"
625 "--output-text Write a plain text file with interesting junctions.\n"
626 "--output-text-all Write a plain test file with all route points.\n"
627 "--output-none Don't write any output files or read any translations.\n"
628 " (If no output option is given then all are written.)\n"
629 "\n"
630 "--profile=<name> Select the loaded profile with this name.\n"
631 "--transport=<transport> Select the transport to use (selects the profile\n"
632 " named after the transport if '--profile' is not used.)\n"
633 "\n"
634 "--shortest Find the shortest route between the waypoints.\n"
635 "--quickest Find the quickest route between the waypoints.\n"
636 "\n"
637 "--lon<n>=<longitude> Specify the longitude of the n'th waypoint.\n"
638 "--lat<n>=<latitude> Specify the latitude of the n'th waypoint.\n"
639 "\n"
640 " Routing preference options\n"
641 "--highway-<highway>=<preference> * preference for highway type (%%).\n"
642 "--speed-<highway>=<speed> * speed for highway type (km/h).\n"
643 "--property-<property>=<preference> * preference for proprty type (%%).\n"
644 "--oneway=(0|1) * oneway streets are to be obeyed.\n"
645 "--weight=<weight> * maximum weight limit (tonnes).\n"
646 "--height=<height> * maximum height limit (metres).\n"
647 "--width=<width> * maximum width limit (metres).\n"
648 "--length=<length> * maximum length limit (metres).\n"
649 "\n"
650 "<transport> defaults to motorcar but can be set to:\n"
651 "%s"
652 "\n"
653 "<highway> can be selected from:\n"
654 "%s"
655 "\n"
656 "<property> can be selected from:\n"
657 "%s",
658 TransportList(),HighwayList(),PropertyList());
659
660 exit(!detail);
661 }

Properties

Name Value
cvs:description Router.