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 542 - (show annotations) (download) (as text)
Sat Dec 18 15:19:33 2010 UTC (14 years, 3 months ago) by amb
File MIME type: text/x-csrc
File size: 21232 byte(s)
Add a Relations data type and write out the turn relations that have been read
in.  Still doesn't perform the required processing after reading the data or use
the information for routing.

1 /***************************************
2 $Header: /home/amb/CVS/routino/src/router.c,v 1.93 2010-12-18 15:19:33 amb Exp $
3
4 OSM router.
5
6 Part of the Routino routing software.
7 ******************/ /******************
8 This file Copyright 2008-2010 Andrew M. Bishop
9
10 This program is free software: you can redistribute it and/or modify
11 it under the terms of the GNU Affero General Public License as published by
12 the Free Software Foundation, either version 3 of the License, or
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU Affero General Public License for more details.
19
20 You should have received a copy of the GNU Affero General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 ***************************************/
23
24
25 #include <stdio.h>
26 #include <string.h>
27 #include <stdlib.h>
28 #include <ctype.h>
29
30 #include "types.h"
31 #include "nodes.h"
32 #include "segments.h"
33 #include "ways.h"
34 #include "relations.h"
35
36 #include "files.h"
37 #include "logging.h"
38 #include "functions.h"
39 #include "fakes.h"
40 #include "translations.h"
41 #include "profiles.h"
42
43
44 /*+ The maximum distance from the specified point to search for a node or segment (in km). +*/
45 #define MAXSEARCH 1
46
47
48 /*+ A set of waypoint latitudes and longitudes. +*/
49 static double point_lon[NWAYPOINTS+1],point_lat[NWAYPOINTS+1];
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;
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
66 /*++++++++++++++++++++++++++++++++++++++
67 The main program for the router.
68 ++++++++++++++++++++++++++++++++++++++*/
69
70 int main(int argc,char** argv)
71 {
72 Nodes *OSMNodes;
73 Segments *OSMSegments;
74 Ways *OSMWays;
75 Relations*OSMRelations;
76 Results *results[NWAYPOINTS+1]={NULL};
77 int point_used[NWAYPOINTS+1]={0};
78 int help_profile=0,help_profile_xml=0,help_profile_json=0,help_profile_pl=0;
79 char *dirname=NULL,*prefix=NULL;
80 char *profiles=NULL,*profilename=NULL;
81 char *translations=NULL,*language=NULL;
82 int exactnodes=0;
83 Transport transport=Transport_None;
84 Profile *profile=NULL;
85 index_t start=NO_NODE,finish=NO_NODE;
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 if(profilename)
183 {
184 profile=GetProfile(profilename);
185
186 if(!profile)
187 {
188 fprintf(stderr,"Error: Cannot find a profile called '%s' in '%s'.\n",profilename,profiles);
189 return(1);
190 }
191 }
192 else
193 profile=GetProfile(TransportName(transport));
194
195 if(!profile)
196 {
197 profile=(Profile*)calloc(1,sizeof(Profile));
198 profile->transport=transport;
199 }
200
201 /* Parse the other command line arguments */
202
203 for(arg=1;arg<argc;arg++)
204 {
205 if(!argv[arg])
206 continue;
207 else if(!strcmp(argv[arg],"--shortest"))
208 option_quickest=0;
209 else if(!strcmp(argv[arg],"--quickest"))
210 option_quickest=1;
211 else if(isdigit(argv[arg][0]) ||
212 ((argv[arg][0]=='-' || argv[arg][0]=='+') && isdigit(argv[arg][1])))
213 {
214 for(point=1;point<=NWAYPOINTS;point++)
215 if(point_used[point]!=3)
216 {
217 if(point_used[point]==0)
218 {
219 point_lon[point]=degrees_to_radians(atof(argv[arg]));
220 point_used[point]=1;
221 }
222 else /* if(point_used[point]==1) */
223 {
224 point_lat[point]=degrees_to_radians(atof(argv[arg]));
225 point_used[point]=3;
226 }
227 break;
228 }
229 }
230 else if(!strncmp(argv[arg],"--lon",5) && isdigit(argv[arg][5]))
231 {
232 char *p=&argv[arg][6];
233 while(isdigit(*p)) p++;
234 if(*p++!='=')
235 print_usage(0,argv[arg],NULL);
236
237 point=atoi(&argv[arg][5]);
238 if(point>NWAYPOINTS || point_used[point]&1)
239 print_usage(0,argv[arg],NULL);
240
241 point_lon[point]=degrees_to_radians(atof(p));
242 point_used[point]+=1;
243 }
244 else if(!strncmp(argv[arg],"--lat",5) && isdigit(argv[arg][5]))
245 {
246 char *p=&argv[arg][6];
247 while(isdigit(*p)) p++;
248 if(*p++!='=')
249 print_usage(0,argv[arg],NULL);
250
251 point=atoi(&argv[arg][5]);
252 if(point>NWAYPOINTS || point_used[point]&2)
253 print_usage(0,argv[arg],NULL);
254
255 point_lat[point]=degrees_to_radians(atof(p));
256 point_used[point]+=2;
257 }
258 else if(!strncmp(argv[arg],"--transport=",12))
259 ; /* Done this already */
260 else if(!strncmp(argv[arg],"--highway-",10))
261 {
262 Highway highway;
263 char *equal=strchr(argv[arg],'=');
264 char *string;
265
266 if(!equal)
267 print_usage(0,argv[arg],NULL);
268
269 string=strcpy((char*)malloc(strlen(argv[arg])),argv[arg]+10);
270 string[equal-argv[arg]-10]=0;
271
272 highway=HighwayType(string);
273
274 if(highway==Way_Count)
275 print_usage(0,argv[arg],NULL);
276
277 profile->highway[highway]=atof(equal+1);
278
279 free(string);
280 }
281 else if(!strncmp(argv[arg],"--speed-",8))
282 {
283 Highway highway;
284 char *equal=strchr(argv[arg],'=');
285 char *string;
286
287 if(!equal)
288 print_usage(0,argv[arg],NULL);
289
290 string=strcpy((char*)malloc(strlen(argv[arg])),argv[arg]+8);
291 string[equal-argv[arg]-8]=0;
292
293 highway=HighwayType(string);
294
295 if(highway==Way_Count)
296 print_usage(0,argv[arg],NULL);
297
298 profile->speed[highway]=kph_to_speed(atof(equal+1));
299
300 free(string);
301 }
302 else if(!strncmp(argv[arg],"--property-",11))
303 {
304 Property property;
305 char *equal=strchr(argv[arg],'=');
306 char *string;
307
308 if(!equal)
309 print_usage(0,argv[arg],NULL);
310
311 string=strcpy((char*)malloc(strlen(argv[arg])),argv[arg]+11);
312 string[equal-argv[arg]-11]=0;
313
314 property=PropertyType(string);
315
316 if(property==Way_Count)
317 print_usage(0,argv[arg],NULL);
318
319 profile->props_yes[property]=atof(equal+1);
320
321 free(string);
322 }
323 else if(!strncmp(argv[arg],"--oneway=",9))
324 profile->oneway=!!atoi(&argv[arg][9]);
325 else if(!strncmp(argv[arg],"--weight=",9))
326 profile->weight=tonnes_to_weight(atof(&argv[arg][9]));
327 else if(!strncmp(argv[arg],"--height=",9))
328 profile->height=metres_to_height(atof(&argv[arg][9]));
329 else if(!strncmp(argv[arg],"--width=",8))
330 profile->width=metres_to_width(atof(&argv[arg][8]));
331 else if(!strncmp(argv[arg],"--length=",9))
332 profile->length=metres_to_length(atof(&argv[arg][9]));
333 else
334 print_usage(0,argv[arg],NULL);
335 }
336
337 for(point=1;point<=NWAYPOINTS;point++)
338 if(point_used[point]==1 || point_used[point]==2)
339 print_usage(0,NULL,"All waypoints must have latitude and longitude.");
340
341 if(help_profile)
342 {
343 PrintProfile(profile);
344
345 return(0);
346 }
347 else if(help_profile_xml)
348 {
349 PrintProfilesXML();
350
351 return(0);
352 }
353 else if(help_profile_json)
354 {
355 PrintProfilesJSON();
356
357 return(0);
358 }
359 else if(help_profile_pl)
360 {
361 PrintProfilesPerl();
362
363 return(0);
364 }
365
366 /* Load in the translations */
367
368 if(option_html==0 && option_gpx_track==0 && option_gpx_route==0 && option_text==0 && option_text_all==0 && option_none==0)
369 option_html=option_gpx_track=option_gpx_route=option_text=option_text_all=1;
370
371 if(option_html || option_gpx_route || option_gpx_track)
372 {
373 if(translations)
374 {
375 if(!ExistsFile(translations))
376 {
377 fprintf(stderr,"Error: The '--translations' option specifies a file that does not exist.\n");
378 return(1);
379 }
380 }
381 else
382 {
383 if(ExistsFile(FileName(dirname,prefix,"translations.xml")))
384 translations=FileName(dirname,prefix,"translations.xml");
385 else if(ExistsFile(FileName(DATADIR,NULL,"translations.xml")))
386 translations=FileName(DATADIR,NULL,"translations.xml");
387 else
388 {
389 fprintf(stderr,"Error: The '--translations' option was not used and the default 'translations.xml' does not exist.\n");
390 return(1);
391 }
392 }
393
394 if(ParseXMLTranslations(translations,language))
395 {
396 fprintf(stderr,"Error: Cannot read the translations in the file '%s'.\n",translations);
397 return(1);
398 }
399 }
400
401 /* Load in the data - Note: No error checking because Load*List() will call exit() in case of an error. */
402
403 OSMNodes=LoadNodeList(FileName(dirname,prefix,"nodes.mem"));
404
405 OSMSegments=LoadSegmentList(FileName(dirname,prefix,"segments.mem"));
406
407 OSMWays=LoadWayList(FileName(dirname,prefix,"ways.mem"));
408
409 OSMRelations=LoadRelationList(FileName(dirname,prefix,"relations.mem"));
410
411 if(UpdateProfile(profile,OSMWays))
412 {
413 fprintf(stderr,"Error: Profile is invalid or not compatible with database.\n");
414 return(1);
415 }
416
417 /* Loop through all pairs of points */
418
419 for(point=1;point<=NWAYPOINTS;point++)
420 {
421 Results *begin,*end;
422 distance_t distmax=km_to_distance(MAXSEARCH);
423 distance_t distmin;
424 index_t segment=NO_SEGMENT;
425 index_t node1,node2;
426
427 if(point_used[point]!=3)
428 continue;
429
430 /* Find the closest point */
431
432 start=finish;
433
434 if(exactnodes)
435 {
436 finish=FindClosestNode(OSMNodes,OSMSegments,OSMWays,point_lat[point],point_lon[point],distmax,profile,&distmin);
437 }
438 else
439 {
440 distance_t dist1,dist2;
441
442 segment=FindClosestSegment(OSMNodes,OSMSegments,OSMWays,point_lat[point],point_lon[point],distmax,profile,&distmin,&node1,&node2,&dist1,&dist2);
443
444 if(segment!=NO_SEGMENT)
445 finish=CreateFakes(OSMNodes,point,LookupSegment(OSMSegments,segment,1),node1,node2,dist1,dist2);
446 else
447 finish=NO_NODE;
448 }
449
450 if(finish==NO_NODE)
451 {
452 fprintf(stderr,"Error: Cannot find node close to specified point %d.\n",point);
453 return(1);
454 }
455
456 if(!option_quiet)
457 {
458 double lat,lon;
459
460 if(IsFakeNode(finish))
461 GetFakeLatLong(finish,&lat,&lon);
462 else
463 GetLatLong(OSMNodes,finish,&lat,&lon);
464
465 if(IsFakeNode(finish))
466 printf("Point %d is segment %d (node %d -> %d): %3.6f %4.6f = %2.3f km\n",point,segment,node1,node2,
467 radians_to_degrees(lon),radians_to_degrees(lat),distance_to_km(distmin));
468 else
469 printf("Point %d is node %d: %3.6f %4.6f = %2.3f km\n",point,finish,
470 radians_to_degrees(lon),radians_to_degrees(lat),distance_to_km(distmin));
471 }
472
473 if(start==NO_NODE)
474 continue;
475
476 if(start==finish)
477 continue;
478
479 /* Calculate the beginning of the route */
480
481 begin=FindStartRoutes(OSMNodes,OSMSegments,OSMWays,OSMRelations,start,profile);
482
483 if(!begin)
484 {
485 fprintf(stderr,"Error: Cannot find initial section of route compatible with profile.\n");
486 return(1);
487 }
488
489 if(FindResult(begin,finish))
490 {
491 FixForwardRoute(begin,finish);
492
493 results[point]=begin;
494
495 if(!option_quiet)
496 {
497 printf("Routed: Super-Nodes Checked = %d\n",begin->number);
498 fflush(stdout);
499 }
500 }
501 else
502 {
503 Results *superresults;
504
505 /* Calculate the end of the route */
506
507 end=FindFinishRoutes(OSMNodes,OSMSegments,OSMWays,OSMRelations,finish,profile);
508
509 if(!end)
510 {
511 fprintf(stderr,"Error: Cannot find final section of route compatible with profile.\n");
512 return(1);
513 }
514
515 /* Calculate the middle of the route */
516
517 superresults=FindMiddleRoute(OSMNodes,OSMSegments,OSMWays,OSMRelations,begin,end,profile);
518
519 FreeResultsList(begin);
520 FreeResultsList(end);
521
522 if(!superresults)
523 {
524 fprintf(stderr,"Error: Cannot find route compatible with profile.\n");
525 return(1);
526 }
527
528 results[point]=CombineRoutes(superresults,OSMNodes,OSMSegments,OSMWays,OSMRelations,profile);
529
530 FreeResultsList(superresults);
531 }
532 }
533
534 /* Print out the combined route */
535
536 if(!option_none)
537 PrintRoute(results,NWAYPOINTS,OSMNodes,OSMSegments,OSMWays,profile);
538
539 return(0);
540 }
541
542
543 /*++++++++++++++++++++++++++++++++++++++
544 Print out the usage information.
545
546 int detail The level of detail to use - 0 = low, 1 = high.
547
548 const char *argerr The argument that gave the error (if there is one).
549
550 const char *err Other error message (if there is one).
551 ++++++++++++++++++++++++++++++++++++++*/
552
553 static void print_usage(int detail,const char *argerr,const char *err)
554 {
555 fprintf(stderr,
556 "Usage: router [--help | --help-profile | --help-profile-xml |\n"
557 " --help-profile-json | --help-profile-perl ]\n"
558 " [--dir=<dirname>] [--prefix=<name>]\n"
559 " [--profiles=<filename>] [--translations=<filename>]\n"
560 " [--exact-nodes-only]\n"
561 " [--loggable | --quiet]\n"
562 " [--language=<lang>]\n"
563 " [--output-html]\n"
564 " [--output-gpx-track] [--output-gpx-route]\n"
565 " [--output-text] [--output-text-all]\n"
566 " [--output-none]\n"
567 " [--profile=<name>]\n"
568 " [--transport=<transport>]\n"
569 " [--shortest | --quickest]\n"
570 " --lon1=<longitude> --lat1=<latitude>\n"
571 " --lon2=<longitude> --lon2=<latitude>\n"
572 " [ ... --lon99=<longitude> --lon99=<latitude>]\n"
573 " [--highway-<highway>=<preference> ...]\n"
574 " [--speed-<highway>=<speed> ...]\n"
575 " [--property-<property>=<preference> ...]\n"
576 " [--oneway=(0|1)]\n"
577 " [--weight=<weight>]\n"
578 " [--height=<height>] [--width=<width>] [--length=<length>]\n");
579
580 if(argerr)
581 fprintf(stderr,
582 "\n"
583 "Error with command line parameter: %s\n",argerr);
584
585 if(err)
586 fprintf(stderr,
587 "\n"
588 "Error: %s\n",err);
589
590 if(detail)
591 fprintf(stderr,
592 "\n"
593 "--help Prints this information.\n"
594 "--help-profile Prints the information about the selected profile.\n"
595 "--help-profile-xml Prints all loaded profiles in XML format.\n"
596 "--help-profile-json Prints all loaded profiles in JSON format.\n"
597 "--help-profile-perl Prints all loaded profiles in Perl format.\n"
598 "\n"
599 "--dir=<dirname> The directory containing the routing database.\n"
600 "--prefix=<name> The filename prefix for the routing database.\n"
601 "--profiles=<filename> The name of the XML file containing the profiles\n"
602 " (defaults to 'profiles.xml' with '--dir' and\n"
603 " '--prefix' options or the file installed in\n"
604 " '" DATADIR "').\n"
605 "--translations=<fname> The name of the XML file containing the translations\n"
606 " (defaults to 'translations.xml' with '--dir' and\n"
607 " '--prefix' options or the file installed in\n"
608 " '" DATADIR "').\n"
609 "\n"
610 "--exact-nodes-only Only route between nodes (don't find closest segment).\n"
611 "\n"
612 "--loggable Print progress messages suitable for logging to file.\n"
613 "--quiet Don't print any screen output when running.\n"
614 "\n"
615 "--language=<lang> Use the translations for specified language.\n"
616 "--output-html Write an HTML description of the route.\n"
617 "--output-gpx-track Write a GPX track file with all route points.\n"
618 "--output-gpx-route Write a GPX route file with interesting junctions.\n"
619 "--output-text Write a plain text file with interesting junctions.\n"
620 "--output-text-all Write a plain test file with all route points.\n"
621 "--output-none Don't write any output files or read any translations.\n"
622 " (If no output option is given then all are written.)\n"
623 "\n"
624 "--profile=<name> Select the loaded profile with this name.\n"
625 "--transport=<transport> Select the transport to use (selects the profile\n"
626 " named after the transport if '--profile' is not used.)\n"
627 "\n"
628 "--shortest Find the shortest route between the waypoints.\n"
629 "--quickest Find the quickest route between the waypoints.\n"
630 "\n"
631 "--lon<n>=<longitude> Specify the longitude of the n'th waypoint.\n"
632 "--lat<n>=<latitude> Specify the latitude of the n'th waypoint.\n"
633 "\n"
634 " Routing preference options\n"
635 "--highway-<highway>=<preference> * preference for highway type (%%).\n"
636 "--speed-<highway>=<speed> * speed for highway type (km/h).\n"
637 "--property-<property>=<preference> * preference for proprty type (%%).\n"
638 "--oneway=(0|1) * oneway streets are to be obeyed.\n"
639 "--weight=<weight> * maximum weight limit (tonnes).\n"
640 "--height=<height> * maximum height limit (metres).\n"
641 "--width=<width> * maximum width limit (metres).\n"
642 "--length=<length> * maximum length limit (metres).\n"
643 "\n"
644 "<transport> defaults to motorcar but can be set to:\n"
645 "%s"
646 "\n"
647 "<highway> can be selected from:\n"
648 "%s"
649 "\n"
650 "<property> can be selected from:\n"
651 "%s",
652 TransportList(),HighwayList(),PropertyList());
653
654 exit(!detail);
655 }

Properties

Name Value
cvs:description Router.