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 675 - (show annotations) (download) (as text)
Fri Apr 22 13:59:27 2011 UTC (13 years, 10 months ago) by amb
File MIME type: text/x-csrc
File size: 22136 byte(s)
Add in the option to specify an initial heading.

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

Properties

Name Value
cvs:description Router.