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 608 -
(show annotations)
(download)
(as text)
Sat Jan 29 16:00:10 2011 UTC (14 years, 2 months ago) by amb
File MIME type: text/x-csrc
File size: 29072 byte(s)
Sat Jan 29 16:00:10 2011 UTC (14 years, 2 months ago) by amb
File MIME type: text/x-csrc
File size: 29072 byte(s)
When finding a normal route check for turn relations (considering previous segment). When finding turn relations convert fake segments into real ones.
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 | segment=FirstSegment(segments,nodes,node1); |
374 | |
375 | while(segment) |
376 | { |
377 | index_t node2,seg2; |
378 | Node *node; |
379 | Way *way; |
380 | score_t segment_pref,segment_score,cumulative_score; |
381 | int i; |
382 | |
383 | if(!IsSuperSegment(segment)) |
384 | goto endloop; |
385 | |
386 | if(profile->oneway && IsOnewayTo(segment,node1)) |
387 | goto endloop; |
388 | |
389 | node2=OtherNode(segment,node1); |
390 | |
391 | if(result1->prev && result1->prev->node==node2) |
392 | goto endloop; |
393 | |
394 | seg2=IndexSegment(segments,segment); |
395 | |
396 | if(turnrelation!=NO_RELATION && !IsTurnAllowed(relations,turnrelation,node1,seg1,seg2,profile->allow)) |
397 | goto endloop; |
398 | |
399 | way=LookupWay(ways,segment->way,1); |
400 | |
401 | if(!(way->allow&profile->allow)) |
402 | goto endloop; |
403 | |
404 | if(!profile->highway[HIGHWAY(way->type)]) |
405 | goto endloop; |
406 | |
407 | if(way->weight && way->weight<profile->weight) |
408 | goto endloop; |
409 | |
410 | if((way->height && way->height<profile->height) || |
411 | (way->width && way->width <profile->width ) || |
412 | (way->length && way->length<profile->length)) |
413 | goto endloop; |
414 | |
415 | segment_pref=profile->highway[HIGHWAY(way->type)]; |
416 | |
417 | for(i=1;i<Property_Count;i++) |
418 | if(ways->file.props & PROPERTIES(i)) |
419 | { |
420 | if(way->props & PROPERTIES(i)) |
421 | segment_pref*=profile->props_yes[i]; |
422 | else |
423 | segment_pref*=profile->props_no[i]; |
424 | } |
425 | |
426 | if(segment_pref==0) |
427 | goto endloop; |
428 | |
429 | node=LookupNode(nodes,node2,2); |
430 | |
431 | if(!(node->allow&profile->allow)) |
432 | goto endloop; |
433 | |
434 | if(option_quickest==0) |
435 | segment_score=(score_t)DISTANCE(segment->distance)/segment_pref; |
436 | else |
437 | segment_score=(score_t)Duration(segment,way,profile)/segment_pref; |
438 | |
439 | cumulative_score=result1->score+segment_score; |
440 | |
441 | if(cumulative_score>finish_score) |
442 | goto endloop; |
443 | |
444 | result2=FindResult(results,node2,seg2); |
445 | |
446 | if(!result2) /* New end node/segment pair */ |
447 | { |
448 | result2=InsertResult(results,node2,seg2); |
449 | result2->prev=result1; |
450 | result2->score=cumulative_score; |
451 | |
452 | if((result3=FindResult(end,node2,seg2))) |
453 | { |
454 | if((result2->score+result3->score)<finish_score) |
455 | { |
456 | finish_score=result2->score+result3->score; |
457 | finish_result=result2; |
458 | } |
459 | } |
460 | else |
461 | { |
462 | double lat,lon; |
463 | distance_t direct; |
464 | |
465 | GetLatLong(nodes,node2,&lat,&lon); |
466 | direct=Distance(lat,lon,finish_lat,finish_lon); |
467 | |
468 | if(option_quickest==0) |
469 | result2->sortby=result2->score+(score_t)direct/profile->max_pref; |
470 | else |
471 | result2->sortby=result2->score+(score_t)distance_speed_to_duration(direct,profile->max_speed)/profile->max_pref; |
472 | |
473 | InsertInQueue(queue,result2); |
474 | } |
475 | } |
476 | else if(cumulative_score<result2->score) /* New end node/segment pair is better */ |
477 | { |
478 | result2->prev=result1; |
479 | result2->score=cumulative_score; |
480 | |
481 | if((result3=FindResult(end,node2,seg2))) |
482 | { |
483 | if((result2->score+result3->score)<finish_score) |
484 | { |
485 | finish_score=result2->score+result3->score; |
486 | finish_result=result2; |
487 | } |
488 | } |
489 | else if(result2->score<finish_score) |
490 | { |
491 | double lat,lon; |
492 | distance_t direct; |
493 | |
494 | GetLatLong(nodes,node2,&lat,&lon); |
495 | direct=Distance(lat,lon,finish_lat,finish_lon); |
496 | |
497 | if(option_quickest==0) |
498 | result2->sortby=result2->score+(score_t)direct/profile->max_pref; |
499 | else |
500 | result2->sortby=result2->score+(score_t)distance_speed_to_duration(direct,profile->max_speed)/profile->max_pref; |
501 | |
502 | InsertInQueue(queue,result2); |
503 | } |
504 | } |
505 | |
506 | endloop: |
507 | |
508 | if(!option_quiet && !(results->number%10000)) |
509 | printf_middle("Routing: Super-Nodes checked = %d",results->number); |
510 | |
511 | segment=NextSegment(segments,segment,node1); |
512 | } |
513 | } |
514 | |
515 | if(!option_quiet) |
516 | printf_last("Routing: Super-Nodes checked = %d",results->number); |
517 | |
518 | FreeQueueList(queue); |
519 | |
520 | /* Check it worked */ |
521 | |
522 | if(!finish_result) |
523 | { |
524 | FreeResultsList(results); |
525 | return(NULL); |
526 | } |
527 | |
528 | /* Finish off the end part of the route. */ |
529 | |
530 | result3=InsertResult(results,end->finish_node,NO_SEGMENT); |
531 | |
532 | result3->prev=finish_result; |
533 | result3->score=finish_score; |
534 | |
535 | FixForwardRoute(results,result3); |
536 | |
537 | return(results); |
538 | } |
539 | |
540 | |
541 | /*++++++++++++++++++++++++++++++++++++++ |
542 | Find all routes from a specified node to any super-node. |
543 | |
544 | Results *FindStartRoutes Returns a set of results. |
545 | |
546 | Nodes *nodes The set of nodes to use. |
547 | |
548 | Segments *segments The set of segments to use. |
549 | |
550 | Ways *ways The set of ways to use. |
551 | |
552 | Relations *relations The set of relations to use. |
553 | |
554 | index_t start_node The start node. |
555 | |
556 | index_t prev_segment The previous segment before the start node. |
557 | |
558 | Profile *profile The profile containing the transport type, speeds and allowed highways. |
559 | ++++++++++++++++++++++++++++++++++++++*/ |
560 | |
561 | Results *FindStartRoutes(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,index_t start_node,index_t prev_segment,Profile *profile) |
562 | { |
563 | Results *results; |
564 | Queue *queue; |
565 | Result *result1,*result2; |
566 | |
567 | /* Create the results and insert the start node */ |
568 | |
569 | results=NewResultsList(8); |
570 | |
571 | results->start_node=start_node; |
572 | results->prev_segment=prev_segment; |
573 | |
574 | result1=InsertResult(results,start_node,prev_segment); |
575 | |
576 | /* Take a shortcut if the first node is a super-node. */ |
577 | |
578 | if(!IsFakeNode(start_node) && IsSuperNode(LookupNode(nodes,start_node,1))) |
579 | return(results); |
580 | |
581 | /* Insert the first node into the queue */ |
582 | |
583 | queue=NewQueueList(); |
584 | |
585 | InsertInQueue(queue,result1); |
586 | |
587 | /* Loop across all nodes in the queue */ |
588 | |
589 | while((result1=PopFromQueue(queue))) |
590 | { |
591 | index_t node1,seg1; |
592 | Segment *segment; |
593 | // index_t turnrelation=NO_RELATION; |
594 | |
595 | node1=result1->node; |
596 | seg1=result1->segment; |
597 | |
598 | // if(IsTurnRestrictedNode(LookupNode(nodes,node1,1))) |
599 | // turnrelation=FindFirstTurnRelation2(relations,node1,seg1); |
600 | |
601 | if(IsFakeNode(node1)) |
602 | segment=FirstFakeSegment(node1); |
603 | else |
604 | segment=FirstSegment(segments,nodes,node1); |
605 | |
606 | while(segment) |
607 | { |
608 | index_t node2,seg2; |
609 | Way *way; |
610 | score_t segment_pref,segment_score,cumulative_score; |
611 | int i; |
612 | |
613 | if(!IsNormalSegment(segment)) |
614 | goto endloop; |
615 | |
616 | if(profile->oneway && IsOnewayTo(segment,node1)) |
617 | goto endloop; |
618 | |
619 | node2=OtherNode(segment,node1); |
620 | |
621 | if(result1->prev && result1->prev->node==node2) |
622 | goto endloop; |
623 | |
624 | if(IsFakeNode(node1) || IsFakeNode(node2)) |
625 | seg2=IndexFakeSegment(segment); |
626 | else |
627 | seg2=IndexSegment(segments,segment); |
628 | |
629 | // if(turnrelation!=NO_RELATION && !IsTurnAllowed(relations,turnrelation,node1,seg1,seg2,profile->allow)) |
630 | // goto endloop; |
631 | |
632 | way=LookupWay(ways,segment->way,1); |
633 | |
634 | if(!(way->allow&profile->allow)) |
635 | goto endloop; |
636 | |
637 | if(!profile->highway[HIGHWAY(way->type)]) |
638 | goto endloop; |
639 | |
640 | if(way->weight && way->weight<profile->weight) |
641 | goto endloop; |
642 | |
643 | if((way->height && way->height<profile->height) || |
644 | (way->width && way->width <profile->width ) || |
645 | (way->length && way->length<profile->length)) |
646 | goto endloop; |
647 | |
648 | segment_pref=profile->highway[HIGHWAY(way->type)]; |
649 | |
650 | for(i=1;i<Property_Count;i++) |
651 | if(ways->file.props & PROPERTIES(i)) |
652 | { |
653 | if(way->props & PROPERTIES(i)) |
654 | segment_pref*=profile->props_yes[i]; |
655 | else |
656 | segment_pref*=profile->props_no[i]; |
657 | } |
658 | |
659 | if(segment_pref==0) |
660 | goto endloop; |
661 | |
662 | if(!IsFakeNode(node2)) |
663 | { |
664 | Node *node=LookupNode(nodes,node2,2); |
665 | |
666 | if(!(node->allow&profile->allow)) |
667 | goto endloop; |
668 | } |
669 | |
670 | if(option_quickest==0) |
671 | segment_score=(score_t)DISTANCE(segment->distance)/segment_pref; |
672 | else |
673 | segment_score=(score_t)Duration(segment,way,profile)/segment_pref; |
674 | |
675 | cumulative_score=result1->score+segment_score; |
676 | |
677 | result2=FindResult(results,node2,seg2); |
678 | |
679 | if(!result2) /* New end node/segment combination */ |
680 | { |
681 | result2=InsertResult(results,node2,seg2); |
682 | result2->prev=result1; |
683 | result2->score=cumulative_score; |
684 | |
685 | if(!IsFakeNode(node2) && !IsSuperNode(LookupNode(nodes,node2,2))) |
686 | { |
687 | result2->sortby=result2->score; |
688 | InsertInQueue(queue,result2); |
689 | } |
690 | } |
691 | else if(cumulative_score<result2->score) /* New end node/segment combination is better */ |
692 | { |
693 | result2->prev=result1; |
694 | result2->score=cumulative_score; |
695 | |
696 | if(!IsFakeNode(node2) && !IsSuperNode(LookupNode(nodes,node2,2))) |
697 | { |
698 | result2->sortby=result2->score; |
699 | InsertInQueue(queue,result2); |
700 | } |
701 | } |
702 | |
703 | endloop: |
704 | |
705 | if(IsFakeNode(node1)) |
706 | segment=NextFakeSegment(segment,node1); |
707 | else |
708 | segment=NextSegment(segments,segment,node1); |
709 | } |
710 | } |
711 | |
712 | FreeQueueList(queue); |
713 | |
714 | /* Check it worked */ |
715 | |
716 | if(results->number==1) |
717 | { |
718 | FreeResultsList(results); |
719 | return(NULL); |
720 | } |
721 | |
722 | return(results); |
723 | } |
724 | |
725 | |
726 | /*++++++++++++++++++++++++++++++++++++++ |
727 | Find all routes from any super-node to a specific node. |
728 | |
729 | Results *FindFinishRoutes Returns a set of results. |
730 | |
731 | Nodes *nodes The set of nodes to use. |
732 | |
733 | Segments *segments The set of segments to use. |
734 | |
735 | Ways *ways The set of ways to use. |
736 | |
737 | Relations *relations The set of relations to use. |
738 | |
739 | index_t finish_node The finishing node. |
740 | |
741 | Profile *profile The profile containing the transport type, speeds and allowed highways. |
742 | ++++++++++++++++++++++++++++++++++++++*/ |
743 | |
744 | Results *FindFinishRoutes(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,index_t finish_node,Profile *profile) |
745 | { |
746 | Results *results,*results2; |
747 | Queue *queue; |
748 | Result *result1,*result2,*result3; |
749 | |
750 | /* Create the results and insert the finish node */ |
751 | |
752 | results=NewResultsList(8); |
753 | |
754 | results->finish_node=finish_node; |
755 | |
756 | result1=InsertResult(results,finish_node,NO_SEGMENT); |
757 | |
758 | /* Take a shortcut if the first node is a super-node. */ |
759 | |
760 | if(!IsFakeNode(finish_node) && IsSuperNode(LookupNode(nodes,finish_node,1))) |
761 | return(results); |
762 | |
763 | /* Insert the first node into the queue */ |
764 | |
765 | queue=NewQueueList(); |
766 | |
767 | InsertInQueue(queue,result1); |
768 | |
769 | /* Loop across all nodes in the queue */ |
770 | |
771 | while((result1=PopFromQueue(queue))) |
772 | { |
773 | index_t node1,seg1; |
774 | Segment *segment; |
775 | index_t turnrelation=NO_RELATION; |
776 | |
777 | node1=result1->node; |
778 | seg1=result1->segment; |
779 | |
780 | if(IsTurnRestrictedNode(LookupNode(nodes,node1,1))) |
781 | turnrelation=FindFirstTurnRelation1(relations,node1); /* working backwards => turn relation sort order doesn't help */ |
782 | |
783 | if(IsFakeNode(node1)) |
784 | segment=FirstFakeSegment(node1); |
785 | else |
786 | segment=FirstSegment(segments,nodes,node1); |
787 | |
788 | while(segment) |
789 | { |
790 | index_t node2,seg2; |
791 | Way *way; |
792 | score_t segment_pref,segment_score,cumulative_score; |
793 | int i; |
794 | |
795 | if(!IsNormalSegment(segment)) |
796 | goto endloop; |
797 | |
798 | if(profile->oneway && IsOnewayFrom(segment,node1)) /* Disallow oneway from node2 *to* node1 */ |
799 | goto endloop; |
800 | |
801 | node2=OtherNode(segment,node1); |
802 | |
803 | if(result1->next && result1->next->node==node2) |
804 | goto endloop; |
805 | |
806 | if(IsFakeNode(node1) || IsFakeNode(node2)) |
807 | seg2=IndexFakeSegment(segment); |
808 | else |
809 | seg2=IndexSegment(segments,segment); |
810 | |
811 | if(turnrelation!=NO_RELATION) |
812 | { |
813 | index_t turnrelation2=FindFirstTurnRelation2(relations,node1,node2); /* node2 -> node1 -> result1->next->node */ |
814 | |
815 | if(turnrelation2!=NO_RELATION && !IsTurnAllowed(relations,turnrelation2,node1,seg2,seg1,profile->allow)) |
816 | goto endloop; |
817 | } |
818 | |
819 | way=LookupWay(ways,segment->way,1); |
820 | |
821 | if(!(way->allow&profile->allow)) |
822 | goto endloop; |
823 | |
824 | if(!profile->highway[HIGHWAY(way->type)]) |
825 | goto endloop; |
826 | |
827 | if(way->weight && way->weight<profile->weight) |
828 | goto endloop; |
829 | |
830 | if((way->height && way->height<profile->height) || |
831 | (way->width && way->width <profile->width ) || |
832 | (way->length && way->length<profile->length)) |
833 | goto endloop; |
834 | |
835 | segment_pref=profile->highway[HIGHWAY(way->type)]; |
836 | |
837 | for(i=1;i<Property_Count;i++) |
838 | if(ways->file.props & PROPERTIES(i)) |
839 | { |
840 | if(way->props & PROPERTIES(i)) |
841 | segment_pref*=profile->props_yes[i]; |
842 | else |
843 | segment_pref*=profile->props_no[i]; |
844 | } |
845 | |
846 | if(segment_pref==0) |
847 | goto endloop; |
848 | |
849 | if(!IsFakeNode(node2)) |
850 | { |
851 | Node *node=LookupNode(nodes,node2,2); |
852 | |
853 | if(!(node->allow&profile->allow)) |
854 | goto endloop; |
855 | } |
856 | |
857 | if(option_quickest==0) |
858 | segment_score=(score_t)DISTANCE(segment->distance)/segment_pref; |
859 | else |
860 | segment_score=(score_t)Duration(segment,way,profile)/segment_pref; |
861 | |
862 | cumulative_score=result1->score+segment_score; |
863 | |
864 | result2=FindResult(results,node2,seg2); |
865 | |
866 | if(!result2) /* New end node */ |
867 | { |
868 | result2=InsertResult(results,node2,seg2); |
869 | result2->next=result1; /* working backwards */ |
870 | result2->score=cumulative_score; |
871 | |
872 | if(!IsFakeNode(node1) && !IsSuperNode(LookupNode(nodes,node1,1))) /* Overshoot by one segment */ |
873 | { |
874 | result2->sortby=result2->score; |
875 | InsertInQueue(queue,result2); |
876 | } |
877 | } |
878 | else if(cumulative_score<result2->score) /* New end node is better */ |
879 | { |
880 | result2->next=result1; /* working backwards */ |
881 | result2->score=cumulative_score; |
882 | |
883 | if(!IsFakeNode(node1) && !IsSuperNode(LookupNode(nodes,node1,1))) /* Overshoot by one segment */ |
884 | { |
885 | result2->sortby=result2->score; |
886 | InsertInQueue(queue,result2); |
887 | } |
888 | } |
889 | |
890 | endloop: |
891 | |
892 | if(IsFakeNode(node1)) |
893 | segment=NextFakeSegment(segment,node1); |
894 | else |
895 | segment=NextSegment(segments,segment,node1); |
896 | } |
897 | } |
898 | |
899 | FreeQueueList(queue); |
900 | |
901 | /* Check it worked */ |
902 | |
903 | if(results->number==1) |
904 | { |
905 | FreeResultsList(results); |
906 | return(NULL); |
907 | } |
908 | |
909 | /* Create a results structure with the node at the end of the segment opposite the start */ |
910 | |
911 | results2=NewResultsList(8); |
912 | |
913 | results2->finish_node=results->finish_node; |
914 | |
915 | result3=FirstResult(results); |
916 | |
917 | while(result3) |
918 | { |
919 | if(result3->next) |
920 | { |
921 | result2=InsertResult(results2,result3->next->node,result3->segment); |
922 | |
923 | result2->score=result3->score; |
924 | } |
925 | |
926 | result3=NextResult(results,result3); |
927 | } |
928 | |
929 | /* Fix up the result->next pointers */ |
930 | |
931 | result3=FirstResult(results); |
932 | |
933 | while(result3) |
934 | { |
935 | if(result3->next && result3->next->next) |
936 | { |
937 | result1=FindResult(results2,result3->next->node,result3->segment); |
938 | result2=FindResult(results2,result3->next->next->node,result3->next->segment); |
939 | |
940 | result1->next=result2; |
941 | } |
942 | |
943 | result3=NextResult(results,result3); |
944 | } |
945 | |
946 | FreeResultsList(results); |
947 | |
948 | return(results2); |
949 | } |
950 | |
951 | |
952 | /*++++++++++++++++++++++++++++++++++++++ |
953 | Create an optimum route given the set of super-nodes to follow. |
954 | |
955 | Results *CombineRoutes Returns the results from joining the super-nodes. |
956 | |
957 | Nodes *nodes The list of nodes. |
958 | |
959 | Segments *segments The set of segments to use. |
960 | |
961 | Ways *ways The list of ways. |
962 | |
963 | Relations *relations The set of relations to use. |
964 | |
965 | Results *results The set of results from the super-nodes. |
966 | |
967 | index_t prev_segment The previous segment before the start node. |
968 | |
969 | Profile *profile The profile containing the transport type, speeds and allowed highways. |
970 | ++++++++++++++++++++++++++++++++++++++*/ |
971 | |
972 | Results *CombineRoutes(Nodes *nodes,Segments *segments,Ways *ways,Relations *relations,Results *results,index_t prev_segment,Profile *profile) |
973 | { |
974 | Result *result1,*result3; |
975 | Results *combined; |
976 | |
977 | combined=NewResultsList(64); |
978 | |
979 | combined->start_node=results->start_node; |
980 | combined->finish_node=results->finish_node; |
981 | |
982 | combined->last_segment=results->last_segment; |
983 | |
984 | /* Sort out the combined route */ |
985 | |
986 | result1=FindResult(results,results->start_node,prev_segment); |
987 | |
988 | result3=InsertResult(combined,results->start_node,prev_segment); |
989 | |
990 | do |
991 | { |
992 | Result *result2,*result4; |
993 | |
994 | if(result1->next) |
995 | { |
996 | Results *results2=FindNormalRoute(nodes,segments,ways,relations,result1->node,result3->segment,result1->next->node,profile); |
997 | |
998 | result2=FindResult(results2,result1->node,result3->segment); |
999 | |
1000 | // printf("CombineRoutes(result2->node=%ld result2->segment=%ld)\n",result2->node,result2->segment); |
1001 | |
1002 | result2=result2->next; |
1003 | |
1004 | /* |
1005 | * result1 result1->next |
1006 | * = = |
1007 | * ---*----------------------------------* = results |
1008 | * |
1009 | * ---*----.----.----.----.----.----.----* = results2 |
1010 | * = |
1011 | * result2 |
1012 | * |
1013 | * ---*----.----.----.----.----.----.----* = combined |
1014 | * = = |
1015 | * result3 result4 |
1016 | */ |
1017 | |
1018 | do |
1019 | { |
1020 | // printf("CombineRoutes(result2->node=%ld result2->segment=%ld)\n",result2->node,result2->segment); |
1021 | |
1022 | result4=InsertResult(combined,result2->node,result2->segment); |
1023 | |
1024 | result4->score=result2->score+result3->score; |
1025 | result4->prev=result3; |
1026 | |
1027 | result2=result2->next; |
1028 | |
1029 | result3=result4; |
1030 | } |
1031 | while(result2); |
1032 | |
1033 | FreeResultsList(results2); |
1034 | } |
1035 | |
1036 | result1=result1->next; |
1037 | } |
1038 | while(result1); |
1039 | |
1040 | FixForwardRoute(combined,result3); |
1041 | |
1042 | return(combined); |
1043 | } |
1044 | |
1045 | |
1046 | /*++++++++++++++++++++++++++++++++++++++ |
1047 | Fix the forward route (i.e. setup next pointers for forward path from prev nodes on reverse path). |
1048 | |
1049 | Results *results The set of results to update. |
1050 | |
1051 | Result *finish_result The finish result. |
1052 | ++++++++++++++++++++++++++++++++++++++*/ |
1053 | |
1054 | void FixForwardRoute(Results *results,Result *finish_result) |
1055 | { |
1056 | Result *result2=finish_result; |
1057 | |
1058 | /* Create the forward links for the optimum path */ |
1059 | |
1060 | do |
1061 | { |
1062 | Result *result1; |
1063 | |
1064 | if(result2->prev) |
1065 | { |
1066 | index_t node1=result2->prev->node; |
1067 | index_t seg1=result2->prev->segment; |
1068 | |
1069 | result1=FindResult(results,node1,seg1); |
1070 | |
1071 | result1->next=result2; |
1072 | |
1073 | result2=result1; |
1074 | } |
1075 | else |
1076 | result2=NULL; |
1077 | } |
1078 | while(result2); |
1079 | |
1080 | results->finish_node=finish_result->node; |
1081 | results->last_segment=finish_result->segment; |
1082 | } |
Properties
Name | Value |
---|---|
cvs:description | Route optimiser. |