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/optimiser.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 735 - (hide annotations) (download) (as text)
Mon May 30 12:25:55 2011 UTC (13 years, 10 months ago) by amb
File MIME type: text/x-csrc
File size: 36868 byte(s)
Fix problem with test case loops WP11.

1 amb 2 /***************************************
2     Routing optimiser.
3 amb 151
4     Part of the Routino routing software.
5 amb 2 ******************/ /******************
6 amb 594 This file Copyright 2008-2011 Andrew M. Bishop
7 amb 2
8 amb 151 This program is free software: you can redistribute it and/or modify
9     it under the terms of the GNU Affero General Public License as published by
10     the Free Software Foundation, either version 3 of the License, or
11     (at your option) any later version.
12    
13     This program is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16     GNU Affero General Public License for more details.
17    
18     You should have received a copy of the GNU Affero General Public License
19     along with this program. If not, see <http://www.gnu.org/licenses/>.
20 amb 2 ***************************************/
21    
22    
23 amb 109 #include <stdio.h>
24 amb 712 #include <assert.h>
25 amb 2
26 amb 96 #include "types.h"
27 amb 109 #include "nodes.h"
28     #include "segments.h"
29     #include "ways.h"
30 amb 596 #include "relations.h"
31 amb 449
32 amb 519 #include "logging.h"
33 amb 449 #include "functions.h"
34 amb 532 #include "fakes.h"
35 amb 28 #include "results.h"
36 amb 2
37 amb 26
38 amb 685 /* Global variables */
39    
40 amb 113 /*+ The option not to print any progress information. +*/
41 amb 107 extern int option_quiet;
42 amb 2
43 amb 113 /*+ The option to calculate the quickest route insted of the shortest. +*/
44     extern int option_quickest;
45 amb 31
46 amb 113
47 amb 685 /* Local functions */
48    
49 amb 721 static index_t FindSuperSegment(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile,index_t endnode,index_t endsegment);
50 amb 685
51    
52 amb 2 /*++++++++++++++++++++++++++++++++++++++
53 amb 727 Find the optimum route between two nodes not passing through a super-node.
54 amb 2
55 amb 238 Results *FindNormalRoute Returns a set of results.
56 amb 26
57     Nodes *nodes The set of nodes to use.
58    
59     Segments *segments The set of segments to use.
60    
61 amb 54 Ways *ways The set of ways to use.
62    
63 amb 542 Relations *relations The set of relations to use.
64    
65 amb 721 Profile *profile The profile containing the transport type, speeds and allowed highways.
66    
67 amb 605 index_t start_node The start node.
68 amb 2
69 amb 605 index_t prev_segment The previous segment before the start node.
70 amb 54
71 amb 605 index_t finish_node The finish node.
72 amb 2 ++++++++++++++++++++++++++++++++++++++*/
73    
74 amb 723 Results *FindNormalRoute(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile,index_t start_node,index_t prev_segment,index_t finish_node)
75 amb 2 {
76 amb 31 Results *results;
77 amb 469 Queue *queue;
78 amb 166 score_t finish_score;
79 amb 219 double finish_lat,finish_lon;
80 amb 605 Result *finish_result;
81 amb 469 Result *result1,*result2;
82 amb 2
83 amb 10 /* Set up the finish conditions */
84    
85 amb 176 finish_score=INF_SCORE;
86 amb 605 finish_result=NULL;
87 amb 10
88 amb 605 if(IsFakeNode(finish_node))
89     GetFakeLatLong(finish_node,&finish_lat,&finish_lon);
90 amb 303 else
91 amb 605 GetLatLong(nodes,finish_node,&finish_lat,&finish_lon);
92 amb 119
93 amb 165 /* Create the list of results and insert the first node into the queue */
94 amb 2
95 amb 238 results=NewResultsList(8);
96 amb 2
97 amb 605 results->start_node=start_node;
98 amb 617 results->prev_segment=prev_segment;
99 amb 165
100 amb 735 result1=InsertResult(results,results->start_node,results->prev_segment);
101 amb 28
102 amb 236 queue=NewQueueList();
103 amb 2
104 amb 236 InsertInQueue(queue,result1);
105    
106 amb 2 /* Loop across all nodes in the queue */
107    
108 amb 236 while((result1=PopFromQueue(queue)))
109 amb 2 {
110 amb 594 Segment *segment;
111 amb 637 index_t node1,seg1,seg1r;
112 amb 608 index_t turnrelation=NO_RELATION;
113 amb 594
114 amb 680 /* score must be better than current best score */
115 amb 238 if(result1->score>finish_score)
116 amb 119 continue;
117    
118 amb 43 node1=result1->node;
119 amb 605 seg1=result1->segment;
120 amb 2
121 amb 637 if(IsFakeSegment(seg1))
122     seg1r=IndexRealSegment(seg1);
123     else
124     seg1r=seg1;
125    
126 amb 680 /* lookup if a turn restriction applies */
127 amb 700 if(profile->turns && !IsFakeNode(node1) && IsTurnRestrictedNode(LookupNode(nodes,node1,1)))
128 amb 637 turnrelation=FindFirstTurnRelation2(relations,node1,seg1r);
129 amb 596
130 amb 680 /* Loop across all segments */
131    
132 amb 303 if(IsFakeNode(node1))
133     segment=FirstFakeSegment(node1);
134     else
135 amb 707 segment=FirstSegment(segments,nodes,node1,1);
136 amb 2
137     while(segment)
138     {
139 amb 594 Way *way;
140 amb 637 index_t node2,seg2,seg2r;
141 amb 298 score_t segment_pref,segment_score,cumulative_score;
142     int i;
143 amb 59
144 amb 680 node2=OtherNode(segment,node1); /* need this here because we use node2 at the end of the loop */
145 amb 303
146 amb 680 /* must be a normal segment */
147 amb 95 if(!IsNormalSegment(segment))
148 amb 90 goto endloop;
149    
150 amb 680 /* must obey one-way restrictions (unless profile allows) */
151 amb 105 if(profile->oneway && IsOnewayTo(segment,node1))
152 amb 64 goto endloop;
153    
154 amb 605 if(IsFakeNode(node1) || IsFakeNode(node2))
155 amb 637 {
156     seg2 =IndexFakeSegment(segment);
157     seg2r=IndexRealSegment(seg2);
158     }
159 amb 605 else
160 amb 637 {
161     seg2 =IndexSegment(segments,segment);
162     seg2r=seg2;
163     }
164 amb 603
165 amb 699 /* must not perform U-turn (unless profile allows) */
166 amb 727 if(profile->turns && (seg1==seg2 || seg1==seg2r || seg1r==seg2 || (seg1r==seg2r && IsFakeUTurn(seg1,seg2))))
167 amb 636 goto endloop;
168    
169 amb 680 /* must obey turn relations */
170 amb 637 if(turnrelation!=NO_RELATION && !IsTurnAllowed(relations,turnrelation,node1,seg1r,seg2r,profile->allow))
171 amb 608 goto endloop;
172 amb 596
173 amb 723 /* must not pass over super-node */
174     if(node2!=finish_node && !IsFakeNode(node2) && IsSuperNode(LookupNode(nodes,node2,2)))
175 amb 238 goto endloop;
176    
177 amb 460 way=LookupWay(ways,segment->way,1);
178 amb 54
179 amb 680 /* mode of transport must be allowed on the highway */
180 amb 82 if(!(way->allow&profile->allow))
181 amb 54 goto endloop;
182    
183 amb 680 /* must obey weight restriction (if exists) */
184 amb 197 if(way->weight && way->weight<profile->weight)
185 amb 135 goto endloop;
186    
187 amb 680 /* must obey height/width/length restriction (if exists) */
188 amb 197 if((way->height && way->height<profile->height) ||
189     (way->width && way->width <profile->width ) ||
190     (way->length && way->length<profile->length))
191 amb 135 goto endloop;
192    
193 amb 298 segment_pref=profile->highway[HIGHWAY(way->type)];
194    
195     for(i=1;i<Property_Count;i++)
196 amb 460 if(ways->file.props & PROPERTIES(i))
197 amb 307 {
198 amb 406 if(way->props & PROPERTIES(i))
199 amb 307 segment_pref*=profile->props_yes[i];
200     else
201     segment_pref*=profile->props_no[i];
202     }
203 amb 298
204 amb 680 /* profile preferences must allow this highway */
205 amb 298 if(segment_pref==0)
206     goto endloop;
207    
208 amb 680 /* mode of transport must be allowed through node2 */
209 amb 471 if(!IsFakeNode(node2))
210     {
211 amb 595 Node *node=LookupNode(nodes,node2,2);
212 amb 469
213 amb 471 if(!(node->allow&profile->allow))
214     goto endloop;
215     }
216 amb 469
217 amb 166 if(option_quickest==0)
218 amb 298 segment_score=(score_t)DISTANCE(segment->distance)/segment_pref;
219 amb 166 else
220 amb 298 segment_score=(score_t)Duration(segment,way,profile)/segment_pref;
221 amb 59
222 amb 170 cumulative_score=result1->score+segment_score;
223 amb 166
224 amb 680 /* score must be better than current best score */
225 amb 166 if(cumulative_score>finish_score)
226 amb 2 goto endloop;
227    
228 amb 605 result2=FindResult(results,node2,seg2);
229 amb 42
230 amb 680 if(!result2) /* New end node/segment combination */
231 amb 2 {
232 amb 605 result2=InsertResult(results,node2,seg2);
233     result2->prev=result1;
234 amb 170 result2->score=cumulative_score;
235 amb 2
236 amb 605 if(node2==finish_node)
237 amb 2 {
238 amb 605 if(cumulative_score<finish_score)
239     {
240     finish_score=cumulative_score;
241     finish_result=result2;
242     }
243 amb 2 }
244     else
245 amb 119 {
246 amb 238 result2->sortby=result2->score;
247 amb 166
248 amb 236 InsertInQueue(queue,result2);
249 amb 119 }
250 amb 2 }
251 amb 605 else if(cumulative_score<result2->score) /* New score for end node/segment combination is better */
252 amb 2 {
253 amb 605 result2->prev=result1;
254 amb 170 result2->score=cumulative_score;
255 amb 605 result2->segment=seg2;
256 amb 166
257 amb 605 if(node2==finish_node)
258 amb 2 {
259 amb 605 if(cumulative_score<finish_score)
260     {
261     finish_score=cumulative_score;
262     finish_result=result2;
263     }
264 amb 2 }
265 amb 166 else
266     {
267 amb 238 result2->sortby=result2->score;
268 amb 2
269 amb 238 if(result2->score<finish_score)
270 amb 236 InsertInQueue(queue,result2);
271 amb 2 }
272     }
273    
274     endloop:
275    
276 amb 303 if(IsFakeNode(node1))
277     segment=NextFakeSegment(segment,node1);
278     else if(IsFakeNode(node2))
279     segment=NULL; /* cannot call NextSegment() with a fake segment */
280     else
281     {
282     segment=NextSegment(segments,segment,node1);
283    
284 amb 605 if(!segment && IsFakeNode(finish_node))
285     segment=ExtraFakeSegment(node1,finish_node);
286 amb 303 }
287 amb 2 }
288     }
289    
290 amb 236 FreeQueueList(queue);
291    
292 amb 77 /* Check it worked */
293    
294 amb 605 if(!finish_result)
295 amb 77 {
296     FreeResultsList(results);
297     return(NULL);
298     }
299    
300 amb 605 FixForwardRoute(results,finish_result);
301 amb 31
302     return(results);
303 amb 2 }
304    
305    
306     /*++++++++++++++++++++++++++++++++++++++
307 amb 680 Find the optimum route between two nodes where the start and end are a set of pre/post-routed super-nodes.
308 amb 34
309 amb 238 Results *FindMiddleRoute Returns a set of results.
310 amb 34
311 amb 95 Nodes *nodes The set of nodes to use.
312 amb 34
313 amb 95 Segments *segments The set of segments to use.
314 amb 34
315 amb 95 Ways *ways The set of ways to use.
316 amb 54
317 amb 542 Relations *relations The set of relations to use.
318    
319 amb 721 Profile *profile The profile containing the transport type, speeds and allowed highways.
320    
321 amb 34 Results *begin The initial portion of the route.
322    
323     Results *end The final portion of the route.
324     ++++++++++++++++++++++++++++++++++++++*/
325    
326 amb 721 Results *FindMiddleRoute(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile,Results *begin,Results *end)
327 amb 34 {
328     Results *results;
329 amb 469 Queue *queue;
330 amb 605 Result *finish_result;
331 amb 166 score_t finish_score;
332 amb 219 double finish_lat,finish_lon;
333 amb 632 Result *result1,*result2,*result3,*result4;
334 amb 34
335 amb 227 if(!option_quiet)
336 amb 519 printf_first("Routing: Super-Nodes checked = 0");
337 amb 227
338 amb 34 /* Set up the finish conditions */
339    
340 amb 302 finish_score=INF_DISTANCE;
341 amb 605 finish_result=NULL;
342 amb 34
343 amb 605 if(IsFakeNode(end->finish_node))
344     GetFakeLatLong(end->finish_node,&finish_lat,&finish_lon);
345 amb 303 else
346 amb 605 GetLatLong(nodes,end->finish_node,&finish_lat,&finish_lon);
347 amb 119
348 amb 165 /* Create the list of results and insert the first node into the queue */
349 amb 34
350 amb 441 results=NewResultsList(2048);
351 amb 34
352 amb 605 results->start_node=begin->start_node;
353     results->prev_segment=begin->prev_segment;
354 amb 34
355 amb 688 if(begin->number==1)
356     {
357 amb 721 index_t superseg=FindSuperSegment(nodes,segments,ways,relations,profile,begin->start_node,begin->prev_segment);
358 amb 34
359 amb 688 results->prev_segment=superseg;
360     }
361    
362     result1=InsertResult(results,results->start_node,results->prev_segment);
363    
364 amb 236 queue=NewQueueList();
365    
366 amb 685 /* Insert the finish points of the beginning part of the path into the queue,
367     translating the segments into super-segments. */
368 amb 34
369 amb 79 result3=FirstResult(begin);
370    
371     while(result3)
372     {
373 amb 735 if((results->start_node!=result3->node || results->prev_segment!=result3->segment) &&
374 amb 722 !IsFakeNode(result3->node) && IsSuperNode(LookupNode(nodes,result3->node,1)))
375 amb 45 {
376 amb 722 Result *result5=result1;
377 amb 721 index_t superseg=FindSuperSegment(nodes,segments,ways,relations,profile,result3->node,result3->segment);
378 amb 34
379 amb 722 if(superseg!=result3->segment)
380     {
381     result5=InsertResult(results,result3->node,result3->segment);
382    
383     result5->prev=result1;
384     }
385    
386 amb 703 if(!FindResult(results,result3->node,superseg))
387     {
388     result2=InsertResult(results,result3->node,superseg);
389 amb 722 result2->prev=result5;
390 amb 685
391 amb 703 result2->score=result3->score;
392     result2->sortby=result3->score;
393 amb 119
394 amb 703 InsertInQueue(queue,result2);
395 amb 632
396 amb 703 if((result4=FindResult(end,result2->node,result2->segment)))
397 amb 632 {
398 amb 703 if((result2->score+result4->score)<finish_score)
399     {
400     finish_score=result2->score+result4->score;
401     finish_result=result2;
402     }
403 amb 632 }
404     }
405 amb 45 }
406 amb 34
407 amb 79 result3=NextResult(begin,result3);
408     }
409    
410 amb 238 if(begin->number==1)
411     InsertInQueue(queue,result1);
412    
413 amb 95 /* Loop across all nodes in the queue */
414 amb 34
415 amb 236 while((result1=PopFromQueue(queue)))
416 amb 34 {
417 amb 605 index_t node1,seg1;
418 amb 594 Segment *segment;
419 amb 596 index_t turnrelation=NO_RELATION;
420 amb 594
421 amb 680 /* score must be better than current best score */
422 amb 238 if(result1->score>finish_score)
423 amb 119 continue;
424    
425 amb 43 node1=result1->node;
426 amb 605 seg1=result1->segment;
427 amb 34
428 amb 680 /* lookup if a turn restriction applies */
429 amb 700 if(profile->turns && IsTurnRestrictedNode(LookupNode(nodes,node1,1))) /* node1 cannot be a fake node (must be a super-node) */
430 amb 605 turnrelation=FindFirstTurnRelation2(relations,node1,seg1);
431 amb 596
432 amb 680 /* Loop across all segments */
433 amb 34
434 amb 707 segment=FirstSegment(segments,nodes,node1,1); /* node1 cannot be a fake node (must be a super-node) */
435 amb 680
436 amb 34 while(segment)
437     {
438 amb 610 Way *way;
439     Node *node;
440 amb 603 index_t node2,seg2;
441 amb 298 score_t segment_pref,segment_score,cumulative_score;
442     int i;
443 amb 59
444 amb 680 /* must be a super segment */
445 amb 95 if(!IsSuperSegment(segment))
446     goto endloop;
447    
448 amb 680 /* must obey one-way restrictions (unless profile allows) */
449 amb 105 if(profile->oneway && IsOnewayTo(segment,node1))
450 amb 64 goto endloop;
451    
452 amb 105 node2=OtherNode(segment,node1);
453 amb 34
454 amb 680 seg2=IndexSegment(segments,segment); /* node2 cannot be a fake node (must be a super-node) */
455 amb 603
456 amb 699 /* must not perform U-turn */
457 amb 680 if(seg1==seg2) /* No fake segments, applies to all profiles */
458 amb 636 goto endloop;
459    
460 amb 680 /* must obey turn relations */
461 amb 605 if(turnrelation!=NO_RELATION && !IsTurnAllowed(relations,turnrelation,node1,seg1,seg2,profile->allow))
462 amb 596 goto endloop;
463    
464 amb 460 way=LookupWay(ways,segment->way,1);
465 amb 54
466 amb 680 /* transport must be allowed on the highway */
467 amb 82 if(!(way->allow&profile->allow))
468 amb 54 goto endloop;
469    
470 amb 680 /* must obey weight restriction (if exists) */
471 amb 197 if(way->weight && way->weight<profile->weight)
472 amb 135 goto endloop;
473    
474 amb 680 /* must obey height/width/length restriction (if exists) */
475 amb 197 if((way->height && way->height<profile->height) ||
476     (way->width && way->width <profile->width ) ||
477     (way->length && way->length<profile->length))
478 amb 135 goto endloop;
479    
480 amb 298 segment_pref=profile->highway[HIGHWAY(way->type)];
481    
482     for(i=1;i<Property_Count;i++)
483 amb 460 if(ways->file.props & PROPERTIES(i))
484 amb 307 {
485 amb 406 if(way->props & PROPERTIES(i))
486 amb 307 segment_pref*=profile->props_yes[i];
487     else
488     segment_pref*=profile->props_no[i];
489     }
490 amb 298
491 amb 680 /* profile preferences must allow this highway */
492 amb 298 if(segment_pref==0)
493     goto endloop;
494    
495 amb 680 node=LookupNode(nodes,node2,2); /* node2 cannot be a fake node (must be a super-node) */
496 amb 469
497 amb 680 /* mode of transport must be allowed through node2 */
498 amb 470 if(!(node->allow&profile->allow))
499 amb 469 goto endloop;
500    
501 amb 166 if(option_quickest==0)
502 amb 298 segment_score=(score_t)DISTANCE(segment->distance)/segment_pref;
503 amb 166 else
504 amb 298 segment_score=(score_t)Duration(segment,way,profile)/segment_pref;
505 amb 34
506 amb 170 cumulative_score=result1->score+segment_score;
507 amb 166
508 amb 680 /* score must be better than current best score */
509 amb 166 if(cumulative_score>finish_score)
510 amb 34 goto endloop;
511    
512 amb 605 result2=FindResult(results,node2,seg2);
513 amb 42
514 amb 680 if(!result2) /* New end node/segment pair */
515 amb 34 {
516 amb 605 result2=InsertResult(results,node2,seg2);
517     result2->prev=result1;
518 amb 170 result2->score=cumulative_score;
519 amb 34
520 amb 605 if((result3=FindResult(end,node2,seg2)))
521 amb 113 {
522 amb 442 if((result2->score+result3->score)<finish_score)
523     {
524     finish_score=result2->score+result3->score;
525 amb 605 finish_result=result2;
526 amb 442 }
527 amb 113 }
528     else
529 amb 119 {
530 amb 219 double lat,lon;
531 amb 166 distance_t direct;
532    
533 amb 680 GetLatLong(nodes,node2,&lat,&lon); /* node2 cannot be a fake node (must be a super-node) */
534    
535 amb 166 direct=Distance(lat,lon,finish_lat,finish_lon);
536 amb 119
537     if(option_quickest==0)
538 amb 173 result2->sortby=result2->score+(score_t)direct/profile->max_pref;
539 amb 119 else
540 amb 173 result2->sortby=result2->score+(score_t)distance_speed_to_duration(direct,profile->max_speed)/profile->max_pref;
541 amb 119
542 amb 236 InsertInQueue(queue,result2);
543 amb 119 }
544 amb 34 }
545 amb 605 else if(cumulative_score<result2->score) /* New end node/segment pair is better */
546 amb 34 {
547 amb 605 result2->prev=result1;
548 amb 170 result2->score=cumulative_score;
549 amb 166
550 amb 605 if((result3=FindResult(end,node2,seg2)))
551 amb 34 {
552 amb 166 if((result2->score+result3->score)<finish_score)
553 amb 113 {
554 amb 166 finish_score=result2->score+result3->score;
555 amb 605 finish_result=result2;
556 amb 113 }
557 amb 34 }
558 amb 238 else if(result2->score<finish_score)
559 amb 34 {
560 amb 219 double lat,lon;
561 amb 166 distance_t direct;
562 amb 34
563 amb 680 GetLatLong(nodes,node2,&lat,&lon); /* node2 cannot be a fake node (must be a super-node) */
564    
565 amb 166 direct=Distance(lat,lon,finish_lat,finish_lon);
566    
567     if(option_quickest==0)
568 amb 173 result2->sortby=result2->score+(score_t)direct/profile->max_pref;
569 amb 113 else
570 amb 173 result2->sortby=result2->score+(score_t)distance_speed_to_duration(direct,profile->max_speed)/profile->max_pref;
571 amb 119
572 amb 238 InsertInQueue(queue,result2);
573 amb 34 }
574     }
575    
576 amb 107 if(!option_quiet && !(results->number%10000))
577 amb 519 printf_middle("Routing: Super-Nodes checked = %d",results->number);
578 amb 34
579 amb 627 endloop:
580    
581 amb 680 segment=NextSegment(segments,segment,node1); /* node1 cannot be a fake node (must be a super-node) */
582 amb 34 }
583     }
584    
585 amb 107 if(!option_quiet)
586 amb 519 printf_last("Routing: Super-Nodes checked = %d",results->number);
587 amb 34
588 amb 236 FreeQueueList(queue);
589    
590 amb 77 /* Check it worked */
591    
592 amb 605 if(!finish_result)
593 amb 77 {
594     FreeResultsList(results);
595     return(NULL);
596     }
597    
598 amb 680 /* Finish off the end part of the route */
599 amb 34
600 amb 616 if(finish_result->node!=end->finish_node)
601     {
602     result3=InsertResult(results,end->finish_node,NO_SEGMENT);
603 amb 605
604 amb 616 result3->prev=finish_result;
605     result3->score=finish_score;
606 amb 605
607 amb 616 finish_result=result3;
608     }
609 amb 605
610 amb 616 FixForwardRoute(results,finish_result);
611    
612 amb 34 return(results);
613     }
614    
615    
616     /*++++++++++++++++++++++++++++++++++++++
617 amb 685 Find the super-segment that represents the route that contains a particular segment.
618    
619     index_t FindSuperSegment Returns the index of the super-segment.
620    
621     Nodes *nodes The set of nodes to use.
622    
623     Segments *segments The set of segments to use.
624    
625     Ways *ways The set of ways to use.
626    
627     Relations *relations The set of relations to use.
628    
629 amb 721 Profile *profile The profile containing the transport type, speeds and allowed highways.
630    
631 amb 685 index_t endnode The super-node that the route ends at.
632    
633     index_t endsegment The segment that the route ends with.
634     ++++++++++++++++++++++++++++++++++++++*/
635    
636 amb 721 static index_t FindSuperSegment(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile,index_t endnode,index_t endsegment)
637 amb 685 {
638     Segment *segment;
639    
640 amb 699 if(IsFakeSegment(endsegment))
641     endsegment=IndexRealSegment(endsegment);
642    
643 amb 707 segment=LookupSegment(segments,endsegment,2);
644 amb 687
645     if(IsSuperSegment(segment))
646     return(endsegment);
647    
648 amb 685 /* Loop across all segments */
649    
650 amb 710 segment=FirstSegment(segments,nodes,endnode,3); /* endnode cannot be a fake node (must be a super-node) */
651 amb 685
652     while(segment)
653     {
654     if(IsSuperSegment(segment))
655     {
656     Results *results;
657     index_t startnode;
658    
659     startnode=OtherNode(segment,endnode);
660    
661 amb 723 results=FindNormalRoute(nodes,segments,ways,relations,profile,startnode,NO_SEGMENT,endnode);
662 amb 685
663     if(results && results->last_segment==endsegment)
664     return(IndexSegment(segments,segment));
665     }
666    
667     segment=NextSegment(segments,segment,endnode); /* endnode cannot be a fake node (must be a super-node) */
668     }
669    
670 amb 687 return(endsegment);
671 amb 685 }
672    
673    
674     /*++++++++++++++++++++++++++++++++++++++
675 amb 95 Find all routes from a specified node to any super-node.
676 amb 3
677 amb 126 Results *FindStartRoutes Returns a set of results.
678 amb 31
679     Nodes *nodes The set of nodes to use.
680    
681     Segments *segments The set of segments to use.
682    
683 amb 54 Ways *ways The set of ways to use.
684    
685 amb 542 Relations *relations The set of relations to use.
686    
687 amb 721 Profile *profile The profile containing the transport type, speeds and allowed highways.
688    
689 amb 605 index_t start_node The start node.
690 amb 31
691 amb 605 index_t prev_segment The previous segment before the start node.
692    
693 amb 729 index_t finish_node The finish node.
694    
695     int *nsuper Returns the number of super-nodes seen.
696 amb 31 ++++++++++++++++++++++++++++++++++++++*/
697    
698 amb 734 Results *FindStartRoutes(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile,index_t start_node,index_t prev_segment,index_t finish_node,int *nsuper)
699 amb 31 {
700     Results *results;
701 amb 469 Queue *queue;
702     Result *result1,*result2;
703 amb 734 int found_finish=0;
704 amb 31
705 amb 531 /* Create the results and insert the start node */
706 amb 31
707 amb 71 results=NewResultsList(8);
708 amb 31
709 amb 605 results->start_node=start_node;
710     results->prev_segment=prev_segment;
711 amb 165
712 amb 735 result1=InsertResult(results,results->start_node,results->prev_segment);
713 amb 31
714 amb 734 /* Take a shortcut if the first node is a super-node. */
715 amb 531
716 amb 734 if(!IsFakeNode(start_node) && IsSuperNode(LookupNode(nodes,start_node,1)))
717 amb 531 return(results);
718    
719     /* Insert the first node into the queue */
720    
721 amb 236 queue=NewQueueList();
722 amb 31
723 amb 236 InsertInQueue(queue,result1);
724    
725 amb 31 /* Loop across all nodes in the queue */
726    
727 amb 236 while((result1=PopFromQueue(queue)))
728 amb 31 {
729 amb 637 index_t node1,seg1,seg1r;
730 amb 594 Segment *segment;
731 amb 719 index_t turnrelation=NO_RELATION;
732 amb 678 int routes_out=0;
733 amb 594
734 amb 43 node1=result1->node;
735 amb 605 seg1=result1->segment;
736 amb 31
737 amb 637 if(IsFakeSegment(seg1))
738     seg1r=IndexRealSegment(seg1);
739     else
740     seg1r=seg1;
741    
742 amb 719 /* lookup if a turn restriction applies */
743     if(profile->turns && !IsFakeNode(node1) && IsTurnRestrictedNode(LookupNode(nodes,node1,1)))
744     turnrelation=FindFirstTurnRelation2(relations,node1,seg1r);
745 amb 680
746     /* Loop across all segments */
747    
748 amb 303 if(IsFakeNode(node1))
749     segment=FirstFakeSegment(node1);
750     else
751 amb 707 segment=FirstSegment(segments,nodes,node1,1);
752 amb 31
753     while(segment)
754     {
755 amb 610 Way *way;
756 amb 637 index_t node2,seg2,seg2r;
757 amb 298 score_t segment_pref,segment_score,cumulative_score;
758     int i;
759 amb 59
760 amb 734 node2=OtherNode(segment,node1); /* need this here because we use node2 at the end of the loop */
761    
762 amb 680 /* must be a normal segment */
763 amb 95 if(!IsNormalSegment(segment))
764     goto endloop;
765    
766 amb 680 /* must obey one-way restrictions (unless profile allows) */
767 amb 105 if(profile->oneway && IsOnewayTo(segment,node1))
768 amb 64 goto endloop;
769    
770 amb 605 if(IsFakeNode(node1) || IsFakeNode(node2))
771 amb 637 {
772     seg2 =IndexFakeSegment(segment);
773     seg2r=IndexRealSegment(seg2);
774     }
775 amb 605 else
776 amb 637 {
777     seg2 =IndexSegment(segments,segment);
778     seg2r=seg2;
779     }
780 amb 603
781 amb 699 /* must not perform U-turn (unless profile allows) */
782 amb 734 if(profile->turns && (seg1==seg2 || seg1==seg2r || seg1r==seg2 || (seg1r==seg2r && IsFakeUTurn(seg1,seg2))))
783 amb 636 goto endloop;
784    
785 amb 719 /* must obey turn relations */
786     if(turnrelation!=NO_RELATION && !IsTurnAllowed(relations,turnrelation,node1,seg1r,seg2r,profile->allow))
787     goto endloop;
788 amb 596
789 amb 460 way=LookupWay(ways,segment->way,1);
790 amb 54
791 amb 680 /* mode of transport must be allowed on the highway */
792 amb 82 if(!(way->allow&profile->allow))
793 amb 54 goto endloop;
794    
795 amb 680 /* must obey weight restriction (if exists) */
796 amb 197 if(way->weight && way->weight<profile->weight)
797 amb 135 goto endloop;
798    
799 amb 680 /* must obey height/width/length restriction (if exists) */
800 amb 197 if((way->height && way->height<profile->height) ||
801     (way->width && way->width <profile->width ) ||
802     (way->length && way->length<profile->length))
803 amb 135 goto endloop;
804    
805 amb 298 segment_pref=profile->highway[HIGHWAY(way->type)];
806    
807     for(i=1;i<Property_Count;i++)
808 amb 460 if(ways->file.props & PROPERTIES(i))
809 amb 307 {
810 amb 406 if(way->props & PROPERTIES(i))
811 amb 307 segment_pref*=profile->props_yes[i];
812     else
813     segment_pref*=profile->props_no[i];
814     }
815 amb 298
816 amb 680 /* profile preferences must allow this highway */
817 amb 298 if(segment_pref==0)
818     goto endloop;
819    
820 amb 680 /* mode of transport must be allowed through node2 */
821 amb 471 if(!IsFakeNode(node2))
822     {
823 amb 595 Node *node=LookupNode(nodes,node2,2);
824 amb 469
825 amb 471 if(!(node->allow&profile->allow))
826     goto endloop;
827     }
828 amb 469
829 amb 678 routes_out++;
830    
831 amb 166 if(option_quickest==0)
832 amb 298 segment_score=(score_t)DISTANCE(segment->distance)/segment_pref;
833 amb 166 else
834 amb 298 segment_score=(score_t)Duration(segment,way,profile)/segment_pref;
835 amb 59
836 amb 170 cumulative_score=result1->score+segment_score;
837 amb 166
838 amb 605 result2=FindResult(results,node2,seg2);
839 amb 31
840 amb 680 if(!result2) /* New end node/segment combination */
841 amb 31 {
842 amb 605 result2=InsertResult(results,node2,seg2);
843     result2->prev=result1;
844 amb 170 result2->score=cumulative_score;
845 amb 31
846 amb 729 if(!IsFakeNode(node2) && IsSuperNode(LookupNode(nodes,node2,2)))
847     (*nsuper)++;
848    
849 amb 734 if(!IsFakeNode(node2) && !IsSuperNode(LookupNode(nodes,node2,2)))
850 amb 119 {
851 amb 166 result2->sortby=result2->score;
852 amb 236 InsertInQueue(queue,result2);
853 amb 119 }
854 amb 734
855     if(node2==finish_node)
856     found_finish=1;
857 amb 31 }
858 amb 605 else if(cumulative_score<result2->score) /* New end node/segment combination is better */
859 amb 31 {
860 amb 605 result2->prev=result1;
861 amb 170 result2->score=cumulative_score;
862 amb 31
863 amb 734 if(!IsFakeNode(node2) && !IsSuperNode(LookupNode(nodes,node2,2)))
864 amb 31 {
865 amb 166 result2->sortby=result2->score;
866 amb 236 InsertInQueue(queue,result2);
867 amb 31 }
868     }
869    
870     endloop:
871    
872 amb 303 if(IsFakeNode(node1))
873     segment=NextFakeSegment(segment,node1);
874 amb 729 else if(IsFakeNode(node2))
875     segment=NULL; /* cannot call NextSegment() with a fake segment */
876 amb 303 else
877 amb 729 {
878 amb 303 segment=NextSegment(segments,segment,node1);
879 amb 678
880 amb 729 if(!segment && IsFakeNode(finish_node))
881     segment=ExtraFakeSegment(node1,finish_node);
882     }
883 amb 31 }
884     }
885    
886 amb 236 FreeQueueList(queue);
887    
888 amb 112 /* Check it worked */
889    
890 amb 734 if(results->number==1 || (*nsuper==0 && found_finish==0))
891 amb 112 {
892     FreeResultsList(results);
893     return(NULL);
894     }
895    
896 amb 31 return(results);
897 amb 2 }
898    
899    
900     /*++++++++++++++++++++++++++++++++++++++
901 amb 680 Find all routes from any super-node to a specific node (by working backwards from the specific node to all super-nodes).
902 amb 34
903 amb 126 Results *FindFinishRoutes Returns a set of results.
904 amb 34
905     Nodes *nodes The set of nodes to use.
906    
907     Segments *segments The set of segments to use.
908    
909 amb 54 Ways *ways The set of ways to use.
910    
911 amb 542 Relations *relations The set of relations to use.
912    
913 amb 721 Profile *profile The profile containing the transport type, speeds and allowed highways.
914    
915 amb 605 index_t finish_node The finishing node.
916 amb 34 ++++++++++++++++++++++++++++++++++++++*/
917    
918 amb 721 Results *FindFinishRoutes(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile,index_t finish_node)
919 amb 34 {
920 amb 605 Results *results,*results2;
921 amb 469 Queue *queue;
922 amb 605 Result *result1,*result2,*result3;
923 amb 34
924 amb 531 /* Create the results and insert the finish node */
925 amb 34
926 amb 71 results=NewResultsList(8);
927 amb 34
928 amb 605 results->finish_node=finish_node;
929 amb 165
930 amb 605 result1=InsertResult(results,finish_node,NO_SEGMENT);
931 amb 34
932 amb 531 /* Insert the first node into the queue */
933    
934 amb 236 queue=NewQueueList();
935 amb 34
936 amb 236 InsertInQueue(queue,result1);
937    
938 amb 34 /* Loop across all nodes in the queue */
939    
940 amb 236 while((result1=PopFromQueue(queue)))
941 amb 34 {
942 amb 637 index_t node1,seg1,seg1r;
943 amb 594 Segment *segment;
944 amb 596 index_t turnrelation=NO_RELATION;
945 amb 594
946 amb 43 node1=result1->node;
947 amb 605 seg1=result1->segment;
948 amb 34
949 amb 637 if(IsFakeSegment(seg1))
950     seg1r=IndexRealSegment(seg1);
951     else
952     seg1r=seg1;
953    
954 amb 680 /* lookup if a turn restriction applies */
955 amb 700 if(profile->turns && !IsFakeNode(node1) && IsTurnRestrictedNode(LookupNode(nodes,node1,1)))
956 amb 596 turnrelation=FindFirstTurnRelation1(relations,node1); /* working backwards => turn relation sort order doesn't help */
957    
958 amb 680 /* Loop across all segments */
959    
960 amb 303 if(IsFakeNode(node1))
961     segment=FirstFakeSegment(node1);
962     else
963 amb 707 segment=FirstSegment(segments,nodes,node1,1);
964 amb 34
965     while(segment)
966     {
967 amb 610 Way *way;
968 amb 637 index_t node2,seg2,seg2r;
969 amb 298 score_t segment_pref,segment_score,cumulative_score;
970     int i;
971 amb 59
972 amb 680 /* must be a normal segment */
973 amb 632 if((IsFakeNode(node1) || !IsSuperNode(LookupNode(nodes,node1,1))) && !IsNormalSegment(segment))
974 amb 34 goto endloop;
975    
976 amb 680 /* must obey one-way restrictions (unless profile allows) */
977 amb 596 if(profile->oneway && IsOnewayFrom(segment,node1)) /* Disallow oneway from node2 *to* node1 */
978 amb 95 goto endloop;
979    
980 amb 105 node2=OtherNode(segment,node1);
981 amb 64
982 amb 605 if(IsFakeNode(node1) || IsFakeNode(node2))
983 amb 637 {
984     seg2 =IndexFakeSegment(segment);
985     seg2r=IndexRealSegment(seg2);
986     }
987 amb 605 else
988 amb 637 {
989     seg2 =IndexSegment(segments,segment);
990     seg2r=seg2;
991     }
992 amb 605
993 amb 699 /* must not perform U-turn (unless profile allows) */
994 amb 727 if(profile->turns && (seg1==seg2 || seg1==seg2r || seg1r==seg2 || (seg1r==seg2r && IsFakeUTurn(seg1,seg2))))
995 amb 636 goto endloop;
996    
997 amb 680 /* must obey turn relations */
998 amb 596 if(turnrelation!=NO_RELATION)
999     {
1000 amb 637 index_t turnrelation2=FindFirstTurnRelation2(relations,node1,seg2r); /* node2 -> node1 -> result1->next->node */
1001 amb 596
1002 amb 637 if(turnrelation2!=NO_RELATION && !IsTurnAllowed(relations,turnrelation2,node1,seg2r,seg1r,profile->allow))
1003 amb 596 goto endloop;
1004     }
1005    
1006 amb 460 way=LookupWay(ways,segment->way,1);
1007 amb 54
1008 amb 680 /* mode of transport must be allowed on the highway */
1009 amb 82 if(!(way->allow&profile->allow))
1010 amb 54 goto endloop;
1011    
1012 amb 680 /* must obey weight restriction (if exists) */
1013 amb 197 if(way->weight && way->weight<profile->weight)
1014 amb 135 goto endloop;
1015    
1016 amb 680 /* must obey height/width/length restriction (if exists) */
1017 amb 197 if((way->height && way->height<profile->height) ||
1018     (way->width && way->width <profile->width ) ||
1019     (way->length && way->length<profile->length))
1020 amb 135 goto endloop;
1021    
1022 amb 298 segment_pref=profile->highway[HIGHWAY(way->type)];
1023    
1024     for(i=1;i<Property_Count;i++)
1025 amb 460 if(ways->file.props & PROPERTIES(i))
1026 amb 307 {
1027 amb 406 if(way->props & PROPERTIES(i))
1028 amb 307 segment_pref*=profile->props_yes[i];
1029     else
1030     segment_pref*=profile->props_no[i];
1031     }
1032 amb 298
1033 amb 680 /* profile preferences must allow this highway */
1034 amb 298 if(segment_pref==0)
1035     goto endloop;
1036    
1037 amb 680 /* mode of transport must be allowed through node2 */
1038 amb 471 if(!IsFakeNode(node2))
1039     {
1040 amb 595 Node *node=LookupNode(nodes,node2,2);
1041 amb 469
1042 amb 471 if(!(node->allow&profile->allow))
1043     goto endloop;
1044     }
1045 amb 469
1046 amb 166 if(option_quickest==0)
1047 amb 298 segment_score=(score_t)DISTANCE(segment->distance)/segment_pref;
1048 amb 166 else
1049 amb 298 segment_score=(score_t)Duration(segment,way,profile)/segment_pref;
1050 amb 59
1051 amb 170 cumulative_score=result1->score+segment_score;
1052 amb 166
1053 amb 605 result2=FindResult(results,node2,seg2);
1054 amb 34
1055 amb 680 if(!result2) /* New end node */
1056 amb 34 {
1057 amb 605 result2=InsertResult(results,node2,seg2);
1058     result2->next=result1; /* working backwards */
1059 amb 170 result2->score=cumulative_score;
1060 amb 34
1061 amb 609 if(IsFakeNode(node1) || (!IsFakeNode(node1) && !IsSuperNode(LookupNode(nodes,node1,1)))) /* Overshoot by one segment */
1062 amb 119 {
1063 amb 166 result2->sortby=result2->score;
1064 amb 236 InsertInQueue(queue,result2);
1065 amb 119 }
1066 amb 34 }
1067 amb 166 else if(cumulative_score<result2->score) /* New end node is better */
1068 amb 34 {
1069 amb 605 result2->next=result1; /* working backwards */
1070 amb 170 result2->score=cumulative_score;
1071 amb 34
1072 amb 609 if(IsFakeNode(node1) || (!IsFakeNode(node1) && !IsSuperNode(LookupNode(nodes,node1,1)))) /* Overshoot by one segment */
1073 amb 34 {
1074 amb 166 result2->sortby=result2->score;
1075 amb 236 InsertInQueue(queue,result2);
1076 amb 34 }
1077     }
1078    
1079     endloop:
1080    
1081 amb 303 if(IsFakeNode(node1))
1082     segment=NextFakeSegment(segment,node1);
1083     else
1084     segment=NextSegment(segments,segment,node1);
1085 amb 34 }
1086     }
1087    
1088 amb 236 FreeQueueList(queue);
1089    
1090 amb 112 /* Check it worked */
1091    
1092     if(results->number==1)
1093     {
1094     FreeResultsList(results);
1095     return(NULL);
1096     }
1097    
1098 amb 605 /* Create a results structure with the node at the end of the segment opposite the start */
1099    
1100     results2=NewResultsList(8);
1101    
1102     results2->finish_node=results->finish_node;
1103    
1104     result3=FirstResult(results);
1105    
1106     while(result3)
1107     {
1108     if(result3->next)
1109     {
1110     result2=InsertResult(results2,result3->next->node,result3->segment);
1111    
1112 amb 616 result2->score=result3->next->score;
1113 amb 605 }
1114    
1115     result3=NextResult(results,result3);
1116     }
1117    
1118     /* Fix up the result->next pointers */
1119    
1120     result3=FirstResult(results);
1121    
1122     while(result3)
1123     {
1124     if(result3->next && result3->next->next)
1125     {
1126     result1=FindResult(results2,result3->next->node,result3->segment);
1127     result2=FindResult(results2,result3->next->next->node,result3->next->segment);
1128    
1129     result1->next=result2;
1130     }
1131    
1132     result3=NextResult(results,result3);
1133     }
1134    
1135     FreeResultsList(results);
1136    
1137     return(results2);
1138 amb 34 }
1139    
1140    
1141     /*++++++++++++++++++++++++++++++++++++++
1142 amb 95 Create an optimum route given the set of super-nodes to follow.
1143 amb 31
1144 amb 58 Results *CombineRoutes Returns the results from joining the super-nodes.
1145 amb 55
1146 amb 680 Nodes *nodes The set of nodes to use.
1147 amb 31
1148     Segments *segments The set of segments to use.
1149    
1150 amb 680 Ways *ways The set of ways to use.
1151 amb 31
1152 amb 542 Relations *relations The set of relations to use.
1153    
1154 amb 721 Profile *profile The profile containing the transport type, speeds and allowed highways.
1155    
1156 amb 722 Results *begin The set of results for the start of the route.
1157    
1158 amb 686 Results *middle The set of results from the super-node route.
1159 amb 31 ++++++++++++++++++++++++++++++++++++++*/
1160    
1161 amb 722 Results *CombineRoutes(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile,Results *begin,Results *middle)
1162 amb 31 {
1163 amb 686 Result *midres,*comres1;
1164 amb 31 Results *combined;
1165    
1166 amb 71 combined=NewResultsList(64);
1167 amb 31
1168 amb 735 combined->start_node=begin->start_node;
1169     combined->prev_segment=begin->prev_segment;
1170 amb 165
1171 amb 722 /* Insert the start point */
1172 amb 31
1173 amb 686 midres=FindResult(middle,middle->start_node,middle->prev_segment);
1174 amb 31
1175 amb 735 comres1=InsertResult(combined,combined->start_node,combined->prev_segment);
1176 amb 31
1177 amb 722 /* Insert the start of the route */
1178    
1179     if(begin->number>1 && midres->next)
1180     {
1181     Result *begres;
1182    
1183     midres=FindResult(middle,midres->next->node,midres->next->segment);
1184    
1185     begres=FindResult(begin,midres->node,midres->segment);
1186    
1187     FixForwardRoute(begin,begres);
1188    
1189     if(midres->next && midres->next->node==midres->node)
1190     midres=midres->next;
1191    
1192     begres=FindResult(begin,begin->start_node,begin->prev_segment);
1193    
1194     begres=begres->next;
1195    
1196     do
1197     {
1198     Result *comres2;
1199    
1200     comres2=InsertResult(combined,begres->node,begres->segment);
1201    
1202     comres2->score=begres->score+comres1->score;
1203     comres2->prev=comres1;
1204    
1205     begres=begres->next;
1206    
1207     comres1=comres2;
1208     }
1209     while(begres);
1210     }
1211    
1212     /* Sort out the combined route */
1213    
1214 amb 58 do
1215     {
1216 amb 686 Result *result;
1217 amb 594
1218 amb 686 if(midres->next)
1219 amb 31 {
1220 amb 723 Results *results=FindNormalRoute(nodes,segments,ways,relations,profile,comres1->node,comres1->segment,midres->next->node);
1221 amb 31
1222 amb 686 if(!results)
1223 amb 677 return(NULL);
1224    
1225 amb 686 result=FindResult(results,midres->node,comres1->segment);
1226 amb 31
1227 amb 686 result=result->next;
1228 amb 36
1229 amb 605 /*
1230 amb 686 * midres midres->next
1231 amb 605 * = =
1232 amb 686 * ---*----------------------------------* = middle
1233 amb 605 *
1234 amb 686 * ---*----.----.----.----.----.----.----* = results
1235 amb 605 * =
1236 amb 686 * result
1237 amb 605 *
1238     * ---*----.----.----.----.----.----.----* = combined
1239     * = =
1240 amb 686 * comres1 comres2
1241 amb 605 */
1242    
1243 amb 31 do
1244     {
1245 amb 686 Result *comres2;
1246 amb 31
1247 amb 686 comres2=InsertResult(combined,result->node,result->segment);
1248 amb 605
1249 amb 686 comres2->score=result->score+comres1->score;
1250     comres2->prev=comres1;
1251 amb 605
1252 amb 686 result=result->next;
1253    
1254     comres1=comres2;
1255 amb 31 }
1256 amb 686 while(result);
1257 amb 31
1258 amb 686 FreeResultsList(results);
1259 amb 605 }
1260 amb 31
1261 amb 686 midres=midres->next;
1262 amb 31 }
1263 amb 686 while(midres);
1264 amb 31
1265 amb 686 FixForwardRoute(combined,comres1);
1266 amb 605
1267 amb 55 return(combined);
1268 amb 31 }
1269 amb 290
1270    
1271     /*++++++++++++++++++++++++++++++++++++++
1272 amb 605 Fix the forward route (i.e. setup next pointers for forward path from prev nodes on reverse path).
1273 amb 290
1274     Results *results The set of results to update.
1275    
1276 amb 680 Result *finish_result The result for the finish point.
1277 amb 290 ++++++++++++++++++++++++++++++++++++++*/
1278    
1279 amb 605 void FixForwardRoute(Results *results,Result *finish_result)
1280 amb 290 {
1281 amb 605 Result *result2=finish_result;
1282 amb 290
1283     /* Create the forward links for the optimum path */
1284    
1285     do
1286     {
1287 amb 594 Result *result1;
1288    
1289 amb 605 if(result2->prev)
1290 amb 290 {
1291 amb 605 index_t node1=result2->prev->node;
1292     index_t seg1=result2->prev->segment;
1293 amb 290
1294 amb 605 result1=FindResult(results,node1,seg1);
1295 amb 290
1296 amb 712 assert(!result1->next); /* Bugs elsewhere can lead to infinite loop here. */
1297    
1298 amb 605 result1->next=result2;
1299 amb 290
1300     result2=result1;
1301     }
1302     else
1303     result2=NULL;
1304     }
1305     while(result2);
1306    
1307 amb 605 results->finish_node=finish_result->node;
1308     results->last_segment=finish_result->segment;
1309 amb 290 }

Properties

Name Value
cvs:description Route optimiser.