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 1844 - (show annotations) (download) (as text)
Mon Dec 14 11:39:43 2015 UTC (9 years, 3 months ago) by amb
File MIME type: text/x-csrc
File size: 57921 byte(s)
Improve the debug output (use a common function for all of them and
add more information).

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

Properties

Name Value
cvs:description Route optimiser.