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 324 - (show annotations) (download) (as text)
Thu Mar 18 18:59:20 2010 UTC (15 years ago) by amb
File MIME type: text/x-csrc
File size: 18809 byte(s)
Allow selection of which outputs are to be created.

1 /***************************************
2 $Header: /home/amb/CVS/routino/src/router.c,v 1.69 2010-03-18 18:59:20 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 "functions.h"
32 #include "profiles.h"
33 #include "nodes.h"
34 #include "segments.h"
35 #include "ways.h"
36
37
38 /*+ The number of waypoints allowed to be specified. +*/
39 #define NWAYPOINTS 99
40
41 /*+ The maximum distance from the specified point to search for a node or segment (in km). +*/
42 #define MAXSEARCH 1
43
44 /*+ The minimum distance along a segment from a node to insert a fake node. (in km). +*/
45 #define MINSEGMENT 0.005
46
47
48 /*+ A set of fake segments to allow start/finish in the middle of a segment. +*/
49 static Segment fake_segments[2*NWAYPOINTS];
50
51 /*+ A set of fake node latitudes and longitudes. +*/
52 static double point_lon[NWAYPOINTS+1],point_lat[NWAYPOINTS+1];
53
54 /*+ The option not to print any progress information. +*/
55 int option_quiet=0;
56
57 /*+ The options to select the format of the output. +*/
58 int option_html=0,option_gpx_track=0,option_gpx_route=0,option_text=0,option_text_all=0;
59
60 /*+ The option to calculate the quickest route insted of the shortest. +*/
61 int option_quickest=0;
62
63
64 int main(int argc,char** argv)
65 {
66 Nodes *OSMNodes;
67 Segments *OSMSegments;
68 Ways *OSMWays;
69 Results *results[NWAYPOINTS+1]={NULL};
70 int point_used[NWAYPOINTS+1]={0};
71 int help_profile=0,help_profile_js=0,help_profile_pl=0;
72 char *dirname=NULL,*prefix=NULL,*filename;
73 int exactnodes=0;
74 Transport transport=Transport_None;
75 Profile profile;
76 index_t start=NO_NODE,finish=NO_NODE;
77 int arg,point;
78
79 /* Parse the command line arguments */
80
81 if(argc<2)
82 {
83 usage:
84
85 fprintf(stderr,"Usage: router [--help | --help-profile | --help-profile-js | --help-profile-pl]\n"
86 " [--dir=<name>] [--prefix=<name>]\n"
87 " [--exact-nodes-only]\n"
88 " [--quiet]\n"
89 " [--output-html]\n"
90 " [--output-gpx-track | --output-gpx-route]\n"
91 " [--output-text | --output-text-all]\n"
92 " --lon1=<longitude> --lat1=<latitude>\n"
93 " --lon2=<longitude> --lon2=<latitude>\n"
94 " [ ... --lon99=<longitude> --lon99=<latitude>]\n"
95 " [--transport=<transport>]\n"
96 " [--highway-<highway>=<preference> ...]\n"
97 " [--speed-<highway>=<speed> ...]\n"
98 " [--property-<property>=<preference> ...]\n"
99 " [--oneway=[0|1]]\n"
100 " [--weight=<weight>]\n"
101 " [--height=<height>] [--width=<width>] [--length=<length>]\n"
102 " [--shortest | --quickest]\n"
103 "\n"
104 "<transport> defaults to motorcar but can be set to:\n"
105 "%s"
106 "\n"
107 "<highway> can be selected from:\n"
108 "%s"
109 "\n"
110 "<property> can be selected from:\n"
111 "%s"
112 "\n"
113 "<preference> is a preference expressed as a percentage\n"
114 "<speed> is a speed in km/hour\n"
115 "<weight> is a weight in tonnes\n"
116 "<height>, <width>, <length> are dimensions in metres\n"
117 "\n",
118 TransportList(),HighwayList(),PropertyList());
119
120 return(1);
121 }
122
123 /* Get the transport type if specified and fill in the default profile */
124
125 for(arg=1;arg<argc;arg++)
126 if(!strncmp(argv[arg],"--transport=",12))
127 {
128 transport=TransportType(&argv[arg][12]);
129
130 if(transport==Transport_None)
131 goto usage;
132 }
133
134 if(transport==Transport_None)
135 transport=Transport_Motorcar;
136
137 profile=*GetProfile(transport);
138
139 /* Parse the other command line arguments */
140
141 for(arg=1;arg<argc;arg++)
142 {
143 if(!strcmp(argv[arg],"--help"))
144 goto usage;
145 else if(!strcmp(argv[arg],"--help-profile"))
146 help_profile=1;
147 else if(!strcmp(argv[arg],"--help-profile-js"))
148 help_profile_js=1;
149 else if(!strcmp(argv[arg],"--help-profile-pl"))
150 help_profile_pl=1;
151 else if(!strncmp(argv[arg],"--dir=",6))
152 dirname=&argv[arg][6];
153 else if(!strncmp(argv[arg],"--prefix=",9))
154 prefix=&argv[arg][9];
155 else if(!strcmp(argv[arg],"--exact-nodes-only"))
156 exactnodes=1;
157 else if(!strcmp(argv[arg],"--quiet"))
158 option_quiet=1;
159 else if(!strcmp(argv[arg],"--output-html"))
160 option_html=1;
161 else if(!strcmp(argv[arg],"--output-gpx-track"))
162 option_gpx_track=1;
163 else if(!strcmp(argv[arg],"--output-gpx-route"))
164 option_gpx_route=1;
165 else if(!strcmp(argv[arg],"--output-text"))
166 option_text=1;
167 else if(!strcmp(argv[arg],"--output-text-all"))
168 option_text_all=1;
169 else if(isdigit(argv[arg][0]) ||
170 ((argv[arg][0]=='-' || argv[arg][0]=='+') && isdigit(argv[arg][1])))
171 {
172 for(point=1;point<=NWAYPOINTS;point++)
173 if(point_used[point]!=3)
174 {
175 if(point_used[point]==0)
176 {
177 point_lon[point]=degrees_to_radians(atof(argv[arg]));
178 point_used[point]=1;
179 }
180 else /* if(point_used[point]==1) */
181 {
182 point_lat[point]=degrees_to_radians(atof(argv[arg]));
183 point_used[point]=3;
184 }
185 break;
186 }
187 }
188 else if(!strncmp(argv[arg],"--lon",5) && isdigit(argv[arg][5]))
189 {
190 char *p=&argv[arg][6];
191 while(isdigit(*p)) p++;
192 if(*p++!='=')
193 goto usage;
194
195 point=atoi(&argv[arg][5]);
196 if(point>NWAYPOINTS || point_used[point]&1)
197 goto usage;
198
199 point_lon[point]=degrees_to_radians(atof(p));
200 point_used[point]+=1;
201 }
202 else if(!strncmp(argv[arg],"--lat",5) && isdigit(argv[arg][5]))
203 {
204 char *p=&argv[arg][6];
205 while(isdigit(*p)) p++;
206 if(*p++!='=')
207 goto usage;
208
209 point=atoi(&argv[arg][5]);
210 if(point>NWAYPOINTS || point_used[point]&2)
211 goto usage;
212
213 point_lat[point]=degrees_to_radians(atof(p));
214 point_used[point]+=2;
215 }
216 else if(!strncmp(argv[arg],"--transport=",12))
217 ; /* Done this already */
218 else if(!strncmp(argv[arg],"--highway-",10))
219 {
220 Highway highway;
221 char *equal=strchr(argv[arg],'=');
222 char *string;
223
224 if(!equal)
225 goto usage;
226
227 string=strcpy((char*)malloc(strlen(argv[arg])),argv[arg]+10);
228 string[equal-argv[arg]-10]=0;
229
230 highway=HighwayType(string);
231
232 if(highway==Way_Count)
233 goto usage;
234
235 profile.highway[highway]=atof(equal+1);
236
237 free(string);
238 }
239 else if(!strncmp(argv[arg],"--speed-",8))
240 {
241 Highway highway;
242 char *equal=strchr(argv[arg],'=');
243 char *string;
244
245 if(!equal)
246 goto usage;
247
248 string=strcpy((char*)malloc(strlen(argv[arg])),argv[arg]+8);
249 string[equal-argv[arg]-8]=0;
250
251 highway=HighwayType(string);
252
253 if(highway==Way_Count)
254 goto usage;
255
256 profile.speed[highway]=kph_to_speed(atof(equal+1));
257
258 free(string);
259 }
260 else if(!strncmp(argv[arg],"--property-",11))
261 {
262 Property property;
263 char *equal=strchr(argv[arg],'=');
264 char *string;
265
266 if(!equal)
267 goto usage;
268
269 string=strcpy((char*)malloc(strlen(argv[arg])),argv[arg]+11);
270 string[equal-argv[arg]-11]=0;
271
272 property=PropertyType(string);
273
274 if(property==Way_Count)
275 goto usage;
276
277 profile.props_yes[property]=atof(equal+1);
278
279 free(string);
280 }
281 else if(!strncmp(argv[arg],"--oneway=",9))
282 profile.oneway=!!atoi(&argv[arg][9]);
283 else if(!strncmp(argv[arg],"--weight=",9))
284 profile.weight=tonnes_to_weight(atof(&argv[arg][9]));
285 else if(!strncmp(argv[arg],"--height=",9))
286 profile.height=metres_to_height(atof(&argv[arg][9]));
287 else if(!strncmp(argv[arg],"--width=",8))
288 profile.width=metres_to_width(atof(&argv[arg][8]));
289 else if(!strncmp(argv[arg],"--length=",9))
290 profile.length=metres_to_length(atof(&argv[arg][9]));
291 else if(!strcmp(argv[arg],"--shortest"))
292 option_quickest=0;
293 else if(!strcmp(argv[arg],"--quickest"))
294 option_quickest=1;
295 else
296 goto usage;
297 }
298
299 for(point=1;point<=NWAYPOINTS;point++)
300 if(point_used[point]==1 || point_used[point]==2)
301 goto usage;
302
303 if(help_profile)
304 {
305 PrintProfile(&profile);
306
307 return(0);
308 }
309 else if(help_profile_js)
310 {
311 PrintProfilesJS();
312
313 return(0);
314 }
315 else if(help_profile_pl)
316 {
317 PrintProfilesPerl();
318
319 return(0);
320 }
321
322 UpdateProfile(&profile);
323
324 /* Load in the data */
325
326 OSMNodes=LoadNodeList(filename=FileName(dirname,prefix,"nodes.mem"));
327
328 if(!OSMNodes)
329 {
330 fprintf(stderr,"Error: Cannot open nodes file '%s'.\n",filename);
331 return(1);
332 }
333
334 OSMSegments=LoadSegmentList(filename=FileName(dirname,prefix,"segments.mem"));
335
336 if(!OSMSegments)
337 {
338 fprintf(stderr,"Error: Cannot open segments file '%s'.\n",filename);
339 return(1);
340 }
341
342 OSMWays=LoadWayList(filename=FileName(dirname,prefix,"ways.mem"));
343
344 if(!OSMWays)
345 {
346 fprintf(stderr,"Error: Cannot open ways file '%s'.\n",filename);
347 return(1);
348 }
349
350 if(!(profile.allow & OSMWays->allow))
351 {
352 fprintf(stderr,"Error: Database was not generated for selected transport.\n");
353 return(1);
354 }
355
356 if(option_html==0 && option_gpx_track==0 && option_gpx_route==0 && option_text==0 && option_text_all==0)
357 option_html=option_gpx_track=option_gpx_route=option_text=option_text_all=1;
358
359 /* Loop through all pairs of points */
360
361 for(point=1;point<=NWAYPOINTS;point++)
362 {
363 Results *begin,*end;
364 distance_t distmax=km_to_distance(MAXSEARCH);
365 distance_t distmin;
366 Segment *segment=NULL;
367 index_t node1,node2;
368
369 if(point_used[point]!=3)
370 continue;
371
372 /* Find the closest point */
373
374 start=finish;
375
376 if(exactnodes)
377 {
378 finish=FindClosestNode(OSMNodes,OSMSegments,OSMWays,point_lat[point],point_lon[point],distmax,&profile,&distmin);
379 }
380 else
381 {
382 distance_t dist1,dist2;
383
384 segment=FindClosestSegment(OSMNodes,OSMSegments,OSMWays,point_lat[point],point_lon[point],distmax,&profile,&distmin,&node1,&node2,&dist1,&dist2);
385
386 finish=CreateFakes(OSMNodes,point,segment,node1,node2,dist1,dist2);
387 }
388
389 if(finish==NO_NODE)
390 {
391 fprintf(stderr,"Error: Cannot find node close to specified point %d.\n",point);
392 return(1);
393 }
394
395 if(!option_quiet)
396 {
397 double lat,lon;
398
399 if(IsFakeNode(finish))
400 GetFakeLatLong(finish,&lat,&lon);
401 else
402 GetLatLong(OSMNodes,finish,&lat,&lon);
403
404 if(IsFakeNode(finish))
405 printf("Point %d is segment %d (node %d -> %d): %3.6f %4.6f = %2.3f km\n",point,IndexSegment(OSMSegments,segment),node1,node2,
406 radians_to_degrees(lon),radians_to_degrees(lat),distance_to_km(distmin));
407 else
408 printf("Point %d is node %d: %3.6f %4.6f = %2.3f km\n",point,finish,
409 radians_to_degrees(lon),radians_to_degrees(lat),distance_to_km(distmin));
410 }
411
412 if(start==NO_NODE)
413 continue;
414
415 /* Calculate the beginning of the route */
416
417 if(!IsFakeNode(start) && IsSuperNode(OSMNodes,start))
418 {
419 Result *result;
420
421 begin=NewResultsList(1);
422
423 begin->start=start;
424
425 result=InsertResult(begin,start);
426
427 ZeroResult(result);
428 }
429 else
430 {
431 begin=FindStartRoutes(OSMNodes,OSMSegments,OSMWays,start,&profile);
432
433 if(!begin)
434 {
435 fprintf(stderr,"Error: Cannot find initial section of route compatible with profile.\n");
436 return(1);
437 }
438 }
439
440 if(FindResult(begin,finish))
441 {
442 FixForwardRoute(begin,finish);
443
444 results[point]=begin;
445
446 if(!option_quiet)
447 {
448 printf("\rRouted: Super-Nodes Checked = %d\n",begin->number);
449 fflush(stdout);
450 }
451 }
452 else
453 {
454 Results *superresults;
455
456 /* Calculate the end of the route */
457
458 if(!IsFakeNode(finish) && IsSuperNode(OSMNodes,finish))
459 {
460 Result *result;
461
462 end=NewResultsList(1);
463
464 end->finish=finish;
465
466 result=InsertResult(end,finish);
467
468 ZeroResult(result);
469 }
470 else
471 {
472 end=FindFinishRoutes(OSMNodes,OSMSegments,OSMWays,finish,&profile);
473
474 if(!end)
475 {
476 fprintf(stderr,"Error: Cannot find final section of route compatible with profile.\n");
477 return(1);
478 }
479 }
480
481 /* Calculate the middle of the route */
482
483 superresults=FindMiddleRoute(OSMNodes,OSMSegments,OSMWays,begin,end,&profile);
484
485 FreeResultsList(begin);
486 FreeResultsList(end);
487
488 if(!superresults)
489 {
490 fprintf(stderr,"Error: Cannot find route compatible with profile.\n");
491 return(1);
492 }
493
494 results[point]=CombineRoutes(superresults,OSMNodes,OSMSegments,OSMWays,&profile);
495
496 FreeResultsList(superresults);
497 }
498 }
499
500 /* Print out the combined route */
501
502 PrintRouteHead(FileName(dirname,prefix,"copyright.txt"));
503
504 PrintRoute(results,NWAYPOINTS,OSMNodes,OSMSegments,OSMWays,&profile);
505
506 PrintRouteTail();
507
508 return(0);
509 }
510
511
512 /*++++++++++++++++++++++++++++++++++++++
513 Create a pair of fake segments corresponding to the given segment split in two.
514
515 index_t CreateFakes Returns the fake node index (or a real one in special cases).
516
517 Nodes *nodes The set of nodes to use.
518
519 int point Which of the waypoints is this.
520
521 Segment *segment The segment to split.
522
523 index_t node1 The first node at the end of this segment.
524
525 index_t node2 The second node at the end of this segment.
526
527 distance_t dist1 The distance to the first node.
528
529 distance_t dist2 The distance to the second node.
530 ++++++++++++++++++++++++++++++++++++++*/
531
532 index_t CreateFakes(Nodes *nodes,int point,Segment *segment,index_t node1,index_t node2,distance_t dist1,distance_t dist2)
533 {
534 index_t fakenode;
535 double lat1,lon1,lat2,lon2;
536
537 /* Check if we are actually close enough to an existing node */
538
539 if(dist1<km_to_distance(MINSEGMENT) && dist2>km_to_distance(MINSEGMENT))
540 return(node1);
541
542 if(dist2<km_to_distance(MINSEGMENT) && dist1>km_to_distance(MINSEGMENT))
543 return(node2);
544
545 if(dist1<km_to_distance(MINSEGMENT) && dist2<km_to_distance(MINSEGMENT))
546 {
547 if(dist1<dist2)
548 return(node1);
549 else
550 return(node2);
551 }
552
553 /* Create the fake node */
554
555 fakenode=point|NODE_SUPER;
556
557 GetLatLong(nodes,node1,&lat1,&lon1);
558 GetLatLong(nodes,node2,&lat2,&lon2);
559
560 if(lat1>3 && lat2<-3)
561 lat2+=2*M_PI;
562 else if(lat1<-3 && lat2>3)
563 lat1+=2*M_PI;
564
565 point_lat[point]=lat1+(lat2-lat1)*(double)dist1/(double)(dist1+dist2);
566 point_lon[point]=lon1+(lon2-lon1)*(double)dist1/(double)(dist1+dist2);
567
568 if(point_lat[point]>M_PI) point_lat[point]-=2*M_PI;
569
570 /* Create the first fake segment */
571
572 fake_segments[2*point-2]=*segment;
573
574 if(segment->node1==node1)
575 fake_segments[2*point-2].node1=fakenode;
576 else
577 fake_segments[2*point-2].node2=fakenode;
578
579 fake_segments[2*point-2].distance=DISTANCE(dist1)|DISTFLAG(segment->distance);
580
581 /* Create the second fake segment */
582
583 fake_segments[2*point-1]=*segment;
584
585 if(segment->node1==node2)
586 fake_segments[2*point-1].node1=fakenode;
587 else
588 fake_segments[2*point-1].node2=fakenode;
589
590 fake_segments[2*point-1].distance=DISTANCE(dist2)|DISTFLAG(segment->distance);
591
592 return(fakenode);
593 }
594
595
596 /*++++++++++++++++++++++++++++++++++++++
597 Lookup the latitude and longitude of a fake node.
598
599 index_t fakenode The node to lookup.
600
601 double *latitude Returns the latitude
602
603 double *longitude Returns the longitude.
604 ++++++++++++++++++++++++++++++++++++++*/
605
606 void GetFakeLatLong(index_t fakenode, double *latitude,double *longitude)
607 {
608 index_t realnode=fakenode&(~NODE_SUPER);
609
610 *latitude =point_lat[realnode];
611 *longitude=point_lon[realnode];
612 }
613
614
615 /*++++++++++++++++++++++++++++++++++++++
616 Finds the first fake segment associated to a fake node.
617
618 Segment *FirstFakeSegment Returns the first fake segment.
619
620 index_t fakenode The node to lookup.
621 ++++++++++++++++++++++++++++++++++++++*/
622
623 Segment *FirstFakeSegment(index_t fakenode)
624 {
625 index_t realnode=fakenode&(~NODE_SUPER);
626
627 return(&fake_segments[2*realnode-2]);
628 }
629
630
631 /*++++++++++++++++++++++++++++++++++++++
632 Finds the next (there can only be two) fake segment associated to a fake node.
633
634 Segment *NextFakeSegment Returns the second fake segment.
635
636 Segment *segment The first fake segment.
637
638 index_t fakenode The node to lookup.
639 ++++++++++++++++++++++++++++++++++++++*/
640
641 Segment *NextFakeSegment(Segment *segment,index_t fakenode)
642 {
643 index_t realnode=fakenode&(~NODE_SUPER);
644
645 if(segment==&fake_segments[2*realnode-2])
646 return(&fake_segments[2*realnode-1]);
647 else
648 return(NULL);
649 }
650
651
652 /*++++++++++++++++++++++++++++++++++++++
653 Finds the next (there can only be two) fake segment associated to a fake node.
654
655 Segment *ExtraFakeSegment Returns a segment between the two specified nodes if it exists.
656
657 index_t node The real node.
658
659 index_t fakenode The fake node to lookup.
660 ++++++++++++++++++++++++++++++++++++++*/
661
662 Segment *ExtraFakeSegment(index_t node,index_t fakenode)
663 {
664 index_t realnode=fakenode&(~NODE_SUPER);
665
666 if(fake_segments[2*realnode-2].node1==node || fake_segments[2*realnode-2].node2==node)
667 return(&fake_segments[2*realnode-2]);
668
669 if(fake_segments[2*realnode-1].node1==node || fake_segments[2*realnode-1].node2==node)
670 return(&fake_segments[2*realnode-1]);
671
672 return(NULL);
673 }

Properties

Name Value
cvs:description Router.