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