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 1842 - (show annotations) (download) (as text)
Mon Dec 7 08:48:50 2015 UTC (9 years, 3 months ago) by amb
File MIME type: text/x-csrc
File size: 59414 byte(s)
Fix bug in last change (FindFinishRoutes is not the same as the other
functions).

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

Properties

Name Value
cvs:description Route optimiser.