Routino SVN Repository Browser

Check out the latest version of Routino: svn co http://routino.org/svn/trunk routino

ViewVC logotype

Annotation of /trunk/src/router.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 305 - (hide annotations) (download) (as text)
Thu Nov 19 18:53:23 2009 UTC (15 years, 4 months ago) by amb
File MIME type: text/x-csrc
File size: 17468 byte(s)
Made the verbose output consistent between different places.

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

Properties

Name Value
cvs:description Router.