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/segments.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 63 - (show annotations) (download) (as text)
Wed Jan 21 19:35:52 2009 UTC (16 years, 2 months ago) by amb
File MIME type: text/x-csrc
File size: 10978 byte(s)
Calculate way speeds at routing time.

1 /***************************************
2 $Header: /home/amb/CVS/routino/src/segments.c,v 1.13 2009-01-21 19:35:52 amb Exp $
3
4 Segment data type functions.
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 <math.h>
17 #include <stdlib.h>
18
19 #include "nodes.h"
20 #include "segments.h"
21 #include "functions.h"
22
23
24 /* Functions */
25
26 static int sort_by_id(Segment *a,Segment *b);
27
28
29 /*++++++++++++++++++++++++++++++++++++++
30 Allocate a new segment list.
31
32 SegmentsMem *NewSegmentList Returns the segment list.
33 ++++++++++++++++++++++++++++++++++++++*/
34
35 SegmentsMem *NewSegmentList(void)
36 {
37 SegmentsMem *segments;
38
39 segments=(SegmentsMem*)malloc(sizeof(SegmentsMem));
40
41 segments->alloced=INCREMENT_SEGMENTS;
42 segments->number=0;
43 segments->sorted=0;
44
45 segments->segments=(Segments*)malloc(sizeof(Segments)+segments->alloced*sizeof(Segment));
46
47 return(segments);
48 }
49
50
51 /*++++++++++++++++++++++++++++++++++++++
52 Load in a segment list from a file.
53
54 Segments* SaveSegmentList Returns the segment list that has just been loaded.
55
56 const char *filename The name of the file to load.
57 ++++++++++++++++++++++++++++++++++++++*/
58
59 Segments *LoadSegmentList(const char *filename)
60 {
61 return((Segments*)MapFile(filename));
62 }
63
64
65 /*++++++++++++++++++++++++++++++++++++++
66 Save the segment list to a file.
67
68 Segments* SaveSegmentList Returns the segment list that has just been saved.
69
70 SegmentsMem* segments The set of segments to save.
71
72 const char *filename The name of the file to save.
73 ++++++++++++++++++++++++++++++++++++++*/
74
75 Segments *SaveSegmentList(SegmentsMem* segments,const char *filename)
76 {
77 assert(segments->sorted); /* Must be sorted */
78
79 if(WriteFile(filename,(void*)segments->segments,sizeof(Segments)-sizeof(segments->segments->segments)+segments->number*sizeof(Segment)))
80 assert(0);
81
82 free(segments->segments);
83 free(segments);
84
85 return(LoadSegmentList(filename));
86 }
87
88
89 /*++++++++++++++++++++++++++++++++++++++
90 Find the first segment with a particular starting node.
91
92 Segment *FindFirstSegment Returns a pointer to the first segment with the specified id.
93
94 Segments* segments The set of segments to process.
95
96 node_t node The node to look for.
97 ++++++++++++++++++++++++++++++++++++++*/
98
99 Segment *FindFirstSegment(Segments* segments,node_t node)
100 {
101 #ifdef NBINS_SEGMENTS
102 int bin=node%NBINS_SEGMENTS;
103 int start=segments->offset[bin];
104 int end=segments->offset[bin+1]-1;
105 #else
106 int start=0;
107 int end=segments->number-1;
108 #endif
109 int mid;
110 int found;
111
112 /* Binary search - search key exact match only is required.
113 *
114 * # <- start | Check mid and move start or end if it doesn't match
115 * # |
116 * # | Since an exact match is wanted we can set end=mid-1
117 * # <- mid | or start=mid+1 because we know that mid doesn't match.
118 * # |
119 * # | Eventually either end=start or end=start+1 and one of
120 * # <- end | start or end is the wanted one.
121 */
122
123 if(end<start) /* There are no nodes */
124 return(NULL);
125 else if(node<segments->segments[start].node1) /* Check key is not before start */
126 return(NULL);
127 else if(node>segments->segments[end].node1) /* Check key is not after end */
128 return(NULL);
129 else
130 {
131 do
132 {
133 mid=(start+end)/2; /* Choose mid point */
134
135 if(segments->segments[mid].node1<node) /* Mid point is too low */
136 start=mid;
137 else if(segments->segments[mid].node1>node) /* Mid point is too high */
138 end=mid;
139 else /* Mid point is correct */
140 {found=mid; goto found;}
141 }
142 while((end-start)>1);
143
144 if(segments->segments[start].node1==node) /* Start is correct */
145 {found=start; goto found;}
146
147 if(segments->segments[end].node1==node) /* End is correct */
148 {found=end; goto found;}
149 }
150
151 return(NULL);
152
153 found:
154
155 while(found>0 && segments->segments[found-1].node1==node)
156 found--;
157
158 return(&segments->segments[found]);
159 }
160
161
162 /*++++++++++++++++++++++++++++++++++++++
163 Find the next segment with a particular starting node.
164
165 Segment *FindNextSegment Returns a pointer to the next segment with the same id.
166
167 Segments* segments The set of segments to process.
168
169 Segment *segment The current segment.
170 ++++++++++++++++++++++++++++++++++++++*/
171
172 Segment *FindNextSegment(Segments* segments,Segment *segment)
173 {
174 Segment *next=segment+1;
175
176 if((next-segments->segments)==segments->number)
177 return(NULL);
178
179 if(next->node1==segment->node1)
180 return(next);
181
182 return(NULL);
183 }
184
185
186 /*++++++++++++++++++++++++++++++++++++++
187 Append a segment to a newly created segment list (unsorted).
188
189 Segment *AppendSegment Returns the appended segment.
190
191 SegmentsMem* segments The set of segments to process.
192
193 node_t node1 The first node in the segment.
194
195 node_t node2 The second node in the segment.
196
197 way_t way The way that the pair of segments are connected by.
198 ++++++++++++++++++++++++++++++++++++++*/
199
200 Segment *AppendSegment(SegmentsMem* segments,node_t node1,node_t node2,way_t way)
201 {
202 /* Check that the array has enough space. */
203
204 if(segments->number==segments->alloced)
205 {
206 segments->alloced+=INCREMENT_SEGMENTS;
207
208 segments->segments=(Segments*)realloc((void*)segments->segments,sizeof(Segments)+segments->alloced*sizeof(Segment));
209 }
210
211 /* Insert the segment */
212
213 segments->segments->segments[segments->number].node1=node1;
214 segments->segments->segments[segments->number].node2=node2;
215 segments->segments->segments[segments->number].way=way;
216 segments->segments->segments[segments->number].distance=0;
217
218 segments->number++;
219
220 segments->sorted=0;
221
222 return(&segments->segments->segments[segments->number-1]);
223 }
224
225
226 /*++++++++++++++++++++++++++++++++++++++
227 Sort the segment list.
228
229 SegmentsMem* segments The set of segments to process.
230 ++++++++++++++++++++++++++++++++++++++*/
231
232 void SortSegmentList(SegmentsMem* segments)
233 {
234 #ifdef NBINS_SEGMENTS
235 int i,bin=0;
236 #endif
237
238 qsort(segments->segments->segments,segments->number,sizeof(Segment),(int (*)(const void*,const void*))sort_by_id);
239
240 while(segments->segments->segments[segments->number-1].node1==~0)
241 segments->number--;
242
243 segments->sorted=1;
244
245 /* Make it searchable */
246
247 segments->segments->number=segments->number;
248
249 #ifdef NBINS_SEGMENTS
250 for(i=0;i<segments->number;i++)
251 for(;bin<=(segments->segments->segments[i].node1%NBINS_SEGMENTS);bin++)
252 segments->segments->offset[bin]=i;
253
254 for(;bin<=NBINS_SEGMENTS;bin++)
255 segments->segments->offset[bin]=segments->number;
256 #endif
257 }
258
259
260 /*++++++++++++++++++++++++++++++++++++++
261 Sort the segments into id order.
262
263 int sort_by_id Returns the comparison of the node fields.
264
265 Segment *a The first Segment.
266
267 Segment *b The second Segment.
268 ++++++++++++++++++++++++++++++++++++++*/
269
270 static int sort_by_id(Segment *a,Segment *b)
271 {
272 node_t a_id1=a->node1,a_id2=a->node2;
273 node_t b_id1=b->node1,b_id2=b->node2;
274
275 #ifdef NBINS_SEGMENTS
276 int a_bin=a->node1%NBINS_SEGMENTS;
277 int b_bin=b->node1%NBINS_SEGMENTS;
278
279 if(a_bin!=b_bin)
280 return(a_bin-b_bin);
281 #endif
282
283 if(a_id1<b_id1)
284 return(-1);
285 else if(a_id1>b_id1)
286 return(1);
287 else /* if(a_id1==b_id1) */
288 {
289 if(a_id2<b_id2)
290 return(-1);
291 else if(a_id2>b_id2)
292 return(1);
293 else
294 return(0);
295 }
296 }
297
298
299 /*++++++++++++++++++++++++++++++++++++++
300 Remove bad segments (zero length or duplicated).
301
302 SegmentsMem *segments The segments to modify.
303 ++++++++++++++++++++++++++++++++++++++*/
304
305 void RemoveBadSegments(SegmentsMem *segments)
306 {
307 int i;
308 int duplicate=0,loop=0;
309 node_t node1=~0,node2=~0;
310
311 for(i=0;i<segments->number;i++)
312 {
313 Segment *segment=&segments->segments->segments[i];
314
315 if(segment->node1==node1 && segment->node2==node2)
316 {
317 duplicate++;
318 segment->node1=~0;
319 }
320 else if(segment->node1==segment->node2)
321 {
322 loop++;
323 segment->node1=~0;
324 }
325
326 node1=segment->node1;
327 node2=segment->node2;
328
329 if(!((i+1)%10000))
330 {
331 printf("\rChecking: Segments=%d Duplicate=%d Loop=%d",i+1,duplicate,loop);
332 fflush(stdout);
333 }
334 }
335
336 printf("\rChecked: Segments=%d Duplicate=%d Loop=%d \n",segments->number,duplicate,loop);
337 fflush(stdout);
338 }
339
340
341 /*++++++++++++++++++++++++++++++++++++++
342 Assign the lengths and durations to all of the segments.
343
344 SegmentsMem* segments The set of segments to process.
345
346 Nodes *nodes The list of nodes to use.
347
348 Ways *ways The list of ways to use.
349 ++++++++++++++++++++++++++++++++++++++*/
350
351 void FixupSegmentLengths(SegmentsMem* segments,Nodes *nodes,Ways *ways)
352 {
353 int i;
354
355 assert(segments->sorted); /* Must be sorted */
356
357 for(i=0;i<segments->number;i++)
358 {
359 Node *node1=FindNode(nodes,segments->segments->segments[i].node1);
360 Node *node2=FindNode(nodes,segments->segments->segments[i].node2);
361
362 if(segments->segments->segments[i].distance!=INVALID_DISTANCE)
363 segments->segments->segments[i].distance=Distance(node1,node2);
364
365 if(!((i+1)%10000))
366 {
367 printf("\rMeasuring Segments: Segments=%d",i+1);
368 fflush(stdout);
369 }
370 }
371
372 printf("\rMeasured Segments: Segments=%d \n",segments->number);
373 fflush(stdout);
374 }
375
376
377 /*++++++++++++++++++++++++++++++++++++++
378 Calculate the distance between two nodes.
379
380 distance_t Distance Returns the distance between the nodes.
381
382 Node *node1 The starting node.
383
384 Node *node2 The end node.
385 ++++++++++++++++++++++++++++++++++++++*/
386
387 distance_t Distance(Node *node1,Node *node2)
388 {
389 double radiant = M_PI / 180;
390
391 double dlon = radiant * (node1->longitude - node2->longitude);
392 double dlat = radiant * (node1->latitude - node2->latitude);
393
394 double a1,a2,a,sa,c,d;
395
396 if(dlon==0 && dlat==0)
397 return 0;
398
399 a1 = sin (dlat / 2);
400 a2 = sin (dlon / 2);
401 a = (a1 * a1) + cos (node1->latitude * radiant) * cos (node2->latitude * radiant) * a2 * a2;
402 sa = sqrt (a);
403 if (sa <= 1.0)
404 {c = 2 * asin (sa);}
405 else
406 {c = 2 * asin (1.0);}
407 d = 6378.137 * c;
408
409 return km_to_distance(d);
410 }
411
412
413 /*++++++++++++++++++++++++++++++++++++++
414 Calculate the duration of segment.
415
416 duration_t Duration Returns the duration of travel between the nodes.
417
418 Segment *segment The segment to traverse.
419
420 Way *way The way that the segment belongs to.
421
422 AllowType transport The type of transport being used.
423 ++++++++++++++++++++++++++++++++++++++*/
424
425 duration_t Duration(Segment *segment,Way *way,AllowType transport)
426 {
427 speed_t speed=WaySpeed(way);
428 distance_t distance=segment->distance;
429
430 if(transport==Allow_Foot)
431 speed=5;
432 else if(transport==Allow_Horse)
433 speed=8;
434 else if(transport==Allow_Bicycle)
435 speed=20;
436
437 return hours_to_duration(distance_to_km(distance)/speed);
438 }

Properties

Name Value
cvs:description Segment data type.