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 88 -
(show annotations)
(download)
(as text)
Tue Jan 27 18:22:37 2009 UTC (16 years, 1 month ago) by amb
File MIME type: text/x-csrc
File size: 34859 byte(s)
Tue Jan 27 18:22:37 2009 UTC (16 years, 1 month ago) by amb
File MIME type: text/x-csrc
File size: 34859 byte(s)
Intermediate version while transitioning data format for nodes and segments.
1 | /*************************************** |
2 | $Header: /home/amb/CVS/routino/src/optimiser.c,v 1.38 2009-01-27 18:22:37 amb Exp $ |
3 | |
4 | Routing optimiser. |
5 | ******************/ /****************** |
6 | Written by Andrew M. Bishop |
7 | |
8 | This file Copyright 2008,2009 Andrew M. Bishop |
9 | It may be distributed under the GNU Public License, version 2, or |
10 | any higher version. See section COPYING of the GNU Public license |
11 | for conditions under which this file may be redistributed. |
12 | ***************************************/ |
13 | |
14 | |
15 | #include <assert.h> |
16 | #include <string.h> |
17 | #include <stdlib.h> |
18 | |
19 | #include "nodes.h" |
20 | #include "ways.h" |
21 | #include "segments.h" |
22 | #include "results.h" |
23 | #include "functions.h" |
24 | |
25 | |
26 | /*+ Print the progress? +*/ |
27 | int print_progress=1; |
28 | |
29 | |
30 | /*++++++++++++++++++++++++++++++++++++++ |
31 | Find the optimum route between two nodes. |
32 | |
33 | Results *FindRoute Returns a set of results. |
34 | |
35 | Nodes *nodes The set of nodes to use. |
36 | |
37 | Segments *segments The set of segments to use. |
38 | |
39 | Ways *ways The set of ways to use. |
40 | |
41 | uint32_t start The start node. |
42 | |
43 | uint32_t finish The finish node. |
44 | |
45 | Profile *profile The profile containing the transport type, speeds and allowed highways. |
46 | |
47 | int all A flag to indicate that a big results structure is required. |
48 | ++++++++++++++++++++++++++++++++++++++*/ |
49 | |
50 | Results *FindRoute(Nodes *nodes,Segments *segments,Ways *ways,uint32_t start,uint32_t finish,Profile *profile,int all) |
51 | { |
52 | Results *results; |
53 | uint32_t node1,node2; |
54 | HalfResult shortest2,quickest2; |
55 | HalfResult shortestfinish,quickestfinish; |
56 | Result *result1,*result2; |
57 | Segment *segment; |
58 | Way *way; |
59 | |
60 | /* Set up the finish conditions */ |
61 | |
62 | shortestfinish.distance=~0; |
63 | shortestfinish.duration=~0; |
64 | quickestfinish.distance=~0; |
65 | quickestfinish.duration=~0; |
66 | |
67 | /* Insert the first node into the queue */ |
68 | |
69 | if(all) |
70 | results=NewResultsList(65536); |
71 | else |
72 | results=NewResultsList(8); |
73 | |
74 | result1=InsertResult(results,start); |
75 | |
76 | result1->node=start; |
77 | result1->shortest.prev=0; |
78 | result1->shortest.next=0; |
79 | result1->shortest.distance=0; |
80 | result1->shortest.duration=0; |
81 | result1->quickest.prev=0; |
82 | result1->quickest.next=0; |
83 | result1->quickest.distance=0; |
84 | result1->quickest.duration=0; |
85 | |
86 | insert_in_queue(result1); |
87 | |
88 | /* Loop across all nodes in the queue */ |
89 | |
90 | while((result1=pop_from_queue())) |
91 | { |
92 | node1=result1->node; |
93 | |
94 | segment=LookupSegment(segments,FirstSegment(nodes,node1)); |
95 | |
96 | while(segment) |
97 | { |
98 | duration_t segment_duration; |
99 | |
100 | if(segment->distance&ONEWAY_OPPOSITE && profile->oneway) |
101 | goto endloop; |
102 | |
103 | node2=segment->node2; |
104 | |
105 | if(result1->shortest.prev==node2 && result1->quickest.prev==node2) |
106 | goto endloop; |
107 | |
108 | way=LookupWay(ways,segment->wayindex); |
109 | |
110 | if(!(way->allow&profile->allow)) |
111 | goto endloop; |
112 | |
113 | if(!profile->highways[HIGHWAY(way->type)]) |
114 | goto endloop; |
115 | |
116 | segment_duration=Duration(segment,way,profile); |
117 | |
118 | shortest2.distance=result1->shortest.distance+DISTANCE(segment->distance); |
119 | shortest2.duration=result1->shortest.duration+segment_duration; |
120 | quickest2.distance=result1->quickest.distance+DISTANCE(segment->distance); |
121 | quickest2.duration=result1->quickest.duration+segment_duration; |
122 | |
123 | if(shortest2.distance>shortestfinish.distance && quickest2.duration>quickestfinish.duration) |
124 | goto endloop; |
125 | |
126 | result2=FindResult(results,node2); |
127 | |
128 | if(!result2) /* New end node */ |
129 | { |
130 | result2=InsertResult(results,node2); |
131 | result2->node=node2; |
132 | result2->shortest.prev=node1; |
133 | result2->shortest.next=0; |
134 | result2->shortest.distance=shortest2.distance; |
135 | result2->shortest.duration=shortest2.duration; |
136 | result2->quickest.prev=node1; |
137 | result2->quickest.next=0; |
138 | result2->quickest.distance=quickest2.distance; |
139 | result2->quickest.duration=quickest2.duration; |
140 | |
141 | if(node2==finish) |
142 | { |
143 | shortestfinish.distance=shortest2.distance; |
144 | shortestfinish.duration=shortest2.duration; |
145 | quickestfinish.distance=quickest2.distance; |
146 | quickestfinish.duration=quickest2.duration; |
147 | } |
148 | else |
149 | insert_in_queue(result2); |
150 | } |
151 | else |
152 | { |
153 | if(shortest2.distance<result2->shortest.distance || |
154 | (shortest2.distance==result2->shortest.distance && |
155 | shortest2.duration<result2->shortest.duration)) /* New end node is shorter */ |
156 | { |
157 | result2->shortest.prev=node1; |
158 | result2->shortest.distance=shortest2.distance; |
159 | result2->shortest.duration=shortest2.duration; |
160 | |
161 | if(node2==finish) |
162 | { |
163 | shortestfinish.distance=shortest2.distance; |
164 | shortestfinish.duration=shortest2.duration; |
165 | } |
166 | else |
167 | insert_in_queue(result2); |
168 | } |
169 | |
170 | if(quickest2.duration<result2->quickest.duration || |
171 | (quickest2.duration==result2->quickest.duration && |
172 | quickest2.distance<result2->quickest.distance)) /* New end node is quicker */ |
173 | { |
174 | result2->quickest.prev=node1; |
175 | result2->quickest.distance=quickest2.distance; |
176 | result2->quickest.duration=quickest2.duration; |
177 | |
178 | if(node2==finish) |
179 | { |
180 | quickestfinish.distance=quickest2.distance; |
181 | quickestfinish.duration=quickest2.duration; |
182 | } |
183 | else |
184 | insert_in_queue(result2); |
185 | } |
186 | } |
187 | |
188 | endloop: |
189 | |
190 | segment=NextSegment(segments,segment); |
191 | } |
192 | |
193 | if(print_progress && !(results->number%10000)) |
194 | { |
195 | printf("\rRouting: End Nodes=%d Shortest=%.1fkm,%.0fmin Quickest=%.1fkm,%.0fmin ",results->number, |
196 | distance_to_km(shortest2.distance),duration_to_minutes(shortest2.duration), |
197 | distance_to_km(quickest2.distance),duration_to_minutes(quickest2.duration)); |
198 | fflush(stdout); |
199 | } |
200 | } |
201 | |
202 | if(print_progress) |
203 | { |
204 | printf("\rRouted: End Nodes=%d Shortest=%.1fkm,%.0fmin Quickest=%.1fkm,%.0fmin\n",results->number, |
205 | distance_to_km(shortestfinish.distance),duration_to_minutes(shortestfinish.duration), |
206 | distance_to_km(quickestfinish.distance),duration_to_minutes(quickestfinish.duration)); |
207 | fflush(stdout); |
208 | } |
209 | |
210 | /* Check it worked */ |
211 | |
212 | result2=FindResult(results,finish); |
213 | |
214 | if(!result2) |
215 | { |
216 | FreeResultsList(results); |
217 | return(NULL); |
218 | } |
219 | |
220 | /* Reverse the results */ |
221 | |
222 | result2=FindResult(results,finish); |
223 | |
224 | do |
225 | { |
226 | if(result2->shortest.prev) |
227 | { |
228 | uint32_t node1=result2->shortest.prev; |
229 | |
230 | result1=FindResult(results,node1); |
231 | |
232 | result1->shortest.next=result2->node; |
233 | |
234 | result2=result1; |
235 | } |
236 | else |
237 | result2=NULL; |
238 | } |
239 | while(result2); |
240 | |
241 | result2=FindResult(results,finish); |
242 | |
243 | do |
244 | { |
245 | if(result2->quickest.prev) |
246 | { |
247 | uint32_t node1=result2->quickest.prev; |
248 | |
249 | result1=FindResult(results,node1); |
250 | |
251 | result1->quickest.next=result2->node; |
252 | |
253 | result2=result1; |
254 | } |
255 | else |
256 | result2=NULL; |
257 | } |
258 | while(result2); |
259 | |
260 | return(results); |
261 | } |
262 | |
263 | |
264 | #if 0 |
265 | |
266 | /*++++++++++++++++++++++++++++++++++++++ |
267 | Find the optimum route between two nodes. |
268 | |
269 | Results *FindRoute3 Returns a set of results. |
270 | |
271 | Nodes *supernodes The set of supernodes to use. |
272 | |
273 | Segments *supersegments The set of supersegments to use. |
274 | |
275 | Ways *superways The set of superways to use. |
276 | |
277 | uint32_t start The start node. |
278 | |
279 | uint32_t finish The finish node. |
280 | |
281 | Results *begin The initial portion of the route. |
282 | |
283 | Results *end The final portion of the route. |
284 | |
285 | Profile *profile The profile containing the transport type, speeds and allowed highways. |
286 | ++++++++++++++++++++++++++++++++++++++*/ |
287 | |
288 | Results *FindRoute3(Nodes *supernodes,Segments *supersegments,Ways *superways,uint32_t start,uint32_t finish,Results *begin,Results *end,Profile *profile) |
289 | { |
290 | Results *results; |
291 | uint32_t node1,node2; |
292 | HalfResult shortest2,quickest2; |
293 | HalfResult shortestfinish,quickestfinish; |
294 | Result *result1,*result2,*result3; |
295 | Segment *segment; |
296 | Way *way; |
297 | |
298 | /* Set up the finish conditions */ |
299 | |
300 | shortestfinish.distance=~0; |
301 | shortestfinish.duration=~0; |
302 | quickestfinish.distance=~0; |
303 | quickestfinish.duration=~0; |
304 | |
305 | /* Insert the start node */ |
306 | |
307 | results=NewResultsList(65536); |
308 | |
309 | result1=InsertResult(results,start); |
310 | result3=FindResult(begin,start); |
311 | |
312 | *result1=*result3; |
313 | |
314 | /* Insert the finish points of the beginning part of the path into the queue */ |
315 | |
316 | result3=FirstResult(begin); |
317 | |
318 | while(result3) |
319 | { |
320 | if(FindNode(supernodes,result3->node)) |
321 | { |
322 | if(!(result2=FindResult(results,result3->node))) |
323 | { |
324 | result2=InsertResult(results,result3->node); |
325 | |
326 | *result2=*result3; |
327 | |
328 | result2->shortest.prev=start; |
329 | result2->quickest.prev=start; |
330 | } |
331 | |
332 | insert_in_queue(result2); |
333 | } |
334 | |
335 | result3=NextResult(begin,result3); |
336 | } |
337 | |
338 | /* Loop across all supernodes in the queue */ |
339 | |
340 | while((result1=pop_from_queue())) |
341 | { |
342 | node1=result1->node; |
343 | |
344 | segment=FindFirstSegment(supersegments,node1); |
345 | |
346 | while(segment) |
347 | { |
348 | duration_t segment_duration; |
349 | |
350 | if(segment->distance&ONEWAY_OPPOSITE && profile->oneway) |
351 | goto endloop; |
352 | |
353 | node2=segment->node2; |
354 | |
355 | if(result1->shortest.prev==node2 && result1->quickest.prev==node2) |
356 | goto endloop; |
357 | |
358 | way=LookupWay(superways,segment->wayindex); |
359 | |
360 | if(!(way->allow&profile->allow)) |
361 | goto endloop; |
362 | |
363 | if(!profile->highways[HIGHWAY(way->type)]) |
364 | goto endloop; |
365 | |
366 | segment_duration=Duration(segment,way,profile); |
367 | |
368 | shortest2.distance=result1->shortest.distance+DISTANCE(segment->distance); |
369 | shortest2.duration=result1->shortest.duration+segment_duration; |
370 | quickest2.distance=result1->quickest.distance+DISTANCE(segment->distance); |
371 | quickest2.duration=result1->quickest.duration+segment_duration; |
372 | |
373 | if(shortest2.distance>shortestfinish.distance && quickest2.duration>quickestfinish.duration) |
374 | goto endloop; |
375 | |
376 | result2=FindResult(results,node2); |
377 | result3=NULL; |
378 | |
379 | if(!result2) /* New end node */ |
380 | { |
381 | result2=InsertResult(results,node2); |
382 | result2->node=node2; |
383 | result2->shortest.prev=node1; |
384 | result2->shortest.next=0; |
385 | result2->shortest.distance=shortest2.distance; |
386 | result2->shortest.duration=shortest2.duration; |
387 | result2->quickest.prev=node1; |
388 | result2->quickest.next=0; |
389 | result2->quickest.distance=quickest2.distance; |
390 | result2->quickest.duration=quickest2.duration; |
391 | |
392 | if(!(result3=FindResult(end,node2))) |
393 | insert_in_queue(result2); |
394 | } |
395 | else |
396 | { |
397 | if(shortest2.distance<result2->shortest.distance || |
398 | (shortest2.distance==result2->shortest.distance && |
399 | shortest2.duration<result2->shortest.duration)) /* New end node is shorter */ |
400 | { |
401 | result2->shortest.prev=node1; |
402 | result2->shortest.distance=shortest2.distance; |
403 | result2->shortest.duration=shortest2.duration; |
404 | |
405 | if(!(result3=FindResult(end,node2))) |
406 | insert_in_queue(result2); |
407 | } |
408 | |
409 | if(quickest2.duration<result2->quickest.duration || |
410 | (quickest2.duration==result2->quickest.duration && |
411 | quickest2.distance<result2->quickest.distance)) /* New end node is quicker */ |
412 | { |
413 | result2->quickest.prev=node1; |
414 | result2->quickest.distance=quickest2.distance; |
415 | result2->quickest.duration=quickest2.duration; |
416 | |
417 | if(!(result3=FindResult(end,node2))) |
418 | insert_in_queue(result2); |
419 | } |
420 | } |
421 | |
422 | if(result3) |
423 | { |
424 | if((shortest2.distance+result3->shortest.distance)<shortestfinish.distance || |
425 | ((shortest2.distance+result3->shortest.distance)==shortestfinish.distance && |
426 | (shortest2.duration+result3->shortest.duration)<shortestfinish.duration)) |
427 | { |
428 | shortestfinish.distance=shortest2.distance+result3->shortest.distance; |
429 | shortestfinish.duration=shortest2.duration+result3->shortest.duration; |
430 | } |
431 | if((quickest2.duration+result3->quickest.duration)<quickestfinish.duration || |
432 | ((quickest2.duration+result3->quickest.duration)==quickestfinish.duration && |
433 | (quickest2.distance+result3->quickest.distance)<quickestfinish.distance)) |
434 | { |
435 | quickestfinish.distance=quickest2.distance+result3->quickest.distance; |
436 | quickestfinish.duration=quickest2.duration+result3->quickest.duration; |
437 | } |
438 | } |
439 | |
440 | endloop: |
441 | |
442 | segment=FindNextSegment(supersegments,segment); |
443 | } |
444 | |
445 | if(print_progress && !(results->number%10000)) |
446 | { |
447 | printf("\rRouting: End Nodes=%d Shortest=%.1fkm,%.0fmin Quickest=%.1fkm,%.0fmin ",results->number, |
448 | distance_to_km(shortest2.distance),duration_to_minutes(shortest2.duration), |
449 | distance_to_km(quickest2.distance),duration_to_minutes(quickest2.duration)); |
450 | fflush(stdout); |
451 | } |
452 | } |
453 | |
454 | if(print_progress) |
455 | { |
456 | printf("\rRouted: End Super-Nodes=%d Shortest=%.1fkm,%.0fmin Quickest=%.1fkm,%.0fmin\n",results->number, |
457 | distance_to_km(shortestfinish.distance),duration_to_minutes(shortestfinish.duration), |
458 | distance_to_km(quickestfinish.distance),duration_to_minutes(quickestfinish.duration)); |
459 | fflush(stdout); |
460 | } |
461 | |
462 | /* Finish off the end part of the route. */ |
463 | |
464 | if(!FindResult(results,finish)) |
465 | { |
466 | result2=InsertResult(results,finish); |
467 | result3=FindResult(end,finish); |
468 | |
469 | *result2=*result3; |
470 | |
471 | result2->shortest.distance=~0; |
472 | result2->shortest.duration=~0; |
473 | result2->quickest.distance=~0; |
474 | result2->quickest.duration=~0; |
475 | |
476 | result3=FirstResult(end); |
477 | |
478 | while(result3) |
479 | { |
480 | if(FindNode(supernodes,result3->node)) |
481 | if((result1=FindResult(results,result3->node))) |
482 | { |
483 | if((result1->shortest.distance+result3->shortest.distance)<result2->shortest.distance || |
484 | ((result1->shortest.distance+result3->shortest.distance)==result2->shortest.distance && |
485 | (result1->shortest.duration+result3->shortest.duration)<result2->shortest.duration)) |
486 | { |
487 | result2->shortest.distance=result1->shortest.distance+result3->shortest.distance; |
488 | result2->shortest.duration=result1->shortest.duration+result3->shortest.duration; |
489 | result2->shortest.prev=result1->node; |
490 | } |
491 | if((result1->quickest.duration+result3->quickest.duration)<result2->quickest.duration || |
492 | ((result1->quickest.duration+result3->quickest.duration)==result2->quickest.duration && |
493 | (result1->quickest.distance+result3->quickest.distance)<result2->quickest.distance)) |
494 | { |
495 | result2->quickest.distance=result1->quickest.distance+result3->quickest.distance; |
496 | result2->quickest.duration=result1->quickest.duration+result3->quickest.duration; |
497 | result2->quickest.prev=result1->node; |
498 | } |
499 | } |
500 | |
501 | result3=NextResult(end,result3); |
502 | } |
503 | } |
504 | |
505 | /* Check it worked */ |
506 | |
507 | result2=FindResult(results,finish); |
508 | |
509 | if(!result2) |
510 | { |
511 | FreeResultsList(results); |
512 | return(NULL); |
513 | } |
514 | |
515 | /* Reverse the results */ |
516 | |
517 | result2=FindResult(results,finish); |
518 | |
519 | do |
520 | { |
521 | if(result2->shortest.prev) |
522 | { |
523 | uint32_t node1=result2->shortest.prev; |
524 | |
525 | result1=FindResult(results,node1); |
526 | |
527 | result1->shortest.next=result2->node; |
528 | |
529 | result2=result1; |
530 | } |
531 | else |
532 | result2=NULL; |
533 | } |
534 | while(result2); |
535 | |
536 | result2=FindResult(results,finish); |
537 | |
538 | do |
539 | { |
540 | if(result2->quickest.prev) |
541 | { |
542 | uint32_t node1=result2->quickest.prev; |
543 | |
544 | result1=FindResult(results,node1); |
545 | |
546 | result1->quickest.next=result2->node; |
547 | |
548 | result2=result1; |
549 | } |
550 | else |
551 | result2=NULL; |
552 | } |
553 | while(result2); |
554 | |
555 | return(results); |
556 | } |
557 | #endif |
558 | |
559 | |
560 | /*++++++++++++++++++++++++++++++++++++++ |
561 | Print the optimum route between two nodes. |
562 | |
563 | Results *Results The set of results to print. |
564 | |
565 | Nodes *nodes The list of nodes. |
566 | |
567 | Segments *segments The set of segments to use. |
568 | |
569 | Ways *ways The list of ways. |
570 | |
571 | Nodes *supernodes The list of super-nodes. |
572 | |
573 | uint32_t start The start node. |
574 | |
575 | uint32_t finish The finish node. |
576 | |
577 | Profile *profile The profile containing the transport type, speeds and allowed highways. |
578 | ++++++++++++++++++++++++++++++++++++++*/ |
579 | |
580 | void PrintRoute(Results *results,Nodes *nodes,Segments *segments,Ways *ways,Nodes *supernodes,uint32_t start,uint32_t finish,Profile *profile) |
581 | { |
582 | FILE *textfile,*gpxfile; |
583 | Result *result; |
584 | |
585 | /* Print the result for the shortest route */ |
586 | |
587 | textfile=fopen("shortest.txt","w"); |
588 | gpxfile=fopen("shortest.gpx","w"); |
589 | |
590 | fprintf(gpxfile,"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); |
591 | fprintf(gpxfile,"<gpx version=\"1.0\" creator=\"Router\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://www.topografix.com/GPX/1/0\" xsi:schemaLocation=\"http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd\">\n"); |
592 | fprintf(gpxfile,"<trk>\n"); |
593 | fprintf(gpxfile,"<trkseg>\n"); |
594 | |
595 | result=FindResult(results,start); |
596 | |
597 | do |
598 | { |
599 | Node *node=LookupNode(nodes,result->node); |
600 | |
601 | fprintf(gpxfile,"<trkpt lat=\"%.6f\" lon=\"%.6f\"></trkpt>\n",node->latitude,node->longitude); |
602 | |
603 | if(result->shortest.prev) |
604 | { |
605 | Segment *segment; |
606 | Way *way; |
607 | |
608 | segment=LookupSegment(segments,FirstSegment(nodes,result->shortest.prev)); |
609 | while(segment->node2!=result->node) |
610 | segment=NextSegment(segments,segment); |
611 | |
612 | way=LookupWay(ways,segment->wayindex); |
613 | |
614 | fprintf(textfile,"%8.4f %9.4f %10d%c %5.3f %5.2f %7.2f %5.1f %3d %s\n",node->latitude,node->longitude, |
615 | result->node,supernodes?'*':' ', |
616 | distance_to_km(segment->distance),duration_to_minutes(Duration(segment,way,profile)), |
617 | distance_to_km(result->shortest.distance),duration_to_minutes(result->shortest.duration), |
618 | profile->speed[HIGHWAY(way->type)],WayName(ways,way)); |
619 | } |
620 | else |
621 | fprintf(textfile,"%8.4f %9.4f %10d%c %5.3f %5.2f %7.2f %5.1f\n",node->latitude,node->longitude, |
622 | result->node,supernodes?'*':' ', |
623 | 0.0,0.0,0.0,0.0); |
624 | |
625 | if(result->shortest.next) |
626 | result=FindResult(results,result->shortest.next); |
627 | else |
628 | result=NULL; |
629 | } |
630 | while(result); |
631 | |
632 | fprintf(gpxfile,"</trkseg>\n"); |
633 | fprintf(gpxfile,"</trk>\n"); |
634 | fprintf(gpxfile,"</gpx>\n"); |
635 | |
636 | fclose(textfile); |
637 | fclose(gpxfile); |
638 | |
639 | /* Print the result for the quickest route */ |
640 | |
641 | textfile=fopen("quickest.txt","w"); |
642 | gpxfile=fopen("quickest.gpx","w"); |
643 | |
644 | fprintf(gpxfile,"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); |
645 | fprintf(gpxfile,"<gpx version=\"1.0\" creator=\"Router\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://www.topografix.com/GPX/1/0\" xsi:schemaLocation=\"http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd\">\n"); |
646 | fprintf(gpxfile,"<trk>\n"); |
647 | fprintf(gpxfile,"<trkseg>\n"); |
648 | |
649 | result=FindResult(results,start); |
650 | |
651 | do |
652 | { |
653 | Node *node=LookupNode(nodes,result->node); |
654 | |
655 | fprintf(gpxfile,"<trkpt lat=\"%.6f\" lon=\"%.6f\"></trkpt>\n",node->latitude,node->longitude); |
656 | |
657 | if(result->quickest.prev) |
658 | { |
659 | Segment *segment; |
660 | Way *way; |
661 | |
662 | segment=LookupSegment(segments,FirstSegment(nodes,result->quickest.prev)); |
663 | while(segment->node2!=result->node) |
664 | segment=NextSegment(segments,segment); |
665 | |
666 | way=LookupWay(ways,segment->wayindex); |
667 | |
668 | fprintf(textfile,"%8.4f %9.4f %10d%c %5.3f %5.2f %7.2f %5.1f %3d %s\n",node->latitude,node->longitude, |
669 | result->node,supernodes?'*':' ', |
670 | distance_to_km(segment->distance),duration_to_minutes(Duration(segment,way,profile)), |
671 | distance_to_km(result->quickest.distance),duration_to_minutes(result->quickest.duration), |
672 | profile->speed[HIGHWAY(way->type)],WayName(ways,way)); |
673 | } |
674 | else |
675 | fprintf(textfile,"%8.4f %9.4f %10d%c %5.3f %5.2f %7.2f %5.1f\n",node->latitude,node->longitude, |
676 | result->node,supernodes?'*':' ', |
677 | 0.0,0.0,0.0,0.0); |
678 | |
679 | if(result->quickest.next) |
680 | result=FindResult(results,result->quickest.next); |
681 | else |
682 | result=NULL; |
683 | } |
684 | while(result); |
685 | |
686 | fprintf(gpxfile,"</trkseg>\n"); |
687 | fprintf(gpxfile,"</trk>\n"); |
688 | fprintf(gpxfile,"</gpx>\n"); |
689 | |
690 | fclose(textfile); |
691 | fclose(gpxfile); |
692 | } |
693 | |
694 | #if 0 |
695 | |
696 | /*++++++++++++++++++++++++++++++++++++++ |
697 | Find all routes from a specified node to any node in the specified list. |
698 | |
699 | Results *FindRoutes 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 | uint32_t start The start node. |
708 | |
709 | Nodes *finish The finishing nodes. |
710 | |
711 | Profile *profile The profile containing the transport type, speeds and allowed highways. |
712 | ++++++++++++++++++++++++++++++++++++++*/ |
713 | |
714 | Results *FindRoutes(Nodes *nodes,Segments *segments,Ways *ways,uint32_t start,Nodes *finish,Profile *profile) |
715 | { |
716 | Results *results; |
717 | uint32_t node1,node2; |
718 | HalfResult shortest2,quickest2; |
719 | Result *result1,*result2; |
720 | Segment *segment; |
721 | Way *way; |
722 | |
723 | /* Insert the first node into the queue */ |
724 | |
725 | results=NewResultsList(8); |
726 | |
727 | result1=InsertResult(results,start); |
728 | |
729 | result1->node=start; |
730 | result1->shortest.prev=0; |
731 | result1->shortest.next=0; |
732 | result1->shortest.distance=0; |
733 | result1->shortest.duration=0; |
734 | result1->quickest.prev=0; |
735 | result1->quickest.next=0; |
736 | result1->quickest.distance=0; |
737 | result1->quickest.duration=0; |
738 | |
739 | insert_in_queue(result1); |
740 | |
741 | /* Loop across all nodes in the queue */ |
742 | |
743 | while((result1=pop_from_queue())) |
744 | { |
745 | node1=result1->node; |
746 | |
747 | segment=FindFirstSegment(segments,node1); |
748 | |
749 | while(segment) |
750 | { |
751 | duration_t segment_duration; |
752 | |
753 | if(segment->distance&ONEWAY_OPPOSITE && profile->oneway) |
754 | goto endloop; |
755 | |
756 | node2=segment->node2; |
757 | |
758 | if(result1->shortest.prev==node2 && result1->quickest.prev==node2) |
759 | goto endloop; |
760 | |
761 | way=LookupWay(ways,segment->wayindex); |
762 | |
763 | if(!(way->allow&profile->allow)) |
764 | goto endloop; |
765 | |
766 | if(!profile->highways[HIGHWAY(way->type)]) |
767 | goto endloop; |
768 | |
769 | segment_duration=Duration(segment,way,profile); |
770 | |
771 | shortest2.distance=result1->shortest.distance+DISTANCE(segment->distance); |
772 | shortest2.duration=result1->shortest.duration+segment_duration; |
773 | quickest2.distance=result1->quickest.distance+DISTANCE(segment->distance); |
774 | quickest2.duration=result1->quickest.duration+segment_duration; |
775 | |
776 | result2=FindResult(results,node2); |
777 | |
778 | if(!result2) /* New end node */ |
779 | { |
780 | result2=InsertResult(results,node2); |
781 | result2->node=node2; |
782 | result2->shortest.prev=node1; |
783 | result2->shortest.next=0; |
784 | result2->shortest.distance=shortest2.distance; |
785 | result2->shortest.duration=shortest2.duration; |
786 | result2->quickest.prev=node1; |
787 | result2->quickest.next=0; |
788 | result2->quickest.distance=quickest2.distance; |
789 | result2->quickest.duration=quickest2.duration; |
790 | |
791 | if(!FindNode(finish,node2)) |
792 | insert_in_queue(result2); |
793 | } |
794 | else |
795 | { |
796 | if(shortest2.distance<result2->shortest.distance || |
797 | (shortest2.distance==result2->shortest.distance && |
798 | shortest2.duration<result2->shortest.duration)) /* New end node is shorter */ |
799 | { |
800 | result2->shortest.prev=node1; |
801 | result2->shortest.distance=shortest2.distance; |
802 | result2->shortest.duration=shortest2.duration; |
803 | |
804 | if(!FindNode(finish,node2)) |
805 | insert_in_queue(result2); |
806 | } |
807 | |
808 | if(quickest2.duration<result2->quickest.duration || |
809 | (quickest2.duration==result2->quickest.duration && |
810 | quickest2.distance<result2->quickest.distance)) /* New end node is quicker */ |
811 | { |
812 | result2->quickest.prev=node1; |
813 | result2->quickest.distance=quickest2.distance; |
814 | result2->quickest.duration=quickest2.duration; |
815 | |
816 | if(!FindNode(finish,node2)) |
817 | insert_in_queue(result2); |
818 | } |
819 | } |
820 | |
821 | endloop: |
822 | |
823 | segment=FindNextSegment(segments,segment); |
824 | } |
825 | } |
826 | |
827 | return(results); |
828 | } |
829 | |
830 | |
831 | /*++++++++++++++++++++++++++++++++++++++ |
832 | Find all routes from any node in the specified list to a specific node. |
833 | |
834 | Results *FindReverseRoute Returns a set of results. |
835 | |
836 | Nodes *nodes The set of nodes to use. |
837 | |
838 | Segments *segments The set of segments to use. |
839 | |
840 | Ways *ways The set of ways to use. |
841 | |
842 | Nodes *start The starting nodes. |
843 | |
844 | uint32_t finish The finishing node. |
845 | |
846 | Profile *profile The profile containing the transport type, speeds and allowed highways. |
847 | ++++++++++++++++++++++++++++++++++++++*/ |
848 | |
849 | Results *FindReverseRoutes(Nodes *nodes,Segments *segments,Ways *ways,Nodes *start,uint32_t finish,Profile *profile) |
850 | { |
851 | Results *results; |
852 | uint32_t node1,node2; |
853 | HalfResult shortest2,quickest2; |
854 | Result *result1,*result2; |
855 | Segment *segment; |
856 | Way *way; |
857 | |
858 | /* Insert the first node into the queue */ |
859 | |
860 | results=NewResultsList(8); |
861 | |
862 | result1=InsertResult(results,finish); |
863 | |
864 | result1->node=finish; |
865 | result1->shortest.prev=0; |
866 | result1->shortest.next=0; |
867 | result1->shortest.distance=0; |
868 | result1->shortest.duration=0; |
869 | result1->quickest.prev=0; |
870 | result1->quickest.next=0; |
871 | result1->quickest.distance=0; |
872 | result1->quickest.duration=0; |
873 | |
874 | insert_in_queue(result1); |
875 | |
876 | /* Loop across all nodes in the queue */ |
877 | |
878 | while((result1=pop_from_queue())) |
879 | { |
880 | node1=result1->node; |
881 | |
882 | segment=FindFirstSegment(segments,node1); |
883 | |
884 | while(segment) |
885 | { |
886 | duration_t reversesegment_duration; |
887 | |
888 | /* Reverse the segment and check it exists */ |
889 | |
890 | uint32_t reversenode; |
891 | Segment *reversesegment; |
892 | |
893 | reversenode=segment->node2; |
894 | reversesegment=FindFirstSegment(segments,reversenode); |
895 | |
896 | while(reversesegment && reversesegment->node2!=node1) |
897 | reversesegment=FindNextSegment(segments,reversesegment); |
898 | |
899 | if(!reversesegment) |
900 | goto endloop; |
901 | |
902 | if(reversesegment->distance&ONEWAY_OPPOSITE && profile->oneway) |
903 | goto endloop; |
904 | |
905 | node2=reversesegment->node1; |
906 | |
907 | if(result1->shortest.prev==node2 && result1->quickest.prev==node2) |
908 | goto endloop; |
909 | |
910 | way=LookupWay(ways,reversesegment->wayindex); |
911 | |
912 | if(!(way->allow&profile->allow)) |
913 | goto endloop; |
914 | |
915 | if(!profile->highways[HIGHWAY(way->type)]) |
916 | goto endloop; |
917 | |
918 | reversesegment_duration=Duration(reversesegment,way,profile); |
919 | |
920 | shortest2.distance=result1->shortest.distance+DISTANCE(reversesegment->distance); |
921 | shortest2.duration=result1->shortest.duration+reversesegment_duration; |
922 | quickest2.distance=result1->quickest.distance+DISTANCE(reversesegment->distance); |
923 | quickest2.duration=result1->quickest.duration+reversesegment_duration; |
924 | |
925 | result2=FindResult(results,node2); |
926 | |
927 | if(!result2) /* New end node */ |
928 | { |
929 | result2=InsertResult(results,node2); |
930 | result2->node=node2; |
931 | result2->shortest.prev=0; |
932 | result2->shortest.next=node1; |
933 | result2->shortest.distance=shortest2.distance; |
934 | result2->shortest.duration=shortest2.duration; |
935 | result2->quickest.prev=0; |
936 | result2->quickest.next=node1; |
937 | result2->quickest.distance=quickest2.distance; |
938 | result2->quickest.duration=quickest2.duration; |
939 | |
940 | if(!FindNode(start,node2)) |
941 | insert_in_queue(result2); |
942 | } |
943 | else |
944 | { |
945 | if(shortest2.distance<result2->shortest.distance || |
946 | (shortest2.distance==result2->shortest.distance && |
947 | shortest2.duration<result2->shortest.duration)) /* New end node is shorter */ |
948 | { |
949 | result2->shortest.next=node1; |
950 | result2->shortest.distance=shortest2.distance; |
951 | result2->shortest.duration=shortest2.duration; |
952 | |
953 | if(!FindNode(start,node2)) |
954 | insert_in_queue(result2); |
955 | } |
956 | |
957 | if(quickest2.duration<result2->quickest.duration || |
958 | (quickest2.duration==result2->quickest.duration && |
959 | quickest2.distance<result2->quickest.distance)) /* New end node is quicker */ |
960 | { |
961 | result2->quickest.next=node1; |
962 | result2->quickest.distance=quickest2.distance; |
963 | result2->quickest.duration=quickest2.duration; |
964 | |
965 | if(!FindNode(start,node2)) |
966 | insert_in_queue(result2); |
967 | } |
968 | } |
969 | |
970 | endloop: |
971 | |
972 | segment=FindNextSegment(segments,segment); |
973 | } |
974 | } |
975 | |
976 | return(results); |
977 | } |
978 | |
979 | |
980 | /*++++++++++++++++++++++++++++++++++++++ |
981 | Print the optimum route between two nodes. |
982 | |
983 | Results *CombineRoutes Returns the results from joining the super-nodes. |
984 | |
985 | Results *results The set of results from the super-nodes. |
986 | |
987 | Nodes *nodes The list of nodes. |
988 | |
989 | Segments *segments The set of segments to use. |
990 | |
991 | Ways *ways The list of ways. |
992 | |
993 | uint32_t start The start node. |
994 | |
995 | uint32_t finish The finish node. |
996 | |
997 | Profile *profile The profile containing the transport type, speeds and allowed highways. |
998 | ++++++++++++++++++++++++++++++++++++++*/ |
999 | |
1000 | Results *CombineRoutes(Results *results,Nodes *nodes,Segments *segments,Ways *ways,uint32_t start,uint32_t finish,Profile *profile) |
1001 | { |
1002 | Result *result1,*result2,*result3,*result4; |
1003 | Results *combined; |
1004 | |
1005 | combined=NewResultsList(64); |
1006 | |
1007 | print_progress=0; |
1008 | |
1009 | /* Sort out the shortest */ |
1010 | |
1011 | result1=FindResult(results,start); |
1012 | |
1013 | result3=InsertResult(combined,start); |
1014 | |
1015 | result3->node=result1->node; |
1016 | |
1017 | result3->shortest.distance=0; |
1018 | result3->shortest.duration=0; |
1019 | result3->shortest.next=0; |
1020 | result3->shortest.prev=0; |
1021 | |
1022 | do |
1023 | { |
1024 | if(result1->shortest.next) |
1025 | { |
1026 | Results *results2=FindRoute(nodes,segments,ways,result1->node,result1->shortest.next,profile,0); |
1027 | |
1028 | result2=FindResult(results2,result1->node); |
1029 | |
1030 | result3->shortest.next=result2->shortest.next; |
1031 | |
1032 | result2=FindResult(results2,result2->shortest.next); |
1033 | |
1034 | do |
1035 | { |
1036 | result4=InsertResult(combined,result2->node); |
1037 | |
1038 | result4->node=result2->node; |
1039 | |
1040 | result4->shortest=result2->shortest; |
1041 | result4->shortest.distance+=result3->shortest.distance; |
1042 | result4->shortest.duration+=result3->shortest.duration; |
1043 | |
1044 | if(result2->shortest.next) |
1045 | result2=FindResult(results2,result2->shortest.next); |
1046 | else |
1047 | result2=NULL; |
1048 | } |
1049 | while(result2); |
1050 | |
1051 | FreeResultsList(results2); |
1052 | |
1053 | result1=FindResult(results,result1->shortest.next); |
1054 | |
1055 | result3=result4; |
1056 | } |
1057 | else |
1058 | result1=NULL; |
1059 | } |
1060 | while(result1); |
1061 | |
1062 | /* Sort out the quickest */ |
1063 | |
1064 | result1=FindResult(results,start); |
1065 | |
1066 | result3=FindResult(combined,start); |
1067 | |
1068 | result3->quickest.distance=0; |
1069 | result3->quickest.duration=0; |
1070 | result3->quickest.next=0; |
1071 | result3->quickest.prev=0; |
1072 | |
1073 | do |
1074 | { |
1075 | if(result1->quickest.next) |
1076 | { |
1077 | Results *results2=FindRoute(nodes,segments,ways,result1->node,result1->quickest.next,profile,0); |
1078 | |
1079 | result2=FindResult(results2,result1->node); |
1080 | |
1081 | result3->quickest.next=result2->quickest.next; |
1082 | |
1083 | result2=FindResult(results2,result2->quickest.next); |
1084 | |
1085 | do |
1086 | { |
1087 | result4=FindResult(combined,result2->node); |
1088 | |
1089 | if(!result4) |
1090 | { |
1091 | result4=InsertResult(combined,result2->node); |
1092 | |
1093 | result4->node=result2->node; |
1094 | } |
1095 | |
1096 | result4->quickest=result2->quickest; |
1097 | result4->quickest.distance+=result3->quickest.distance; |
1098 | result4->quickest.duration+=result3->quickest.duration; |
1099 | |
1100 | if(result2->quickest.next) |
1101 | result2=FindResult(results2,result2->quickest.next); |
1102 | else |
1103 | result2=NULL; |
1104 | } |
1105 | while(result2); |
1106 | |
1107 | FreeResultsList(results2); |
1108 | |
1109 | result1=FindResult(results,result1->quickest.next); |
1110 | |
1111 | result3=result4; |
1112 | } |
1113 | else |
1114 | result1=NULL; |
1115 | } |
1116 | while(result1); |
1117 | |
1118 | /* Now print out the result normally */ |
1119 | |
1120 | print_progress=1; |
1121 | |
1122 | return(combined); |
1123 | } |
1124 | |
1125 | |
1126 | /*++++++++++++++++++++++++++++++++++++++ |
1127 | Find all routes from a specified node to any node in the specified list that follows a certain type of way. |
1128 | |
1129 | Results *FindRoutesWay Returns a set of results. |
1130 | |
1131 | Nodes *nodes The set of nodes to use. |
1132 | |
1133 | Segments *segments The set of segments to use. |
1134 | |
1135 | Ways *ways The set of ways to use. |
1136 | |
1137 | uint32_t start The start node. |
1138 | |
1139 | Nodes *finish The finishing nodes. |
1140 | |
1141 | Way *match The way that the route must match. |
1142 | ++++++++++++++++++++++++++++++++++++++*/ |
1143 | |
1144 | Results *FindRoutesWay(Nodes *nodes,Segments *segments,Ways *ways,uint32_t start,Nodes *finish,Way *match) |
1145 | { |
1146 | Results *results; |
1147 | uint32_t node1,node2; |
1148 | HalfResult shortest2; |
1149 | Result *result1,*result2; |
1150 | Segment *segment; |
1151 | Way *way; |
1152 | |
1153 | /* Insert the first node into the queue */ |
1154 | |
1155 | results=NewResultsList(8); |
1156 | |
1157 | result1=InsertResult(results,start); |
1158 | |
1159 | result1->node=start; |
1160 | result1->shortest.prev=0; |
1161 | result1->shortest.next=0; |
1162 | result1->shortest.distance=0; |
1163 | |
1164 | insert_in_queue(result1); |
1165 | |
1166 | /* Loop across all nodes in the queue */ |
1167 | |
1168 | while((result1=pop_from_queue())) |
1169 | { |
1170 | node1=result1->node; |
1171 | |
1172 | segment=FindFirstSegment(segments,node1); |
1173 | |
1174 | while(segment) |
1175 | { |
1176 | if(segment->distance&ONEWAY_OPPOSITE) |
1177 | goto endloop; |
1178 | |
1179 | node2=segment->node2; |
1180 | |
1181 | if(result1->shortest.prev==node2) |
1182 | goto endloop; |
1183 | |
1184 | way=LookupWay(ways,segment->wayindex); |
1185 | |
1186 | if(way->type !=match->type || |
1187 | way->allow!=match->allow || |
1188 | way->limit!=match->limit) |
1189 | goto endloop; |
1190 | |
1191 | shortest2.distance=result1->shortest.distance+DISTANCE(segment->distance); |
1192 | |
1193 | result2=FindResult(results,node2); |
1194 | |
1195 | if(!result2) /* New end node */ |
1196 | { |
1197 | result2=InsertResult(results,node2); |
1198 | result2->node=node2; |
1199 | result2->shortest.prev=node1; |
1200 | result2->shortest.next=0; |
1201 | result2->shortest.distance=shortest2.distance; |
1202 | |
1203 | if(!FindNode(finish,node2)) |
1204 | insert_in_queue(result2); |
1205 | } |
1206 | else |
1207 | { |
1208 | if(shortest2.distance<result2->shortest.distance) |
1209 | { |
1210 | result2->shortest.prev=node1; |
1211 | result2->shortest.distance=shortest2.distance; |
1212 | |
1213 | if(!FindNode(finish,node2)) |
1214 | insert_in_queue(result2); |
1215 | } |
1216 | } |
1217 | |
1218 | endloop: |
1219 | |
1220 | segment=FindNextSegment(segments,segment); |
1221 | } |
1222 | } |
1223 | |
1224 | return(results); |
1225 | } |
1226 | |
1227 | #endif |
Properties
Name | Value |
---|---|
cvs:description | Route optimiser. |