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 1860 - (show annotations) (download) (as text)
Thu Feb 25 18:35:18 2016 UTC (9 years, 1 month ago) by amb
File MIME type: text/x-csrc
File size: 60359 byte(s)
Merge from trunk r1846 to r1848 (optimiser.c beginning and end of route changes).

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

Properties

Name Value
cvs:description Route optimiser.