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 531 - (show annotations) (download) (as text)
Sat Nov 27 14:43:55 2010 UTC (14 years, 3 months ago) by amb
File MIME type: text/x-csrc
File size: 21038 byte(s)
Move some of the complexity from router.c to optimiser.c.

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

Properties

Name Value
cvs:description Router.