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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 412 - (show annotations) (download) (as text)
Sun May 30 12:50:40 2010 UTC (14 years, 10 months ago) by amb
File MIME type: text/x-csrc
File size: 23510 byte(s)
Fix printing the number of super-segments tried.

1 /***************************************
2 $Header: /home/amb/CVS/routino/src/optimiser.c,v 1.84 2010-05-30 12:50:40 amb Exp $
3
4 Routing optimiser.
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
27 #include "types.h"
28 #include "functions.h"
29 #include "nodes.h"
30 #include "segments.h"
31 #include "ways.h"
32 #include "results.h"
33
34
35 /*+ The option not to print any progress information. +*/
36 extern int option_quiet;
37
38 /*+ The option to calculate the quickest route insted of the shortest. +*/
39 extern int option_quickest;
40
41
42 /*++++++++++++++++++++++++++++++++++++++
43 Find the optimum route between two nodes not passing through a super-node.
44
45 Results *FindNormalRoute Returns a set of results.
46
47 Nodes *nodes The set of nodes to use.
48
49 Segments *segments The set of segments to use.
50
51 Ways *ways The set of ways to use.
52
53 index_t start The start node.
54
55 index_t finish The finish node.
56
57 Profile *profile The profile containing the transport type, speeds and allowed highways.
58 ++++++++++++++++++++++++++++++++++++++*/
59
60 Results *FindNormalRoute(Nodes *nodes,Segments *segments,Ways *ways,index_t start,index_t finish,Profile *profile)
61 {
62 Results *results;
63 Queue *queue;
64 index_t node1,node2;
65 score_t finish_score;
66 double finish_lat,finish_lon;
67 Result *result1,*result2;
68 Segment *segment;
69 Way *way;
70
71 /* Set up the finish conditions */
72
73 finish_score=INF_SCORE;
74
75 if(IsFakeNode(finish))
76 GetFakeLatLong(finish,&finish_lat,&finish_lon);
77 else
78 GetLatLong(nodes,finish,&finish_lat,&finish_lon);
79
80 /* Create the list of results and insert the first node into the queue */
81
82 results=NewResultsList(8);
83
84 results->start=start;
85 results->finish=finish;
86
87 result1=InsertResult(results,start);
88
89 ZeroResult(result1);
90
91 queue=NewQueueList();
92
93 InsertInQueue(queue,result1);
94
95 /* Loop across all nodes in the queue */
96
97 while((result1=PopFromQueue(queue)))
98 {
99 if(result1->score>finish_score)
100 continue;
101
102 node1=result1->node;
103
104 if(IsFakeNode(node1))
105 segment=FirstFakeSegment(node1);
106 else
107 segment=FirstSegment(segments,nodes,node1);
108
109 while(segment)
110 {
111 score_t segment_pref,segment_score,cumulative_score;
112 int i;
113
114 node2=OtherNode(segment,node1); /* need this here because we use node2 later */
115
116 if(!IsNormalSegment(segment))
117 goto endloop;
118
119 if(profile->oneway && IsOnewayTo(segment,node1))
120 goto endloop;
121
122 if(result1->prev==node2)
123 goto endloop;
124
125 if(node2!=finish && !IsFakeNode(node2) && IsSuperNode(nodes,node2))
126 goto endloop;
127
128 way=LookupWay(ways,segment->way);
129
130 if(!(way->allow&profile->allow))
131 goto endloop;
132
133 if(!profile->highway[HIGHWAY(way->type)])
134 goto endloop;
135
136 if(way->weight && way->weight<profile->weight)
137 goto endloop;
138
139 if((way->height && way->height<profile->height) ||
140 (way->width && way->width <profile->width ) ||
141 (way->length && way->length<profile->length))
142 goto endloop;
143
144 segment_pref=profile->highway[HIGHWAY(way->type)];
145
146 for(i=1;i<Property_Count;i++)
147 if(ways->props & PROPERTIES(i))
148 {
149 if(way->props & PROPERTIES(i))
150 segment_pref*=profile->props_yes[i];
151 else
152 segment_pref*=profile->props_no[i];
153 }
154
155 if(segment_pref==0)
156 goto endloop;
157
158 if(option_quickest==0)
159 segment_score=(score_t)DISTANCE(segment->distance)/segment_pref;
160 else
161 segment_score=(score_t)Duration(segment,way,profile)/segment_pref;
162
163 cumulative_score=result1->score+segment_score;
164
165 if(cumulative_score>finish_score)
166 goto endloop;
167
168 result2=FindResult(results,node2);
169
170 if(!result2) /* New end node */
171 {
172 result2=InsertResult(results,node2);
173 result2->prev=node1;
174 result2->next=NO_NODE;
175 result2->score=cumulative_score;
176 result2->segment=segment;
177
178 if(node2==finish)
179 {
180 finish_score=cumulative_score;
181 }
182 else
183 {
184 result2->sortby=result2->score;
185
186 InsertInQueue(queue,result2);
187 }
188 }
189 else if(cumulative_score<result2->score) /* New end node is better */
190 {
191 result2->prev=node1;
192 result2->score=cumulative_score;
193 result2->segment=segment;
194
195 if(node2==finish)
196 {
197 finish_score=cumulative_score;
198 }
199 else
200 {
201 result2->sortby=result2->score;
202
203 if(result2->score<finish_score)
204 InsertInQueue(queue,result2);
205 }
206 }
207
208 endloop:
209
210 if(IsFakeNode(node1))
211 segment=NextFakeSegment(segment,node1);
212 else if(IsFakeNode(node2))
213 segment=NULL; /* cannot call NextSegment() with a fake segment */
214 else
215 {
216 segment=NextSegment(segments,segment,node1);
217
218 if(!segment && IsFakeNode(finish))
219 segment=ExtraFakeSegment(node1,finish);
220 }
221 }
222 }
223
224 FreeQueueList(queue);
225
226 /* Check it worked */
227
228 if(!FindResult(results,finish))
229 {
230 FreeResultsList(results);
231 return(NULL);
232 }
233
234 FixForwardRoute(results,finish);
235
236 return(results);
237 }
238
239
240 /*++++++++++++++++++++++++++++++++++++++
241 Find the optimum route between two nodes where the start and end are a set of pre-routed super-nodes.
242
243 Results *FindMiddleRoute Returns a set of results.
244
245 Nodes *nodes The set of nodes to use.
246
247 Segments *segments The set of segments to use.
248
249 Ways *ways The set of ways to use.
250
251 Results *begin The initial portion of the route.
252
253 Results *end The final portion of the route.
254
255 Profile *profile The profile containing the transport type, speeds and allowed highways.
256 ++++++++++++++++++++++++++++++++++++++*/
257
258 Results *FindMiddleRoute(Nodes *nodes,Segments *segments,Ways *ways,Results *begin,Results *end,Profile *profile)
259 {
260 Results *results;
261 Queue *queue;
262 index_t node1,node2;
263 score_t finish_score;
264 double finish_lat,finish_lon;
265 Result *result1,*result2,*result3;
266 Segment *segment;
267 Way *way;
268
269 if(!option_quiet)
270 {
271 printf("Routing: Super-Nodes checked = 0");
272 fflush(stdout);
273 }
274
275 /* Set up the finish conditions */
276
277 finish_score=INF_DISTANCE;
278
279 if(IsFakeNode(end->finish))
280 GetFakeLatLong(end->finish,&finish_lat,&finish_lon);
281 else
282 GetLatLong(nodes,end->finish,&finish_lat,&finish_lon);
283
284 /* Create the list of results and insert the first node into the queue */
285
286 results=NewResultsList(65536);
287
288 results->start=begin->start;
289 results->finish=end->finish;
290
291 result1=InsertResult(results,begin->start);
292 result3=FindResult(begin,begin->start);
293
294 *result1=*result3;
295
296 queue=NewQueueList();
297
298 /* Insert the finish points of the beginning part of the path into the queue */
299
300 result3=FirstResult(begin);
301
302 while(result3)
303 {
304 if(result3->node!=begin->start && !IsFakeNode(result3->node) && IsSuperNode(nodes,result3->node))
305 {
306 result2=InsertResult(results,result3->node);
307
308 *result2=*result3;
309
310 result2->prev=begin->start;
311
312 result2->sortby=result2->score;
313
314 InsertInQueue(queue,result2);
315 }
316
317 result3=NextResult(begin,result3);
318 }
319
320 if(begin->number==1)
321 InsertInQueue(queue,result1);
322
323 /* Loop across all nodes in the queue */
324
325 while((result1=PopFromQueue(queue)))
326 {
327 if(result1->score>finish_score)
328 continue;
329
330 node1=result1->node;
331
332 if(IsFakeNode(node1))
333 segment=FirstFakeSegment(node1);
334 else
335 segment=FirstSegment(segments,nodes,node1);
336
337 while(segment)
338 {
339 score_t segment_pref,segment_score,cumulative_score;
340 int i;
341
342 if(!IsSuperSegment(segment))
343 goto endloop;
344
345 if(profile->oneway && IsOnewayTo(segment,node1))
346 goto endloop;
347
348 node2=OtherNode(segment,node1);
349
350 if(result1->prev==node2)
351 goto endloop;
352
353 way=LookupWay(ways,segment->way);
354
355 if(!(way->allow&profile->allow))
356 goto endloop;
357
358 if(!profile->highway[HIGHWAY(way->type)])
359 goto endloop;
360
361 if(way->weight && way->weight<profile->weight)
362 goto endloop;
363
364 if((way->height && way->height<profile->height) ||
365 (way->width && way->width <profile->width ) ||
366 (way->length && way->length<profile->length))
367 goto endloop;
368
369 segment_pref=profile->highway[HIGHWAY(way->type)];
370
371 for(i=1;i<Property_Count;i++)
372 if(ways->props & PROPERTIES(i))
373 {
374 if(way->props & PROPERTIES(i))
375 segment_pref*=profile->props_yes[i];
376 else
377 segment_pref*=profile->props_no[i];
378 }
379
380 if(segment_pref==0)
381 goto endloop;
382
383 if(option_quickest==0)
384 segment_score=(score_t)DISTANCE(segment->distance)/segment_pref;
385 else
386 segment_score=(score_t)Duration(segment,way,profile)/segment_pref;
387
388 cumulative_score=result1->score+segment_score;
389
390 if(cumulative_score>finish_score)
391 goto endloop;
392
393 result2=FindResult(results,node2);
394
395 if(!result2) /* New end node */
396 {
397 result2=InsertResult(results,node2);
398 result2->prev=node1;
399 result2->next=NO_NODE;
400 result2->score=cumulative_score;
401 result2->segment=segment;
402
403 if((result3=FindResult(end,node2)))
404 {
405 finish_score=result2->score+result3->score;
406 }
407 else
408 {
409 double lat,lon;
410 distance_t direct;
411
412 if(IsFakeNode(node2))
413 GetFakeLatLong(node2,&lat,&lon);
414 else
415 GetLatLong(nodes,node2,&lat,&lon);
416 direct=Distance(lat,lon,finish_lat,finish_lon);
417
418 if(option_quickest==0)
419 result2->sortby=result2->score+(score_t)direct/profile->max_pref;
420 else
421 result2->sortby=result2->score+(score_t)distance_speed_to_duration(direct,profile->max_speed)/profile->max_pref;
422
423 InsertInQueue(queue,result2);
424 }
425 }
426 else if(cumulative_score<result2->score) /* New end node is better */
427 {
428 result2->prev=node1;
429 result2->score=cumulative_score;
430 result2->segment=segment;
431
432 if((result3=FindResult(end,node2)))
433 {
434 if((result2->score+result3->score)<finish_score)
435 {
436 finish_score=result2->score+result3->score;
437 }
438 }
439 else if(result2->score<finish_score)
440 {
441 double lat,lon;
442 distance_t direct;
443
444 if(IsFakeNode(node2))
445 GetFakeLatLong(node2,&lat,&lon);
446 else
447 GetLatLong(nodes,node2,&lat,&lon);
448 direct=Distance(lat,lon,finish_lat,finish_lon);
449
450 if(option_quickest==0)
451 result2->sortby=result2->score+(score_t)direct/profile->max_pref;
452 else
453 result2->sortby=result2->score+(score_t)distance_speed_to_duration(direct,profile->max_speed)/profile->max_pref;
454
455 InsertInQueue(queue,result2);
456 }
457 }
458
459 endloop:
460
461 if(!option_quiet && !(results->number%10000))
462 {
463 printf("\rRouting: Super-Nodes checked = %d",results->number);
464 fflush(stdout);
465 }
466
467 if(IsFakeNode(node1))
468 segment=NextFakeSegment(segment,node1);
469 else
470 segment=NextSegment(segments,segment,node1);
471 }
472 }
473
474 if(!option_quiet)
475 {
476 printf("\rRouted: Super-Nodes checked = %d \n",results->number);
477 fflush(stdout);
478 }
479
480 /* Finish off the end part of the route. */
481
482 if(!FindResult(results,end->finish))
483 {
484 result2=InsertResult(results,end->finish);
485 result3=FindResult(end,end->finish);
486
487 *result2=*result3;
488
489 result2->score=INF_DISTANCE;
490
491 result3=FirstResult(end);
492
493 while(result3)
494 {
495 if(!IsFakeNode(result3->node) && IsSuperNode(nodes,result3->node))
496 if((result1=FindResult(results,result3->node)))
497 if((result1->score+result3->score)<result2->score)
498 {
499 result2->score=result1->score+result3->score;
500 result2->prev=result1->node;
501 }
502
503 result3=NextResult(end,result3);
504 }
505 }
506
507 FreeQueueList(queue);
508
509 /* Check it worked */
510
511 if(!FindResult(results,end->finish))
512 {
513 FreeResultsList(results);
514 return(NULL);
515 }
516
517 FixForwardRoute(results,end->finish);
518
519 return(results);
520 }
521
522
523 /*++++++++++++++++++++++++++++++++++++++
524 Find all routes from a specified node to any super-node.
525
526 Results *FindStartRoutes Returns a set of results.
527
528 Nodes *nodes The set of nodes to use.
529
530 Segments *segments The set of segments to use.
531
532 Ways *ways The set of ways to use.
533
534 index_t start The start node.
535
536 Profile *profile The profile containing the transport type, speeds and allowed highways.
537 ++++++++++++++++++++++++++++++++++++++*/
538
539 Results *FindStartRoutes(Nodes *nodes,Segments *segments,Ways *ways,index_t start,Profile *profile)
540 {
541 Results *results;
542 Queue *queue;
543 index_t node1,node2;
544 Result *result1,*result2;
545 Segment *segment;
546 Way *way;
547
548 /* Insert the first node into the queue */
549
550 results=NewResultsList(8);
551
552 results->start=start;
553
554 result1=InsertResult(results,start);
555
556 ZeroResult(result1);
557
558 queue=NewQueueList();
559
560 InsertInQueue(queue,result1);
561
562 /* Loop across all nodes in the queue */
563
564 while((result1=PopFromQueue(queue)))
565 {
566 node1=result1->node;
567
568 if(IsFakeNode(node1))
569 segment=FirstFakeSegment(node1);
570 else
571 segment=FirstSegment(segments,nodes,node1);
572
573 while(segment)
574 {
575 score_t segment_pref,segment_score,cumulative_score;
576 int i;
577
578 if(!IsNormalSegment(segment))
579 goto endloop;
580
581 if(profile->oneway && IsOnewayTo(segment,node1))
582 goto endloop;
583
584 node2=OtherNode(segment,node1);
585
586 if(result1->prev==node2)
587 goto endloop;
588
589 way=LookupWay(ways,segment->way);
590
591 if(!(way->allow&profile->allow))
592 goto endloop;
593
594 if(!profile->highway[HIGHWAY(way->type)])
595 goto endloop;
596
597 if(way->weight && way->weight<profile->weight)
598 goto endloop;
599
600 if((way->height && way->height<profile->height) ||
601 (way->width && way->width <profile->width ) ||
602 (way->length && way->length<profile->length))
603 goto endloop;
604
605 segment_pref=profile->highway[HIGHWAY(way->type)];
606
607 for(i=1;i<Property_Count;i++)
608 if(ways->props & PROPERTIES(i))
609 {
610 if(way->props & PROPERTIES(i))
611 segment_pref*=profile->props_yes[i];
612 else
613 segment_pref*=profile->props_no[i];
614 }
615
616 if(segment_pref==0)
617 goto endloop;
618
619 if(option_quickest==0)
620 segment_score=(score_t)DISTANCE(segment->distance)/segment_pref;
621 else
622 segment_score=(score_t)Duration(segment,way,profile)/segment_pref;
623
624 cumulative_score=result1->score+segment_score;
625
626 result2=FindResult(results,node2);
627
628 if(!result2) /* New end node */
629 {
630 result2=InsertResult(results,node2);
631 result2->prev=node1;
632 result2->next=NO_NODE;
633 result2->score=cumulative_score;
634 result2->segment=segment;
635
636 if(!IsFakeNode(node2) && !IsSuperNode(nodes,node2))
637 {
638 result2->sortby=result2->score;
639 InsertInQueue(queue,result2);
640 }
641 }
642 else if(cumulative_score<result2->score) /* New end node is better */
643 {
644 result2->prev=node1;
645 result2->score=cumulative_score;
646 result2->segment=segment;
647
648 if(!IsFakeNode(node2) && !IsSuperNode(nodes,node2))
649 {
650 result2->sortby=result2->score;
651 InsertInQueue(queue,result2);
652 }
653 }
654
655 endloop:
656
657 if(IsFakeNode(node1))
658 segment=NextFakeSegment(segment,node1);
659 else
660 segment=NextSegment(segments,segment,node1);
661 }
662 }
663
664 FreeQueueList(queue);
665
666 /* Check it worked */
667
668 if(results->number==1)
669 {
670 FreeResultsList(results);
671 return(NULL);
672 }
673
674 return(results);
675 }
676
677
678 /*++++++++++++++++++++++++++++++++++++++
679 Find all routes from any super-node to a specific node.
680
681 Results *FindFinishRoutes Returns a set of results.
682
683 Nodes *nodes The set of nodes to use.
684
685 Segments *segments The set of segments to use.
686
687 Ways *ways The set of ways to use.
688
689 index_t finish The finishing node.
690
691 Profile *profile The profile containing the transport type, speeds and allowed highways.
692 ++++++++++++++++++++++++++++++++++++++*/
693
694 Results *FindFinishRoutes(Nodes *nodes,Segments *segments,Ways *ways,index_t finish,Profile *profile)
695 {
696 Results *results;
697 Queue *queue;
698 index_t node1,node2;
699 Result *result1,*result2;
700 Segment *segment;
701 Way *way;
702
703 /* Insert the first node into the queue */
704
705 results=NewResultsList(8);
706
707 results->finish=finish;
708
709 result1=InsertResult(results,finish);
710
711 ZeroResult(result1);
712
713 queue=NewQueueList();
714
715 InsertInQueue(queue,result1);
716
717 /* Loop across all nodes in the queue */
718
719 while((result1=PopFromQueue(queue)))
720 {
721 node1=result1->node;
722
723 if(IsFakeNode(node1))
724 segment=FirstFakeSegment(node1);
725 else
726 segment=FirstSegment(segments,nodes,node1);
727
728 while(segment)
729 {
730 score_t segment_pref,segment_score,cumulative_score;
731 int i;
732
733 if(!IsNormalSegment(segment))
734 goto endloop;
735
736 if(profile->oneway && IsOnewayFrom(segment,node1))
737 goto endloop;
738
739 node2=OtherNode(segment,node1);
740
741 if(result1->next==node2)
742 goto endloop;
743
744 way=LookupWay(ways,segment->way);
745
746 if(!(way->allow&profile->allow))
747 goto endloop;
748
749 if(!profile->highway[HIGHWAY(way->type)])
750 goto endloop;
751
752 if(way->weight && way->weight<profile->weight)
753 goto endloop;
754
755 if((way->height && way->height<profile->height) ||
756 (way->width && way->width <profile->width ) ||
757 (way->length && way->length<profile->length))
758 goto endloop;
759
760 segment_pref=profile->highway[HIGHWAY(way->type)];
761
762 for(i=1;i<Property_Count;i++)
763 if(ways->props & PROPERTIES(i))
764 {
765 if(way->props & PROPERTIES(i))
766 segment_pref*=profile->props_yes[i];
767 else
768 segment_pref*=profile->props_no[i];
769 }
770
771 if(segment_pref==0)
772 goto endloop;
773
774 if(option_quickest==0)
775 segment_score=(score_t)DISTANCE(segment->distance)/segment_pref;
776 else
777 segment_score=(score_t)Duration(segment,way,profile)/segment_pref;
778
779 cumulative_score=result1->score+segment_score;
780
781 result2=FindResult(results,node2);
782
783 if(!result2) /* New end node */
784 {
785 result2=InsertResult(results,node2);
786 result2->prev=NO_NODE;
787 result2->next=node1;
788 result2->score=cumulative_score;
789 result2->segment=segment;
790
791 if(!IsFakeNode(node2) && !IsSuperNode(nodes,node2))
792 {
793 result2->sortby=result2->score;
794 InsertInQueue(queue,result2);
795 }
796 }
797 else if(cumulative_score<result2->score) /* New end node is better */
798 {
799 result2->next=node1;
800 result2->score=cumulative_score;
801 result2->segment=segment;
802
803 if(!IsFakeNode(node2) && !IsSuperNode(nodes,node2))
804 {
805 result2->sortby=result2->score;
806 InsertInQueue(queue,result2);
807 }
808 }
809
810 endloop:
811
812 if(IsFakeNode(node1))
813 segment=NextFakeSegment(segment,node1);
814 else
815 segment=NextSegment(segments,segment,node1);
816 }
817 }
818
819 FreeQueueList(queue);
820
821 /* Check it worked */
822
823 if(results->number==1)
824 {
825 FreeResultsList(results);
826 return(NULL);
827 }
828
829 return(results);
830 }
831
832
833 /*++++++++++++++++++++++++++++++++++++++
834 Create an optimum route given the set of super-nodes to follow.
835
836 Results *CombineRoutes Returns the results from joining the super-nodes.
837
838 Results *results The set of results from the super-nodes.
839
840 Nodes *nodes The list of nodes.
841
842 Segments *segments The set of segments to use.
843
844 Ways *ways The list of ways.
845
846 Profile *profile The profile containing the transport type, speeds and allowed highways.
847 ++++++++++++++++++++++++++++++++++++++*/
848
849 Results *CombineRoutes(Results *results,Nodes *nodes,Segments *segments,Ways *ways,Profile *profile)
850 {
851 Result *result1,*result2,*result3,*result4;
852 Results *combined;
853
854 combined=NewResultsList(64);
855
856 combined->start=results->start;
857 combined->finish=results->finish;
858
859 /* Sort out the combined route */
860
861 result1=FindResult(results,results->start);
862
863 result3=InsertResult(combined,results->start);
864
865 ZeroResult(result3);
866
867 do
868 {
869 if(result1->next!=NO_NODE)
870 {
871 Results *results2=FindNormalRoute(nodes,segments,ways,result1->node,result1->next,profile);
872
873 result2=FindResult(results2,result1->node);
874
875 result3->next=result2->next;
876
877 result2=FindResult(results2,result2->next);
878
879 do
880 {
881 result4=InsertResult(combined,result2->node);
882
883 *result4=*result2;
884 result4->score+=result3->score;
885
886 if(result2->next!=NO_NODE)
887 result2=FindResult(results2,result2->next);
888 else
889 result2=NULL;
890 }
891 while(result2);
892
893 FreeResultsList(results2);
894
895 result1=FindResult(results,result1->next);
896
897 result3=result4;
898 }
899 else
900 result1=NULL;
901 }
902 while(result1);
903
904 return(combined);
905 }
906
907
908 /*++++++++++++++++++++++++++++++++++++++
909 Fx the forward route (i.e. setup next nodes for forward path from prev nodes on reverse path).
910
911 Results *results The set of results to update.
912
913 index_t finish The finish point.
914 ++++++++++++++++++++++++++++++++++++++*/
915
916 void FixForwardRoute(Results *results,index_t finish)
917 {
918 Result *result2=FindResult(results,finish);
919 Result *result1;
920
921 /* Create the forward links for the optimum path */
922
923 do
924 {
925 if(result2->prev!=NO_NODE)
926 {
927 index_t node1=result2->prev;
928
929 result1=FindResult(results,node1);
930
931 result1->next=result2->node;
932
933 result2=result1;
934 }
935 else
936 result2=NULL;
937 }
938 while(result2);
939
940 results->finish=finish;
941 }

Properties

Name Value
cvs:description Route optimiser.