Routino SVN Repository Browser

Check out the latest version of Routino: svn co http://routino.org/svn/trunk routino

ViewVC logotype

Contents of /branches/destination-access/src/optimiser.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1639 - (show annotations) (download) (as text)
Mon Mar 30 18:53:28 2015 UTC (10 years ago) by amb
File MIME type: text/x-csrc
File size: 52495 byte(s)
Merge change from trunk: "Fix bug with indenting of debug output in
FindMiddleRoute() function."

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 printf(" -------- normal route (between super-nodes)\n");
332
333 while(r)
334 {
335 printf(" node=%"Pindex_t" segment=%"Pindex_t" score=%f%s%s%s\n",r->node,r->segment,r->score,
336 (IsSuperNode(LookupNode(nodes,r->node,1))?" (super)":""),
337 (r->node==results->start_node&&r->segment==results->prev_segment?" (start)":""),
338 (r->node==results->finish_node?" (finish)":""));
339
340 r=r->next;
341 }
342 #endif
343
344 return(results);
345 }
346
347
348 /*++++++++++++++++++++++++++++++++++++++
349 Find the optimum route between two nodes where the start and end are a set of pre/post-routed super-nodes.
350
351 Results *FindMiddleRoute Returns a set of results.
352
353 Nodes *nodes The set of nodes to use.
354
355 Segments *segments The set of segments to use.
356
357 Ways *ways The set of ways to use.
358
359 Relations *relations The set of relations to use.
360
361 Profile *profile The profile containing the transport type, speeds and allowed highways.
362
363 Results *begin The initial portion of the route.
364
365 Results *end The final portion of the route.
366 ++++++++++++++++++++++++++++++++++++++*/
367
368 Results *FindMiddleRoute(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile,Results *begin,Results *end)
369 {
370 Results *results;
371 Queue *queue;
372 Result *finish_result;
373 score_t finish_score;
374 double finish_lat,finish_lon;
375 Result *result1,*result2,*result3,*result4;
376 int force_uturn=0;
377
378 #if DEBUG
379 printf(" FindMiddleRoute(...,[begin has %d nodes],[end has %d nodes])\n",begin->number,end->number);
380 #endif
381
382 #if !DEBUG
383 if(!option_quiet)
384 printf_first("Finding Middle Route: Super-Nodes checked = 0");
385 #endif
386
387 /* Set up the finish conditions */
388
389 finish_score=INF_SCORE;
390 finish_result=NULL;
391
392 if(IsFakeNode(end->finish_node))
393 GetFakeLatLong(end->finish_node,&finish_lat,&finish_lon);
394 else
395 GetLatLong(nodes,end->finish_node,NULL,&finish_lat,&finish_lon);
396
397 /* Create the list of results and insert the first node into the queue */
398
399 results=NewResultsList(20);
400 queue=NewQueueList(12);
401
402 results->start_node=begin->start_node;
403 results->prev_segment=begin->prev_segment;
404
405 if(begin->number==1 && begin->prev_segment!=NO_SEGMENT)
406 {
407 index_t superseg=FindSuperSegment(nodes,segments,ways,relations,profile,begin->start_node,begin->prev_segment);
408
409 results->prev_segment=superseg;
410 }
411
412 result1=InsertResult(results,results->start_node,results->prev_segment);
413
414 /* Insert the finish points of the beginning part of the path into the queue,
415 translating the segments into super-segments. */
416
417 result3=FirstResult(begin);
418
419 while(result3)
420 {
421 if((results->start_node!=result3->node || results->prev_segment!=result3->segment) &&
422 !IsFakeNode(result3->node) && IsSuperNode(LookupNode(nodes,result3->node,3)))
423 {
424 Result *result5=result1;
425 index_t superseg=FindSuperSegment(nodes,segments,ways,relations,profile,result3->node,result3->segment);
426
427 if(superseg!=result3->segment)
428 {
429 result5=InsertResult(results,result3->node,result3->segment);
430
431 result5->score=result3->score;
432
433 result5->prev=result1;
434 }
435
436 if(!FindResult(results,result3->node,superseg))
437 {
438 result2=InsertResult(results,result3->node,superseg);
439 result2->prev=result5;
440
441 result2->score=result3->score;
442
443 InsertInQueue(queue,result2,result3->score);
444
445 if((result4=FindResult(end,result2->node,result2->segment)))
446 {
447 if((result2->score+result4->score)<finish_score)
448 {
449 finish_score=result2->score+result4->score;
450 finish_result=result2;
451 }
452 }
453 }
454 }
455
456 result3=NextResult(begin,result3);
457 }
458
459 if(begin->number==1)
460 InsertInQueue(queue,result1,0);
461
462 /* Check for barrier at start waypoint - must perform U-turn */
463
464 if(begin->number==1 && results->prev_segment!=NO_SEGMENT)
465 {
466 Node *startp=LookupNode(nodes,result1->node,1);
467
468 if(!(startp->allow&profile->allow))
469 force_uturn=1;
470 }
471
472 /* Loop across all nodes in the queue */
473
474 while((result1=PopFromQueue(queue)))
475 {
476 Node *node1p;
477 Segment *segmentp;
478 index_t node1,seg1;
479 index_t turnrelation=NO_RELATION;
480
481 /* score must be better than current best score */
482 if(result1->score>=finish_score)
483 continue;
484
485 node1=result1->node;
486 seg1=result1->segment;
487
488 node1p=LookupNode(nodes,node1,1); /* node1 cannot be a fake node (must be a super-node) */
489
490 /* lookup if a turn restriction applies */
491 if(profile->turns && IsTurnRestrictedNode(node1p)) /* node1 cannot be a fake node (must be a super-node) */
492 turnrelation=FindFirstTurnRelation2(relations,node1,seg1);
493
494 /* Loop across all segments */
495
496 segmentp=FirstSegment(segments,node1p,1); /* node1 cannot be a fake node (must be a super-node) */
497
498 while(segmentp)
499 {
500 Node *node2p;
501 Way *wayp;
502 index_t node2,seg2;
503 score_t segment_pref,segment_score,cumulative_score;
504 int i;
505
506 /* must be a super segment */
507 if(!IsSuperSegment(segmentp))
508 goto endloop;
509
510 /* must obey one-way restrictions (unless profile allows) */
511 if(profile->oneway && IsOnewayTo(segmentp,node1))
512 {
513 if(profile->allow!=Transports_Bicycle)
514 goto endloop;
515
516 wayp=LookupWay(ways,segmentp->way,1);
517
518 if(!(wayp->type&Highway_CycleBothWays))
519 goto endloop;
520 }
521
522 seg2=IndexSegment(segments,segmentp); /* segment cannot be a fake segment (must be a super-segment) */
523
524 /* must perform U-turn in special cases */
525 if(force_uturn && node1==results->start_node)
526 {
527 if(seg2!=result1->segment)
528 goto endloop;
529 }
530 else
531 /* must not perform U-turn */
532 if(seg1==seg2) /* No fake segments, applies to all profiles */
533 goto endloop;
534
535 /* must obey turn relations */
536 if(turnrelation!=NO_RELATION && !IsTurnAllowed(relations,turnrelation,node1,seg1,seg2,profile->allow))
537 goto endloop;
538
539 wayp=LookupWay(ways,segmentp->way,1);
540
541 /* mode of transport must be allowed on the highway */
542 if(!(wayp->allow&profile->allow))
543 goto endloop;
544
545 /* must obey weight restriction (if exists) */
546 if(wayp->weight && wayp->weight<profile->weight)
547 goto endloop;
548
549 /* must obey height/width/length restriction (if exist) */
550 if((wayp->height && wayp->height<profile->height) ||
551 (wayp->width && wayp->width <profile->width ) ||
552 (wayp->length && wayp->length<profile->length))
553 goto endloop;
554
555 segment_pref=profile->highway[HIGHWAY(wayp->type)];
556
557 /* highway preferences must allow this highway */
558 if(segment_pref==0)
559 goto endloop;
560
561 for(i=1;i<Property_Count;i++)
562 if(ways->file.props & PROPERTIES(i))
563 {
564 if(wayp->props & PROPERTIES(i))
565 segment_pref*=profile->props_yes[i];
566 else
567 segment_pref*=profile->props_no[i];
568 }
569
570 /* profile preferences must allow this highway */
571 if(segment_pref==0)
572 goto endloop;
573
574 node2=OtherNode(segmentp,node1);
575
576 node2p=LookupNode(nodes,node2,2); /* node2 cannot be a fake node (must be a super-node) */
577
578 /* mode of transport must be allowed through node2 unless it is the final node */
579 if(node2!=end->finish_node && !(node2p->allow&profile->allow))
580 goto endloop;
581
582 /* calculate the score for the segment and cumulative */
583 if(option_quickest==0)
584 segment_score=(score_t)DISTANCE(segmentp->distance)/segment_pref;
585 else
586 segment_score=(score_t)Duration(segmentp,wayp,profile)/segment_pref;
587
588 cumulative_score=result1->score+segment_score;
589
590 /* score must be better than current best score */
591 if(cumulative_score>=finish_score)
592 goto endloop;
593
594 /* find whether the node/segment combination already exists */
595 result2=FindResult(results,node2,seg2);
596
597 if(!result2) /* New end node/segment pair */
598 {
599 result2=InsertResult(results,node2,seg2);
600 result2->prev=result1;
601 result2->score=cumulative_score;
602 }
603 else if(cumulative_score<result2->score) /* New end node/segment pair is better */
604 {
605 result2->prev=result1;
606 result2->score=cumulative_score;
607 }
608 else
609 goto endloop;
610
611 if((result3=FindResult(end,node2,seg2)))
612 {
613 if((result2->score+result3->score)<finish_score)
614 {
615 finish_score=result2->score+result3->score;
616 finish_result=result2;
617
618 results->finish_node=node2;
619 results->last_segment=seg2;
620 }
621 }
622 else
623 {
624 double lat,lon;
625 distance_t direct;
626 score_t potential_score;
627
628 GetLatLong(nodes,node2,node2p,&lat,&lon); /* node2 cannot be a fake node (must be a super-node) */
629
630 direct=Distance(lat,lon,finish_lat,finish_lon);
631
632 if(option_quickest==0)
633 potential_score=result2->score+(score_t)direct/profile->max_pref;
634 else
635 potential_score=result2->score+(score_t)distance_speed_to_duration(direct,profile->max_speed)/profile->max_pref;
636
637 if(potential_score<finish_score)
638 InsertInQueue(queue,result2,potential_score);
639 }
640
641 endloop:
642
643 segmentp=NextSegment(segments,segmentp,node1); /* node1 cannot be a fake node (must be a super-node) */
644 }
645 }
646
647 FreeQueueList(queue);
648
649 /* Check it worked */
650
651 if(!finish_result)
652 {
653 #if DEBUG
654 printf(" Failed\n");
655 #endif
656
657 #if !DEBUG
658 if(!option_quiet)
659 printf_last("Found Middle Route: Super-Nodes checked = %d - Fail",results->number);
660 #endif
661
662 FreeResultsList(results);
663 return(NULL);
664 }
665
666 FixForwardRoute(results,finish_result);
667
668 #if DEBUG
669 Result *r=FindResult(results,results->start_node,results->prev_segment);
670
671 printf(" -------- middle route (start route then via super-nodes/segments)\n");
672
673 while(r)
674 {
675 printf(" node=%"Pindex_t" segment=%"Pindex_t" score=%f%s%s%s\n",r->node,r->segment,r->score,
676 (IsSuperNode(LookupNode(nodes,r->node,1))?" (super)":""),
677 (r->node==results->start_node&&r->segment==results->prev_segment?" (start)":""),
678 (r->node==results->finish_node?" (finish)":""));
679
680 r=r->next;
681 }
682 #endif
683
684 #if !DEBUG
685 if(!option_quiet)
686 printf_last("Found Middle Route: Super-Nodes checked = %d",results->number);
687 #endif
688
689 return(results);
690 }
691
692
693 /*++++++++++++++++++++++++++++++++++++++
694 Find the super-segment that represents the route that contains a particular segment.
695
696 index_t FindSuperSegment Returns the index of the super-segment.
697
698 Nodes *nodes The set of nodes to use.
699
700 Segments *segments The set of segments to use.
701
702 Ways *ways The set of ways to use.
703
704 Relations *relations The set of relations to use.
705
706 Profile *profile The profile containing the transport type, speeds and allowed highways.
707
708 index_t finish_node The super-node that the route ends at.
709
710 index_t finish_segment The segment that the route ends with.
711 ++++++++++++++++++++++++++++++++++++++*/
712
713 static index_t FindSuperSegment(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile,index_t finish_node,index_t finish_segment)
714 {
715 Node *supernodep;
716 Segment *supersegmentp;
717
718 if(IsFakeSegment(finish_segment))
719 finish_segment=IndexRealSegment(finish_segment);
720
721 supernodep=LookupNode(nodes,finish_node,3); /* finish_node cannot be a fake node (must be a super-node) */
722 supersegmentp=LookupSegment(segments,finish_segment,4); /* finish_segment cannot be a fake segment. */
723
724 if(IsSuperSegment(supersegmentp))
725 return(finish_segment);
726
727 /* Loop across all segments */
728
729 supersegmentp=FirstSegment(segments,supernodep,4); /* supernode cannot be a fake node (must be a super-node) */
730
731 while(supersegmentp)
732 {
733 if(IsSuperSegment(supersegmentp))
734 {
735 Results *results;
736 Result *result;
737 index_t start_node;
738
739 start_node=OtherNode(supersegmentp,finish_node);
740
741 results=FindSuperRoute(nodes,segments,ways,relations,profile,start_node,finish_node);
742
743 if(!results)
744 continue;
745
746 result=FindResult(results,finish_node,finish_segment);
747
748 if(result && (distance_t)result->score==DISTANCE(supersegmentp->distance))
749 {
750 FreeResultsList(results);
751 return(IndexSegment(segments,supersegmentp));
752 }
753
754 if(results)
755 FreeResultsList(results);
756 }
757
758 supersegmentp=NextSegment(segments,supersegmentp,finish_node); /* finish_node cannot be a fake node (must be a super-node) */
759 }
760
761 return(finish_segment);
762 }
763
764
765 /*++++++++++++++++++++++++++++++++++++++
766 Find the shortest route between two super-nodes using only normal nodes.
767 This is effectively the same function as is used in superx.c when finding super-segments initially.
768
769 Results *FindSuperRoute Returns a set of results.
770
771 Nodes *nodes The set of nodes to use.
772
773 Segments *segments The set of segments to use.
774
775 Ways *ways The set of ways to use.
776
777 Relations *relations The set of relations to use.
778
779 Profile *profile The profile containing the transport type, speeds and allowed highways.
780
781 index_t start_node The start node.
782
783 index_t finish_node The finish node.
784 ++++++++++++++++++++++++++++++++++++++*/
785
786 static Results *FindSuperRoute(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile,index_t start_node,index_t finish_node)
787 {
788 Results *results;
789 Queue *queue;
790 Result *result1,*result2;
791
792 #if DEBUG
793 printf(" FindSuperRoute(...,start_node=%"Pindex_t" finish_node=%"Pindex_t")\n",start_node,finish_node);
794 #endif
795
796 /* Create the list of results and insert the first node into the queue */
797
798 results=NewResultsList(8);
799 queue=NewQueueList(8);
800
801 results->start_node=start_node;
802 results->prev_segment=NO_SEGMENT;
803
804 result1=InsertResult(results,results->start_node,results->prev_segment);
805
806 InsertInQueue(queue,result1,0);
807
808 /* Loop across all nodes in the queue */
809
810 while((result1=PopFromQueue(queue)))
811 {
812 Node *node1p=NULL;
813 Segment *segmentp;
814 index_t node1,seg1;
815
816 node1=result1->node;
817 seg1=result1->segment;
818
819 node1p=LookupNode(nodes,node1,3); /* node1 cannot be a fake node */
820
821 /* Loop across all segments */
822
823 segmentp=FirstSegment(segments,node1p,3); /* node1 cannot be a fake node */
824
825 while(segmentp)
826 {
827 Node *node2p=NULL;
828 index_t node2,seg2;
829 score_t cumulative_score;
830
831 /* must be a normal segment */
832 if(!IsNormalSegment(segmentp))
833 goto endloop;
834
835 /* must obey one-way restrictions */
836 if(IsOnewayTo(segmentp,node1))
837 {
838 Way *wayp;
839
840 if(profile->allow!=Transports_Bicycle)
841 goto endloop;
842
843 wayp=LookupWay(ways,segmentp->way,2);
844
845 if(!(wayp->type&Highway_CycleBothWays))
846 goto endloop;
847 }
848
849 seg2=IndexSegment(segments,segmentp);
850
851 /* must not perform U-turn */
852 if(seg1==seg2)
853 goto endloop;
854
855 node2=OtherNode(segmentp,node1);
856
857 node2p=LookupNode(nodes,node2,4); /* node2 cannot be a fake node */
858
859 /* must not pass over super-node */
860 if(node2!=finish_node && IsSuperNode(node2p))
861 goto endloop;
862
863 /* Specifically looking for the shortest route to emulate superx.c */
864 cumulative_score=result1->score+(score_t)DISTANCE(segmentp->distance);
865
866 result2=FindResult(results,node2,seg2);
867
868 if(!result2) /* New end node/segment combination */
869 {
870 result2=InsertResult(results,node2,seg2);
871 result2->prev=result1;
872 result2->score=cumulative_score;
873 }
874 else if(cumulative_score<result2->score) /* New score for end node/segment combination is better */
875 {
876 result2->prev=result1;
877 result2->segment=seg2;
878 result2->score=cumulative_score;
879 }
880 else goto endloop;
881
882 /* don't route beyond a super-node. */
883 if(!IsSuperNode(node2p))
884 InsertInQueue(queue,result2,result2->score);
885
886 endloop:
887
888 segmentp=NextSegment(segments,segmentp,node1);
889 }
890 }
891
892 FreeQueueList(queue);
893
894 #if DEBUG
895 Result *s=FirstResult(results);
896
897 while(s)
898 {
899 if(s->node==finish_node)
900 {
901 Result *r=FindResult(results,s->node,s->segment);
902
903 printf(" -------- super-route\n");
904
905 while(r)
906 {
907 printf(" node=%"Pindex_t" segment=%"Pindex_t" score=%f%s%s%s\n",r->node,r->segment,r->score,
908 (IsSuperNode(LookupNode(nodes,r->node,1))?" (super)":""),
909 (r->node==start_node?" (start)":""),
910 (r->node==finish_node?" (finish)":""));
911
912 r=r->prev;
913 }
914 }
915
916 s=NextResult(results,s);
917 }
918 #endif
919
920 return(results);
921 }
922
923
924 /*++++++++++++++++++++++++++++++++++++++
925 Find all routes from a specified node to any super-node.
926
927 Results *FindStartRoutes Returns a set of results.
928
929 Nodes *nodes The set of nodes to use.
930
931 Segments *segments The set of segments to use.
932
933 Ways *ways The set of ways to use.
934
935 Relations *relations The set of relations to use.
936
937 Profile *profile The profile containing the transport type, speeds and allowed highways.
938
939 index_t start_node The start node.
940
941 index_t prev_segment The previous segment before the start node.
942
943 index_t finish_node The finish node.
944
945 int allow_destination The option to allow routing to follow highways tagged as 'destination'.
946 ++++++++++++++++++++++++++++++++++++++*/
947
948 Results *FindStartRoutes(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile,index_t start_node,index_t prev_segment,index_t finish_node,int allow_destination)
949 {
950 Results *results;
951 Queue *queue,*superqueue;
952 Result *result1,*result2;
953 Result *finish_result=NULL;
954 score_t finish_score=INF_SCORE;
955 int nsuper=0,force_uturn=0;
956
957 #if DEBUG
958 printf(" FindStartRoutes(...,start_node=%"Pindex_t" prev_segment=%"Pindex_t" finish_node=%"Pindex_t")\n",start_node,prev_segment,finish_node);
959 #endif
960
961 #if !DEBUG
962 if(!option_quiet)
963 printf_first("Finding Start Route: Nodes checked = 0");
964 #endif
965
966 /* Create the list of results and insert the first node into the queue */
967
968 results=NewResultsList(8);
969 queue=NewQueueList(8);
970 superqueue=NewQueueList(8);
971
972 results->start_node=start_node;
973 results->prev_segment=prev_segment;
974
975 result1=InsertResult(results,results->start_node,results->prev_segment);
976
977 InsertInQueue(queue,result1,0);
978
979 /* Check for barrier at start waypoint - must perform U-turn */
980
981 if(prev_segment!=NO_SEGMENT && !IsFakeNode(start_node))
982 {
983 Node *startp=LookupNode(nodes,start_node,1);
984
985 if(!(startp->allow&profile->allow))
986 force_uturn=1;
987 }
988
989 /* Loop across all nodes in the queue */
990
991 while((result1=PopFromQueue(queue)))
992 {
993 Node *node1p=NULL;
994 Segment *segmentp;
995 index_t node1,seg1,seg1r;
996 index_t turnrelation=NO_RELATION;
997
998 /* score must be better than current best score */
999 if(result1->score>=finish_score)
1000 continue;
1001
1002 node1=result1->node;
1003 seg1=result1->segment;
1004
1005 if(IsFakeSegment(seg1))
1006 seg1r=IndexRealSegment(seg1);
1007 else
1008 seg1r=seg1;
1009
1010 if(!IsFakeNode(node1))
1011 node1p=LookupNode(nodes,node1,1);
1012
1013 /* lookup if a turn restriction applies */
1014 if(profile->turns && node1p && IsTurnRestrictedNode(node1p))
1015 turnrelation=FindFirstTurnRelation2(relations,node1,seg1r);
1016
1017 /* Loop across all segments */
1018
1019 if(IsFakeNode(node1))
1020 segmentp=FirstFakeSegment(node1);
1021 else
1022 segmentp=FirstSegment(segments,node1p,1);
1023
1024 while(segmentp)
1025 {
1026 Node *node2p=NULL;
1027 Way *wayp;
1028 index_t node2,seg2,seg2r;
1029 score_t segment_pref,segment_score,cumulative_score;
1030 int i;
1031
1032 node2=OtherNode(segmentp,node1); /* need this here because we use node2 at the end of the loop */
1033
1034 /* must be a normal segment */
1035 if(!IsNormalSegment(segmentp))
1036 goto endloop;
1037
1038 /* must obey one-way restrictions (unless profile allows) */
1039 if(profile->oneway && IsOnewayTo(segmentp,node1))
1040 {
1041 if(profile->allow!=Transports_Bicycle)
1042 goto endloop;
1043
1044 wayp=LookupWay(ways,segmentp->way,1);
1045
1046 if(!(wayp->type&Highway_CycleBothWays))
1047 goto endloop;
1048 }
1049
1050 if(IsFakeNode(node1) || IsFakeNode(node2))
1051 {
1052 seg2 =IndexFakeSegment(segmentp);
1053 seg2r=IndexRealSegment(seg2);
1054 }
1055 else
1056 {
1057 seg2 =IndexSegment(segments,segmentp);
1058 seg2r=seg2;
1059 }
1060
1061 /* must perform U-turn in special cases */
1062 if(node1==start_node && force_uturn)
1063 {
1064 if(seg2r!=result1->segment)
1065 goto endloop;
1066 }
1067 else
1068 /* must not perform U-turn (unless profile allows) */
1069 if(profile->turns && (seg1==seg2 || seg1==seg2r || seg1r==seg2 || (seg1r==seg2r && IsFakeUTurn(seg1,seg2))))
1070 goto endloop;
1071
1072 /* must obey turn relations */
1073 if(turnrelation!=NO_RELATION && !IsTurnAllowed(relations,turnrelation,node1,seg1r,seg2r,profile->allow))
1074 goto endloop;
1075
1076 wayp=LookupWay(ways,segmentp->way,1);
1077
1078 /* mode of transport must be allowed on the highway (optionally as destination only) */
1079 if(!(wayp->allow&profile->allow) && !(allow_destination && wayp->destination&profile->allow))
1080 goto endloop;
1081
1082 /* must obey weight restriction (if exists) */
1083 if(wayp->weight && wayp->weight<profile->weight)
1084 goto endloop;
1085
1086 /* must obey height/width/length restriction (if exists) */
1087 if((wayp->height && wayp->height<profile->height) ||
1088 (wayp->width && wayp->width <profile->width ) ||
1089 (wayp->length && wayp->length<profile->length))
1090 goto endloop;
1091
1092 segment_pref=profile->highway[HIGHWAY(wayp->type)];
1093
1094 /* highway preferences must allow this highway */
1095 if(segment_pref==0)
1096 goto endloop;
1097
1098 for(i=1;i<Property_Count;i++)
1099 if(ways->file.props & PROPERTIES(i))
1100 {
1101 if(wayp->props & PROPERTIES(i))
1102 segment_pref*=profile->props_yes[i];
1103 else
1104 segment_pref*=profile->props_no[i];
1105 }
1106
1107 /* profile preferences must allow this highway */
1108 if(segment_pref==0)
1109 goto endloop;
1110
1111 if(!IsFakeNode(node2))
1112 node2p=LookupNode(nodes,node2,2);
1113
1114 /* mode of transport must be allowed through node2 unless it is the final node (optionally as destination only) */
1115 if(node2p && node2!=finish_node && !(node2p->allow&profile->allow) && !(allow_destination && node2p->destination&profile->allow))
1116 goto endloop;
1117
1118 /* calculate the score for the segment and cumulative */
1119 if(option_quickest==0)
1120 segment_score=(score_t)DISTANCE(segmentp->distance)/segment_pref;
1121 else
1122 segment_score=(score_t)Duration(segmentp,wayp,profile)/segment_pref;
1123
1124 /* prefer not to follow two fake segments when one would do (special case) */
1125 if(IsFakeSegment(seg2))
1126 segment_score*=1.01;
1127
1128 cumulative_score=result1->score+segment_score;
1129
1130 /* score must be better than current best score */
1131 if(cumulative_score>=finish_score)
1132 goto endloop;
1133
1134 /* find whether the node/segment combination already exists */
1135 result2=FindResult(results,node2,seg2);
1136
1137 if(!result2) /* New end node/segment combination */
1138 {
1139 result2=InsertResult(results,node2,seg2);
1140 result2->prev=result1;
1141 result2->score=cumulative_score;
1142
1143 if(node2p && IsSuperNode(node2p))
1144 nsuper++;
1145 }
1146 else if(cumulative_score<result2->score) /* New score for end node/segment combination is better */
1147 {
1148 result2->prev=result1;
1149 result2->score=cumulative_score;
1150 }
1151 else
1152 goto endloop;
1153
1154 if(node2==finish_node)
1155 {
1156 if(!finish_result)
1157 {
1158 Result *result3;
1159
1160 while((result3=PopFromQueue(superqueue)))
1161 InsertInQueue(queue,result3,result3->score);
1162 }
1163
1164 if(cumulative_score<finish_score)
1165 {
1166 finish_score=cumulative_score;
1167 finish_result=result2;
1168
1169 results->finish_node=node2;
1170 results->last_segment=seg2;
1171 }
1172 }
1173
1174 if(finish_result || (node2p && !IsSuperNode(node2p)))
1175 InsertInQueue(queue,result2,result2->score);
1176 else if(node2p && IsSuperNode(node2p))
1177 InsertInQueue(superqueue,result2,result2->score);
1178
1179 endloop:
1180
1181 if(IsFakeNode(node1))
1182 segmentp=NextFakeSegment(segmentp,node1);
1183 else if(IsFakeNode(node2))
1184 segmentp=NULL; /* cannot call NextSegment() with a fake segment */
1185 else
1186 {
1187 segmentp=NextSegment(segments,segmentp,node1);
1188
1189 if(!segmentp && IsFakeNode(finish_node))
1190 segmentp=ExtraFakeSegment(node1,finish_node);
1191 }
1192 }
1193 }
1194
1195 FreeQueueList(queue);
1196 FreeQueueList(superqueue);
1197
1198 /* Check it worked */
1199
1200 if(results->number==1 || (nsuper==0 && !finish_result))
1201 {
1202 #if DEBUG
1203 printf(" Failed (%d results, %d super)\n",results->number,nsuper);
1204 #endif
1205
1206 #if !DEBUG
1207 if(!option_quiet)
1208 printf_last("Found Start Route: Nodes checked = %d - Fail",results->number);
1209 #endif
1210
1211 FreeResultsList(results);
1212 return(NULL);
1213 }
1214
1215 /* If we found the finish node then make a proper route */
1216
1217 if(finish_result)
1218 FixForwardRoute(results,finish_result);
1219
1220 #if DEBUG
1221 Result *s=FirstResult(results);
1222
1223 while(s)
1224 {
1225 if(s->node==finish_node || (!IsFakeNode(s->node) && IsSuperNode(LookupNode(nodes,s->node,1))))
1226 {
1227 Result *r=FindResult(results,s->node,s->segment);
1228
1229 printf(" -------- possible start route\n");
1230
1231 while(r)
1232 {
1233 printf(" node=%"Pindex_t" segment=%"Pindex_t" score=%f%s%s%s\n",r->node,r->segment,r->score,
1234 (IsSuperNode(LookupNode(nodes,r->node,1))?" (super)":""),
1235 (r->node==start_node&&r->segment==prev_segment?" (start)":""),
1236 (r->node==finish_node?" (finish)":""));
1237
1238 r=r->prev;
1239 }
1240 }
1241
1242 s=NextResult(results,s);
1243 }
1244 #endif
1245
1246 #if !DEBUG
1247 if(!option_quiet)
1248 printf_last("Found Start Route: Nodes checked = %d",results->number);
1249 #endif
1250
1251 return(results);
1252 }
1253
1254
1255 /*++++++++++++++++++++++++++++++++++++++
1256 Find all routes from any super-node to a specific node (by working backwards from the specific node to all super-nodes).
1257
1258 Results *FindFinishRoutes Returns a set of results.
1259
1260 Nodes *nodes The set of nodes to use.
1261
1262 Segments *segments The set of segments to use.
1263
1264 Ways *ways The set of ways to use.
1265
1266 Relations *relations The set of relations to use.
1267
1268 Profile *profile The profile containing the transport type, speeds and allowed highways.
1269
1270 index_t finish_node The finishing node.
1271
1272 int allow_destination The option to allow routing to follow highways tagged as 'destination'.
1273 ++++++++++++++++++++++++++++++++++++++*/
1274
1275 Results *FindFinishRoutes(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile,index_t finish_node,int allow_destination)
1276 {
1277 Results *results,*results2;
1278 Queue *queue;
1279 Result *result1,*result2,*result3;
1280
1281 #if DEBUG
1282 printf(" FindFinishRoutes(...,finish_node=%"Pindex_t")\n",finish_node);
1283 #endif
1284
1285 #if !DEBUG
1286 if(!option_quiet)
1287 printf_first("Finding Finish Route: Nodes checked = 0");
1288 #endif
1289
1290 /* Create the results and insert the finish node into the queue */
1291
1292 results=NewResultsList(8);
1293 queue=NewQueueList(8);
1294
1295 results->finish_node=finish_node;
1296
1297 result1=InsertResult(results,finish_node,NO_SEGMENT);
1298
1299 InsertInQueue(queue,result1,0);
1300
1301 /* Loop across all nodes in the queue */
1302
1303 while((result1=PopFromQueue(queue)))
1304 {
1305 Node *node1p=NULL;
1306 Segment *segmentp;
1307 index_t node1,seg1,seg1r;
1308 index_t turnrelation=NO_RELATION;
1309
1310 node1=result1->node;
1311 seg1=result1->segment;
1312
1313 if(seg1!=NO_SEGMENT && IsFakeSegment(seg1))
1314 seg1r=IndexRealSegment(seg1);
1315 else
1316 seg1r=seg1;
1317
1318 if(!IsFakeNode(node1))
1319 node1p=LookupNode(nodes,node1,1);
1320
1321 /* lookup if a turn restriction applies */
1322 if(profile->turns && node1p && IsTurnRestrictedNode(node1p))
1323 turnrelation=FindFirstTurnRelation1(relations,node1); /* working backwards => turn relation sort order doesn't help */
1324
1325 /* Loop across all segments */
1326
1327 if(IsFakeNode(node1))
1328 segmentp=FirstFakeSegment(node1);
1329 else
1330 segmentp=FirstSegment(segments,node1p,1);
1331
1332 while(segmentp)
1333 {
1334 Node *node2p=NULL;
1335 Way *wayp;
1336 index_t node2,seg2,seg2r;
1337 score_t segment_pref,segment_score,cumulative_score;
1338 int i;
1339
1340 /* must be a normal segment unless node1 is a super-node (see below). */
1341 if((IsFakeNode(node1) || !IsSuperNode(node1p)) && !IsNormalSegment(segmentp))
1342 goto endloop;
1343
1344 /* must be a super segment if node1 is a super-node to give starting super-segment for finding middle route. */
1345 if((!IsFakeNode(node1) && IsSuperNode(node1p)) && !IsSuperSegment(segmentp))
1346 goto endloop;
1347
1348 /* must obey one-way restrictions (unless profile allows) */
1349 if(profile->oneway && IsOnewayFrom(segmentp,node1)) /* working backwards => disallow oneway *from* node1 */
1350 {
1351 if(profile->allow!=Transports_Bicycle)
1352 goto endloop;
1353
1354 wayp=LookupWay(ways,segmentp->way,1);
1355
1356 if(!(wayp->type&Highway_CycleBothWays))
1357 goto endloop;
1358 }
1359
1360 node2=OtherNode(segmentp,node1);
1361
1362 if(IsFakeNode(node1) || IsFakeNode(node2))
1363 {
1364 seg2 =IndexFakeSegment(segmentp);
1365 seg2r=IndexRealSegment(seg2);
1366 }
1367 else
1368 {
1369 seg2 =IndexSegment(segments,segmentp);
1370 seg2r=seg2;
1371 }
1372
1373 /* must not perform U-turn (unless profile allows) */
1374 if(profile->turns && seg1!=NO_SEGMENT)
1375 {
1376 if(IsFakeNode(node1) || !IsSuperNode(node1p))
1377 {
1378 if(seg1==seg2 || seg1==seg2r || seg1r==seg2 || (seg1r==seg2r && IsFakeUTurn(seg1,seg2)))
1379 goto endloop;
1380 }
1381 else
1382 {
1383 index_t superseg=FindSuperSegment(nodes,segments,ways,relations,profile,node1,seg1);
1384
1385 if(seg2==superseg)
1386 goto endloop;
1387 }
1388 }
1389
1390 /* must obey turn relations */
1391 if(turnrelation!=NO_RELATION && seg1!=NO_SEGMENT)
1392 {
1393 index_t turnrelation2=FindFirstTurnRelation2(relations,node1,seg2r); /* node2 -> node1 -> result1->next->node */
1394
1395 if(turnrelation2!=NO_RELATION && !IsTurnAllowed(relations,turnrelation2,node1,seg2r,seg1r,profile->allow))
1396 goto endloop;
1397 }
1398
1399 wayp=LookupWay(ways,segmentp->way,1);
1400
1401 /* mode of transport must be allowed on the highway (optionally as destination only) */
1402 if(!(wayp->allow&profile->allow) && !(allow_destination && wayp->destination&profile->allow))
1403 goto endloop;
1404
1405 /* must obey weight restriction (if exists) */
1406 if(wayp->weight && wayp->weight<profile->weight)
1407 goto endloop;
1408
1409 /* must obey height/width/length restriction (if exist) */
1410 if((wayp->height && wayp->height<profile->height) ||
1411 (wayp->width && wayp->width <profile->width ) ||
1412 (wayp->length && wayp->length<profile->length))
1413 goto endloop;
1414
1415 segment_pref=profile->highway[HIGHWAY(wayp->type)];
1416
1417 /* highway preferences must allow this highway */
1418 if(segment_pref==0)
1419 goto endloop;
1420
1421 for(i=1;i<Property_Count;i++)
1422 if(ways->file.props & PROPERTIES(i))
1423 {
1424 if(wayp->props & PROPERTIES(i))
1425 segment_pref*=profile->props_yes[i];
1426 else
1427 segment_pref*=profile->props_no[i];
1428 }
1429
1430 /* profile preferences must allow this highway */
1431 if(segment_pref==0)
1432 goto endloop;
1433
1434 if(!IsFakeNode(node2))
1435 node2p=LookupNode(nodes,node2,2);
1436
1437 /* mode of transport must be allowed through node2 (optionally as destination only) */
1438 if(node2p && !(node2p->allow&profile->allow) && !(allow_destination && node2p->destination&profile->allow))
1439 goto endloop;
1440
1441 /* calculate the score for the segment and cumulative */
1442 if(option_quickest==0)
1443 segment_score=(score_t)DISTANCE(segmentp->distance)/segment_pref;
1444 else
1445 segment_score=(score_t)Duration(segmentp,wayp,profile)/segment_pref;
1446
1447 /* prefer not to follow two fake segments when one would do (special case) */
1448 if(IsFakeSegment(seg1))
1449 segment_score*=1.01;
1450
1451 cumulative_score=result1->score+segment_score;
1452
1453 /* find whether the node/segment combination already exists */
1454 result2=FindResult(results,node2,seg2);
1455
1456 if(!result2) /* New end node */
1457 {
1458 result2=InsertResult(results,node2,seg2);
1459 result2->next=result1; /* working backwards */
1460 result2->score=cumulative_score;
1461 }
1462 else if(cumulative_score<result2->score) /* New end node is better */
1463 {
1464 result2->next=result1; /* working backwards */
1465 result2->score=cumulative_score;
1466 }
1467 else
1468 goto endloop;
1469
1470 if(IsFakeNode(node1) || !IsSuperNode(node1p))
1471 InsertInQueue(queue,result2,result2->score);
1472
1473 endloop:
1474
1475 if(IsFakeNode(node1))
1476 segmentp=NextFakeSegment(segmentp,node1);
1477 else
1478 segmentp=NextSegment(segments,segmentp,node1);
1479 }
1480 }
1481
1482 FreeQueueList(queue);
1483
1484 /* Check it worked */
1485
1486 if(results->number==1)
1487 {
1488 #if DEBUG
1489 printf(" Failed\n");
1490 #endif
1491
1492 #if !DEBUG
1493 if(!option_quiet)
1494 printf_last("Found Finish Route: Nodes checked = %d - Fail",results->number);
1495 #endif
1496
1497 FreeResultsList(results);
1498 return(NULL);
1499 }
1500
1501 /* Create a results structure with the node at the end of the segment opposite the start */
1502
1503 results2=NewResultsList(8);
1504
1505 results2->finish_node=results->finish_node;
1506
1507 result3=FirstResult(results);
1508
1509 while(result3)
1510 {
1511 if(result3->next)
1512 {
1513 result2=InsertResult(results2,result3->next->node,result3->segment);
1514
1515 result2->score=result3->next->score;
1516 }
1517
1518 result3=NextResult(results,result3);
1519 }
1520
1521 /* Fix up the result->next pointers */
1522
1523 result3=FirstResult(results);
1524
1525 while(result3)
1526 {
1527 if(result3->next && result3->next->next)
1528 {
1529 result1=FindResult(results2,result3->next->node,result3->segment);
1530 result2=FindResult(results2,result3->next->next->node,result3->next->segment);
1531
1532 result1->next=result2;
1533 }
1534
1535 result3=NextResult(results,result3);
1536 }
1537
1538 FreeResultsList(results);
1539
1540 #if DEBUG
1541 Result *s=FirstResult(results2);
1542
1543 while(s)
1544 {
1545 if(!IsFakeNode(s->node) && IsSuperNode(LookupNode(nodes,s->node,1)))
1546 {
1547 Result *r=FindResult(results2,s->node,s->segment);
1548
1549 printf(" -------- possible finish route\n");
1550
1551 while(r)
1552 {
1553 printf(" node=%"Pindex_t" segment=%"Pindex_t" score=%f%s%s\n",r->node,r->segment,r->score,
1554 (IsSuperNode(LookupNode(nodes,r->node,1))?" (super)":""),
1555 (r->node==finish_node?" (finish)":""));
1556
1557 r=r->next;
1558 }
1559 }
1560
1561 s=NextResult(results2,s);
1562 }
1563 #endif
1564
1565 #if !DEBUG
1566 if(!option_quiet)
1567 printf_last("Found Finish Route: Nodes checked = %d",results->number);
1568 #endif
1569
1570 return(results2);
1571 }
1572
1573
1574 /*++++++++++++++++++++++++++++++++++++++
1575 Create an optimum route given the set of super-nodes to follow.
1576
1577 Results *CombineRoutes Returns the results from joining the super-nodes.
1578
1579 Nodes *nodes The set of nodes to use.
1580
1581 Segments *segments The set of segments to use.
1582
1583 Ways *ways The set of ways to use.
1584
1585 Relations *relations The set of relations to use.
1586
1587 Profile *profile The profile containing the transport type, speeds and allowed highways.
1588
1589 Results *begin The set of results for the start of the route.
1590
1591 Results *middle The set of results from the super-node route.
1592
1593 Results *end The set of results for the end of the route.
1594 ++++++++++++++++++++++++++++++++++++++*/
1595
1596 Results *CombineRoutes(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Profile *profile,Results *begin,Results *middle,Results *end)
1597 {
1598 Result *midres,*comres;
1599 Results *combined;
1600
1601 #if DEBUG
1602 printf(" CombineRoutes(...,[begin has %d nodes],[middle has %d nodes],[end has %d nodes])\n",begin->number,middle->number,end->number);
1603 #endif
1604
1605 #if !DEBUG
1606 if(!option_quiet)
1607 printf_first("Finding Combined Route: Nodes = 0");
1608 #endif
1609
1610 combined=NewResultsList(10);
1611
1612 combined->start_node=begin->start_node;
1613 combined->prev_segment=begin->prev_segment;
1614
1615 /* Insert the start point */
1616
1617 midres=FindResult(middle,middle->start_node,middle->prev_segment);
1618
1619 comres=InsertResult(combined,combined->start_node,combined->prev_segment);
1620
1621 /* Insert the start of the route */
1622
1623 if(begin->number>1 && midres->next)
1624 {
1625 Result *begres;
1626
1627 midres=FindResult(middle,midres->next->node,midres->next->segment);
1628
1629 begres=FindResult(begin,midres->node,midres->segment);
1630
1631 FixForwardRoute(begin,begres);
1632
1633 if(midres->next && midres->next->node==midres->node)
1634 midres=midres->next;
1635
1636 begres=FindResult(begin,begin->start_node,begin->prev_segment);
1637
1638 begres=begres->next;
1639
1640 do
1641 {
1642 Result *comres2;
1643
1644 comres2=InsertResult(combined,begres->node,begres->segment);
1645
1646 comres2->score=begres->score;
1647 comres2->prev=comres;
1648
1649 begres=begres->next;
1650
1651 comres=comres2;
1652 }
1653 while(begres);
1654 }
1655
1656 /* Sort out the combined route */
1657
1658 while(midres->next)
1659 {
1660 Results *results=FindNormalRoute(nodes,segments,ways,relations,profile,comres->node,comres->segment,midres->next->node);
1661 Result *result;
1662
1663 if(!results)
1664 {
1665 #if !DEBUG
1666 if(!option_quiet)
1667 printf_last("Found Combined Route: Nodes = %d - Fail",combined->number);
1668 #endif
1669
1670 FreeResultsList(combined);
1671 return(NULL);
1672 }
1673
1674 result=FindResult(results,midres->node,comres->segment);
1675
1676 result=result->next;
1677
1678 /*
1679 * midres midres->next
1680 * = =
1681 * ---*----------------------------------* = middle
1682 *
1683 * ---*----.----.----.----.----.----.----* = results
1684 * =
1685 * result
1686 *
1687 * ---*----.----.----.----.----.----.----* = combined
1688 * = =
1689 * comres comres2
1690 */
1691
1692 do
1693 {
1694 Result *comres2;
1695
1696 comres2=InsertResult(combined,result->node,result->segment);
1697
1698 comres2->score=midres->score+result->score;
1699 comres2->prev=comres;
1700
1701 result=result->next;
1702
1703 comres=comres2;
1704 }
1705 while(result);
1706
1707 FreeResultsList(results);
1708
1709 midres=midres->next;
1710 }
1711
1712 /* Insert the end of the route */
1713
1714 if(end->number>1)
1715 {
1716 Result *endres=FindResult(end,midres->node,midres->segment);
1717
1718 while(endres->next)
1719 {
1720 Result *comres2;
1721
1722 comres2=InsertResult(combined,endres->next->node,endres->next->segment);
1723
1724 comres2->score=comres->score+(endres->score-endres->next->score);
1725 comres2->prev=comres;
1726
1727 endres=endres->next;
1728
1729 comres=comres2;
1730 }
1731 }
1732
1733 /* Turn the route round */
1734
1735 combined->finish_node=comres->node;
1736 combined->last_segment=comres->segment;
1737
1738 FixForwardRoute(combined,comres);
1739
1740 #if DEBUG
1741 Result *r=FindResult(combined,combined->start_node,combined->prev_segment);
1742
1743 printf(" -------- combined route (end-to-end)\n");
1744
1745 while(r)
1746 {
1747 printf(" node=%"Pindex_t" segment=%"Pindex_t" score=%f%s%s%s\n",r->node,r->segment,r->score,
1748 (IsSuperNode(LookupNode(nodes,r->node,1))?" (super)":""),
1749 (r->node==combined->start_node&&r->segment==combined->prev_segment?" (start)":""),
1750 (r->node==combined->finish_node?" (finish)":""));
1751
1752 r=r->next;
1753 }
1754 #endif
1755
1756 #if !DEBUG
1757 if(!option_quiet)
1758 printf_last("Found Combined Route: Nodes = %d",combined->number);
1759 #endif
1760
1761 return(combined);
1762 }
1763
1764
1765 /*++++++++++++++++++++++++++++++++++++++
1766 Fix the forward route (i.e. setup next pointers for forward path from prev nodes on reverse path).
1767
1768 Results *results The set of results to update.
1769
1770 Result *finish_result The result for the finish point.
1771 ++++++++++++++++++++++++++++++++++++++*/
1772
1773 void FixForwardRoute(Results *results,Result *finish_result)
1774 {
1775 Result *result2=finish_result;
1776
1777 /* Erase the old route if there is one */
1778
1779 if(results->finish_node!=NO_NODE)
1780 {
1781 Result *result1=FirstResult(results);
1782
1783 while(result1)
1784 {
1785 result1->next=NULL;
1786
1787 result1=NextResult(results,result1);
1788 }
1789 }
1790
1791 /* Create the forward links for the optimum path */
1792
1793 do
1794 {
1795 Result *result1;
1796
1797 if(result2->prev)
1798 {
1799 index_t node1=result2->prev->node;
1800 index_t seg1=result2->prev->segment;
1801
1802 result1=FindResult(results,node1,seg1);
1803
1804 logassert(!result1->next,"Unable to reverse route through results (report a bug)"); /* Bugs elsewhere can lead to infinite loop here. */
1805
1806 result1->next=result2;
1807
1808 result2=result1;
1809 }
1810 else
1811 result2=NULL;
1812 }
1813 while(result2);
1814
1815 results->finish_node=finish_result->node;
1816 results->last_segment=finish_result->segment;
1817 }

Properties

Name Value
cvs:description Route optimiser.