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