Check out the latest version of Routino: svn co http://routino.org/svn/trunk routino
Contents of /trunk/src/router.c
Parent Directory
|
Revision Log
Revision 1565 -
(show annotations)
(download)
(as text)
Sat May 10 10:22:15 2014 UTC (10 years, 11 months ago) by amb
File MIME type: text/x-csrc
File size: 28367 byte(s)
Sat May 10 10:22:15 2014 UTC (10 years, 11 months ago) by amb
File MIME type: text/x-csrc
File size: 28367 byte(s)
Don't crash if the specified route contains two consecutive coincident waypoints (route instructions at those points may not be perfect).
1 | /*************************************** |
2 | OSM router. |
3 | |
4 | Part of the Routino routing software. |
5 | ******************/ /****************** |
6 | This file Copyright 2008-2014 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 | /*+ To help when debugging +*/ |
43 | #define DEBUG 0 |
44 | |
45 | /*+ The maximum distance from the specified point to search for a node or segment (in km). +*/ |
46 | #define MAXSEARCH 1 |
47 | |
48 | |
49 | /* Global variables */ |
50 | |
51 | /*+ The option not to print any progress information. +*/ |
52 | int option_quiet=0; |
53 | |
54 | /*+ The options to select the format of the output. +*/ |
55 | int option_html=0,option_gpx_track=0,option_gpx_route=0,option_text=0,option_text_all=0,option_none=0,option_stdout=0; |
56 | |
57 | /*+ The option to calculate the quickest route insted of the shortest. +*/ |
58 | int option_quickest=0; |
59 | |
60 | |
61 | /* Local functions */ |
62 | |
63 | static void print_usage(int detail,const char *argerr,const char *err); |
64 | |
65 | static Results *CalculateRoute(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile, |
66 | index_t start_node,index_t prev_segment,index_t finish_node, |
67 | int start_waypoint,int finish_waypoint); |
68 | |
69 | |
70 | /*++++++++++++++++++++++++++++++++++++++ |
71 | The main program for the router. |
72 | ++++++++++++++++++++++++++++++++++++++*/ |
73 | |
74 | int main(int argc,char** argv) |
75 | { |
76 | Nodes *OSMNodes; |
77 | Segments *OSMSegments; |
78 | Ways *OSMWays; |
79 | Relations *OSMRelations; |
80 | Results *results[NWAYPOINTS+1]={NULL}; |
81 | int point_used[NWAYPOINTS+1]={0}; |
82 | double point_lon[NWAYPOINTS+1],point_lat[NWAYPOINTS+1]; |
83 | double heading=-999; |
84 | int help_profile=0,help_profile_xml=0,help_profile_json=0,help_profile_pl=0; |
85 | char *dirname=NULL,*prefix=NULL; |
86 | char *profiles=NULL,*profilename=NULL; |
87 | char *translations=NULL,*language=NULL; |
88 | int exactnodes=0,reverse=0,loop=0; |
89 | Transport transport=Transport_None; |
90 | Profile *profile=NULL; |
91 | index_t start_node,finish_node=NO_NODE,first_node=NO_NODE; |
92 | index_t join_segment=NO_SEGMENT; |
93 | int arg,nresults=0; |
94 | waypoint_t start_waypoint,finish_waypoint=NO_WAYPOINT; |
95 | waypoint_t first_waypoint=NWAYPOINTS,last_waypoint=1,inc_dec_waypoint,waypoint; |
96 | |
97 | /* Parse the command line arguments */ |
98 | |
99 | if(argc<2) |
100 | print_usage(0,NULL,NULL); |
101 | |
102 | /* Get the non-routing, general program options */ |
103 | |
104 | for(arg=1;arg<argc;arg++) |
105 | { |
106 | if(!strcmp(argv[arg],"--help")) |
107 | print_usage(1,NULL,NULL); |
108 | else if(!strcmp(argv[arg],"--help-profile")) |
109 | help_profile=1; |
110 | else if(!strcmp(argv[arg],"--help-profile-xml")) |
111 | help_profile_xml=1; |
112 | else if(!strcmp(argv[arg],"--help-profile-json")) |
113 | help_profile_json=1; |
114 | else if(!strcmp(argv[arg],"--help-profile-perl")) |
115 | help_profile_pl=1; |
116 | else if(!strncmp(argv[arg],"--dir=",6)) |
117 | dirname=&argv[arg][6]; |
118 | else if(!strncmp(argv[arg],"--prefix=",9)) |
119 | prefix=&argv[arg][9]; |
120 | else if(!strncmp(argv[arg],"--profiles=",11)) |
121 | profiles=&argv[arg][11]; |
122 | else if(!strncmp(argv[arg],"--translations=",15)) |
123 | translations=&argv[arg][15]; |
124 | else if(!strcmp(argv[arg],"--exact-nodes-only")) |
125 | exactnodes=1; |
126 | else if(!strcmp(argv[arg],"--reverse")) |
127 | reverse=1; |
128 | else if(!strcmp(argv[arg],"--loop")) |
129 | loop=1; |
130 | else if(!strcmp(argv[arg],"--quiet")) |
131 | option_quiet=1; |
132 | else if(!strcmp(argv[arg],"--loggable")) |
133 | option_loggable=1; |
134 | else if(!strcmp(argv[arg],"--output-html")) |
135 | option_html=1; |
136 | else if(!strcmp(argv[arg],"--output-gpx-track")) |
137 | option_gpx_track=1; |
138 | else if(!strcmp(argv[arg],"--output-gpx-route")) |
139 | option_gpx_route=1; |
140 | else if(!strcmp(argv[arg],"--output-text")) |
141 | option_text=1; |
142 | else if(!strcmp(argv[arg],"--output-text-all")) |
143 | option_text_all=1; |
144 | else if(!strcmp(argv[arg],"--output-none")) |
145 | option_none=1; |
146 | else if(!strcmp(argv[arg],"--output-stdout")) |
147 | { option_stdout=1; option_quiet=1; } |
148 | else if(!strncmp(argv[arg],"--profile=",10)) |
149 | profilename=&argv[arg][10]; |
150 | else if(!strncmp(argv[arg],"--language=",11)) |
151 | language=&argv[arg][11]; |
152 | else if(!strncmp(argv[arg],"--transport=",12)) |
153 | { |
154 | transport=TransportType(&argv[arg][12]); |
155 | |
156 | if(transport==Transport_None) |
157 | print_usage(0,argv[arg],NULL); |
158 | } |
159 | else |
160 | continue; |
161 | |
162 | argv[arg]=NULL; |
163 | } |
164 | |
165 | if(option_stdout && (option_html+option_gpx_track+option_gpx_route+option_text+option_text_all)!=1) |
166 | { |
167 | fprintf(stderr,"Error: The '--output-stdout' option requires exactly one other output option (but not '--output-none').\n"); |
168 | exit(EXIT_FAILURE); |
169 | } |
170 | |
171 | /* Load in the profiles */ |
172 | |
173 | if(transport==Transport_None) |
174 | transport=Transport_Motorcar; |
175 | |
176 | if(profiles) |
177 | { |
178 | if(!ExistsFile(profiles)) |
179 | { |
180 | fprintf(stderr,"Error: The '--profiles' option specifies a file that does not exist.\n"); |
181 | exit(EXIT_FAILURE); |
182 | } |
183 | } |
184 | else |
185 | { |
186 | if(ExistsFile(FileName(dirname,prefix,"profiles.xml"))) |
187 | profiles=FileName(dirname,prefix,"profiles.xml"); |
188 | else if(ExistsFile(FileName(DATADIR,NULL,"profiles.xml"))) |
189 | profiles=FileName(DATADIR,NULL,"profiles.xml"); |
190 | else |
191 | { |
192 | fprintf(stderr,"Error: The '--profiles' option was not used and the default 'profiles.xml' does not exist.\n"); |
193 | exit(EXIT_FAILURE); |
194 | } |
195 | } |
196 | |
197 | if(ParseXMLProfiles(profiles)) |
198 | { |
199 | fprintf(stderr,"Error: Cannot read the profiles in the file '%s'.\n",profiles); |
200 | exit(EXIT_FAILURE); |
201 | } |
202 | |
203 | /* Choose the selected profile. */ |
204 | |
205 | if(profilename) |
206 | { |
207 | profile=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 | else |
216 | profile=GetProfile(TransportName(transport)); |
217 | |
218 | if(!profile) |
219 | { |
220 | profile=(Profile*)calloc(1,sizeof(Profile)); |
221 | profile->transport=transport; |
222 | } |
223 | |
224 | /* Parse the other command line arguments */ |
225 | |
226 | for(arg=1;arg<argc;arg++) |
227 | { |
228 | if(!argv[arg]) |
229 | continue; |
230 | else if(!strcmp(argv[arg],"--shortest")) |
231 | option_quickest=0; |
232 | else if(!strcmp(argv[arg],"--quickest")) |
233 | option_quickest=1; |
234 | else if(!strncmp(argv[arg],"--lon",5) && isdigit(argv[arg][5])) |
235 | { |
236 | int point; |
237 | char *p=&argv[arg][6]; |
238 | |
239 | while(isdigit(*p)) p++; |
240 | if(*p++!='=') |
241 | print_usage(0,argv[arg],NULL); |
242 | |
243 | point=atoi(&argv[arg][5]); |
244 | if(point>NWAYPOINTS || point_used[point]&1) |
245 | print_usage(0,argv[arg],NULL); |
246 | |
247 | point_lon[point]=degrees_to_radians(atof(p)); |
248 | point_used[point]+=1; |
249 | |
250 | if(point<first_waypoint) |
251 | first_waypoint=point; |
252 | if(point>last_waypoint) |
253 | last_waypoint=point; |
254 | } |
255 | else if(!strncmp(argv[arg],"--lat",5) && isdigit(argv[arg][5])) |
256 | { |
257 | int point; |
258 | char *p=&argv[arg][6]; |
259 | |
260 | while(isdigit(*p)) p++; |
261 | if(*p++!='=') |
262 | print_usage(0,argv[arg],NULL); |
263 | |
264 | point=atoi(&argv[arg][5]); |
265 | if(point>NWAYPOINTS || point_used[point]&2) |
266 | print_usage(0,argv[arg],NULL); |
267 | |
268 | point_lat[point]=degrees_to_radians(atof(p)); |
269 | point_used[point]+=2; |
270 | |
271 | if(point<first_waypoint) |
272 | first_waypoint=point; |
273 | if(point>last_waypoint) |
274 | last_waypoint=point; |
275 | } |
276 | else if(!strncmp(argv[arg],"--heading=",10)) |
277 | { |
278 | double h=atof(&argv[arg][10]); |
279 | |
280 | if(h>=-360 && h<=360) |
281 | { |
282 | heading=h; |
283 | |
284 | if(heading<0) heading+=360; |
285 | } |
286 | } |
287 | else if(!strncmp(argv[arg],"--transport=",12)) |
288 | ; /* Done this already */ |
289 | else if(!strncmp(argv[arg],"--highway-",10)) |
290 | { |
291 | Highway highway; |
292 | char *equal=strchr(argv[arg],'='); |
293 | char *string; |
294 | |
295 | if(!equal) |
296 | print_usage(0,argv[arg],NULL); |
297 | |
298 | string=strcpy((char*)malloc(strlen(argv[arg])),argv[arg]+10); |
299 | string[equal-argv[arg]-10]=0; |
300 | |
301 | highway=HighwayType(string); |
302 | |
303 | if(highway==Highway_None) |
304 | print_usage(0,argv[arg],NULL); |
305 | |
306 | profile->highway[highway]=atof(equal+1); |
307 | |
308 | free(string); |
309 | } |
310 | else if(!strncmp(argv[arg],"--speed-",8)) |
311 | { |
312 | Highway highway; |
313 | char *equal=strchr(argv[arg],'='); |
314 | char *string; |
315 | |
316 | if(!equal) |
317 | print_usage(0,argv[arg],NULL); |
318 | |
319 | string=strcpy((char*)malloc(strlen(argv[arg])),argv[arg]+8); |
320 | string[equal-argv[arg]-8]=0; |
321 | |
322 | highway=HighwayType(string); |
323 | |
324 | if(highway==Highway_None) |
325 | print_usage(0,argv[arg],NULL); |
326 | |
327 | profile->speed[highway]=kph_to_speed(atof(equal+1)); |
328 | |
329 | free(string); |
330 | } |
331 | else if(!strncmp(argv[arg],"--property-",11)) |
332 | { |
333 | Property property; |
334 | char *equal=strchr(argv[arg],'='); |
335 | char *string; |
336 | |
337 | if(!equal) |
338 | print_usage(0,argv[arg],NULL); |
339 | |
340 | string=strcpy((char*)malloc(strlen(argv[arg])),argv[arg]+11); |
341 | string[equal-argv[arg]-11]=0; |
342 | |
343 | property=PropertyType(string); |
344 | |
345 | if(property==Property_None) |
346 | print_usage(0,argv[arg],NULL); |
347 | |
348 | profile->props_yes[property]=atof(equal+1); |
349 | |
350 | free(string); |
351 | } |
352 | else if(!strncmp(argv[arg],"--oneway=",9)) |
353 | profile->oneway=!!atoi(&argv[arg][9]); |
354 | else if(!strncmp(argv[arg],"--turns=",8)) |
355 | profile->turns=!!atoi(&argv[arg][8]); |
356 | else if(!strncmp(argv[arg],"--weight=",9)) |
357 | profile->weight=tonnes_to_weight(atof(&argv[arg][9])); |
358 | else if(!strncmp(argv[arg],"--height=",9)) |
359 | profile->height=metres_to_height(atof(&argv[arg][9])); |
360 | else if(!strncmp(argv[arg],"--width=",8)) |
361 | profile->width=metres_to_width(atof(&argv[arg][8])); |
362 | else if(!strncmp(argv[arg],"--length=",9)) |
363 | profile->length=metres_to_length(atof(&argv[arg][9])); |
364 | else |
365 | print_usage(0,argv[arg],NULL); |
366 | } |
367 | |
368 | /* Print one of the profiles if requested */ |
369 | |
370 | if(help_profile) |
371 | { |
372 | PrintProfile(profile); |
373 | |
374 | return(0); |
375 | } |
376 | else if(help_profile_xml) |
377 | { |
378 | PrintProfilesXML(); |
379 | |
380 | return(0); |
381 | } |
382 | else if(help_profile_json) |
383 | { |
384 | PrintProfilesJSON(); |
385 | |
386 | return(0); |
387 | } |
388 | else if(help_profile_pl) |
389 | { |
390 | PrintProfilesPerl(); |
391 | |
392 | return(0); |
393 | } |
394 | |
395 | /* Check the waypoints are valid */ |
396 | |
397 | for(waypoint=1;waypoint<=NWAYPOINTS;waypoint++) |
398 | if(point_used[waypoint]==1 || point_used[waypoint]==2) |
399 | print_usage(0,NULL,"All waypoints must have latitude and longitude."); |
400 | |
401 | if(first_waypoint>=last_waypoint) |
402 | print_usage(0,NULL,"At least two waypoints must be specified."); |
403 | |
404 | /* Load in the translations */ |
405 | |
406 | if(option_html==0 && option_gpx_track==0 && option_gpx_route==0 && option_text==0 && option_text_all==0 && option_none==0) |
407 | option_html=option_gpx_track=option_gpx_route=option_text=option_text_all=1; |
408 | |
409 | if(option_html || option_gpx_route || option_gpx_track) |
410 | { |
411 | if(translations) |
412 | { |
413 | if(!ExistsFile(translations)) |
414 | { |
415 | fprintf(stderr,"Error: The '--translations' option specifies a file that does not exist.\n"); |
416 | exit(EXIT_FAILURE); |
417 | } |
418 | } |
419 | else |
420 | { |
421 | if(ExistsFile(FileName(dirname,prefix,"translations.xml"))) |
422 | translations=FileName(dirname,prefix,"translations.xml"); |
423 | else if(ExistsFile(FileName(DATADIR,NULL,"translations.xml"))) |
424 | translations=FileName(DATADIR,NULL,"translations.xml"); |
425 | else |
426 | { |
427 | fprintf(stderr,"Error: The '--translations' option was not used and the default 'translations.xml' does not exist.\n"); |
428 | exit(EXIT_FAILURE); |
429 | } |
430 | } |
431 | |
432 | if(ParseXMLTranslations(translations,language)) |
433 | { |
434 | fprintf(stderr,"Error: Cannot read the translations in the file '%s'.\n",translations); |
435 | exit(EXIT_FAILURE); |
436 | } |
437 | } |
438 | |
439 | /* Load in the data - Note: No error checking because Load*List() will call exit() in case of an error. */ |
440 | |
441 | OSMNodes=LoadNodeList(FileName(dirname,prefix,"nodes.mem")); |
442 | |
443 | OSMSegments=LoadSegmentList(FileName(dirname,prefix,"segments.mem")); |
444 | |
445 | OSMWays=LoadWayList(FileName(dirname,prefix,"ways.mem")); |
446 | |
447 | OSMRelations=LoadRelationList(FileName(dirname,prefix,"relations.mem")); |
448 | |
449 | if(UpdateProfile(profile,OSMWays)) |
450 | { |
451 | fprintf(stderr,"Error: Profile is invalid or not compatible with database.\n"); |
452 | exit(EXIT_FAILURE); |
453 | } |
454 | |
455 | /* Check for reverse direction */ |
456 | |
457 | if(reverse) |
458 | { |
459 | waypoint_t temp; |
460 | |
461 | temp=first_waypoint; |
462 | first_waypoint=last_waypoint; |
463 | last_waypoint=temp; |
464 | |
465 | last_waypoint--; |
466 | |
467 | inc_dec_waypoint=-1; |
468 | } |
469 | else |
470 | { |
471 | last_waypoint++; |
472 | |
473 | inc_dec_waypoint=1; |
474 | } |
475 | |
476 | /* Loop through all pairs of waypoints */ |
477 | |
478 | for(waypoint=first_waypoint;waypoint!=last_waypoint;waypoint+=inc_dec_waypoint) |
479 | { |
480 | distance_t distmax=km_to_distance(MAXSEARCH); |
481 | distance_t distmin; |
482 | index_t segment=NO_SEGMENT; |
483 | index_t node1,node2; |
484 | |
485 | if(point_used[waypoint]!=3) |
486 | continue; |
487 | |
488 | /* Find the closest point */ |
489 | |
490 | start_node=finish_node; |
491 | start_waypoint=finish_waypoint; |
492 | |
493 | if(exactnodes) |
494 | { |
495 | finish_node=FindClosestNode(OSMNodes,OSMSegments,OSMWays,point_lat[waypoint],point_lon[waypoint],distmax,profile,&distmin); |
496 | } |
497 | else |
498 | { |
499 | distance_t dist1,dist2; |
500 | |
501 | segment=FindClosestSegment(OSMNodes,OSMSegments,OSMWays,point_lat[waypoint],point_lon[waypoint],distmax,profile,&distmin,&node1,&node2,&dist1,&dist2); |
502 | |
503 | if(segment!=NO_SEGMENT) |
504 | finish_node=CreateFakes(OSMNodes,OSMSegments,waypoint,LookupSegment(OSMSegments,segment,1),node1,node2,dist1,dist2); |
505 | else |
506 | finish_node=NO_NODE; |
507 | } |
508 | |
509 | if(finish_node==NO_NODE) |
510 | { |
511 | fprintf(stderr,"Error: Cannot find node close to specified point %d.\n",waypoint); |
512 | exit(EXIT_FAILURE); |
513 | } |
514 | |
515 | finish_waypoint=waypoint; |
516 | |
517 | if(!option_quiet) |
518 | { |
519 | double lat,lon; |
520 | |
521 | if(IsFakeNode(finish_node)) |
522 | GetFakeLatLong(finish_node,&lat,&lon); |
523 | else |
524 | GetLatLong(OSMNodes,finish_node,NULL,&lat,&lon); |
525 | |
526 | if(IsFakeNode(finish_node)) |
527 | printf("Waypoint %d is segment %"Pindex_t" (node %"Pindex_t" -> %"Pindex_t"): %3.6f %4.6f = %2.3f km\n",waypoint,segment,node1,node2, |
528 | radians_to_degrees(lon),radians_to_degrees(lat),distance_to_km(distmin)); |
529 | else |
530 | printf("Waypoint %d is node %"Pindex_t": %3.6f %4.6f = %2.3f km\n",waypoint,finish_node, |
531 | radians_to_degrees(lon),radians_to_degrees(lat),distance_to_km(distmin)); |
532 | } |
533 | |
534 | /* Check the nodes */ |
535 | |
536 | if(start_node==NO_NODE) |
537 | continue; |
538 | |
539 | if(first_node==NO_NODE) |
540 | first_node=start_node; |
541 | |
542 | if(heading!=-999 && join_segment==NO_SEGMENT) |
543 | join_segment=FindClosestSegmentHeading(OSMNodes,OSMSegments,OSMWays,start_node,heading,profile); |
544 | |
545 | /* Calculate the route */ |
546 | |
547 | results[nresults]=CalculateRoute(OSMNodes,OSMSegments,OSMWays,OSMRelations,profile,start_node,join_segment,finish_node,start_waypoint,finish_waypoint); |
548 | |
549 | join_segment=results[nresults]->last_segment; |
550 | |
551 | nresults++; |
552 | } |
553 | |
554 | /* Finish the loop */ |
555 | |
556 | if(loop && finish_node!=NO_NODE) |
557 | { |
558 | results[nresults]=CalculateRoute(OSMNodes,OSMSegments,OSMWays,OSMRelations,profile,finish_node,join_segment,first_node,last_waypoint,first_waypoint); |
559 | |
560 | nresults++; |
561 | } |
562 | |
563 | if(!option_quiet) |
564 | { |
565 | printf("Routed OK\n"); |
566 | fflush(stdout); |
567 | } |
568 | |
569 | /* Print out the combined route */ |
570 | |
571 | if(!option_none) |
572 | PrintRoute(results,nresults,OSMNodes,OSMSegments,OSMWays,profile); |
573 | |
574 | /* Destroy the remaining results lists and data structures */ |
575 | |
576 | #if 0 |
577 | |
578 | for(waypoint=0;waypoint<=nresults;waypoint++) |
579 | FreeResultsList(results[waypoint]); |
580 | |
581 | DestroyNodeList(OSMNodes); |
582 | DestroySegmentList(OSMSegments); |
583 | DestroyWayList(OSMWays); |
584 | DestroyRelationList(OSMRelations); |
585 | |
586 | #endif |
587 | |
588 | return(0); |
589 | } |
590 | |
591 | |
592 | /*++++++++++++++++++++++++++++++++++++++ |
593 | Find a complete route from a specified node to another node. |
594 | |
595 | Results *CalculateRoute Returns a set of results. |
596 | |
597 | Nodes *nodes The set of nodes to use. |
598 | |
599 | Segments *segments The set of segments to use. |
600 | |
601 | Ways *ways The set of ways to use. |
602 | |
603 | Relations *relations The set of relations to use. |
604 | |
605 | Profile *profile The profile containing the transport type, speeds and allowed highways. |
606 | |
607 | index_t start_node The start node. |
608 | |
609 | index_t prev_segment The previous segment before the start node. |
610 | |
611 | index_t finish_node The finish node. |
612 | |
613 | int start_waypoint The starting waypoint. |
614 | |
615 | int finish_waypoint The finish waypoint. |
616 | ++++++++++++++++++++++++++++++++++++++*/ |
617 | |
618 | static Results *CalculateRoute(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile, |
619 | index_t start_node,index_t prev_segment,index_t finish_node, |
620 | int start_waypoint,int finish_waypoint) |
621 | { |
622 | Results *complete=NULL; |
623 | |
624 | /* A special case if the first and last nodes are the same */ |
625 | |
626 | if(start_node==finish_node) |
627 | { |
628 | index_t fake_segment; |
629 | Result *result1,*result2; |
630 | |
631 | complete=NewResultsList(8); |
632 | |
633 | if(prev_segment==NO_SEGMENT) |
634 | { |
635 | double lat,lon; |
636 | distance_t distmin,dist1,dist2; |
637 | index_t node1,node2; |
638 | |
639 | GetLatLong(nodes,start_node,NULL,&lat,&lon); |
640 | |
641 | prev_segment=FindClosestSegment(nodes,segments,ways,lat,lon,1,profile,&distmin,&node1,&node2,&dist1,&dist2); |
642 | } |
643 | |
644 | fake_segment=CreateFakeNullSegment(segments,start_node,prev_segment,finish_waypoint); |
645 | |
646 | result1=InsertResult(complete,start_node,prev_segment); |
647 | result2=InsertResult(complete,finish_node,fake_segment); |
648 | |
649 | result1->next=result2; |
650 | |
651 | complete->start_node=start_node; |
652 | complete->prev_segment=prev_segment; |
653 | |
654 | complete->finish_node=finish_node; |
655 | complete->last_segment=prev_segment; |
656 | |
657 | complete->last_segment=result2->segment; |
658 | } |
659 | else |
660 | { |
661 | Results *begin,*end; |
662 | |
663 | /* Calculate the beginning of the route */ |
664 | |
665 | begin=FindStartRoutes(nodes,segments,ways,relations,profile,start_node,prev_segment,finish_node); |
666 | |
667 | if(begin) |
668 | { |
669 | /* Check if the end of the route was reached */ |
670 | |
671 | if(begin->finish_node!=NO_NODE) |
672 | complete=ExtendStartRoutes(nodes,segments,ways,relations,profile,begin,finish_node); |
673 | } |
674 | else |
675 | { |
676 | if(prev_segment!=NO_SEGMENT) |
677 | { |
678 | /* Try again but allow a U-turn at the start waypoint - |
679 | this solves the problem of facing a dead-end that contains no super-nodes. */ |
680 | |
681 | prev_segment=NO_SEGMENT; |
682 | |
683 | begin=FindStartRoutes(nodes,segments,ways,relations,profile,start_node,prev_segment,finish_node); |
684 | } |
685 | |
686 | if(begin) |
687 | { |
688 | /* Check if the end of the route was reached */ |
689 | |
690 | if(begin->finish_node!=NO_NODE) |
691 | complete=ExtendStartRoutes(nodes,segments,ways,relations,profile,begin,finish_node); |
692 | } |
693 | else |
694 | { |
695 | fprintf(stderr,"Error: Cannot find initial section of route compatible with profile.\n"); |
696 | exit(EXIT_FAILURE); |
697 | } |
698 | } |
699 | |
700 | /* Calculate the rest of the route */ |
701 | |
702 | if(!complete) |
703 | { |
704 | Results *middle; |
705 | |
706 | /* Calculate the end of the route */ |
707 | |
708 | end=FindFinishRoutes(nodes,segments,ways,relations,profile,finish_node); |
709 | |
710 | if(!end) |
711 | { |
712 | fprintf(stderr,"Error: Cannot find final section of route compatible with profile.\n"); |
713 | exit(EXIT_FAILURE); |
714 | } |
715 | |
716 | /* Calculate the middle of the route */ |
717 | |
718 | middle=FindMiddleRoute(nodes,segments,ways,relations,profile,begin,end); |
719 | |
720 | if(!middle && prev_segment!=NO_SEGMENT) |
721 | { |
722 | /* Try again but allow a U-turn at the start waypoint - |
723 | this solves the problem of facing a dead-end that contains some super-nodes. */ |
724 | |
725 | FreeResultsList(begin); |
726 | |
727 | begin=FindStartRoutes(nodes,segments,ways,relations,profile,start_node,NO_SEGMENT,finish_node); |
728 | |
729 | if(begin) |
730 | middle=FindMiddleRoute(nodes,segments,ways,relations,profile,begin,end); |
731 | } |
732 | |
733 | FreeResultsList(end); |
734 | |
735 | if(!middle) |
736 | { |
737 | fprintf(stderr,"Error: Cannot find super-route compatible with profile.\n"); |
738 | exit(EXIT_FAILURE); |
739 | } |
740 | |
741 | complete=CombineRoutes(nodes,segments,ways,relations,profile,begin,middle); |
742 | |
743 | if(!complete) |
744 | { |
745 | fprintf(stderr,"Error: Cannot create combined route following super-route.\n"); |
746 | exit(EXIT_FAILURE); |
747 | } |
748 | |
749 | FreeResultsList(begin); |
750 | |
751 | FreeResultsList(middle); |
752 | } |
753 | } |
754 | |
755 | complete->start_waypoint=start_waypoint; |
756 | complete->finish_waypoint=finish_waypoint; |
757 | |
758 | #if DEBUG |
759 | Result *r=FindResult(complete,complete->start_node,complete->prev_segment); |
760 | |
761 | printf("The final route is:\n"); |
762 | |
763 | while(r) |
764 | { |
765 | printf(" node=%"Pindex_t" segment=%"Pindex_t" score=%f\n",r->node,r->segment,r->score); |
766 | |
767 | r=r->next; |
768 | } |
769 | #endif |
770 | |
771 | return(complete); |
772 | } |
773 | |
774 | |
775 | /*++++++++++++++++++++++++++++++++++++++ |
776 | Print out the usage information. |
777 | |
778 | int detail The level of detail to use - 0 = low, 1 = high. |
779 | |
780 | const char *argerr The argument that gave the error (if there is one). |
781 | |
782 | const char *err Other error message (if there is one). |
783 | ++++++++++++++++++++++++++++++++++++++*/ |
784 | |
785 | static void print_usage(int detail,const char *argerr,const char *err) |
786 | { |
787 | fprintf(stderr, |
788 | "Usage: router [--help | --help-profile | --help-profile-xml |\n" |
789 | " --help-profile-json | --help-profile-perl ]\n" |
790 | " [--dir=<dirname>] [--prefix=<name>]\n" |
791 | " [--profiles=<filename>] [--translations=<filename>]\n" |
792 | " [--exact-nodes-only]\n" |
793 | " [--loggable | --quiet]\n" |
794 | " [--language=<lang>]\n" |
795 | " [--output-html]\n" |
796 | " [--output-gpx-track] [--output-gpx-route]\n" |
797 | " [--output-text] [--output-text-all]\n" |
798 | " [--output-none] [--output-stdout]\n" |
799 | " [--profile=<name>]\n" |
800 | " [--transport=<transport>]\n" |
801 | " [--shortest | --quickest]\n" |
802 | " --lon1=<longitude> --lat1=<latitude>\n" |
803 | " --lon2=<longitude> --lon2=<latitude>\n" |
804 | " [ ... --lon99=<longitude> --lon99=<latitude>]\n" |
805 | " [--reverse] [--loop]\n" |
806 | " [--highway-<highway>=<preference> ...]\n" |
807 | " [--speed-<highway>=<speed> ...]\n" |
808 | " [--property-<property>=<preference> ...]\n" |
809 | " [--oneway=(0|1)] [--turns=(0|1)]\n" |
810 | " [--weight=<weight>]\n" |
811 | " [--height=<height>] [--width=<width>] [--length=<length>]\n"); |
812 | |
813 | if(argerr) |
814 | fprintf(stderr, |
815 | "\n" |
816 | "Error with command line parameter: %s\n",argerr); |
817 | |
818 | if(err) |
819 | fprintf(stderr, |
820 | "\n" |
821 | "Error: %s\n",err); |
822 | |
823 | if(detail) |
824 | fprintf(stderr, |
825 | "\n" |
826 | "--help Prints this information.\n" |
827 | "--help-profile Prints the information about the selected profile.\n" |
828 | "--help-profile-xml Prints all loaded profiles in XML format.\n" |
829 | "--help-profile-json Prints all loaded profiles in JSON format.\n" |
830 | "--help-profile-perl Prints all loaded profiles in Perl format.\n" |
831 | "\n" |
832 | "--dir=<dirname> The directory containing the routing database.\n" |
833 | "--prefix=<name> The filename prefix for the routing database.\n" |
834 | "--profiles=<filename> The name of the XML file containing the profiles\n" |
835 | " (defaults to 'profiles.xml' with '--dir' and\n" |
836 | " '--prefix' options or the file installed in\n" |
837 | " '" DATADIR "').\n" |
838 | "--translations=<fname> The name of the XML file containing the translations\n" |
839 | " (defaults to 'translations.xml' with '--dir' and\n" |
840 | " '--prefix' options or the file installed in\n" |
841 | " '" DATADIR "').\n" |
842 | "\n" |
843 | "--exact-nodes-only Only route between nodes (don't find closest segment).\n" |
844 | "\n" |
845 | "--loggable Print progress messages suitable for logging to file.\n" |
846 | "--quiet Don't print any screen output when running.\n" |
847 | "\n" |
848 | "--language=<lang> Use the translations for specified language.\n" |
849 | "--output-html Write an HTML description of the route.\n" |
850 | "--output-gpx-track Write a GPX track file with all route points.\n" |
851 | "--output-gpx-route Write a GPX route file with interesting junctions.\n" |
852 | "--output-text Write a plain text file with interesting junctions.\n" |
853 | "--output-text-all Write a plain test file with all route points.\n" |
854 | "--output-none Don't write any output files or read any translations.\n" |
855 | " (If no output option is given then all are written.)\n" |
856 | "--output-stdout Write to stdout instead of a file (requires exactly\n" |
857 | " one output format option, implies '--quiet').\n" |
858 | "\n" |
859 | "--profile=<name> Select the loaded profile with this name.\n" |
860 | "--transport=<transport> Select the transport to use (selects the profile\n" |
861 | " named after the transport if '--profile' is not used.)\n" |
862 | "\n" |
863 | "--shortest Find the shortest route between the waypoints.\n" |
864 | "--quickest Find the quickest route between the waypoints.\n" |
865 | "\n" |
866 | "--lon<n>=<longitude> Specify the longitude of the n'th waypoint.\n" |
867 | "--lat<n>=<latitude> Specify the latitude of the n'th waypoint.\n" |
868 | "\n" |
869 | "--reverse Find a route between the waypoints in reverse order.\n" |
870 | "--loop Find a route that returns to the first waypoint.\n" |
871 | "\n" |
872 | "--heading=<bearing> Initial compass bearing at lowest numbered waypoint.\n" |
873 | "\n" |
874 | " Routing preference options\n" |
875 | "--highway-<highway>=<preference> * preference for highway type (%%).\n" |
876 | "--speed-<highway>=<speed> * speed for highway type (km/h).\n" |
877 | "--property-<property>=<preference> * preference for proprty type (%%).\n" |
878 | "--oneway=(0|1) * oneway restrictions are to be obeyed.\n" |
879 | "--turns=(0|1) * turn restrictions are to be obeyed.\n" |
880 | "--weight=<weight> * maximum weight limit (tonnes).\n" |
881 | "--height=<height> * maximum height limit (metres).\n" |
882 | "--width=<width> * maximum width limit (metres).\n" |
883 | "--length=<length> * maximum length limit (metres).\n" |
884 | "\n" |
885 | "<transport> defaults to motorcar but can be set to:\n" |
886 | "%s" |
887 | "\n" |
888 | "<highway> can be selected from:\n" |
889 | "%s" |
890 | "\n" |
891 | "<property> can be selected from:\n" |
892 | "%s", |
893 | TransportList(),HighwayList(),PropertyList()); |
894 | |
895 | exit(!detail); |
896 | } |
Properties
Name | Value |
---|---|
cvs:description | Router. |