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 1627 - (show annotations) (download) (as text)
Sat Mar 21 19:23:20 2015 UTC (10 years ago) by amb
File MIME type: text/x-csrc
File size: 56538 byte(s)
Make sure that all complete routes have finish_node and last_segment
filled in.

1 /***************************************
2 Routing optimiser.
3
4 Part of the Routino routing software.
5 ******************/ /******************
6 This file Copyright 2008-2015 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 "types.h"
24 #include "nodes.h"
25 #include "segments.h"
26 #include "ways.h"
27 #include "relations.h"
28
29 #include "logging.h"
30 #include "functions.h"
31 #include "fakes.h"
32 #include "results.h"
33
34
35 /*+ To help when debugging +*/
36 #define DEBUG 0
37
38
39 /* Global variables */
40
41 /*+ The option not to print any progress information. +*/
42 extern int option_quiet;
43
44 /*+ The option to calculate the quickest route insted of the shortest. +*/
45 extern int option_quickest;
46
47
48 /* Local functions */
49
50 static index_t FindSuperSegment(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile,index_t finish_node,index_t finish_segment);
51 static Results *FindSuperRoute(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile,index_t start_node,index_t finish_node);
52
53
54 /*++++++++++++++++++++++++++++++++++++++
55 Find the optimum route between two nodes not passing through a super-node.
56
57 Results *FindNormalRoute Returns a set of results.
58
59 Nodes *nodes The set of nodes to use.
60
61 Segments *segments The set of segments to use.
62
63 Ways *ways The set of ways to use.
64
65 Relations *relations The set of relations to use.
66
67 Profile *profile The profile containing the transport type, speeds and allowed highways.
68
69 index_t start_node The start node.
70
71 index_t prev_segment The previous segment before the start node.
72
73 index_t finish_node The finish node.
74 ++++++++++++++++++++++++++++++++++++++*/
75
76 Results *FindNormalRoute(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile,index_t start_node,index_t prev_segment,index_t finish_node)
77 {
78 Results *results;
79 Queue *queue;
80 score_t finish_score;
81 double finish_lat,finish_lon;
82 Result *finish_result;
83 Result *result1,*result2;
84 int force_uturn=0;
85
86 #if DEBUG
87 printf(" FindNormalRoute(...,start_node=%"Pindex_t" prev_segment=%"Pindex_t" finish_node=%"Pindex_t")\n",start_node,prev_segment,finish_node);
88 #endif
89
90 /* Set up the finish conditions */
91
92 finish_score=INF_SCORE;
93 finish_result=NULL;
94
95 if(IsFakeNode(finish_node))
96 GetFakeLatLong(finish_node,&finish_lat,&finish_lon);
97 else
98 GetLatLong(nodes,finish_node,NULL,&finish_lat,&finish_lon);
99
100 /* Create the list of results and insert the first node into the queue */
101
102 results=NewResultsList(8);
103 queue=NewQueueList(8);
104
105 results->start_node=start_node;
106 results->prev_segment=prev_segment;
107
108 result1=InsertResult(results,results->start_node,results->prev_segment);
109
110 InsertInQueue(queue,result1,0);
111
112 /* Check for barrier at start waypoint - must perform U-turn */
113
114 if(prev_segment!=NO_SEGMENT && !IsFakeNode(start_node))
115 {
116 Node *startp=LookupNode(nodes,start_node,1);
117
118 if(!(startp->allow&profile->allow))
119 force_uturn=1;
120 }
121
122 /* Loop across all nodes in the queue */
123
124 while((result1=PopFromQueue(queue)))
125 {
126 Node *node1p=NULL;
127 Segment *segmentp;
128 index_t node1,seg1,seg1r;
129 index_t turnrelation=NO_RELATION;
130
131 /* score must be better than current best score */
132 if(result1->score>=finish_score)
133 continue;
134
135 node1=result1->node;
136 seg1=result1->segment;
137
138 if(IsFakeSegment(seg1))
139 seg1r=IndexRealSegment(seg1);
140 else
141 seg1r=seg1;
142
143 if(!IsFakeNode(node1))
144 node1p=LookupNode(nodes,node1,1);
145
146 /* lookup if a turn restriction applies */
147 if(profile->turns && node1p && IsTurnRestrictedNode(node1p))
148 turnrelation=FindFirstTurnRelation2(relations,node1,seg1r);
149
150 /* Loop across all segments */
151
152 if(IsFakeNode(node1))
153 segmentp=FirstFakeSegment(node1);
154 else
155 segmentp=FirstSegment(segments,node1p,1);
156
157 while(segmentp)
158 {
159 Node *node2p=NULL;
160 Way *wayp;
161 index_t node2,seg2,seg2r;
162 score_t segment_pref,segment_score,cumulative_score;
163 int i;
164
165 node2=OtherNode(segmentp,node1); /* need this here because we use node2 at the end of the loop */
166
167 /* must be a normal segment */
168 if(!IsNormalSegment(segmentp))
169 goto endloop;
170
171 /* must obey one-way restrictions (unless profile allows) */
172 if(profile->oneway && IsOnewayTo(segmentp,node1))
173 {
174 if(profile->allow!=Transports_Bicycle)
175 goto endloop;
176
177 wayp=LookupWay(ways,segmentp->way,1);
178
179 if(!(wayp->type&Highway_CycleBothWays))
180 goto endloop;
181 }
182
183 if(IsFakeNode(node1) || IsFakeNode(node2))
184 {
185 seg2 =IndexFakeSegment(segmentp);
186 seg2r=IndexRealSegment(seg2);
187 }
188 else
189 {
190 seg2 =IndexSegment(segments,segmentp);
191 seg2r=seg2;
192 }
193
194 /* must perform U-turn in special cases */
195 if(force_uturn && node1==results->start_node)
196 {
197 if(seg2r!=result1->segment)
198 goto endloop;
199 }
200 else
201 /* must not perform U-turn (unless profile allows) */
202 if(profile->turns && (seg1==seg2 || seg1==seg2r || seg1r==seg2 || (seg1r==seg2r && IsFakeUTurn(seg1,seg2))))
203 goto endloop;
204
205 /* must obey turn relations */
206 if(turnrelation!=NO_RELATION && !IsTurnAllowed(relations,turnrelation,node1,seg1r,seg2r,profile->allow))
207 goto endloop;
208
209 if(!IsFakeNode(node2))
210 node2p=LookupNode(nodes,node2,2);
211
212 /* must not pass over super-node */
213 if(node2!=finish_node && node2p && IsSuperNode(node2p))
214 goto endloop;
215
216 wayp=LookupWay(ways,segmentp->way,1);
217
218 /* mode of transport must be allowed on the highway */
219 if(!(wayp->allow&profile->allow))
220 goto endloop;
221
222 /* must obey weight restriction (if exists) */
223 if(wayp->weight && wayp->weight<profile->weight)
224 goto endloop;
225
226 /* must obey height/width/length restriction (if exist) */
227 if((wayp->height && wayp->height<profile->height) ||
228 (wayp->width && wayp->width <profile->width ) ||
229 (wayp->length && wayp->length<profile->length))
230 goto endloop;
231
232 segment_pref=profile->highway[HIGHWAY(wayp->type)];
233
234 /* highway preferences must allow this highway */
235 if(segment_pref==0)
236 goto endloop;
237
238 for(i=1;i<Property_Count;i++)
239 if(ways->file.props & PROPERTIES(i))
240 {
241 if(wayp->props & PROPERTIES(i))
242 segment_pref*=profile->props_yes[i];
243 else
244 segment_pref*=profile->props_no[i];
245 }
246
247 /* profile preferences must allow this highway */
248 if(segment_pref==0)
249 goto endloop;
250
251 /* mode of transport must be allowed through node2 unless it is the final node */
252 if(node2p && node2!=finish_node && !(node2p->allow&profile->allow))
253 goto endloop;
254
255 /* calculate the score for the segment and cumulative */
256 if(option_quickest==0)
257 segment_score=(score_t)DISTANCE(segmentp->distance)/segment_pref;
258 else
259 segment_score=(score_t)Duration(segmentp,wayp,profile)/segment_pref;
260
261 cumulative_score=result1->score+segment_score;
262
263 /* score must be better than current best score */
264 if(cumulative_score>=finish_score)
265 goto endloop;
266
267 /* find whether the node/segment combination already exists */
268 result2=FindResult(results,node2,seg2);
269
270 if(!result2) /* New end node/segment combination */
271 {
272 result2=InsertResult(results,node2,seg2);
273 result2->prev=result1;
274 result2->score=cumulative_score;
275 }
276 else if(cumulative_score<result2->score) /* New score for end node/segment combination is better */
277 {
278 result2->prev=result1;
279 result2->score=cumulative_score;
280 result2->segment=seg2;
281 }
282 else
283 goto endloop;
284
285 if(node2==finish_node)
286 {
287 finish_score=cumulative_score;
288 finish_result=result2;
289
290 results->finish_node=node2;
291 results->last_segment=seg2;
292 }
293 else
294 InsertInQueue(queue,result2,result2->score);
295
296 endloop:
297
298 if(IsFakeNode(node1))
299 segmentp=NextFakeSegment(segmentp,node1);
300 else if(IsFakeNode(node2))
301 segmentp=NULL; /* cannot call NextSegment() with a fake segment */
302 else
303 {
304 segmentp=NextSegment(segments,segmentp,node1);
305
306 if(!segmentp && IsFakeNode(finish_node))
307 segmentp=ExtraFakeSegment(node1,finish_node);
308 }
309 }
310 }
311
312 FreeQueueList(queue);
313
314 /* Check it worked */
315
316 if(!finish_result)
317 {
318 #if DEBUG
319 printf(" Failed\n");
320 #endif
321
322 FreeResultsList(results);
323 return(NULL);
324 }
325
326 FixForwardRoute(results,finish_result);
327
328 #if DEBUG
329 Result *r=FindResult(results,results->start_node,results->prev_segment);
330
331 while(r)
332 {
333 printf(" node=%"Pindex_t" segment=%"Pindex_t" score=%f\n",r->node,r->segment,r->score);
334
335 r=r->next;
336 }
337 #endif
338
339 return(results);
340 }
341
342
343 /*++++++++++++++++++++++++++++++++++++++
344 Find the optimum route between two nodes where the start and end are a set of pre/post-routed super-nodes.
345
346 Results *FindMiddleRoute Returns a set of results.
347
348 Nodes *nodes The set of nodes to use.
349
350 Segments *segments The set of segments to use.
351
352 Ways *ways The set of ways to use.
353
354 Relations *relations The set of relations to use.
355
356 Profile *profile The profile containing the transport type, speeds and allowed highways.
357
358 Results *begin The initial portion of the route.
359
360 Results *end The final portion of the route.
361 ++++++++++++++++++++++++++++++++++++++*/
362
363 Results *FindMiddleRoute(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile,Results *begin,Results *end)
364 {
365 Results *results;
366 Queue *queue;
367 Result *finish_result;
368 score_t finish_score;
369 double finish_lat,finish_lon;
370 Result *result1,*result2,*result3,*result4;
371 int force_uturn=0;
372
373 #if DEBUG
374 printf(" FindMiddleRoute(...,[begin has %d nodes],[end has %d nodes])\n",begin->number,end->number);
375 #endif
376
377 #if !DEBUG
378 if(!option_quiet)
379 printf_first("Finding Middle Route: Super-Nodes checked = 0");
380 #endif
381
382 /* Set up the finish conditions */
383
384 finish_score=INF_SCORE;
385 finish_result=NULL;
386
387 if(IsFakeNode(end->finish_node))
388 GetFakeLatLong(end->finish_node,&finish_lat,&finish_lon);
389 else
390 GetLatLong(nodes,end->finish_node,NULL,&finish_lat,&finish_lon);
391
392 /* Create the list of results and insert the first node into the queue */
393
394 results=NewResultsList(20);
395 queue=NewQueueList(12);
396
397 results->start_node=begin->start_node;
398 results->prev_segment=begin->prev_segment;
399
400 if(begin->number==1 && begin->prev_segment!=NO_SEGMENT)
401 {
402 index_t superseg=FindSuperSegment(nodes,segments,ways,relations,profile,begin->start_node,begin->prev_segment);
403
404 results->prev_segment=superseg;
405 }
406
407 result1=InsertResult(results,results->start_node,results->prev_segment);
408
409 /* Insert the finish points of the beginning part of the path into the queue,
410 translating the segments into super-segments. */
411
412 result3=FirstResult(begin);
413
414 while(result3)
415 {
416 if((results->start_node!=result3->node || results->prev_segment!=result3->segment) &&
417 !IsFakeNode(result3->node) && IsSuperNode(LookupNode(nodes,result3->node,3)))
418 {
419 Result *result5=result1;
420 index_t superseg=FindSuperSegment(nodes,segments,ways,relations,profile,result3->node,result3->segment);
421
422 if(superseg!=result3->segment)
423 {
424 result5=InsertResult(results,result3->node,result3->segment);
425
426 result5->score=result3->score;
427
428 result5->prev=result1;
429 }
430
431 if(!FindResult(results,result3->node,superseg))
432 {
433 result2=InsertResult(results,result3->node,superseg);
434 result2->prev=result5;
435
436 result2->score=result3->score;
437
438 InsertInQueue(queue,result2,result3->score);
439
440 if((result4=FindResult(end,result2->node,result2->segment)))
441 {
442 if((result2->score+result4->score)<finish_score)
443 {
444 finish_score=result2->score+result4->score;
445 finish_result=result2;
446 }
447 }
448 }
449 }
450
451 result3=NextResult(begin,result3);
452 }
453
454 if(begin->number==1)
455 InsertInQueue(queue,result1,0);
456
457 /* Check for barrier at start waypoint - must perform U-turn */
458
459 if(begin->number==1 && results->prev_segment!=NO_SEGMENT)
460 {
461 Node *startp=LookupNode(nodes,result1->node,1);
462
463 if(!(startp->allow&profile->allow))
464 force_uturn=1;
465 }
466
467 /* Loop across all nodes in the queue */
468
469 while((result1=PopFromQueue(queue)))
470 {
471 Node *node1p;
472 Segment *segmentp;
473 index_t node1,seg1;
474 index_t turnrelation=NO_RELATION;
475
476 /* score must be better than current best score */
477 if(result1->score>=finish_score)
478 continue;
479
480 node1=result1->node;
481 seg1=result1->segment;
482
483 node1p=LookupNode(nodes,node1,1); /* node1 cannot be a fake node (must be a super-node) */
484
485 /* lookup if a turn restriction applies */
486 if(profile->turns && IsTurnRestrictedNode(node1p)) /* node1 cannot be a fake node (must be a super-node) */
487 turnrelation=FindFirstTurnRelation2(relations,node1,seg1);
488
489 /* Loop across all segments */
490
491 segmentp=FirstSegment(segments,node1p,1); /* node1 cannot be a fake node (must be a super-node) */
492
493 while(segmentp)
494 {
495 Node *node2p;
496 Way *wayp;
497 index_t node2,seg2;
498 score_t segment_pref,segment_score,cumulative_score;
499 int i;
500
501 /* must be a super segment */
502 if(!IsSuperSegment(segmentp))
503 goto endloop;
504
505 /* must obey one-way restrictions (unless profile allows) */
506 if(profile->oneway && IsOnewayTo(segmentp,node1))
507 {
508 if(profile->allow!=Transports_Bicycle)
509 goto endloop;
510
511 wayp=LookupWay(ways,segmentp->way,1);
512
513 if(!(wayp->type&Highway_CycleBothWays))
514 goto endloop;
515 }
516
517 seg2=IndexSegment(segments,segmentp); /* segment cannot be a fake segment (must be a super-segment) */
518
519 /* must perform U-turn in special cases */
520 if(force_uturn && node1==results->start_node)
521 {
522 if(seg2!=result1->segment)
523 goto endloop;
524 }
525 else
526 /* must not perform U-turn */
527 if(seg1==seg2) /* No fake segments, applies to all profiles */
528 goto endloop;
529
530 /* must obey turn relations */
531 if(turnrelation!=NO_RELATION && !IsTurnAllowed(relations,turnrelation,node1,seg1,seg2,profile->allow))
532 goto endloop;
533
534 wayp=LookupWay(ways,segmentp->way,1);
535
536 /* mode of transport must be allowed on the highway */
537 if(!(wayp->allow&profile->allow))
538 goto endloop;
539
540 /* must obey weight restriction (if exists) */
541 if(wayp->weight && wayp->weight<profile->weight)
542 goto endloop;
543
544 /* must obey height/width/length restriction (if exist) */
545 if((wayp->height && wayp->height<profile->height) ||
546 (wayp->width && wayp->width <profile->width ) ||
547 (wayp->length && wayp->length<profile->length))
548 goto endloop;
549
550 segment_pref=profile->highway[HIGHWAY(wayp->type)];
551
552 /* highway preferences must allow this highway */
553 if(segment_pref==0)
554 goto endloop;
555
556 for(i=1;i<Property_Count;i++)
557 if(ways->file.props & PROPERTIES(i))
558 {
559 if(wayp->props & PROPERTIES(i))
560 segment_pref*=profile->props_yes[i];
561 else
562 segment_pref*=profile->props_no[i];
563 }
564
565 /* profile preferences must allow this highway */
566 if(segment_pref==0)
567 goto endloop;
568
569 node2=OtherNode(segmentp,node1);
570
571 node2p=LookupNode(nodes,node2,2); /* node2 cannot be a fake node (must be a super-node) */
572
573 /* mode of transport must be allowed through node2 unless it is the final node */
574 if(node2!=end->finish_node && !(node2p->allow&profile->allow))
575 goto endloop;
576
577 /* calculate the score for the segment and cumulative */
578 if(option_quickest==0)
579 segment_score=(score_t)DISTANCE(segmentp->distance)/segment_pref;
580 else
581 segment_score=(score_t)Duration(segmentp,wayp,profile)/segment_pref;
582
583 cumulative_score=result1->score+segment_score;
584
585 /* score must be better than current best score */
586 if(cumulative_score>=finish_score)
587 goto endloop;
588
589 /* find whether the node/segment combination already exists */
590 result2=FindResult(results,node2,seg2);
591
592 if(!result2) /* New end node/segment pair */
593 {
594 result2=InsertResult(results,node2,seg2);
595 result2->prev=result1;
596 result2->score=cumulative_score;
597 }
598 else if(cumulative_score<result2->score) /* New end node/segment pair is better */
599 {
600 result2->prev=result1;
601 result2->score=cumulative_score;
602 }
603 else
604 goto endloop;
605
606 if((result3=FindResult(end,node2,seg2)))
607 {
608 if((result2->score+result3->score)<finish_score)
609 {
610 finish_score=result2->score+result3->score;
611 finish_result=result2;
612
613 results->finish_node=node2;
614 results->last_segment=seg2;
615 }
616 }
617 else
618 {
619 double lat,lon;
620 distance_t direct;
621 score_t potential_score;
622
623 GetLatLong(nodes,node2,node2p,&lat,&lon); /* node2 cannot be a fake node (must be a super-node) */
624
625 direct=Distance(lat,lon,finish_lat,finish_lon);
626
627 if(option_quickest==0)
628 potential_score=result2->score+(score_t)direct/profile->max_pref;
629 else
630 potential_score=result2->score+(score_t)distance_speed_to_duration(direct,profile->max_speed)/profile->max_pref;
631
632 if(potential_score<finish_score)
633 InsertInQueue(queue,result2,potential_score);
634 }
635
636 endloop:
637
638 segmentp=NextSegment(segments,segmentp,node1); /* node1 cannot be a fake node (must be a super-node) */
639 }
640 }
641
642 FreeQueueList(queue);
643
644 /* Check it worked */
645
646 if(!finish_result)
647 {
648 #if DEBUG
649 printf(" Failed\n");
650 #endif
651
652 #if !DEBUG
653 if(!option_quiet)
654 printf_last("Found Middle Route: Super-Nodes checked = %d - Fail",results->number);
655 #endif
656
657 FreeResultsList(results);
658 return(NULL);
659 }
660
661 FixForwardRoute(results,finish_result);
662
663 #if DEBUG
664 Result *r=FindResult(results,results->start_node,results->prev_segment);
665
666 while(r)
667 {
668 printf(" node=%"Pindex_t" segment=%"Pindex_t" score=%f\n",r->node,r->segment,r->score);
669
670 r=r->next;
671 }
672 #endif
673
674 #if !DEBUG
675 if(!option_quiet)
676 printf_last("Found Middle Route: Super-Nodes checked = %d",results->number);
677 #endif
678
679 return(results);
680 }
681
682
683 /*++++++++++++++++++++++++++++++++++++++
684 Find the super-segment that represents the route that contains a particular segment.
685
686 index_t FindSuperSegment Returns the index of the super-segment.
687
688 Nodes *nodes The set of nodes to use.
689
690 Segments *segments The set of segments to use.
691
692 Ways *ways The set of ways to use.
693
694 Relations *relations The set of relations to use.
695
696 Profile *profile The profile containing the transport type, speeds and allowed highways.
697
698 index_t finish_node The super-node that the route ends at.
699
700 index_t finish_segment The segment that the route ends with.
701 ++++++++++++++++++++++++++++++++++++++*/
702
703 static index_t FindSuperSegment(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile,index_t finish_node,index_t finish_segment)
704 {
705 Node *supernodep;
706 Segment *supersegmentp;
707
708 if(IsFakeSegment(finish_segment))
709 finish_segment=IndexRealSegment(finish_segment);
710
711 supernodep=LookupNode(nodes,finish_node,3); /* finish_node cannot be a fake node (must be a super-node) */
712 supersegmentp=LookupSegment(segments,finish_segment,4); /* finish_segment cannot be a fake segment. */
713
714 if(IsSuperSegment(supersegmentp))
715 return(finish_segment);
716
717 /* Loop across all segments */
718
719 supersegmentp=FirstSegment(segments,supernodep,4); /* supernode cannot be a fake node (must be a super-node) */
720
721 while(supersegmentp)
722 {
723 if(IsSuperSegment(supersegmentp))
724 {
725 Results *results;
726 Result *result;
727 index_t start_node;
728
729 start_node=OtherNode(supersegmentp,finish_node);
730
731 results=FindSuperRoute(nodes,segments,ways,relations,profile,start_node,finish_node);
732
733 if(!results)
734 continue;
735
736 result=FindResult(results,finish_node,finish_segment);
737
738 if(result && (distance_t)result->score==DISTANCE(supersegmentp->distance))
739 {
740 FreeResultsList(results);
741 return(IndexSegment(segments,supersegmentp));
742 }
743
744 if(results)
745 FreeResultsList(results);
746 }
747
748 supersegmentp=NextSegment(segments,supersegmentp,finish_node); /* finish_node cannot be a fake node (must be a super-node) */
749 }
750
751 return(finish_segment);
752 }
753
754
755 /*++++++++++++++++++++++++++++++++++++++
756 Find the shortest route between two super-nodes using only normal nodes.
757 This is effectively the same function as is used in superx.c when finding super-segments initially.
758
759 Results *FindSuperRoute Returns a set of results.
760
761 Nodes *nodes The set of nodes to use.
762
763 Segments *segments The set of segments to use.
764
765 Ways *ways The set of ways to use.
766
767 Relations *relations The set of relations to use.
768
769 Profile *profile The profile containing the transport type, speeds and allowed highways.
770
771 index_t start_node The start node.
772
773 index_t finish_node The finish node.
774 ++++++++++++++++++++++++++++++++++++++*/
775
776 static Results *FindSuperRoute(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile,index_t start_node,index_t finish_node)
777 {
778 Results *results;
779 Queue *queue;
780 Result *result1,*result2;
781
782 #if DEBUG
783 printf(" FindSuperRoute(...,start_node=%"Pindex_t" finish_node=%"Pindex_t")\n",start_node,finish_node);
784 #endif
785
786 /* Create the list of results and insert the first node into the queue */
787
788 results=NewResultsList(8);
789 queue=NewQueueList(8);
790
791 results->start_node=start_node;
792 results->prev_segment=NO_SEGMENT;
793
794 result1=InsertResult(results,results->start_node,results->prev_segment);
795
796 InsertInQueue(queue,result1,0);
797
798 /* Loop across all nodes in the queue */
799
800 while((result1=PopFromQueue(queue)))
801 {
802 Node *node1p=NULL;
803 Segment *segmentp;
804 index_t node1,seg1;
805
806 node1=result1->node;
807 seg1=result1->segment;
808
809 node1p=LookupNode(nodes,node1,3); /* node1 cannot be a fake node */
810
811 /* Loop across all segments */
812
813 segmentp=FirstSegment(segments,node1p,3); /* node1 cannot be a fake node */
814
815 while(segmentp)
816 {
817 Node *node2p=NULL;
818 index_t node2,seg2;
819 score_t cumulative_score;
820
821 /* must be a normal segment */
822 if(!IsNormalSegment(segmentp))
823 goto endloop;
824
825 /* must obey one-way restrictions */
826 if(IsOnewayTo(segmentp,node1))
827 {
828 Way *wayp;
829
830 if(profile->allow!=Transports_Bicycle)
831 goto endloop;
832
833 wayp=LookupWay(ways,segmentp->way,2);
834
835 if(!(wayp->type&Highway_CycleBothWays))
836 goto endloop;
837 }
838
839 seg2=IndexSegment(segments,segmentp);
840
841 /* must not perform U-turn */
842 if(seg1==seg2)
843 goto endloop;
844
845 node2=OtherNode(segmentp,node1);
846
847 node2p=LookupNode(nodes,node2,4); /* node2 cannot be a fake node */
848
849 /* must not pass over super-node */
850 if(node2!=finish_node && IsSuperNode(node2p))
851 goto endloop;
852
853 /* Specifically looking for the shortest route to emulate superx.c */
854 cumulative_score=result1->score+(score_t)DISTANCE(segmentp->distance);
855
856 result2=FindResult(results,node2,seg2);
857
858 if(!result2) /* New end node/segment combination */
859 {
860 result2=InsertResult(results,node2,seg2);
861 result2->prev=result1;
862 result2->score=cumulative_score;
863 }
864 else if(cumulative_score<result2->score) /* New score for end node/segment combination is better */
865 {
866 result2->prev=result1;
867 result2->segment=seg2;
868 result2->score=cumulative_score;
869 }
870 else goto endloop;
871
872 /* don't route beyond a super-node. */
873 if(!IsSuperNode(node2p))
874 InsertInQueue(queue,result2,result2->score);
875
876 endloop:
877
878 segmentp=NextSegment(segments,segmentp,node1);
879 }
880 }
881
882 FreeQueueList(queue);
883
884 #if DEBUG
885 Result *r=FindResult(results,results->start_node,results->prev_segment);
886
887 while(r)
888 {
889 printf(" node=%"Pindex_t" segment=%"Pindex_t" score=%f\n",r->node,r->segment,r->score);
890
891 r=r->next;
892 }
893 #endif
894
895 return(results);
896 }
897
898
899 /*++++++++++++++++++++++++++++++++++++++
900 Find all routes from a specified node to any super-node.
901
902 Results *FindStartRoutes Returns a set of results.
903
904 Nodes *nodes The set of nodes to use.
905
906 Segments *segments The set of segments to use.
907
908 Ways *ways The set of ways to use.
909
910 Relations *relations The set of relations to use.
911
912 Profile *profile The profile containing the transport type, speeds and allowed highways.
913
914 index_t start_node The start node.
915
916 index_t prev_segment The previous segment before the start node.
917
918 index_t finish_node The finish node.
919 ++++++++++++++++++++++++++++++++++++++*/
920
921 Results *FindStartRoutes(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile,index_t start_node,index_t prev_segment,index_t finish_node)
922 {
923 Results *results;
924 Queue *queue;
925 Result *result1,*result2;
926 int nsuper=0,force_uturn=0;
927
928 #if DEBUG
929 printf(" FindStartRoutes(...,start_node=%"Pindex_t" prev_segment=%"Pindex_t" finish_node=%"Pindex_t")\n",start_node,prev_segment,finish_node);
930 #endif
931
932 #if !DEBUG
933 if(!option_quiet)
934 printf_first("Finding Start Route: Nodes checked = 0");
935 #endif
936
937 /* Create the list of results and insert the first node into the queue */
938
939 results=NewResultsList(8);
940 queue=NewQueueList(8);
941
942 results->start_node=start_node;
943 results->prev_segment=prev_segment;
944
945 result1=InsertResult(results,results->start_node,results->prev_segment);
946
947 InsertInQueue(queue,result1,0);
948
949 /* Check for barrier at start waypoint - must perform U-turn */
950
951 if(prev_segment!=NO_SEGMENT && !IsFakeNode(start_node))
952 {
953 Node *startp=LookupNode(nodes,start_node,1);
954
955 if(!(startp->allow&profile->allow))
956 force_uturn=1;
957 }
958
959 /* Loop across all nodes in the queue */
960
961 while((result1=PopFromQueue(queue)))
962 {
963 Node *node1p=NULL;
964 Segment *segmentp;
965 index_t node1,seg1,seg1r;
966 index_t turnrelation=NO_RELATION;
967
968 node1=result1->node;
969 seg1=result1->segment;
970
971 if(IsFakeSegment(seg1))
972 seg1r=IndexRealSegment(seg1);
973 else
974 seg1r=seg1;
975
976 if(!IsFakeNode(node1))
977 node1p=LookupNode(nodes,node1,1);
978
979 /* lookup if a turn restriction applies */
980 if(profile->turns && node1p && IsTurnRestrictedNode(node1p))
981 turnrelation=FindFirstTurnRelation2(relations,node1,seg1r);
982
983 /* Loop across all segments */
984
985 if(IsFakeNode(node1))
986 segmentp=FirstFakeSegment(node1);
987 else
988 segmentp=FirstSegment(segments,node1p,1);
989
990 while(segmentp)
991 {
992 Node *node2p=NULL;
993 Way *wayp;
994 index_t node2,seg2,seg2r;
995 score_t segment_pref,segment_score,cumulative_score;
996 int i;
997
998 node2=OtherNode(segmentp,node1); /* need this here because we use node2 at the end of the loop */
999
1000 /* must be a normal segment */
1001 if(!IsNormalSegment(segmentp))
1002 goto endloop;
1003
1004 /* must obey one-way restrictions (unless profile allows) */
1005 if(profile->oneway && IsOnewayTo(segmentp,node1))
1006 {
1007 if(profile->allow!=Transports_Bicycle)
1008 goto endloop;
1009
1010 wayp=LookupWay(ways,segmentp->way,1);
1011
1012 if(!(wayp->type&Highway_CycleBothWays))
1013 goto endloop;
1014 }
1015
1016 if(IsFakeNode(node1) || IsFakeNode(node2))
1017 {
1018 seg2 =IndexFakeSegment(segmentp);
1019 seg2r=IndexRealSegment(seg2);
1020 }
1021 else
1022 {
1023 seg2 =IndexSegment(segments,segmentp);
1024 seg2r=seg2;
1025 }
1026
1027 /* must perform U-turn in special cases */
1028 if(node1==start_node && force_uturn)
1029 {
1030 if(seg2r!=result1->segment)
1031 goto endloop;
1032 }
1033 else
1034 /* must not perform U-turn (unless profile allows) */
1035 if(profile->turns && (seg1==seg2 || seg1==seg2r || seg1r==seg2 || (seg1r==seg2r && IsFakeUTurn(seg1,seg2))))
1036 goto endloop;
1037
1038 /* must obey turn relations */
1039 if(turnrelation!=NO_RELATION && !IsTurnAllowed(relations,turnrelation,node1,seg1r,seg2r,profile->allow))
1040 goto endloop;
1041
1042 wayp=LookupWay(ways,segmentp->way,1);
1043
1044 /* mode of transport must be allowed on the highway */
1045 if(!(wayp->allow&profile->allow))
1046 goto endloop;
1047
1048 /* must obey weight restriction (if exists) */
1049 if(wayp->weight && wayp->weight<profile->weight)
1050 goto endloop;
1051
1052 /* must obey height/width/length restriction (if exists) */
1053 if((wayp->height && wayp->height<profile->height) ||
1054 (wayp->width && wayp->width <profile->width ) ||
1055 (wayp->length && wayp->length<profile->length))
1056 goto endloop;
1057
1058 segment_pref=profile->highway[HIGHWAY(wayp->type)];
1059
1060 /* highway preferences must allow this highway */
1061 if(segment_pref==0)
1062 goto endloop;
1063
1064 for(i=1;i<Property_Count;i++)
1065 if(ways->file.props & PROPERTIES(i))
1066 {
1067 if(wayp->props & PROPERTIES(i))
1068 segment_pref*=profile->props_yes[i];
1069 else
1070 segment_pref*=profile->props_no[i];
1071 }
1072
1073 /* profile preferences must allow this highway */
1074 if(segment_pref==0)
1075 goto endloop;
1076
1077 if(!IsFakeNode(node2))
1078 node2p=LookupNode(nodes,node2,2);
1079
1080 /* mode of transport must be allowed through node2 unless it is the final node */
1081 if(node2p && node2!=finish_node && !(node2p->allow&profile->allow))
1082 goto endloop;
1083
1084 /* calculate the score for the segment and cumulative */
1085 if(option_quickest==0)
1086 segment_score=(score_t)DISTANCE(segmentp->distance)/segment_pref;
1087 else
1088 segment_score=(score_t)Duration(segmentp,wayp,profile)/segment_pref;
1089
1090 /* prefer not to follow two fake segments when one would do (special case) */
1091 if(IsFakeSegment(seg2))
1092 segment_score*=1.01;
1093
1094 cumulative_score=result1->score+segment_score;
1095
1096 /* find whether the node/segment combination already exists */
1097 result2=FindResult(results,node2,seg2);
1098
1099 if(!result2) /* New end node/segment combination */
1100 {
1101 result2=InsertResult(results,node2,seg2);
1102 result2->prev=result1;
1103 result2->score=cumulative_score;
1104
1105 if(node2p && IsSuperNode(node2p))
1106 nsuper++;
1107
1108 if(node2==finish_node)
1109 nsuper++;
1110
1111 if(node2==finish_node)
1112 {
1113 results->finish_node=node2;
1114 results->last_segment=seg2;
1115 }
1116 }
1117 else if(cumulative_score<result2->score) /* New score for end node/segment combination is better */
1118 {
1119 result2->prev=result1;
1120 result2->score=cumulative_score;
1121
1122 if(node2==finish_node)
1123 {
1124 results->finish_node=node2;
1125 results->last_segment=seg2;
1126 }
1127 }
1128 else
1129 goto endloop;
1130
1131 if(node2p && !IsSuperNode(node2p))
1132 InsertInQueue(queue,result2,result2->score);
1133
1134 endloop:
1135
1136 if(IsFakeNode(node1))
1137 segmentp=NextFakeSegment(segmentp,node1);
1138 else if(IsFakeNode(node2))
1139 segmentp=NULL; /* cannot call NextSegment() with a fake segment */
1140 else
1141 {
1142 segmentp=NextSegment(segments,segmentp,node1);
1143
1144 if(!segmentp && IsFakeNode(finish_node))
1145 segmentp=ExtraFakeSegment(node1,finish_node);
1146 }
1147 }
1148 }
1149
1150 FreeQueueList(queue);
1151
1152 /* Check it worked */
1153
1154 if(results->number==1 || nsuper==0)
1155 {
1156 #if DEBUG
1157 printf(" Failed (%d results, %d super)\n",results->number,nsuper);
1158 #endif
1159
1160 #if !DEBUG
1161 if(!option_quiet)
1162 printf_last("Found Start Route: Nodes checked = %d - Fail",results->number);
1163 #endif
1164
1165 FreeResultsList(results);
1166 return(NULL);
1167 }
1168
1169 #if DEBUG
1170 Result *s=FirstResult(results);
1171
1172 while(s)
1173 {
1174 if(s->node==finish_node)
1175 {
1176 Result *r=FindResult(results,s->node,s->segment);
1177
1178 printf(" -------- route to finish node\n");
1179
1180 while(r)
1181 {
1182 printf(" node=%"Pindex_t" segment=%"Pindex_t" score=%f\n",r->node,r->segment,r->score);
1183
1184 r=r->prev;
1185 }
1186 }
1187
1188 if(!IsFakeNode(s->node))
1189 {
1190 Node *n=LookupNode(nodes,s->node,1);
1191
1192 if(IsSuperNode(n))
1193 {
1194 Result *r=FindResult(results,s->node,s->segment);
1195
1196 printf(" -------- route to super node\n");
1197
1198 while(r)
1199 {
1200 printf(" node=%"Pindex_t" segment=%"Pindex_t" score=%f\n",r->node,r->segment,r->score);
1201
1202 r=r->prev;
1203 }
1204 }
1205 }
1206
1207 s=NextResult(results,s);
1208 }
1209 #endif
1210
1211 #if !DEBUG
1212 if(!option_quiet)
1213 printf_last("Found Start Route: Nodes checked = %d",results->number);
1214 #endif
1215
1216 return(results);
1217 }
1218
1219
1220 /*++++++++++++++++++++++++++++++++++++++
1221 Continue finding routes from a set of super-nodes to a finish point.
1222
1223 Results *ExtendStartRoutes Returns the set of results that were passed in.
1224
1225 Nodes *nodes The set of nodes to use.
1226
1227 Segments *segments The set of segments to use.
1228
1229 Ways *ways The set of ways to use.
1230
1231 Relations *relations The set of relations to use.
1232
1233 Profile *profile The profile containing the transport type, speeds and allowed highways.
1234
1235 Results *begin The partial set of routes already computed.
1236
1237 index_t finish_node The finish node.
1238 ++++++++++++++++++++++++++++++++++++++*/
1239
1240 Results *ExtendStartRoutes(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile,Results *begin,index_t finish_node)
1241 {
1242 Results *results=begin;
1243 Queue *queue;
1244 Result *result1,*result2,*result3;
1245 Result *finish_result=NULL;
1246 score_t finish_score=INF_SCORE;
1247
1248 #if DEBUG
1249 printf(" ExtendStartRoutes(...,[begin has %d nodes],finish_node=%"Pindex_t")\n",begin->number,finish_node);
1250 #endif
1251
1252 #if !DEBUG
1253 if(!option_quiet)
1254 printf_first("Extending Start Route: Nodes checked = 0");
1255 #endif
1256
1257 /* Check the list of results and insert the super nodes into the queue */
1258
1259 queue=NewQueueList(8);
1260
1261 result3=FirstResult(begin);
1262
1263 while(result3)
1264 {
1265 if(result3->node==finish_node)
1266 if(result3->score<finish_score)
1267 {
1268 finish_score=result3->score;
1269 finish_result=result3;
1270 }
1271
1272 if(!IsFakeNode(result3->node))
1273 if(IsSuperNode(LookupNode(nodes,result3->node,3)))
1274 InsertInQueue(queue,result3,result3->score);
1275
1276 result3=NextResult(results,result3);
1277 }
1278
1279 /* Loop across all nodes in the queue */
1280
1281 while((result1=PopFromQueue(queue)))
1282 {
1283 Node *node1p=NULL;
1284 Segment *segmentp;
1285 index_t node1,seg1,seg1r;
1286 index_t turnrelation=NO_RELATION;
1287
1288 /* score must be better than current best score */
1289 if(result1->score>=finish_score)
1290 continue;
1291
1292 node1=result1->node;
1293 seg1=result1->segment;
1294
1295 if(IsFakeSegment(seg1))
1296 seg1r=IndexRealSegment(seg1);
1297 else
1298 seg1r=seg1;
1299
1300 if(!IsFakeNode(node1))
1301 node1p=LookupNode(nodes,node1,1);
1302
1303 /* lookup if a turn restriction applies */
1304 if(profile->turns && node1p && IsTurnRestrictedNode(node1p))
1305 turnrelation=FindFirstTurnRelation2(relations,node1,seg1r);
1306
1307 /* Loop across all segments */
1308
1309 if(IsFakeNode(node1))
1310 segmentp=FirstFakeSegment(node1);
1311 else
1312 segmentp=FirstSegment(segments,node1p,1);
1313
1314 while(segmentp)
1315 {
1316 Node *node2p=NULL;
1317 Way *wayp;
1318 index_t node2,seg2,seg2r;
1319 score_t segment_pref,segment_score,cumulative_score;
1320 int i;
1321
1322 node2=OtherNode(segmentp,node1); /* need this here because we use node2 at the end of the loop */
1323
1324 /* must be a normal segment */
1325 if(!IsNormalSegment(segmentp))
1326 goto endloop;
1327
1328 /* must obey one-way restrictions (unless profile allows) */
1329 if(profile->oneway && IsOnewayTo(segmentp,node1))
1330 {
1331 if(profile->allow!=Transports_Bicycle)
1332 goto endloop;
1333
1334 wayp=LookupWay(ways,segmentp->way,1);
1335
1336 if(!(wayp->type&Highway_CycleBothWays))
1337 goto endloop;
1338 }
1339
1340 if(IsFakeNode(node1) || IsFakeNode(node2))
1341 {
1342 seg2 =IndexFakeSegment(segmentp);
1343 seg2r=IndexRealSegment(seg2);
1344 }
1345 else
1346 {
1347 seg2 =IndexSegment(segments,segmentp);
1348 seg2r=seg2;
1349 }
1350
1351 /* must not perform U-turn (unless profile allows) */
1352 if(profile->turns && (seg1==seg2 || seg1==seg2r || seg1r==seg2 || (seg1r==seg2r && IsFakeUTurn(seg1,seg2))))
1353 goto endloop;
1354
1355 /* must obey turn relations */
1356 if(turnrelation!=NO_RELATION && !IsTurnAllowed(relations,turnrelation,node1,seg1r,seg2r,profile->allow))
1357 goto endloop;
1358
1359 wayp=LookupWay(ways,segmentp->way,1);
1360
1361 /* mode of transport must be allowed on the highway */
1362 if(!(wayp->allow&profile->allow))
1363 goto endloop;
1364
1365 /* must obey weight restriction (if exists) */
1366 if(wayp->weight && wayp->weight<profile->weight)
1367 goto endloop;
1368
1369 /* must obey height/width/length restriction (if exists) */
1370 if((wayp->height && wayp->height<profile->height) ||
1371 (wayp->width && wayp->width <profile->width ) ||
1372 (wayp->length && wayp->length<profile->length))
1373 goto endloop;
1374
1375 segment_pref=profile->highway[HIGHWAY(wayp->type)];
1376
1377 /* highway preferences must allow this highway */
1378 if(segment_pref==0)
1379 goto endloop;
1380
1381 for(i=1;i<Property_Count;i++)
1382 if(ways->file.props & PROPERTIES(i))
1383 {
1384 if(wayp->props & PROPERTIES(i))
1385 segment_pref*=profile->props_yes[i];
1386 else
1387 segment_pref*=profile->props_no[i];
1388 }
1389
1390 /* profile preferences must allow this highway */
1391 if(segment_pref==0)
1392 goto endloop;
1393
1394 if(!IsFakeNode(node2))
1395 node2p=LookupNode(nodes,node2,2);
1396
1397 /* mode of transport must be allowed through node2 unless it is the final node */
1398 if(node2p && node2!=finish_node && !(node2p->allow&profile->allow))
1399 goto endloop;
1400
1401 /* calculate the score for the segment and cumulative */
1402 if(option_quickest==0)
1403 segment_score=(score_t)DISTANCE(segmentp->distance)/segment_pref;
1404 else
1405 segment_score=(score_t)Duration(segmentp,wayp,profile)/segment_pref;
1406
1407 /* prefer not to follow two fake segments when one would do (special case) */
1408 if(IsFakeSegment(seg2))
1409 segment_score*=1.01;
1410
1411 cumulative_score=result1->score+segment_score;
1412
1413 /* score must be better than current best score */
1414 if(cumulative_score>=finish_score)
1415 goto endloop;
1416
1417 /* find whether the node/segment combination already exists */
1418 result2=FindResult(results,node2,seg2);
1419
1420 if(!result2) /* New end node/segment combination */
1421 {
1422 result2=InsertResult(results,node2,seg2);
1423 result2->prev=result1;
1424 result2->score=cumulative_score;
1425 }
1426 else if(cumulative_score<result2->score) /* New score for end node/segment combination is better */
1427 {
1428 result2->prev=result1;
1429 result2->score=cumulative_score;
1430 }
1431 else
1432 goto endloop;
1433
1434 if(node2==finish_node)
1435 {
1436 if(cumulative_score<finish_score)
1437 {
1438 finish_score=cumulative_score;
1439 finish_result=result2;
1440
1441 results->finish_node=node2;
1442 results->last_segment=seg2;
1443 }
1444 }
1445 else
1446 InsertInQueue(queue,result2,result2->score);
1447
1448 endloop:
1449
1450 if(IsFakeNode(node1))
1451 segmentp=NextFakeSegment(segmentp,node1);
1452 else if(IsFakeNode(node2))
1453 segmentp=NULL; /* cannot call NextSegment() with a fake segment */
1454 else
1455 {
1456 segmentp=NextSegment(segments,segmentp,node1);
1457
1458 if(!segmentp && IsFakeNode(finish_node))
1459 segmentp=ExtraFakeSegment(node1,finish_node);
1460 }
1461 }
1462 }
1463
1464 FreeQueueList(queue);
1465
1466 FixForwardRoute(results,finish_result);
1467
1468 #if DEBUG
1469 Result *r=FindResult(results,results->start_node,results->prev_segment);
1470
1471 while(r)
1472 {
1473 printf(" node=%"Pindex_t" segment=%"Pindex_t" score=%f\n",r->node,r->segment,r->score);
1474
1475 r=r->next;
1476 }
1477 #endif
1478
1479 #if !DEBUG
1480 if(!option_quiet)
1481 printf_last("Extended Start Route: Nodes checked = %d",results->number);
1482 #endif
1483
1484 return(results);
1485 }
1486
1487
1488 /*++++++++++++++++++++++++++++++++++++++
1489 Find all routes from any super-node to a specific node (by working backwards from the specific node to all super-nodes).
1490
1491 Results *FindFinishRoutes Returns a set of results.
1492
1493 Nodes *nodes The set of nodes to use.
1494
1495 Segments *segments The set of segments to use.
1496
1497 Ways *ways The set of ways to use.
1498
1499 Relations *relations The set of relations to use.
1500
1501 Profile *profile The profile containing the transport type, speeds and allowed highways.
1502
1503 index_t finish_node The finishing node.
1504 ++++++++++++++++++++++++++++++++++++++*/
1505
1506 Results *FindFinishRoutes(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile,index_t finish_node)
1507 {
1508 Results *results,*results2;
1509 Queue *queue;
1510 Result *result1,*result2,*result3;
1511
1512 #if DEBUG
1513 printf(" FindFinishRoutes(...,finish_node=%"Pindex_t")\n",finish_node);
1514 #endif
1515
1516 #if !DEBUG
1517 if(!option_quiet)
1518 printf_first("Finding Finish Route: Nodes checked = 0");
1519 #endif
1520
1521 /* Create the results and insert the finish node into the queue */
1522
1523 results=NewResultsList(8);
1524 queue=NewQueueList(8);
1525
1526 results->finish_node=finish_node;
1527
1528 result1=InsertResult(results,finish_node,NO_SEGMENT);
1529
1530 InsertInQueue(queue,result1,0);
1531
1532 /* Loop across all nodes in the queue */
1533
1534 while((result1=PopFromQueue(queue)))
1535 {
1536 Node *node1p=NULL;
1537 Segment *segmentp;
1538 index_t node1,seg1,seg1r;
1539 index_t turnrelation=NO_RELATION;
1540
1541 node1=result1->node;
1542 seg1=result1->segment;
1543
1544 if(seg1!=NO_SEGMENT && IsFakeSegment(seg1))
1545 seg1r=IndexRealSegment(seg1);
1546 else
1547 seg1r=seg1;
1548
1549 if(!IsFakeNode(node1))
1550 node1p=LookupNode(nodes,node1,1);
1551
1552 /* lookup if a turn restriction applies */
1553 if(profile->turns && node1p && IsTurnRestrictedNode(node1p))
1554 turnrelation=FindFirstTurnRelation1(relations,node1); /* working backwards => turn relation sort order doesn't help */
1555
1556 /* Loop across all segments */
1557
1558 if(IsFakeNode(node1))
1559 segmentp=FirstFakeSegment(node1);
1560 else
1561 segmentp=FirstSegment(segments,node1p,1);
1562
1563 while(segmentp)
1564 {
1565 Node *node2p=NULL;
1566 Way *wayp;
1567 index_t node2,seg2,seg2r;
1568 score_t segment_pref,segment_score,cumulative_score;
1569 int i;
1570
1571 /* must be a normal segment unless node1 is a super-node (see below). */
1572 if((IsFakeNode(node1) || !IsSuperNode(node1p)) && !IsNormalSegment(segmentp))
1573 goto endloop;
1574
1575 /* must be a super segment if node1 is a super-node to give starting super-segment for finding middle route. */
1576 if((!IsFakeNode(node1) && IsSuperNode(node1p)) && !IsSuperSegment(segmentp))
1577 goto endloop;
1578
1579 /* must obey one-way restrictions (unless profile allows) */
1580 if(profile->oneway && IsOnewayFrom(segmentp,node1)) /* working backwards => disallow oneway *from* node1 */
1581 {
1582 if(profile->allow!=Transports_Bicycle)
1583 goto endloop;
1584
1585 wayp=LookupWay(ways,segmentp->way,1);
1586
1587 if(!(wayp->type&Highway_CycleBothWays))
1588 goto endloop;
1589 }
1590
1591 node2=OtherNode(segmentp,node1);
1592
1593 if(IsFakeNode(node1) || IsFakeNode(node2))
1594 {
1595 seg2 =IndexFakeSegment(segmentp);
1596 seg2r=IndexRealSegment(seg2);
1597 }
1598 else
1599 {
1600 seg2 =IndexSegment(segments,segmentp);
1601 seg2r=seg2;
1602 }
1603
1604 /* must not perform U-turn (unless profile allows) */
1605 if(profile->turns && seg1!=NO_SEGMENT)
1606 {
1607 if(IsFakeNode(node1) || !IsSuperNode(node1p))
1608 {
1609 if(seg1==seg2 || seg1==seg2r || seg1r==seg2 || (seg1r==seg2r && IsFakeUTurn(seg1,seg2)))
1610 goto endloop;
1611 }
1612 else
1613 {
1614 index_t superseg=FindSuperSegment(nodes,segments,ways,relations,profile,node1,seg1);
1615
1616 if(seg2==superseg)
1617 goto endloop;
1618 }
1619 }
1620
1621 /* must obey turn relations */
1622 if(turnrelation!=NO_RELATION && seg1!=NO_SEGMENT)
1623 {
1624 index_t turnrelation2=FindFirstTurnRelation2(relations,node1,seg2r); /* node2 -> node1 -> result1->next->node */
1625
1626 if(turnrelation2!=NO_RELATION && !IsTurnAllowed(relations,turnrelation2,node1,seg2r,seg1r,profile->allow))
1627 goto endloop;
1628 }
1629
1630 wayp=LookupWay(ways,segmentp->way,1);
1631
1632 /* mode of transport must be allowed on the highway */
1633 if(!(wayp->allow&profile->allow))
1634 goto endloop;
1635
1636 /* must obey weight restriction (if exists) */
1637 if(wayp->weight && wayp->weight<profile->weight)
1638 goto endloop;
1639
1640 /* must obey height/width/length restriction (if exist) */
1641 if((wayp->height && wayp->height<profile->height) ||
1642 (wayp->width && wayp->width <profile->width ) ||
1643 (wayp->length && wayp->length<profile->length))
1644 goto endloop;
1645
1646 segment_pref=profile->highway[HIGHWAY(wayp->type)];
1647
1648 /* highway preferences must allow this highway */
1649 if(segment_pref==0)
1650 goto endloop;
1651
1652 for(i=1;i<Property_Count;i++)
1653 if(ways->file.props & PROPERTIES(i))
1654 {
1655 if(wayp->props & PROPERTIES(i))
1656 segment_pref*=profile->props_yes[i];
1657 else
1658 segment_pref*=profile->props_no[i];
1659 }
1660
1661 /* profile preferences must allow this highway */
1662 if(segment_pref==0)
1663 goto endloop;
1664
1665 if(!IsFakeNode(node2))
1666 node2p=LookupNode(nodes,node2,2);
1667
1668 /* mode of transport must be allowed through node2 */
1669 if(node2p && !(node2p->allow&profile->allow))
1670 goto endloop;
1671
1672 /* calculate the score for the segment and cumulative */
1673 if(option_quickest==0)
1674 segment_score=(score_t)DISTANCE(segmentp->distance)/segment_pref;
1675 else
1676 segment_score=(score_t)Duration(segmentp,wayp,profile)/segment_pref;
1677
1678 /* prefer not to follow two fake segments when one would do (special case) */
1679 if(IsFakeSegment(seg1))
1680 segment_score*=1.01;
1681
1682 cumulative_score=result1->score+segment_score;
1683
1684 /* find whether the node/segment combination already exists */
1685 result2=FindResult(results,node2,seg2);
1686
1687 if(!result2) /* New end node */
1688 {
1689 result2=InsertResult(results,node2,seg2);
1690 result2->next=result1; /* working backwards */
1691 result2->score=cumulative_score;
1692 }
1693 else if(cumulative_score<result2->score) /* New end node is better */
1694 {
1695 result2->next=result1; /* working backwards */
1696 result2->score=cumulative_score;
1697 }
1698 else
1699 goto endloop;
1700
1701 if(IsFakeNode(node1) || !IsSuperNode(node1p))
1702 InsertInQueue(queue,result2,result2->score);
1703
1704 endloop:
1705
1706 if(IsFakeNode(node1))
1707 segmentp=NextFakeSegment(segmentp,node1);
1708 else
1709 segmentp=NextSegment(segments,segmentp,node1);
1710 }
1711 }
1712
1713 FreeQueueList(queue);
1714
1715 /* Check it worked */
1716
1717 if(results->number==1)
1718 {
1719 #if DEBUG
1720 printf(" Failed\n");
1721 #endif
1722
1723 #if !DEBUG
1724 if(!option_quiet)
1725 printf_last("Found Finish Route: Nodes checked = %d - Fail",results->number);
1726 #endif
1727
1728 FreeResultsList(results);
1729 return(NULL);
1730 }
1731
1732 /* Create a results structure with the node at the end of the segment opposite the start */
1733
1734 results2=NewResultsList(8);
1735
1736 results2->finish_node=results->finish_node;
1737
1738 result3=FirstResult(results);
1739
1740 while(result3)
1741 {
1742 if(result3->next)
1743 {
1744 result2=InsertResult(results2,result3->next->node,result3->segment);
1745
1746 result2->score=result3->next->score;
1747 }
1748
1749 result3=NextResult(results,result3);
1750 }
1751
1752 /* Fix up the result->next pointers */
1753
1754 result3=FirstResult(results);
1755
1756 while(result3)
1757 {
1758 if(result3->next && result3->next->next)
1759 {
1760 result1=FindResult(results2,result3->next->node,result3->segment);
1761 result2=FindResult(results2,result3->next->next->node,result3->next->segment);
1762
1763 result1->next=result2;
1764 }
1765
1766 result3=NextResult(results,result3);
1767 }
1768
1769 FreeResultsList(results);
1770
1771 #if DEBUG
1772 Result *s=FirstResult(results2);
1773
1774 while(s)
1775 {
1776 if(!IsFakeNode(s->node))
1777 {
1778 Node *n=LookupNode(nodes,s->node,1);
1779
1780 if(IsSuperNode(n))
1781 {
1782 Result *r=FindResult(results2,s->node,s->segment);
1783
1784 printf(" --------\n");
1785
1786 while(r)
1787 {
1788 printf(" node=%"Pindex_t" segment=%"Pindex_t" score=%f\n",r->node,r->segment,r->score);
1789
1790 r=r->next;
1791 }
1792 }
1793 }
1794
1795 s=NextResult(results2,s);
1796 }
1797 #endif
1798
1799 #if !DEBUG
1800 if(!option_quiet)
1801 printf_last("Found Finish Route: Nodes checked = %d",results->number);
1802 #endif
1803
1804 return(results2);
1805 }
1806
1807
1808 /*++++++++++++++++++++++++++++++++++++++
1809 Create an optimum route given the set of super-nodes to follow.
1810
1811 Results *CombineRoutes Returns the results from joining the super-nodes.
1812
1813 Nodes *nodes The set of nodes to use.
1814
1815 Segments *segments The set of segments to use.
1816
1817 Ways *ways The set of ways to use.
1818
1819 Relations *relations The set of relations to use.
1820
1821 Profile *profile The profile containing the transport type, speeds and allowed highways.
1822
1823 Results *begin The set of results for the start of the route.
1824
1825 Results *middle The set of results from the super-node route.
1826
1827 Results *end The set of results for the end of the route.
1828 ++++++++++++++++++++++++++++++++++++++*/
1829
1830 Results *CombineRoutes(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile,Results *begin,Results *middle,Results *end)
1831 {
1832 Result *midres,*comres;
1833 Results *combined;
1834
1835 #if DEBUG
1836 printf(" CombineRoutes(...,[begin has %d nodes],[middle has %d nodes],[end has %d nodes])\n",begin->number,middle->number,end->number);
1837 #endif
1838
1839 #if !DEBUG
1840 if(!option_quiet)
1841 printf_first("Finding Combined Route: Nodes = 0");
1842 #endif
1843
1844 combined=NewResultsList(10);
1845
1846 combined->start_node=begin->start_node;
1847 combined->prev_segment=begin->prev_segment;
1848
1849 /* Insert the start point */
1850
1851 midres=FindResult(middle,middle->start_node,middle->prev_segment);
1852
1853 comres=InsertResult(combined,combined->start_node,combined->prev_segment);
1854
1855 /* Insert the start of the route */
1856
1857 if(begin->number>1 && midres->next)
1858 {
1859 Result *begres;
1860
1861 midres=FindResult(middle,midres->next->node,midres->next->segment);
1862
1863 begres=FindResult(begin,midres->node,midres->segment);
1864
1865 FixForwardRoute(begin,begres);
1866
1867 if(midres->next && midres->next->node==midres->node)
1868 midres=midres->next;
1869
1870 begres=FindResult(begin,begin->start_node,begin->prev_segment);
1871
1872 begres=begres->next;
1873
1874 do
1875 {
1876 Result *comres2;
1877
1878 comres2=InsertResult(combined,begres->node,begres->segment);
1879
1880 comres2->score=begres->score;
1881 comres2->prev=comres;
1882
1883 begres=begres->next;
1884
1885 comres=comres2;
1886 }
1887 while(begres);
1888 }
1889
1890 /* Sort out the combined route */
1891
1892 while(midres->next)
1893 {
1894 Results *results=FindNormalRoute(nodes,segments,ways,relations,profile,comres->node,comres->segment,midres->next->node);
1895 Result *result;
1896
1897 if(!results)
1898 {
1899 #if !DEBUG
1900 if(!option_quiet)
1901 printf_last("Found Combined Route: Nodes = %d - Fail",combined->number);
1902 #endif
1903
1904 FreeResultsList(combined);
1905 return(NULL);
1906 }
1907
1908 result=FindResult(results,midres->node,comres->segment);
1909
1910 result=result->next;
1911
1912 /*
1913 * midres midres->next
1914 * = =
1915 * ---*----------------------------------* = middle
1916 *
1917 * ---*----.----.----.----.----.----.----* = results
1918 * =
1919 * result
1920 *
1921 * ---*----.----.----.----.----.----.----* = combined
1922 * = =
1923 * comres comres2
1924 */
1925
1926 do
1927 {
1928 Result *comres2;
1929
1930 comres2=InsertResult(combined,result->node,result->segment);
1931
1932 comres2->score=midres->score+result->score;
1933 comres2->prev=comres;
1934
1935 result=result->next;
1936
1937 comres=comres2;
1938 }
1939 while(result);
1940
1941 FreeResultsList(results);
1942
1943 midres=midres->next;
1944 }
1945
1946 /* Insert the end of the route */
1947
1948 if(end->number>1)
1949 {
1950 Result *endres=FindResult(end,midres->node,midres->segment);
1951
1952 while(endres->next)
1953 {
1954 Result *comres2;
1955
1956 comres2=InsertResult(combined,endres->next->node,endres->next->segment);
1957
1958 comres2->score=comres->score+(endres->score-endres->next->score);
1959 comres2->prev=comres;
1960
1961 endres=endres->next;
1962
1963 comres=comres2;
1964 }
1965 }
1966
1967 /* Turn the route round */
1968
1969 combined->finish_node=comres->node;
1970 combined->last_segment=comres->segment;
1971
1972 FixForwardRoute(combined,comres);
1973
1974 #if DEBUG
1975 Result *r=FindResult(combined,combined->start_node,combined->prev_segment);
1976
1977 printf(" CombinedRoute(...)\n");
1978
1979 while(r)
1980 {
1981 printf(" node=%"Pindex_t" segment=%"Pindex_t" score=%f\n",r->node,r->segment,r->score);
1982
1983 r=r->next;
1984 }
1985 #endif
1986
1987 #if !DEBUG
1988 if(!option_quiet)
1989 printf_last("Found Combined Route: Nodes = %d",combined->number);
1990 #endif
1991
1992 return(combined);
1993 }
1994
1995
1996 /*++++++++++++++++++++++++++++++++++++++
1997 Fix the forward route (i.e. setup next pointers for forward path from prev nodes on reverse path).
1998
1999 Results *results The set of results to update.
2000
2001 Result *finish_result The result for the finish point.
2002 ++++++++++++++++++++++++++++++++++++++*/
2003
2004 void FixForwardRoute(Results *results,Result *finish_result)
2005 {
2006 Result *result2=finish_result;
2007
2008 /* Erase the old route if there is one */
2009
2010 if(results->finish_node!=NO_NODE)
2011 {
2012 Result *result1=FirstResult(results);
2013
2014 while(result1)
2015 {
2016 result1->next=NULL;
2017
2018 result1=NextResult(results,result1);
2019 }
2020 }
2021
2022 /* Create the forward links for the optimum path */
2023
2024 do
2025 {
2026 Result *result1;
2027
2028 if(result2->prev)
2029 {
2030 index_t node1=result2->prev->node;
2031 index_t seg1=result2->prev->segment;
2032
2033 result1=FindResult(results,node1,seg1);
2034
2035 logassert(!result1->next,"Unable to reverse route through results (report a bug)"); /* Bugs elsewhere can lead to infinite loop here. */
2036
2037 result1->next=result2;
2038
2039 result2=result1;
2040 }
2041 else
2042 result2=NULL;
2043 }
2044 while(result2);
2045
2046 results->finish_node=finish_result->node;
2047 results->last_segment=finish_result->segment;
2048 }

Properties

Name Value
cvs:description Route optimiser.