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 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)
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. |