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 610 -
(show annotations)
(download)
(as text)
Sat Jan 29 17:50:15 2011 UTC (14 years, 2 months ago) by amb
File MIME type: text/x-csrc
File size: 29511 byte(s)
Sat Jan 29 17:50:15 2011 UTC (14 years, 2 months ago) by amb
File MIME type: text/x-csrc
File size: 29511 byte(s)
Add some comments, shuffle a few lines of code.
1 | /*************************************** |
2 | Routing optimiser. |
3 | |
4 | Part of the Routino routing software. |
5 | ******************/ /****************** |
6 | This file Copyright 2008-2011 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 <stdio.h> |
24 | |
25 | #include "types.h" |
26 | #include "nodes.h" |
27 | #include "segments.h" |
28 | #include "ways.h" |
29 | #include "relations.h" |
30 | |
31 | #include "logging.h" |
32 | #include "functions.h" |
33 | #include "fakes.h" |
34 | #include "results.h" |
35 | |
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 | /*++++++++++++++++++++++++++++++++++++++ |
45 | Find the optimum route between two nodes not passing through a super-node. |
46 | |
47 | Results *FindNormalRoute Returns a set of results. |
48 | |
49 | Nodes *nodes The set of nodes to use. |
50 | |
51 | Segments *segments The set of segments to use. |
52 | |
53 | Ways *ways The set of ways to use. |
54 | |
55 | Relations *relations The set of relations to use. |
56 | |
57 | index_t start_node The start node. |
58 | |
59 | index_t prev_segment The previous segment before the start node. |
60 | |
61 | index_t finish_node The finish node. |
62 | |
63 | Profile *profile The profile containing the transport type, speeds and allowed highways. |
64 | ++++++++++++++++++++++++++++++++++++++*/ |
65 | |
66 | Results *FindNormalRoute(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,index_t start_node,index_t prev_segment,index_t finish_node,Profile *profile) |
67 | { |
68 | Results *results; |
69 | Queue *queue; |
70 | score_t finish_score; |
71 | double finish_lat,finish_lon; |
72 | Result *finish_result; |
73 | Result *result1,*result2; |
74 | |
75 | // printf("FindNormalRoute(start_node=%ld prev_segment=%ld finish_node=%ld)\n",start_node,prev_segment,finish_node); |
76 | |
77 | /* Set up the finish conditions */ |
78 | |
79 | finish_score=INF_SCORE; |
80 | finish_result=NULL; |
81 | |
82 | if(IsFakeNode(finish_node)) |
83 | GetFakeLatLong(finish_node,&finish_lat,&finish_lon); |
84 | else |
85 | GetLatLong(nodes,finish_node,&finish_lat,&finish_lon); |
86 | |
87 | /* Create the list of results and insert the first node into the queue */ |
88 | |
89 | results=NewResultsList(8); |
90 | |
91 | results->start_node=start_node; |
92 | results->finish_node=finish_node; |
93 | |
94 | result1=InsertResult(results,start_node,prev_segment); |
95 | |
96 | queue=NewQueueList(); |
97 | |
98 | InsertInQueue(queue,result1); |
99 | |
100 | /* Loop across all nodes in the queue */ |
101 | |
102 | while((result1=PopFromQueue(queue))) |
103 | { |
104 | Segment *segment; |
105 | index_t node1,seg1; |
106 | index_t turnrelation=NO_RELATION; |
107 | |
108 | if(result1->score>finish_score) |
109 | continue; |
110 | |
111 | node1=result1->node; |
112 | seg1=result1->segment; |
113 | |
114 | if(IsTurnRestrictedNode(LookupNode(nodes,node1,1))) |
115 | turnrelation=FindFirstTurnRelation2(relations,node1,seg1); |
116 | |
117 | if(IsFakeNode(node1)) |
118 | segment=FirstFakeSegment(node1); |
119 | else |
120 | segment=FirstSegment(segments,nodes,node1); |
121 | |
122 | while(segment) |
123 | { |
124 | Way *way; |
125 | index_t node2,seg2; |
126 | score_t segment_pref,segment_score,cumulative_score; |
127 | int i; |
128 | |
129 | node2=OtherNode(segment,node1); /* need this here because we use node2 at the end of the loop */ |
130 | |
131 | if(!IsNormalSegment(segment)) |
132 | goto endloop; |
133 | |
134 | if(profile->oneway && IsOnewayTo(segment,node1)) |
135 | goto endloop; |
136 | |
137 | if(result1->prev && result1->prev->node==node2) |
138 | goto endloop; |
139 | |
140 | if(IsFakeNode(node1) || IsFakeNode(node2)) |
141 | seg2=IndexFakeSegment(segment); |
142 | else |
143 | seg2=IndexSegment(segments,segment); |
144 | |
145 | if(turnrelation!=NO_RELATION && !IsTurnAllowed(relations,turnrelation,node1,seg1,seg2,profile->allow)) |
146 | goto endloop; |
147 | |
148 | if(node2!=finish_node && !IsFakeNode(node2) && IsSuperNode(LookupNode(nodes,node2,2))) |
149 | goto endloop; |
150 | |
151 | way=LookupWay(ways,segment->way,1); |
152 | |
153 | if(!(way->allow&profile->allow)) |
154 | goto endloop; |
155 | |
156 | if(!profile->highway[HIGHWAY(way->type)]) |
157 | goto endloop; |
158 | |
159 | if(way->weight && way->weight<profile->weight) |
160 | goto endloop; |
161 | |
162 | if((way->height && way->height<profile->height) || |
163 | (way->width && way->width <profile->width ) || |
164 | (way->length && way->length<profile->length)) |
165 | goto endloop; |
166 | |
167 | segment_pref=profile->highway[HIGHWAY(way->type)]; |
168 | |
169 | for(i=1;i<Property_Count;i++) |
170 | if(ways->file.props & PROPERTIES(i)) |
171 | { |
172 | if(way->props & PROPERTIES(i)) |
173 | segment_pref*=profile->props_yes[i]; |
174 | else |
175 | segment_pref*=profile->props_no[i]; |
176 | } |
177 | |
178 | if(segment_pref==0) |
179 | goto endloop; |
180 | |
181 | if(!IsFakeNode(node2)) |
182 | { |
183 | Node *node=LookupNode(nodes,node2,2); |
184 | |
185 | if(!(node->allow&profile->allow)) |
186 | goto endloop; |
187 | } |
188 | |
189 | if(option_quickest==0) |
190 | segment_score=(score_t)DISTANCE(segment->distance)/segment_pref; |
191 | else |
192 | segment_score=(score_t)Duration(segment,way,profile)/segment_pref; |
193 | |
194 | cumulative_score=result1->score+segment_score; |
195 | |
196 | if(cumulative_score>finish_score) |
197 | goto endloop; |
198 | |
199 | result2=FindResult(results,node2,seg2); |
200 | |
201 | if(!result2) /* New end node/segment combination */ |
202 | { |
203 | result2=InsertResult(results,node2,seg2); |
204 | result2->prev=result1; |
205 | result2->score=cumulative_score; |
206 | |
207 | if(node2==finish_node) |
208 | { |
209 | if(cumulative_score<finish_score) |
210 | { |
211 | finish_score=cumulative_score; |
212 | finish_result=result2; |
213 | } |
214 | } |
215 | else |
216 | { |
217 | result2->sortby=result2->score; |
218 | |
219 | InsertInQueue(queue,result2); |
220 | } |
221 | } |
222 | else if(cumulative_score<result2->score) /* New score for end node/segment combination is better */ |
223 | { |
224 | result2->prev=result1; |
225 | result2->score=cumulative_score; |
226 | result2->segment=seg2; |
227 | |
228 | if(node2==finish_node) |
229 | { |
230 | if(cumulative_score<finish_score) |
231 | { |
232 | finish_score=cumulative_score; |
233 | finish_result=result2; |
234 | } |
235 | } |
236 | else |
237 | { |
238 | result2->sortby=result2->score; |
239 | |
240 | if(result2->score<finish_score) |
241 | InsertInQueue(queue,result2); |
242 | } |
243 | } |
244 | |
245 | endloop: |
246 | |
247 | if(IsFakeNode(node1)) |
248 | segment=NextFakeSegment(segment,node1); |
249 | else if(IsFakeNode(node2)) |
250 | segment=NULL; /* cannot call NextSegment() with a fake segment */ |
251 | else |
252 | { |
253 | segment=NextSegment(segments,segment,node1); |
254 | |
255 | if(!segment && IsFakeNode(finish_node)) |
256 | segment=ExtraFakeSegment(node1,finish_node); |
257 | } |
258 | } |
259 | } |
260 | |
261 | FreeQueueList(queue); |
262 | |
263 | /* Check it worked */ |
264 | |
265 | if(!finish_result) |
266 | { |
267 | FreeResultsList(results); |
268 | return(NULL); |
269 | } |
270 | |
271 | FixForwardRoute(results,finish_result); |
272 | |
273 | return(results); |
274 | } |
275 | |
276 | |
277 | /*++++++++++++++++++++++++++++++++++++++ |
278 | Find the optimum route between two nodes where the start and end are a set of pre-routed super-nodes. |
279 | |
280 | Results *FindMiddleRoute Returns a set of results. |
281 | |
282 | Nodes *nodes The set of nodes to use. |
283 | |
284 | Segments *segments The set of segments to use. |
285 | |
286 | Ways *ways The set of ways to use. |
287 | |
288 | Relations *relations The set of relations to use. |
289 | |
290 | Results *begin The initial portion of the route. |
291 | |
292 | Results *end The final portion of the route. |
293 | |
294 | Profile *profile The profile containing the transport type, speeds and allowed highways. |
295 | ++++++++++++++++++++++++++++++++++++++*/ |
296 | |
297 | Results *FindMiddleRoute(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Results *begin,Results *end,Profile *profile) |
298 | { |
299 | Results *results; |
300 | Queue *queue; |
301 | Result *finish_result; |
302 | score_t finish_score; |
303 | double finish_lat,finish_lon; |
304 | Result *result1,*result2,*result3; |
305 | |
306 | if(!option_quiet) |
307 | printf_first("Routing: Super-Nodes checked = 0"); |
308 | |
309 | /* Set up the finish conditions */ |
310 | |
311 | finish_score=INF_DISTANCE; |
312 | finish_result=NULL; |
313 | |
314 | if(IsFakeNode(end->finish_node)) |
315 | GetFakeLatLong(end->finish_node,&finish_lat,&finish_lon); |
316 | else |
317 | GetLatLong(nodes,end->finish_node,&finish_lat,&finish_lon); |
318 | |
319 | /* Create the list of results and insert the first node into the queue */ |
320 | |
321 | results=NewResultsList(2048); |
322 | |
323 | results->start_node=begin->start_node; |
324 | results->prev_segment=begin->prev_segment; |
325 | |
326 | results->finish_node=end->finish_node; |
327 | |
328 | result1=InsertResult(results,begin->start_node,begin->prev_segment); |
329 | |
330 | queue=NewQueueList(); |
331 | |
332 | /* Insert the finish points of the beginning part of the path into the queue */ |
333 | |
334 | result3=FirstResult(begin); |
335 | |
336 | while(result3) |
337 | { |
338 | if(result3->node!=begin->start_node && !IsFakeNode(result3->node) && IsSuperNode(LookupNode(nodes,result3->node,1))) |
339 | { |
340 | result2=InsertResult(results,result3->node,result3->segment); |
341 | |
342 | result2->prev=result1; |
343 | |
344 | result2->score=result3->score; |
345 | result2->sortby=result3->score; |
346 | |
347 | InsertInQueue(queue,result2); |
348 | } |
349 | |
350 | result3=NextResult(begin,result3); |
351 | } |
352 | |
353 | if(begin->number==1) |
354 | InsertInQueue(queue,result1); |
355 | |
356 | /* Loop across all nodes in the queue */ |
357 | |
358 | while((result1=PopFromQueue(queue))) |
359 | { |
360 | index_t node1,seg1; |
361 | Segment *segment; |
362 | index_t turnrelation=NO_RELATION; |
363 | |
364 | if(result1->score>finish_score) |
365 | continue; |
366 | |
367 | node1=result1->node; |
368 | seg1=result1->segment; |
369 | |
370 | if(IsTurnRestrictedNode(LookupNode(nodes,node1,1))) |
371 | turnrelation=FindFirstTurnRelation2(relations,node1,seg1); |
372 | |
373 | /* node1 cannot be a fake node (must be a super-node) */ |
374 | segment=FirstSegment(segments,nodes,node1); |
375 | |
376 | while(segment) |
377 | { |
378 | Way *way; |
379 | Node *node; |
380 | index_t node2,seg2; |
381 | score_t segment_pref,segment_score,cumulative_score; |
382 | int i; |
383 | |
384 | if(!IsSuperSegment(segment)) |
385 | goto endloop; |
386 | |
387 | if(profile->oneway && IsOnewayTo(segment,node1)) |
388 | goto endloop; |
389 | |
390 | node2=OtherNode(segment,node1); |
391 | |
392 | if(result1->prev && result1->prev->node==node2) |
393 | goto endloop; |
394 | |
395 | /* node2 cannot be a fake node (must be a super-node) */ |
396 | seg2=IndexSegment(segments,segment); |
397 | |
398 | if(turnrelation!=NO_RELATION && !IsTurnAllowed(relations,turnrelation,node1,seg1,seg2,profile->allow)) |
399 | goto endloop; |
400 | |
401 | way=LookupWay(ways,segment->way,1); |
402 | |
403 | if(!(way->allow&profile->allow)) |
404 | goto endloop; |
405 | |
406 | if(!profile->highway[HIGHWAY(way->type)]) |
407 | goto endloop; |
408 | |
409 | if(way->weight && way->weight<profile->weight) |
410 | goto endloop; |
411 | |
412 | if((way->height && way->height<profile->height) || |
413 | (way->width && way->width <profile->width ) || |
414 | (way->length && way->length<profile->length)) |
415 | goto endloop; |
416 | |
417 | segment_pref=profile->highway[HIGHWAY(way->type)]; |
418 | |
419 | for(i=1;i<Property_Count;i++) |
420 | if(ways->file.props & PROPERTIES(i)) |
421 | { |
422 | if(way->props & PROPERTIES(i)) |
423 | segment_pref*=profile->props_yes[i]; |
424 | else |
425 | segment_pref*=profile->props_no[i]; |
426 | } |
427 | |
428 | if(segment_pref==0) |
429 | goto endloop; |
430 | |
431 | /* node2 cannot be a fake node (must be a super-node) */ |
432 | node=LookupNode(nodes,node2,2); |
433 | |
434 | if(!(node->allow&profile->allow)) |
435 | goto endloop; |
436 | |
437 | if(option_quickest==0) |
438 | segment_score=(score_t)DISTANCE(segment->distance)/segment_pref; |
439 | else |
440 | segment_score=(score_t)Duration(segment,way,profile)/segment_pref; |
441 | |
442 | cumulative_score=result1->score+segment_score; |
443 | |
444 | if(cumulative_score>finish_score) |
445 | goto endloop; |
446 | |
447 | result2=FindResult(results,node2,seg2); |
448 | |
449 | if(!result2) /* New end node/segment pair */ |
450 | { |
451 | result2=InsertResult(results,node2,seg2); |
452 | result2->prev=result1; |
453 | result2->score=cumulative_score; |
454 | |
455 | if((result3=FindResult(end,node2,seg2))) |
456 | { |
457 | if((result2->score+result3->score)<finish_score) |
458 | { |
459 | finish_score=result2->score+result3->score; |
460 | finish_result=result2; |
461 | } |
462 | } |
463 | else |
464 | { |
465 | double lat,lon; |
466 | distance_t direct; |
467 | |
468 | /* node2 cannot be a fake node (must be a super-node) */ |
469 | GetLatLong(nodes,node2,&lat,&lon); |
470 | direct=Distance(lat,lon,finish_lat,finish_lon); |
471 | |
472 | if(option_quickest==0) |
473 | result2->sortby=result2->score+(score_t)direct/profile->max_pref; |
474 | else |
475 | result2->sortby=result2->score+(score_t)distance_speed_to_duration(direct,profile->max_speed)/profile->max_pref; |
476 | |
477 | InsertInQueue(queue,result2); |
478 | } |
479 | } |
480 | else if(cumulative_score<result2->score) /* New end node/segment pair is better */ |
481 | { |
482 | result2->prev=result1; |
483 | result2->score=cumulative_score; |
484 | |
485 | if((result3=FindResult(end,node2,seg2))) |
486 | { |
487 | if((result2->score+result3->score)<finish_score) |
488 | { |
489 | finish_score=result2->score+result3->score; |
490 | finish_result=result2; |
491 | } |
492 | } |
493 | else if(result2->score<finish_score) |
494 | { |
495 | double lat,lon; |
496 | distance_t direct; |
497 | |
498 | /* node2 cannot be a fake node (must be a super-node) */ |
499 | GetLatLong(nodes,node2,&lat,&lon); |
500 | direct=Distance(lat,lon,finish_lat,finish_lon); |
501 | |
502 | if(option_quickest==0) |
503 | result2->sortby=result2->score+(score_t)direct/profile->max_pref; |
504 | else |
505 | result2->sortby=result2->score+(score_t)distance_speed_to_duration(direct,profile->max_speed)/profile->max_pref; |
506 | |
507 | InsertInQueue(queue,result2); |
508 | } |
509 | } |
510 | |
511 | endloop: |
512 | |
513 | if(!option_quiet && !(results->number%10000)) |
514 | printf_middle("Routing: Super-Nodes checked = %d",results->number); |
515 | |
516 | /* node1 cannot be a fake node (must be a super-node) */ |
517 | segment=NextSegment(segments,segment,node1); |
518 | } |
519 | } |
520 | |
521 | if(!option_quiet) |
522 | printf_last("Routing: Super-Nodes checked = %d",results->number); |
523 | |
524 | FreeQueueList(queue); |
525 | |
526 | /* Check it worked */ |
527 | |
528 | if(!finish_result) |
529 | { |
530 | FreeResultsList(results); |
531 | return(NULL); |
532 | } |
533 | |
534 | /* Finish off the end part of the route. */ |
535 | |
536 | result3=InsertResult(results,end->finish_node,NO_SEGMENT); |
537 | |
538 | result3->prev=finish_result; |
539 | result3->score=finish_score; |
540 | |
541 | FixForwardRoute(results,result3); |
542 | |
543 | return(results); |
544 | } |
545 | |
546 | |
547 | /*++++++++++++++++++++++++++++++++++++++ |
548 | Find all routes from a specified node to any super-node. |
549 | |
550 | Results *FindStartRoutes Returns a set of results. |
551 | |
552 | Nodes *nodes The set of nodes to use. |
553 | |
554 | Segments *segments The set of segments to use. |
555 | |
556 | Ways *ways The set of ways to use. |
557 | |
558 | Relations *relations The set of relations to use. |
559 | |
560 | index_t start_node The start node. |
561 | |
562 | index_t prev_segment The previous segment before the start node. |
563 | |
564 | Profile *profile The profile containing the transport type, speeds and allowed highways. |
565 | ++++++++++++++++++++++++++++++++++++++*/ |
566 | |
567 | Results *FindStartRoutes(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,index_t start_node,index_t prev_segment,Profile *profile) |
568 | { |
569 | Results *results; |
570 | Queue *queue; |
571 | Result *result1,*result2; |
572 | |
573 | /* Create the results and insert the start node */ |
574 | |
575 | results=NewResultsList(8); |
576 | |
577 | results->start_node=start_node; |
578 | results->prev_segment=prev_segment; |
579 | |
580 | result1=InsertResult(results,start_node,prev_segment); |
581 | |
582 | /* Take a shortcut if the first node is a super-node. */ |
583 | |
584 | if(!IsFakeNode(start_node) && IsSuperNode(LookupNode(nodes,start_node,1))) |
585 | return(results); |
586 | |
587 | /* Insert the first node into the queue */ |
588 | |
589 | queue=NewQueueList(); |
590 | |
591 | InsertInQueue(queue,result1); |
592 | |
593 | /* Loop across all nodes in the queue */ |
594 | |
595 | while((result1=PopFromQueue(queue))) |
596 | { |
597 | index_t node1,seg1; |
598 | Segment *segment; |
599 | // index_t turnrelation=NO_RELATION; |
600 | |
601 | node1=result1->node; |
602 | seg1=result1->segment; |
603 | |
604 | if(IsFakeNode(node1)) |
605 | segment=FirstFakeSegment(node1); |
606 | else |
607 | segment=FirstSegment(segments,nodes,node1); |
608 | |
609 | // if(IsTurnRestrictedNode(LookupNode(nodes,node1,1))) |
610 | // turnrelation=FindFirstTurnRelation2(relations,node1,seg1); |
611 | |
612 | while(segment) |
613 | { |
614 | Way *way; |
615 | index_t node2,seg2; |
616 | score_t segment_pref,segment_score,cumulative_score; |
617 | int i; |
618 | |
619 | if(!IsNormalSegment(segment)) |
620 | goto endloop; |
621 | |
622 | if(profile->oneway && IsOnewayTo(segment,node1)) |
623 | goto endloop; |
624 | |
625 | node2=OtherNode(segment,node1); |
626 | |
627 | if(result1->prev && result1->prev->node==node2) |
628 | goto endloop; |
629 | |
630 | if(IsFakeNode(node1) || IsFakeNode(node2)) |
631 | seg2=IndexFakeSegment(segment); |
632 | else |
633 | seg2=IndexSegment(segments,segment); |
634 | |
635 | // if(turnrelation!=NO_RELATION && !IsTurnAllowed(relations,turnrelation,node1,seg1,seg2,profile->allow)) |
636 | // goto endloop; |
637 | |
638 | way=LookupWay(ways,segment->way,1); |
639 | |
640 | if(!(way->allow&profile->allow)) |
641 | goto endloop; |
642 | |
643 | if(!profile->highway[HIGHWAY(way->type)]) |
644 | goto endloop; |
645 | |
646 | if(way->weight && way->weight<profile->weight) |
647 | goto endloop; |
648 | |
649 | if((way->height && way->height<profile->height) || |
650 | (way->width && way->width <profile->width ) || |
651 | (way->length && way->length<profile->length)) |
652 | goto endloop; |
653 | |
654 | segment_pref=profile->highway[HIGHWAY(way->type)]; |
655 | |
656 | for(i=1;i<Property_Count;i++) |
657 | if(ways->file.props & PROPERTIES(i)) |
658 | { |
659 | if(way->props & PROPERTIES(i)) |
660 | segment_pref*=profile->props_yes[i]; |
661 | else |
662 | segment_pref*=profile->props_no[i]; |
663 | } |
664 | |
665 | if(segment_pref==0) |
666 | goto endloop; |
667 | |
668 | if(!IsFakeNode(node2)) |
669 | { |
670 | Node *node=LookupNode(nodes,node2,2); |
671 | |
672 | if(!(node->allow&profile->allow)) |
673 | goto endloop; |
674 | } |
675 | |
676 | if(option_quickest==0) |
677 | segment_score=(score_t)DISTANCE(segment->distance)/segment_pref; |
678 | else |
679 | segment_score=(score_t)Duration(segment,way,profile)/segment_pref; |
680 | |
681 | cumulative_score=result1->score+segment_score; |
682 | |
683 | result2=FindResult(results,node2,seg2); |
684 | |
685 | if(!result2) /* New end node/segment combination */ |
686 | { |
687 | result2=InsertResult(results,node2,seg2); |
688 | result2->prev=result1; |
689 | result2->score=cumulative_score; |
690 | |
691 | if(!IsFakeNode(node2) && !IsSuperNode(LookupNode(nodes,node2,2))) |
692 | { |
693 | result2->sortby=result2->score; |
694 | InsertInQueue(queue,result2); |
695 | } |
696 | } |
697 | else if(cumulative_score<result2->score) /* New end node/segment combination is better */ |
698 | { |
699 | result2->prev=result1; |
700 | result2->score=cumulative_score; |
701 | |
702 | if(!IsFakeNode(node2) && !IsSuperNode(LookupNode(nodes,node2,2))) |
703 | { |
704 | result2->sortby=result2->score; |
705 | InsertInQueue(queue,result2); |
706 | } |
707 | } |
708 | |
709 | endloop: |
710 | |
711 | if(IsFakeNode(node1)) |
712 | segment=NextFakeSegment(segment,node1); |
713 | else |
714 | segment=NextSegment(segments,segment,node1); |
715 | } |
716 | } |
717 | |
718 | FreeQueueList(queue); |
719 | |
720 | /* Check it worked */ |
721 | |
722 | if(results->number==1) |
723 | { |
724 | FreeResultsList(results); |
725 | return(NULL); |
726 | } |
727 | |
728 | return(results); |
729 | } |
730 | |
731 | |
732 | /*++++++++++++++++++++++++++++++++++++++ |
733 | Find all routes from any super-node to a specific node. |
734 | |
735 | Results *FindFinishRoutes Returns a set of results. |
736 | |
737 | Nodes *nodes The set of nodes to use. |
738 | |
739 | Segments *segments The set of segments to use. |
740 | |
741 | Ways *ways The set of ways to use. |
742 | |
743 | Relations *relations The set of relations to use. |
744 | |
745 | index_t finish_node The finishing node. |
746 | |
747 | Profile *profile The profile containing the transport type, speeds and allowed highways. |
748 | ++++++++++++++++++++++++++++++++++++++*/ |
749 | |
750 | Results *FindFinishRoutes(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,index_t finish_node,Profile *profile) |
751 | { |
752 | Results *results,*results2; |
753 | Queue *queue; |
754 | Result *result1,*result2,*result3; |
755 | |
756 | /* Create the results and insert the finish node */ |
757 | |
758 | results=NewResultsList(8); |
759 | |
760 | results->finish_node=finish_node; |
761 | |
762 | result1=InsertResult(results,finish_node,NO_SEGMENT); |
763 | |
764 | /* Take a shortcut if the first node is a super-node. */ |
765 | |
766 | if(!IsFakeNode(finish_node) && IsSuperNode(LookupNode(nodes,finish_node,1))) |
767 | return(results); |
768 | |
769 | /* Insert the first node into the queue */ |
770 | |
771 | queue=NewQueueList(); |
772 | |
773 | InsertInQueue(queue,result1); |
774 | |
775 | /* Loop across all nodes in the queue */ |
776 | |
777 | while((result1=PopFromQueue(queue))) |
778 | { |
779 | index_t node1,seg1; |
780 | Segment *segment; |
781 | index_t turnrelation=NO_RELATION; |
782 | |
783 | node1=result1->node; |
784 | seg1=result1->segment; |
785 | |
786 | if(IsTurnRestrictedNode(LookupNode(nodes,node1,1))) |
787 | turnrelation=FindFirstTurnRelation1(relations,node1); /* working backwards => turn relation sort order doesn't help */ |
788 | |
789 | if(IsFakeNode(node1)) |
790 | segment=FirstFakeSegment(node1); |
791 | else |
792 | segment=FirstSegment(segments,nodes,node1); |
793 | |
794 | while(segment) |
795 | { |
796 | Way *way; |
797 | index_t node2,seg2; |
798 | score_t segment_pref,segment_score,cumulative_score; |
799 | int i; |
800 | |
801 | if(!IsNormalSegment(segment)) |
802 | goto endloop; |
803 | |
804 | if(profile->oneway && IsOnewayFrom(segment,node1)) /* Disallow oneway from node2 *to* node1 */ |
805 | goto endloop; |
806 | |
807 | node2=OtherNode(segment,node1); |
808 | |
809 | if(result1->next && result1->next->node==node2) |
810 | goto endloop; |
811 | |
812 | if(IsFakeNode(node1) || IsFakeNode(node2)) |
813 | seg2=IndexFakeSegment(segment); |
814 | else |
815 | seg2=IndexSegment(segments,segment); |
816 | |
817 | if(turnrelation!=NO_RELATION) |
818 | { |
819 | index_t turnrelation2=FindFirstTurnRelation2(relations,node1,node2); /* node2 -> node1 -> result1->next->node */ |
820 | |
821 | if(turnrelation2!=NO_RELATION && !IsTurnAllowed(relations,turnrelation2,node1,seg2,seg1,profile->allow)) |
822 | goto endloop; |
823 | } |
824 | |
825 | way=LookupWay(ways,segment->way,1); |
826 | |
827 | if(!(way->allow&profile->allow)) |
828 | goto endloop; |
829 | |
830 | if(!profile->highway[HIGHWAY(way->type)]) |
831 | goto endloop; |
832 | |
833 | if(way->weight && way->weight<profile->weight) |
834 | goto endloop; |
835 | |
836 | if((way->height && way->height<profile->height) || |
837 | (way->width && way->width <profile->width ) || |
838 | (way->length && way->length<profile->length)) |
839 | goto endloop; |
840 | |
841 | segment_pref=profile->highway[HIGHWAY(way->type)]; |
842 | |
843 | for(i=1;i<Property_Count;i++) |
844 | if(ways->file.props & PROPERTIES(i)) |
845 | { |
846 | if(way->props & PROPERTIES(i)) |
847 | segment_pref*=profile->props_yes[i]; |
848 | else |
849 | segment_pref*=profile->props_no[i]; |
850 | } |
851 | |
852 | if(segment_pref==0) |
853 | goto endloop; |
854 | |
855 | if(!IsFakeNode(node2)) |
856 | { |
857 | Node *node=LookupNode(nodes,node2,2); |
858 | |
859 | if(!(node->allow&profile->allow)) |
860 | goto endloop; |
861 | } |
862 | |
863 | if(option_quickest==0) |
864 | segment_score=(score_t)DISTANCE(segment->distance)/segment_pref; |
865 | else |
866 | segment_score=(score_t)Duration(segment,way,profile)/segment_pref; |
867 | |
868 | cumulative_score=result1->score+segment_score; |
869 | |
870 | result2=FindResult(results,node2,seg2); |
871 | |
872 | if(!result2) /* New end node */ |
873 | { |
874 | result2=InsertResult(results,node2,seg2); |
875 | result2->next=result1; /* working backwards */ |
876 | result2->score=cumulative_score; |
877 | |
878 | if(IsFakeNode(node1) || (!IsFakeNode(node1) && !IsSuperNode(LookupNode(nodes,node1,1)))) /* Overshoot by one segment */ |
879 | { |
880 | result2->sortby=result2->score; |
881 | InsertInQueue(queue,result2); |
882 | } |
883 | } |
884 | else if(cumulative_score<result2->score) /* New end node is better */ |
885 | { |
886 | result2->next=result1; /* working backwards */ |
887 | result2->score=cumulative_score; |
888 | |
889 | if(IsFakeNode(node1) || (!IsFakeNode(node1) && !IsSuperNode(LookupNode(nodes,node1,1)))) /* Overshoot by one segment */ |
890 | { |
891 | result2->sortby=result2->score; |
892 | InsertInQueue(queue,result2); |
893 | } |
894 | } |
895 | |
896 | endloop: |
897 | |
898 | if(IsFakeNode(node1)) |
899 | segment=NextFakeSegment(segment,node1); |
900 | else |
901 | segment=NextSegment(segments,segment,node1); |
902 | } |
903 | } |
904 | |
905 | FreeQueueList(queue); |
906 | |
907 | /* Check it worked */ |
908 | |
909 | if(results->number==1) |
910 | { |
911 | FreeResultsList(results); |
912 | return(NULL); |
913 | } |
914 | |
915 | /* Create a results structure with the node at the end of the segment opposite the start */ |
916 | |
917 | results2=NewResultsList(8); |
918 | |
919 | results2->finish_node=results->finish_node; |
920 | |
921 | result3=FirstResult(results); |
922 | |
923 | while(result3) |
924 | { |
925 | if(result3->next) |
926 | { |
927 | result2=InsertResult(results2,result3->next->node,result3->segment); |
928 | |
929 | result2->score=result3->score; |
930 | } |
931 | |
932 | result3=NextResult(results,result3); |
933 | } |
934 | |
935 | /* Fix up the result->next pointers */ |
936 | |
937 | result3=FirstResult(results); |
938 | |
939 | while(result3) |
940 | { |
941 | if(result3->next && result3->next->next) |
942 | { |
943 | result1=FindResult(results2,result3->next->node,result3->segment); |
944 | result2=FindResult(results2,result3->next->next->node,result3->next->segment); |
945 | |
946 | result1->next=result2; |
947 | } |
948 | |
949 | result3=NextResult(results,result3); |
950 | } |
951 | |
952 | FreeResultsList(results); |
953 | |
954 | return(results2); |
955 | } |
956 | |
957 | |
958 | /*++++++++++++++++++++++++++++++++++++++ |
959 | Create an optimum route given the set of super-nodes to follow. |
960 | |
961 | Results *CombineRoutes Returns the results from joining the super-nodes. |
962 | |
963 | Nodes *nodes The list of nodes. |
964 | |
965 | Segments *segments The set of segments to use. |
966 | |
967 | Ways *ways The list of ways. |
968 | |
969 | Relations *relations The set of relations to use. |
970 | |
971 | Results *results The set of results from the super-nodes. |
972 | |
973 | index_t prev_segment The previous segment before the start node. |
974 | |
975 | Profile *profile The profile containing the transport type, speeds and allowed highways. |
976 | ++++++++++++++++++++++++++++++++++++++*/ |
977 | |
978 | Results *CombineRoutes(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Results *results,index_t prev_segment,Profile *profile) |
979 | { |
980 | Result *result1,*result3; |
981 | Results *combined; |
982 | |
983 | combined=NewResultsList(64); |
984 | |
985 | combined->start_node=results->start_node; |
986 | combined->finish_node=results->finish_node; |
987 | |
988 | combined->last_segment=results->last_segment; |
989 | |
990 | /* Sort out the combined route */ |
991 | |
992 | result1=FindResult(results,results->start_node,prev_segment); |
993 | |
994 | result3=InsertResult(combined,results->start_node,prev_segment); |
995 | |
996 | do |
997 | { |
998 | Result *result2,*result4; |
999 | |
1000 | if(result1->next) |
1001 | { |
1002 | Results *results2=FindNormalRoute(nodes,segments,ways,relations,result1->node,result3->segment,result1->next->node,profile); |
1003 | |
1004 | result2=FindResult(results2,result1->node,result3->segment); |
1005 | |
1006 | // printf("CombineRoutes(result2->node=%ld result2->segment=%ld)\n",result2->node,result2->segment); |
1007 | |
1008 | result2=result2->next; |
1009 | |
1010 | /* |
1011 | * result1 result1->next |
1012 | * = = |
1013 | * ---*----------------------------------* = results |
1014 | * |
1015 | * ---*----.----.----.----.----.----.----* = results2 |
1016 | * = |
1017 | * result2 |
1018 | * |
1019 | * ---*----.----.----.----.----.----.----* = combined |
1020 | * = = |
1021 | * result3 result4 |
1022 | */ |
1023 | |
1024 | do |
1025 | { |
1026 | // printf("CombineRoutes(result2->node=%ld result2->segment=%ld)\n",result2->node,result2->segment); |
1027 | |
1028 | result4=InsertResult(combined,result2->node,result2->segment); |
1029 | |
1030 | result4->score=result2->score+result3->score; |
1031 | result4->prev=result3; |
1032 | |
1033 | result2=result2->next; |
1034 | |
1035 | result3=result4; |
1036 | } |
1037 | while(result2); |
1038 | |
1039 | FreeResultsList(results2); |
1040 | } |
1041 | |
1042 | result1=result1->next; |
1043 | } |
1044 | while(result1); |
1045 | |
1046 | FixForwardRoute(combined,result3); |
1047 | |
1048 | return(combined); |
1049 | } |
1050 | |
1051 | |
1052 | /*++++++++++++++++++++++++++++++++++++++ |
1053 | Fix the forward route (i.e. setup next pointers for forward path from prev nodes on reverse path). |
1054 | |
1055 | Results *results The set of results to update. |
1056 | |
1057 | Result *finish_result The finish result. |
1058 | ++++++++++++++++++++++++++++++++++++++*/ |
1059 | |
1060 | void FixForwardRoute(Results *results,Result *finish_result) |
1061 | { |
1062 | Result *result2=finish_result; |
1063 | |
1064 | /* Create the forward links for the optimum path */ |
1065 | |
1066 | do |
1067 | { |
1068 | Result *result1; |
1069 | |
1070 | if(result2->prev) |
1071 | { |
1072 | index_t node1=result2->prev->node; |
1073 | index_t seg1=result2->prev->segment; |
1074 | |
1075 | result1=FindResult(results,node1,seg1); |
1076 | |
1077 | result1->next=result2; |
1078 | |
1079 | result2=result1; |
1080 | } |
1081 | else |
1082 | result2=NULL; |
1083 | } |
1084 | while(result2); |
1085 | |
1086 | results->finish_node=finish_result->node; |
1087 | results->last_segment=finish_result->segment; |
1088 | } |
Properties
Name | Value |
---|---|
cvs:description | Route optimiser. |