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 10 -
(hide annotations)
(download)
(as text)
Sun Jan 4 19:32:31 2009 UTC (16 years, 2 months ago) by amb
File MIME type: text/x-csrc
File size: 17951 byte(s)
Sun Jan 4 19:32:31 2009 UTC (16 years, 2 months ago) by amb
File MIME type: text/x-csrc
File size: 17951 byte(s)
Introduced some new data types to simplify the code.
1 | amb | 2 | /*************************************** |
2 | amb | 10 | $Header: /home/amb/CVS/routino/src/optimiser.c,v 1.6 2009-01-04 19:32:31 amb Exp $ |
3 | amb | 2 | |
4 | Routing optimiser. | ||
5 | ******************/ /****************** | ||
6 | Written by Andrew M. Bishop | ||
7 | |||
8 | amb | 3 | This file Copyright 2008,2009 Andrew M. Bishop |
9 | amb | 2 | 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 <string.h> | ||
16 | #include <stdlib.h> | ||
17 | |||
18 | #include "functions.h" | ||
19 | #include "types.h" | ||
20 | |||
21 | #define INCREMENT 10*1024 | ||
22 | #define NBINS 64 | ||
23 | |||
24 | amb | 10 | /*+ One part of the result for a node. +*/ |
25 | typedef struct _HalfResult | ||
26 | { | ||
27 | Node *Prev; /*+ The previous Node following the shortest path. +*/ | ||
28 | distance_t distance; /*+ The distance travelled to the node following the shortest path. +*/ | ||
29 | duration_t duration; /*+ The time taken to the node following the shortest path. +*/ | ||
30 | } | ||
31 | HalfResult; | ||
32 | |||
33 | /*+ One complete result for a node. +*/ | ||
34 | amb | 2 | typedef struct _Result |
35 | { | ||
36 | node_t node; /*+ The end node. +*/ | ||
37 | amb | 10 | Node *Node; /*+ The end Node. +*/ |
38 | HalfResult shortest; /*+ The result for the shortest path. +*/ | ||
39 | HalfResult quickest; /*+ The result for the quickest path. +*/ | ||
40 | amb | 2 | } |
41 | Result; | ||
42 | |||
43 | /*+ A list of results. +*/ | ||
44 | typedef struct _Results | ||
45 | { | ||
46 | uint32_t alloced; /*+ The amount of space allocated for results in the array +*/ | ||
47 | uint32_t number[NBINS]; /*+ The number of occupied results in the array +*/ | ||
48 | Result **results[NBINS]; /*+ An array of pointers to arrays of results +*/ | ||
49 | } | ||
50 | Results; | ||
51 | |||
52 | |||
53 | /*+ A queue results. +*/ | ||
54 | typedef struct _Queue | ||
55 | { | ||
56 | uint32_t alloced; /*+ The amount of space allocated for results in the array +*/ | ||
57 | uint32_t number; /*+ The number of occupied results in the array +*/ | ||
58 | Result *queue[1024]; /*+ An array of results whose size is not | ||
59 | necessarily limited to 1024 (i.e. may | ||
60 | overflow the end of this structure). +*/ | ||
61 | } | ||
62 | Queue; | ||
63 | |||
64 | |||
65 | /*+ The queue of nodes. +*/ | ||
66 | Queue *OSMQueue=NULL; | ||
67 | |||
68 | /*+ The list of results. +*/ | ||
69 | Results *OSMResults=NULL; | ||
70 | |||
71 | /* Functions */ | ||
72 | |||
73 | static void insert_in_queue(Result *result); | ||
74 | static Result *find_insert_result(node_t node); | ||
75 | static Result *find_result(node_t node); | ||
76 | |||
77 | |||
78 | /*++++++++++++++++++++++++++++++++++++++ | ||
79 | Find the optimum route between two nodes. | ||
80 | |||
81 | node_t start The start node. | ||
82 | |||
83 | node_t finish The finish node. | ||
84 | ++++++++++++++++++++++++++++++++++++++*/ | ||
85 | |||
86 | void FindRoute(node_t start,node_t finish) | ||
87 | { | ||
88 | Node *Start,*Finish; | ||
89 | amb | 10 | node_t node2; |
90 | amb | 2 | Node *Node1,*Node2; |
91 | amb | 10 | HalfResult shortest1,quickest1; |
92 | HalfResult shortest2,quickest2; | ||
93 | HalfResult shortestfinish,quickestfinish; | ||
94 | amb | 2 | distance_t totalcrow,crow; |
95 | Result *result1,*result2; | ||
96 | Segment *segment; | ||
97 | int nresults=0; | ||
98 | |||
99 | amb | 10 | /* Set up the finish conditions */ |
100 | |||
101 | shortestfinish.distance=~0; | ||
102 | shortestfinish.duration=~0; | ||
103 | quickestfinish.distance=~0; | ||
104 | quickestfinish.duration=~0; | ||
105 | |||
106 | amb | 2 | /* Work out the distance as the crow flies */ |
107 | |||
108 | Start=FindNode(start); | ||
109 | Finish=FindNode(finish); | ||
110 | |||
111 | amb | 8 | totalcrow=Distance(Start,Finish); |
112 | amb | 2 | |
113 | /* Insert the first node into the queue */ | ||
114 | |||
115 | result1=find_insert_result(start); | ||
116 | |||
117 | result1->node=start; | ||
118 | result1->Node=Start; | ||
119 | amb | 10 | result1->shortest.Prev=NULL; |
120 | result1->shortest.distance=0; | ||
121 | result1->shortest.duration=0; | ||
122 | result1->quickest.Prev=NULL; | ||
123 | result1->quickest.distance=0; | ||
124 | result1->quickest.duration=0; | ||
125 | amb | 2 | |
126 | insert_in_queue(result1); | ||
127 | |||
128 | /* Loop across all nodes in the queue */ | ||
129 | |||
130 | while(OSMQueue->number>0) | ||
131 | { | ||
132 | result1=OSMQueue->queue[--OSMQueue->number]; | ||
133 | Node1=result1->Node; | ||
134 | amb | 10 | shortest1.distance=result1->shortest.distance; |
135 | shortest1.duration=result1->shortest.duration; | ||
136 | quickest1.distance=result1->quickest.distance; | ||
137 | quickest1.duration=result1->quickest.duration; | ||
138 | amb | 2 | |
139 | amb | 10 | segment=FindFirstSegment(Node1->id); |
140 | amb | 2 | |
141 | while(segment) | ||
142 | { | ||
143 | node2=segment->node2; | ||
144 | |||
145 | amb | 10 | shortest2.distance=shortest1.distance+segment->distance; |
146 | shortest2.duration=shortest1.duration+segment->duration; | ||
147 | quickest2.distance=quickest1.distance+segment->distance; | ||
148 | quickest2.duration=quickest1.duration+segment->duration; | ||
149 | amb | 2 | |
150 | result2=find_result(node2); | ||
151 | if(result2) | ||
152 | Node2=result2->Node; | ||
153 | else | ||
154 | Node2=FindNode(node2); | ||
155 | |||
156 | amb | 8 | crow=Distance(Node2,Finish); |
157 | amb | 2 | |
158 | amb | 10 | if((crow+shortest2.distance)>(km_to_distance(10)+1.4*totalcrow)) |
159 | amb | 2 | goto endloop; |
160 | |||
161 | amb | 10 | if(shortest2.distance>shortestfinish.distance && quickest2.duration>quickestfinish.duration) |
162 | amb | 2 | goto endloop; |
163 | |||
164 | if(!result2) /* New end node */ | ||
165 | { | ||
166 | result2=find_insert_result(node2); | ||
167 | result2->node=node2; | ||
168 | result2->Node=Node2; | ||
169 | amb | 10 | result2->shortest.Prev=Node1; |
170 | result2->shortest.distance=shortest2.distance; | ||
171 | result2->shortest.duration=shortest2.duration; | ||
172 | result2->quickest.Prev=Node1; | ||
173 | result2->quickest.distance=quickest2.distance; | ||
174 | result2->quickest.duration=quickest2.duration; | ||
175 | amb | 2 | |
176 | nresults++; | ||
177 | |||
178 | if(node2==finish) | ||
179 | { | ||
180 | amb | 10 | shortestfinish.distance=shortest2.distance; |
181 | shortestfinish.duration=shortest2.duration; | ||
182 | quickestfinish.distance=quickest2.distance; | ||
183 | quickestfinish.duration=quickest2.duration; | ||
184 | amb | 2 | } |
185 | else | ||
186 | insert_in_queue(result2); | ||
187 | } | ||
188 | else | ||
189 | { | ||
190 | amb | 10 | if(shortest2.distance<result2->shortest.distance || |
191 | (shortest2.distance==result2->shortest.distance && | ||
192 | shortest2.duration<result2->shortest.duration)) /* New end node is shorter */ | ||
193 | amb | 2 | { |
194 | amb | 10 | result2->shortest.Prev=Node1; |
195 | result2->shortest.distance=shortest2.distance; | ||
196 | result2->shortest.duration=shortest2.duration; | ||
197 | amb | 2 | |
198 | if(node2==finish) | ||
199 | { | ||
200 | amb | 10 | shortestfinish.distance=shortest2.distance; |
201 | shortestfinish.duration=shortest2.duration; | ||
202 | amb | 2 | } |
203 | else | ||
204 | insert_in_queue(result2); | ||
205 | } | ||
206 | |||
207 | amb | 10 | if(quickest2.duration<result2->quickest.duration || |
208 | (quickest2.duration==result2->quickest.duration && | ||
209 | quickest2.distance<result2->quickest.distance)) /* New end node is quicker */ | ||
210 | amb | 2 | { |
211 | amb | 10 | result2->quickest.Prev=Node1; |
212 | result2->quickest.distance=quickest2.distance; | ||
213 | result2->quickest.duration=quickest2.duration; | ||
214 | amb | 2 | |
215 | if(node2==finish) | ||
216 | { | ||
217 | amb | 10 | quickestfinish.distance=quickest2.distance; |
218 | quickestfinish.duration=quickest2.duration; | ||
219 | amb | 2 | } |
220 | else | ||
221 | insert_in_queue(result2); | ||
222 | } | ||
223 | } | ||
224 | |||
225 | endloop: | ||
226 | |||
227 | segment=FindNextSegment(segment); | ||
228 | } | ||
229 | |||
230 | if(!(nresults%1000)) | ||
231 | { | ||
232 | printf("\rRouting: End Nodes=%d Queue=%d Journey=%.1fkm,%.0fmin ",nresults,OSMQueue->number, | ||
233 | amb | 10 | distance_to_km(shortest2.distance),duration_to_minutes(quickest2.duration)); |
234 | amb | 2 | fflush(stdout); |
235 | } | ||
236 | } | ||
237 | |||
238 | printf("\rRouted: End Nodes=%d Shortest=%.1fkm,%.0fmin Quickest=%.1fkm,%.0fmin\n",nresults, | ||
239 | amb | 10 | distance_to_km(shortestfinish.distance),duration_to_minutes(shortestfinish.duration), |
240 | distance_to_km(quickestfinish.distance),duration_to_minutes(quickestfinish.duration)); | ||
241 | amb | 2 | fflush(stdout); |
242 | } | ||
243 | |||
244 | |||
245 | /*++++++++++++++++++++++++++++++++++++++ | ||
246 | Print the optimum route between two nodes. | ||
247 | |||
248 | node_t start The start node. | ||
249 | |||
250 | node_t finish The finish node. | ||
251 | ++++++++++++++++++++++++++++++++++++++*/ | ||
252 | |||
253 | void PrintRoute(node_t start,node_t finish) | ||
254 | { | ||
255 | FILE *file; | ||
256 | Result *result; | ||
257 | amb | 3 | // int i,j; |
258 | amb | 2 | |
259 | /* Print the result for the shortest route */ | ||
260 | |||
261 | file=fopen("shortest.txt","w"); | ||
262 | |||
263 | result=find_result(finish); | ||
264 | |||
265 | do | ||
266 | { | ||
267 | amb | 10 | if(result->shortest.Prev) |
268 | amb | 2 | { |
269 | amb | 6 | Segment *segment; |
270 | Way *way; | ||
271 | amb | 2 | |
272 | amb | 10 | segment=FindFirstSegment(result->shortest.Prev->id); |
273 | amb | 2 | while(segment->node2!=result->Node->id) |
274 | segment=FindNextSegment(segment); | ||
275 | |||
276 | amb | 6 | way=FindWay(segment->way); |
277 | |||
278 | fprintf(file,"%9.5f %9.5f %9d %5.3f %5.2f %3.0f %s\n",result->Node->latitude,result->Node->longitude,result->node, | ||
279 | amb | 5 | distance_to_km(segment->distance),duration_to_minutes(segment->duration), |
280 | amb | 6 | distance_to_km(segment->distance)/duration_to_hours(segment->duration), |
281 | WayName(way)); | ||
282 | amb | 2 | |
283 | amb | 10 | result=find_result(result->shortest.Prev->id); |
284 | amb | 2 | } |
285 | else | ||
286 | { | ||
287 | fprintf(file,"%9.5f %9.5f %9d\n",result->Node->latitude,result->Node->longitude,result->node); | ||
288 | |||
289 | result=NULL; | ||
290 | } | ||
291 | } | ||
292 | while(result); | ||
293 | |||
294 | fclose(file); | ||
295 | |||
296 | /* Print the result for the quickest route */ | ||
297 | |||
298 | file=fopen("quickest.txt","w"); | ||
299 | |||
300 | result=find_result(finish); | ||
301 | |||
302 | do | ||
303 | { | ||
304 | amb | 10 | if(result->quickest.Prev) |
305 | amb | 2 | { |
306 | amb | 6 | Segment *segment; |
307 | Way *way; | ||
308 | amb | 2 | |
309 | amb | 10 | segment=FindFirstSegment(result->quickest.Prev->id); |
310 | amb | 2 | while(segment->node2!=result->Node->id) |
311 | segment=FindNextSegment(segment); | ||
312 | |||
313 | amb | 6 | way=FindWay(segment->way); |
314 | |||
315 | fprintf(file,"%9.5f %9.5f %9d %5.3f %5.2f %3.0f %s\n",result->Node->latitude,result->Node->longitude,result->node, | ||
316 | amb | 5 | distance_to_km(segment->distance),duration_to_minutes(segment->duration), |
317 | amb | 6 | distance_to_km(segment->distance)/duration_to_hours(segment->duration), |
318 | WayName(way)); | ||
319 | amb | 2 | |
320 | amb | 10 | result=find_result(result->quickest.Prev->id); |
321 | amb | 2 | } |
322 | else | ||
323 | { | ||
324 | fprintf(file,"%9.5f %9.5f %9d\n",result->Node->latitude,result->Node->longitude,result->node); | ||
325 | |||
326 | result=NULL; | ||
327 | } | ||
328 | } | ||
329 | while(result); | ||
330 | |||
331 | amb | 3 | /* Print all the distance results. */ |
332 | |||
333 | // file=fopen("distance.txt","w"); | ||
334 | // | ||
335 | // for(i=0;i<NBINS;i++) | ||
336 | // for(j=0;j<OSMResults->number[i];j++) | ||
337 | // { | ||
338 | // result=OSMResults->results[i][j]; | ||
339 | // | ||
340 | // fprintf(file,"%9.5f %9.5f 0 %5.3f\n",result->Node->latitude,result->Node->longitude, | ||
341 | amb | 10 | // distance_to_km(result->shortest.distance)); |
342 | amb | 3 | // } |
343 | // | ||
344 | // fclose(file); | ||
345 | |||
346 | /* Print all the duration results. */ | ||
347 | |||
348 | // file=fopen("duration.txt","w"); | ||
349 | // | ||
350 | // for(i=0;i<NBINS;i++) | ||
351 | // for(j=0;j<OSMResults->number[i];j++) | ||
352 | // { | ||
353 | // result=OSMResults->results[i][j]; | ||
354 | // | ||
355 | // fprintf(file,"%9.5f %9.5f 0 %5.3f\n",result->Node->latitude,result->Node->longitude, | ||
356 | amb | 10 | // duration_to_minutes(result->quickest.duration)); |
357 | amb | 3 | // } |
358 | // | ||
359 | // fclose(file); | ||
360 | amb | 2 | } |
361 | |||
362 | |||
363 | /*++++++++++++++++++++++++++++++++++++++ | ||
364 | Insert an item into the queue in the right order. | ||
365 | |||
366 | Result *result The result to insert into the queue. | ||
367 | ++++++++++++++++++++++++++++++++++++++*/ | ||
368 | |||
369 | static void insert_in_queue(Result *result) | ||
370 | { | ||
371 | int start; | ||
372 | int end; | ||
373 | int mid; | ||
374 | int insert=-1; | ||
375 | |||
376 | /* Check that the whole thing is allocated. */ | ||
377 | |||
378 | if(!OSMQueue) | ||
379 | { | ||
380 | OSMQueue=(Queue*)calloc(1,sizeof(Queue)); | ||
381 | OSMQueue->alloced=sizeof(OSMQueue->queue)/sizeof(OSMQueue->queue[0]); | ||
382 | } | ||
383 | |||
384 | /* Check that the arrays have enough space. */ | ||
385 | |||
386 | if(OSMQueue->number==OSMQueue->alloced) | ||
387 | { | ||
388 | OSMQueue=(Queue*)realloc((void*)OSMQueue,sizeof(Queue)-sizeof(OSMQueue->queue)+(OSMQueue->alloced+INCREMENT)*sizeof(Result*)); | ||
389 | |||
390 | OSMQueue->alloced+=INCREMENT; | ||
391 | } | ||
392 | |||
393 | /* Binary search - search key may not match, new insertion point required | ||
394 | * | ||
395 | * # <- start | Check mid and move start or end if it doesn't match | ||
396 | * # | | ||
397 | * # | Since there may not be an exact match we must set end=mid | ||
398 | * # <- mid | or start=mid because we know that mid doesn't match. | ||
399 | * # | | ||
400 | * # | Eventually end=start+1 and the insertion point is before | ||
401 | * # <- end | end (since it cannot be before the initial start or end). | ||
402 | */ | ||
403 | |||
404 | start=0; | ||
405 | end=OSMQueue->number-1; | ||
406 | |||
407 | if(OSMQueue->number==0) /* There is nothing in the queue */ | ||
408 | insert=start; | ||
409 | amb | 10 | else if(result->shortest.distance>OSMQueue->queue[start]->shortest.distance) /* Check key is not before start */ |
410 | amb | 2 | insert=start; |
411 | amb | 10 | else if(result->shortest.distance<OSMQueue->queue[end]->shortest.distance) /* Check key is not after end */ |
412 | amb | 2 | insert=end+1; |
413 | else | ||
414 | { | ||
415 | do | ||
416 | { | ||
417 | mid=(start+end)/2; /* Choose mid point */ | ||
418 | |||
419 | amb | 10 | if(OSMQueue->queue[mid]->shortest.distance>result->shortest.distance) /* Mid point is too low */ |
420 | amb | 2 | start=mid; |
421 | amb | 10 | else if(OSMQueue->queue[mid]->shortest.distance<result->shortest.distance) /* Mid point is too high */ |
422 | amb | 2 | end=mid; |
423 | else /* Mid point is correct */ | ||
424 | { | ||
425 | if(OSMQueue->queue[mid]==result) | ||
426 | return; | ||
427 | |||
428 | insert=mid; | ||
429 | break; | ||
430 | } | ||
431 | } | ||
432 | while((end-start)>1); | ||
433 | |||
434 | if(insert==-1) | ||
435 | insert=end; | ||
436 | } | ||
437 | |||
438 | /* Shuffle the array up */ | ||
439 | |||
440 | if(insert!=OSMQueue->number) | ||
441 | memmove(&OSMQueue->queue[insert+1],&OSMQueue->queue[insert],(OSMQueue->number-insert)*sizeof(Result*)); | ||
442 | |||
443 | /* Insert the new entry */ | ||
444 | |||
445 | OSMQueue->queue[insert]=result; | ||
446 | |||
447 | OSMQueue->number++; | ||
448 | } | ||
449 | |||
450 | |||
451 | /*++++++++++++++++++++++++++++++++++++++ | ||
452 | Find an existing result or insert a new one into the results in the right order. | ||
453 | |||
454 | node_t node The node that is to be inserted into the results. | ||
455 | ++++++++++++++++++++++++++++++++++++++*/ | ||
456 | |||
457 | static Result *find_insert_result(node_t node) | ||
458 | { | ||
459 | int start; | ||
460 | int end; | ||
461 | int mid; | ||
462 | int insert=-1,found=-1; | ||
463 | int bin=node%NBINS; | ||
464 | |||
465 | /* Check that the whole thing is allocated. */ | ||
466 | |||
467 | if(!OSMResults) | ||
468 | { | ||
469 | int i; | ||
470 | |||
471 | OSMResults=(Results*)calloc(1,sizeof(Results)); | ||
472 | OSMResults->alloced=INCREMENT; | ||
473 | |||
474 | for(i=0;i<NBINS;i++) | ||
475 | OSMResults->results[i]=(Result**)malloc(OSMResults->alloced*sizeof(Result*)); | ||
476 | } | ||
477 | |||
478 | /* Check that the arrays have enough space. */ | ||
479 | |||
480 | if(OSMResults->number[bin]==OSMResults->alloced) | ||
481 | { | ||
482 | int i; | ||
483 | |||
484 | OSMResults->alloced+=INCREMENT; | ||
485 | |||
486 | for(i=0;i<NBINS;i++) | ||
487 | OSMResults->results[i]=(Result**)realloc((void*)OSMResults->results[i],OSMResults->alloced*sizeof(Result*)); | ||
488 | } | ||
489 | |||
490 | /* Binary search - search key may not match, if not then insertion point required | ||
491 | * | ||
492 | * # <- start | Check mid and move start or end if it doesn't match | ||
493 | * # | | ||
494 | * # | Since there may not be an exact match we must set end=mid | ||
495 | * # <- mid | or start=mid because we know that mid doesn't match. | ||
496 | * # | | ||
497 | * # | Eventually end=start+1 and the insertion point is before | ||
498 | * # <- end | end (since it cannot be before the initial start or end). | ||
499 | */ | ||
500 | |||
501 | start=0; | ||
502 | end=OSMResults->number[bin]-1; | ||
503 | |||
504 | if(OSMResults->number[bin]==0) /* There are no results */ | ||
505 | insert=start; | ||
506 | else if(node<OSMResults->results[bin][start]->node) /* Check key is not before start */ | ||
507 | insert=start; | ||
508 | else if(node>OSMResults->results[bin][end]->node) /* Check key is not after end */ | ||
509 | insert=end+1; | ||
510 | else | ||
511 | { | ||
512 | do | ||
513 | { | ||
514 | mid=(start+end)/2; /* Choose mid point */ | ||
515 | |||
516 | if(OSMResults->results[bin][mid]->node<node) /* Mid point is too low */ | ||
517 | start=mid; | ||
518 | else if(OSMResults->results[bin][mid]->node>node) /* Mid point is too high */ | ||
519 | end=mid; | ||
520 | else /* Mid point is correct */ | ||
521 | { | ||
522 | found=mid; | ||
523 | break; | ||
524 | } | ||
525 | } | ||
526 | while((end-start)>1); | ||
527 | |||
528 | if(found==-1) | ||
529 | { | ||
530 | if(OSMResults->results[bin][start]->node==node) /* Start is correct */ | ||
531 | found=start; | ||
532 | else if(OSMResults->results[bin][end]->node==node)/* End is correct */ | ||
533 | found=end; | ||
534 | else | ||
535 | insert=end; | ||
536 | } | ||
537 | } | ||
538 | |||
539 | /* Shuffle the array up */ | ||
540 | |||
541 | if(insert!=-1 && insert!=OSMResults->number[bin]) | ||
542 | memmove(&OSMResults->results[bin][insert+1],&OSMResults->results[bin][insert],(OSMResults->number[bin]-insert)*sizeof(Result*)); | ||
543 | |||
544 | if(insert!=-1) | ||
545 | found=insert; | ||
546 | |||
547 | /* Insert the insert entry */ | ||
548 | |||
549 | if(insert!=-1) | ||
550 | { | ||
551 | OSMResults->number[bin]++; | ||
552 | |||
553 | OSMResults->results[bin][found]=(Result*)malloc(sizeof(Result)); | ||
554 | } | ||
555 | |||
556 | return(OSMResults->results[bin][found]); | ||
557 | } | ||
558 | |||
559 | |||
560 | /*++++++++++++++++++++++++++++++++++++++ | ||
561 | Find a result, ordered by node. | ||
562 | |||
563 | node_t node The node that is to be found. | ||
564 | ++++++++++++++++++++++++++++++++++++++*/ | ||
565 | |||
566 | static Result *find_result(node_t node) | ||
567 | { | ||
568 | int start; | ||
569 | int end; | ||
570 | int mid; | ||
571 | int bin=node%NBINS; | ||
572 | |||
573 | /* Binary search - search key exact match only is required. | ||
574 | * | ||
575 | * # <- start | Check mid and move start or end if it doesn't match | ||
576 | * # | | ||
577 | * # | Since an exact match is wanted we can set end=mid-1 | ||
578 | * # <- mid | or start=mid+1 because we know that mid doesn't match. | ||
579 | * # | | ||
580 | * # | Eventually either end=start or end=start+1 and one of | ||
581 | * # <- end | start or end is the wanted one. | ||
582 | */ | ||
583 | |||
584 | start=0; | ||
585 | end=OSMResults->number[bin]-1; | ||
586 | |||
587 | if(OSMResults->number[bin]==0) /* There are no results */ | ||
588 | return(NULL); | ||
589 | else if(node<OSMResults->results[bin][start]->node) /* Check key is not before start */ | ||
590 | return(NULL); | ||
591 | else if(node>OSMResults->results[bin][end]->node) /* Check key is not after end */ | ||
592 | return(NULL); | ||
593 | else | ||
594 | { | ||
595 | do | ||
596 | { | ||
597 | mid=(start+end)/2; /* Choose mid point */ | ||
598 | |||
599 | if(OSMResults->results[bin][mid]->node<node) /* Mid point is too low */ | ||
600 | start=mid+1; | ||
601 | else if(OSMResults->results[bin][mid]->node>node) /* Mid point is too high */ | ||
602 | end=mid-1; | ||
603 | else /* Mid point is correct */ | ||
604 | return(OSMResults->results[bin][mid]); | ||
605 | } | ||
606 | while((end-start)>1); | ||
607 | |||
608 | if(OSMResults->results[bin][start]->node==node) /* Start is correct */ | ||
609 | return(OSMResults->results[bin][start]); | ||
610 | |||
611 | if(OSMResults->results[bin][end]->node==node) /* End is correct */ | ||
612 | return(OSMResults->results[bin][end]); | ||
613 | } | ||
614 | |||
615 | return(NULL); | ||
616 | } |
Properties
Name | Value |
---|---|
cvs:description | Route optimiser. |