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 317 - (hide annotations) (download) (as text)
Fri Jan 15 19:48:46 2010 UTC (15 years, 2 months ago) by amb
File MIME type: text/x-csrc
File size: 17903 byte(s)
Change the test output formats to add turn, node type and bearing information.

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

Properties

Name Value
cvs:description Router.