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 719 - (show annotations) (download) (as text)
Sun May 15 17:57:56 2011 UTC (13 years, 11 months ago) by amb
File MIME type: text/x-csrc
File size: 23157 byte(s)
Finally find a way out of dead-ends, might have some nasty side-effects though.

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

Properties

Name Value
cvs:description Router.