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