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 1217 - (show annotations) (download) (as text)
Mon Dec 17 19:56:55 2012 UTC (12 years, 3 months ago) by amb
File MIME type: text/x-csrc
File size: 41494 byte(s)
Refactor to remove duplicated code in each branch of if statement (in each
optimiser loop).

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

Properties

Name Value
cvs:description Route optimiser.