Routino SVN Repository Browser

Check out the latest version of Routino: svn co http://routino.org/svn/trunk routino

ViewVC logotype

Contents of /trunk/src/optimiser.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 28 - (show annotations) (download) (as text)
Sat Jan 10 13:39:51 2009 UTC (16 years, 2 months ago) by amb
File MIME type: text/x-csrc
File size: 12527 byte(s)
Move the results data type into new files.

1 /***************************************
2 $Header: /home/amb/CVS/routino/src/optimiser.c,v 1.9 2009-01-10 13:39:51 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 #define INCREMENT 1024
27 #define NBINS 256
28
29
30 /*+ A queue results. +*/
31 typedef struct _Queue
32 {
33 uint32_t alloced; /*+ The amount of space allocated for results in the array +*/
34 uint32_t number; /*+ The number of occupied results in the array +*/
35 Result *queue[1024]; /*+ An array of results whose size is not
36 necessarily limited to 1024 (i.e. may
37 overflow the end of this structure). +*/
38 }
39 Queue;
40
41
42 /*+ The queue of nodes. +*/
43 Queue *OSMQueue=NULL;
44
45 /*+ The list of results. +*/
46 Results *OSMResults=NULL;
47
48 /* Functions */
49
50 static void insert_in_queue(Result *result);
51
52
53 /*++++++++++++++++++++++++++++++++++++++
54 Find the optimum route between two nodes.
55
56 Results *FindRoute Returns a set of results.
57
58 Nodes *nodes The set of nodes to use.
59
60 Segments *segments The set of segments to use.
61
62 node_t start The start node.
63
64 node_t finish The finish node.
65 ++++++++++++++++++++++++++++++++++++++*/
66
67 void FindRoute(Nodes *nodes,Segments *segments,node_t start,node_t finish)
68 {
69 Node *Start,*Finish;
70 node_t node2;
71 Node *Node1,*Node2;
72 HalfResult shortest1,quickest1;
73 HalfResult shortest2,quickest2;
74 HalfResult shortestfinish,quickestfinish;
75 distance_t totalcrow,crow;
76 Result *result1,*result2;
77 Segment *segment;
78 int nresults=0;
79
80 /* Set up the finish conditions */
81
82 shortestfinish.distance=~0;
83 shortestfinish.duration=~0;
84 quickestfinish.distance=~0;
85 quickestfinish.duration=~0;
86
87 /* Work out the distance as the crow flies */
88
89 Start=FindNode(nodes,start);
90 Finish=FindNode(nodes,finish);
91
92 totalcrow=Distance(Start,Finish);
93
94 /* Insert the first node into the queue */
95
96 OSMResults=NewResultsList();
97
98 result1=InsertResult(OSMResults,start);
99
100 result1->node=start;
101 result1->Node=Start;
102 result1->shortest.Prev=NULL;
103 result1->shortest.distance=0;
104 result1->shortest.duration=0;
105 result1->quickest.Prev=NULL;
106 result1->quickest.distance=0;
107 result1->quickest.duration=0;
108
109 insert_in_queue(result1);
110
111 /* Loop across all nodes in the queue */
112
113 while(OSMQueue->number>0)
114 {
115 result1=OSMQueue->queue[--OSMQueue->number];
116 Node1=result1->Node;
117 shortest1.distance=result1->shortest.distance;
118 shortest1.duration=result1->shortest.duration;
119 quickest1.distance=result1->quickest.distance;
120 quickest1.duration=result1->quickest.duration;
121
122 segment=FindFirstSegment(segments,Node1->id);
123
124 while(segment)
125 {
126 node2=segment->node2;
127
128 shortest2.distance=shortest1.distance+segment->distance;
129 shortest2.duration=shortest1.duration+segment->duration;
130 quickest2.distance=quickest1.distance+segment->distance;
131 quickest2.duration=quickest1.duration+segment->duration;
132
133 result2=FindResult(OSMResults,node2);
134 if(result2)
135 Node2=result2->Node;
136 else
137 Node2=FindNode(nodes,node2);
138
139 crow=Distance(Node2,Finish);
140
141 if((crow+shortest2.distance)>(km_to_distance(10)+1.4*totalcrow))
142 goto endloop;
143
144 if(shortest2.distance>shortestfinish.distance && quickest2.duration>quickestfinish.duration)
145 goto endloop;
146
147 if(!result2) /* New end node */
148 {
149 result2=InsertResult(OSMResults,node2);
150 result2->node=node2;
151 result2->Node=Node2;
152 result2->shortest.Prev=Node1;
153 result2->shortest.distance=shortest2.distance;
154 result2->shortest.duration=shortest2.duration;
155 result2->quickest.Prev=Node1;
156 result2->quickest.distance=quickest2.distance;
157 result2->quickest.duration=quickest2.duration;
158
159 nresults++;
160
161 if(node2==finish)
162 {
163 shortestfinish.distance=shortest2.distance;
164 shortestfinish.duration=shortest2.duration;
165 quickestfinish.distance=quickest2.distance;
166 quickestfinish.duration=quickest2.duration;
167 }
168 else
169 insert_in_queue(result2);
170 }
171 else
172 {
173 if(shortest2.distance<result2->shortest.distance ||
174 (shortest2.distance==result2->shortest.distance &&
175 shortest2.duration<result2->shortest.duration)) /* New end node is shorter */
176 {
177 result2->shortest.Prev=Node1;
178 result2->shortest.distance=shortest2.distance;
179 result2->shortest.duration=shortest2.duration;
180
181 if(node2==finish)
182 {
183 shortestfinish.distance=shortest2.distance;
184 shortestfinish.duration=shortest2.duration;
185 }
186 else
187 insert_in_queue(result2);
188 }
189
190 if(quickest2.duration<result2->quickest.duration ||
191 (quickest2.duration==result2->quickest.duration &&
192 quickest2.distance<result2->quickest.distance)) /* New end node is quicker */
193 {
194 result2->quickest.Prev=Node1;
195 result2->quickest.distance=quickest2.distance;
196 result2->quickest.duration=quickest2.duration;
197
198 if(node2==finish)
199 {
200 quickestfinish.distance=quickest2.distance;
201 quickestfinish.duration=quickest2.duration;
202 }
203 else
204 insert_in_queue(result2);
205 }
206 }
207
208 endloop:
209
210 segment=FindNextSegment(segments,segment);
211 }
212
213 if(!(nresults%1000))
214 {
215 printf("\rRouting: End Nodes=%d Queue=%d Journey=%.1fkm,%.0fmin ",nresults,OSMQueue->number,
216 distance_to_km(shortest2.distance),duration_to_minutes(quickest2.duration));
217 fflush(stdout);
218 }
219 }
220
221 printf("\rRouted: End Nodes=%d Shortest=%.1fkm,%.0fmin Quickest=%.1fkm,%.0fmin\n",nresults,
222 distance_to_km(shortestfinish.distance),duration_to_minutes(shortestfinish.duration),
223 distance_to_km(quickestfinish.distance),duration_to_minutes(quickestfinish.duration));
224 fflush(stdout);
225 }
226
227
228 /*++++++++++++++++++++++++++++++++++++++
229 Print the optimum route between two nodes.
230
231 Segments *segments The set of segments to use.
232
233 Ways *ways The list of ways.
234
235 node_t start The start node.
236
237 node_t finish The finish node.
238 ++++++++++++++++++++++++++++++++++++++*/
239
240 void PrintRoute(Segments *segments,Ways *ways,node_t start,node_t finish)
241 {
242 FILE *file;
243 Result *result;
244 // int i,j;
245
246 /* Print the result for the shortest route */
247
248 file=fopen("shortest.txt","w");
249
250 result=FindResult(OSMResults,finish);
251
252 do
253 {
254 if(result->shortest.Prev)
255 {
256 Segment *segment;
257 Way *way;
258
259 segment=FindFirstSegment(segments,result->shortest.Prev->id);
260 while(segment->node2!=result->Node->id)
261 segment=FindNextSegment(segments,segment);
262
263 way=FindWay(ways,segment->way);
264
265 fprintf(file,"%9.5f %9.5f %9d %5.3f %5.2f %3.0f %s\n",result->Node->latitude,result->Node->longitude,result->node,
266 distance_to_km(segment->distance),duration_to_minutes(segment->duration),
267 distance_to_km(segment->distance)/duration_to_hours(segment->duration),
268 WayName(ways,way));
269
270 result=FindResult(OSMResults,result->shortest.Prev->id);
271 }
272 else
273 {
274 fprintf(file,"%9.5f %9.5f %9d\n",result->Node->latitude,result->Node->longitude,result->node);
275
276 result=NULL;
277 }
278 }
279 while(result);
280
281 fclose(file);
282
283 /* Print the result for the quickest route */
284
285 file=fopen("quickest.txt","w");
286
287 result=FindResult(OSMResults,finish);
288
289 do
290 {
291 if(result->quickest.Prev)
292 {
293 Segment *segment;
294 Way *way;
295
296 segment=FindFirstSegment(segments,result->quickest.Prev->id);
297 while(segment->node2!=result->Node->id)
298 segment=FindNextSegment(segments,segment);
299
300 way=FindWay(ways,segment->way);
301
302 fprintf(file,"%9.5f %9.5f %9d %5.3f %5.2f %3.0f %s\n",result->Node->latitude,result->Node->longitude,result->node,
303 distance_to_km(segment->distance),duration_to_minutes(segment->duration),
304 distance_to_km(segment->distance)/duration_to_hours(segment->duration),
305 WayName(ways,way));
306
307 result=FindResult(OSMResults,result->quickest.Prev->id);
308 }
309 else
310 {
311 fprintf(file,"%9.5f %9.5f %9d\n",result->Node->latitude,result->Node->longitude,result->node);
312
313 result=NULL;
314 }
315 }
316 while(result);
317
318 /* Print all the distance results. */
319
320 // file=fopen("distance.txt","w");
321 //
322 // for(i=0;i<NBINS;i++)
323 // for(j=0;j<OSMResults->number[i];j++)
324 // {
325 // result=OSMResults->results[i][j];
326 //
327 // fprintf(file,"%9.5f %9.5f 0 %5.3f\n",result->Node->latitude,result->Node->longitude,
328 // distance_to_km(result->shortest.distance));
329 // }
330 //
331 // fclose(file);
332
333 /* Print all the duration results. */
334
335 // file=fopen("duration.txt","w");
336 //
337 // for(i=0;i<NBINS;i++)
338 // for(j=0;j<OSMResults->number[i];j++)
339 // {
340 // result=OSMResults->results[i][j];
341 //
342 // fprintf(file,"%9.5f %9.5f 0 %5.3f\n",result->Node->latitude,result->Node->longitude,
343 // duration_to_minutes(result->quickest.duration));
344 // }
345 //
346 // fclose(file);
347 }
348
349
350 /*++++++++++++++++++++++++++++++++++++++
351 Insert an item into the queue in the right order.
352
353 Result *result The result to insert into the queue.
354 ++++++++++++++++++++++++++++++++++++++*/
355
356 static void insert_in_queue(Result *result)
357 {
358 int start;
359 int end;
360 int mid;
361 int insert=-1;
362
363 /* Check that the whole thing is allocated. */
364
365 if(!OSMQueue)
366 {
367 OSMQueue=(Queue*)malloc(sizeof(Queue)-sizeof(OSMQueue->queue)+INCREMENT*sizeof(Result*));
368
369 OSMQueue->alloced=INCREMENT;
370 OSMQueue->number=0;
371 }
372
373 /* Check that the arrays have enough space. */
374
375 if(OSMQueue->number==OSMQueue->alloced)
376 {
377 OSMQueue->alloced+=INCREMENT;
378 OSMQueue=(Queue*)realloc((void*)OSMQueue,sizeof(Queue)-sizeof(OSMQueue->queue)+OSMQueue->alloced*sizeof(Result*));
379 }
380
381 /* Binary search - search key may not match, new insertion point required
382 *
383 * # <- start | Check mid and move start or end if it doesn't match
384 * # |
385 * # | Since there may not be an exact match we must set end=mid
386 * # <- mid | or start=mid because we know that mid doesn't match.
387 * # |
388 * # | Eventually end=start+1 and the insertion point is before
389 * # <- end | end (since it cannot be before the initial start or end).
390 */
391
392 start=0;
393 end=OSMQueue->number-1;
394
395 if(OSMQueue->number==0) /* There is nothing in the queue */
396 insert=start;
397 else if(result->shortest.distance>OSMQueue->queue[start]->shortest.distance) /* Check key is not before start */
398 insert=start;
399 else if(result->shortest.distance<OSMQueue->queue[end]->shortest.distance) /* Check key is not after end */
400 insert=end+1;
401 else
402 {
403 do
404 {
405 mid=(start+end)/2; /* Choose mid point */
406
407 if(OSMQueue->queue[mid]->shortest.distance>result->shortest.distance) /* Mid point is too low */
408 start=mid;
409 else if(OSMQueue->queue[mid]->shortest.distance<result->shortest.distance) /* Mid point is too high */
410 end=mid;
411 else /* Mid point is correct */
412 {
413 if(OSMQueue->queue[mid]==result)
414 return;
415
416 insert=mid;
417 break;
418 }
419 }
420 while((end-start)>1);
421
422 if(insert==-1)
423 insert=end;
424 }
425
426 /* Shuffle the array up */
427
428 if(insert!=OSMQueue->number)
429 memmove(&OSMQueue->queue[insert+1],&OSMQueue->queue[insert],(OSMQueue->number-insert)*sizeof(Result*));
430
431 /* Insert the new entry */
432
433 OSMQueue->queue[insert]=result;
434
435 OSMQueue->number++;
436 }
437
438

Properties

Name Value
cvs:description Route optimiser.