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 710 - (show annotations) (download) (as text)
Sun May 8 17:59:28 2011 UTC (13 years, 10 months ago) by amb
File MIME type: text/x-csrc
File size: 35945 byte(s)
Remove clash of cache locations.

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

Properties

Name Value
cvs:description Route optimiser.