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