Check out the latest version of Routino: svn co http://routino.org/svn/trunk routino
Contents of /trunk/src/segments.c
Parent Directory
|
Revision Log
Revision 74 -
(show annotations)
(download)
(as text)
Fri Jan 23 16:09:09 2009 UTC (16 years, 2 months ago) by amb
File MIME type: text/x-csrc
File size: 10856 byte(s)
Fri Jan 23 16:09:09 2009 UTC (16 years, 2 months ago) by amb
File MIME type: text/x-csrc
File size: 10856 byte(s)
Add enumerated type Transport. Replace variables of AllowType with Transport where more appropriate. Replace AllowType with Allowed. Replace WayType with Highway.
1 | /*************************************** |
2 | $Header: /home/amb/CVS/routino/src/segments.c,v 1.16 2009-01-23 16:09:08 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 | int bin=node%NBINS_SEGMENTS; |
102 | int start=segments->offset[bin]; |
103 | int end=segments->offset[bin+1]-1; /* &offset[NBINS+1] == &number */ |
104 | int mid; |
105 | int found; |
106 | |
107 | /* Binary search - search key exact match only is required. |
108 | * |
109 | * # <- start | Check mid and move start or end if it doesn't match |
110 | * # | |
111 | * # | Since an exact match is wanted we can set end=mid-1 |
112 | * # <- mid | or start=mid+1 because we know that mid doesn't match. |
113 | * # | |
114 | * # | Eventually either end=start or end=start+1 and one of |
115 | * # <- end | start or end is the wanted one. |
116 | */ |
117 | |
118 | if(end<start) /* There are no nodes */ |
119 | return(NULL); |
120 | else if(node<segments->segments[start].node1) /* Check key is not before start */ |
121 | return(NULL); |
122 | else if(node>segments->segments[end].node1) /* Check key is not after end */ |
123 | return(NULL); |
124 | else |
125 | { |
126 | do |
127 | { |
128 | mid=(start+end)/2; /* Choose mid point */ |
129 | |
130 | if(segments->segments[mid].node1<node) /* Mid point is too low */ |
131 | start=mid; |
132 | else if(segments->segments[mid].node1>node) /* Mid point is too high */ |
133 | end=mid; |
134 | else /* Mid point is correct */ |
135 | {found=mid; goto found;} |
136 | } |
137 | while((end-start)>1); |
138 | |
139 | if(segments->segments[start].node1==node) /* Start is correct */ |
140 | {found=start; goto found;} |
141 | |
142 | if(segments->segments[end].node1==node) /* End is correct */ |
143 | {found=end; goto found;} |
144 | } |
145 | |
146 | return(NULL); |
147 | |
148 | found: |
149 | |
150 | while(found>0 && segments->segments[found-1].node1==node) |
151 | found--; |
152 | |
153 | return(&segments->segments[found]); |
154 | } |
155 | |
156 | |
157 | /*++++++++++++++++++++++++++++++++++++++ |
158 | Find the next segment with a particular starting node. |
159 | |
160 | Segment *FindNextSegment Returns a pointer to the next segment with the same id. |
161 | |
162 | Segments* segments The set of segments to process. |
163 | |
164 | Segment *segment The current segment. |
165 | ++++++++++++++++++++++++++++++++++++++*/ |
166 | |
167 | Segment *FindNextSegment(Segments* segments,Segment *segment) |
168 | { |
169 | Segment *next=segment+1; |
170 | |
171 | if((next-segments->segments)==segments->number) |
172 | return(NULL); |
173 | |
174 | if(next->node1==segment->node1) |
175 | return(next); |
176 | |
177 | return(NULL); |
178 | } |
179 | |
180 | |
181 | /*++++++++++++++++++++++++++++++++++++++ |
182 | Append a segment to a newly created segment list (unsorted). |
183 | |
184 | Segment *AppendSegment Returns the appended segment. |
185 | |
186 | SegmentsMem* segments The set of segments to process. |
187 | |
188 | node_t node1 The first node in the segment. |
189 | |
190 | node_t node2 The second node in the segment. |
191 | |
192 | way_t way The way that the pair of segments are connected by. |
193 | ++++++++++++++++++++++++++++++++++++++*/ |
194 | |
195 | Segment *AppendSegment(SegmentsMem* segments,node_t node1,node_t node2,way_t way) |
196 | { |
197 | /* Check that the array has enough space. */ |
198 | |
199 | if(segments->number==segments->alloced) |
200 | { |
201 | segments->alloced+=INCREMENT_SEGMENTS; |
202 | |
203 | segments->segments=(Segments*)realloc((void*)segments->segments,sizeof(Segments)+segments->alloced*sizeof(Segment)); |
204 | } |
205 | |
206 | /* Insert the segment */ |
207 | |
208 | segments->segments->segments[segments->number].node1=node1; |
209 | segments->segments->segments[segments->number].node2=node2; |
210 | segments->segments->segments[segments->number].way=way; |
211 | segments->segments->segments[segments->number].distance=0; |
212 | |
213 | segments->number++; |
214 | |
215 | segments->sorted=0; |
216 | |
217 | return(&segments->segments->segments[segments->number-1]); |
218 | } |
219 | |
220 | |
221 | /*++++++++++++++++++++++++++++++++++++++ |
222 | Sort the segment list. |
223 | |
224 | SegmentsMem* segments The set of segments to process. |
225 | ++++++++++++++++++++++++++++++++++++++*/ |
226 | |
227 | void SortSegmentList(SegmentsMem* segments) |
228 | { |
229 | int i,bin=0; |
230 | |
231 | qsort(segments->segments->segments,segments->number,sizeof(Segment),(int (*)(const void*,const void*))sort_by_id); |
232 | |
233 | while(segments->segments->segments[segments->number-1].node1==~0) |
234 | segments->number--; |
235 | |
236 | segments->sorted=1; |
237 | |
238 | /* Make it searchable */ |
239 | |
240 | segments->segments->number=segments->number; |
241 | |
242 | for(i=0;i<segments->number;i++) |
243 | for(;bin<=(segments->segments->segments[i].node1%NBINS_SEGMENTS);bin++) |
244 | segments->segments->offset[bin]=i; |
245 | |
246 | for(;bin<NBINS_SEGMENTS;bin++) |
247 | segments->segments->offset[bin]=segments->number; |
248 | } |
249 | |
250 | |
251 | /*++++++++++++++++++++++++++++++++++++++ |
252 | Sort the segments into id order. |
253 | |
254 | int sort_by_id Returns the comparison of the node fields. |
255 | |
256 | Segment *a The first Segment. |
257 | |
258 | Segment *b The second Segment. |
259 | ++++++++++++++++++++++++++++++++++++++*/ |
260 | |
261 | static int sort_by_id(Segment *a,Segment *b) |
262 | { |
263 | node_t a_id1=a->node1,a_id2=a->node2; |
264 | node_t b_id1=b->node1,b_id2=b->node2; |
265 | |
266 | int a_bin=a->node1%NBINS_SEGMENTS; |
267 | int b_bin=b->node1%NBINS_SEGMENTS; |
268 | |
269 | if(a_bin!=b_bin) |
270 | return(a_bin-b_bin); |
271 | |
272 | if(a_id1<b_id1) |
273 | return(-1); |
274 | else if(a_id1>b_id1) |
275 | return(1); |
276 | else /* if(a_id1==b_id1) */ |
277 | { |
278 | if(a_id2<b_id2) |
279 | return(-1); |
280 | else if(a_id2>b_id2) |
281 | return(1); |
282 | else |
283 | return(0); |
284 | } |
285 | } |
286 | |
287 | |
288 | /*++++++++++++++++++++++++++++++++++++++ |
289 | Remove bad segments (zero length or duplicated). |
290 | |
291 | SegmentsMem *segments The segments to modify. |
292 | ++++++++++++++++++++++++++++++++++++++*/ |
293 | |
294 | void RemoveBadSegments(SegmentsMem *segments) |
295 | { |
296 | int i; |
297 | int duplicate=0,loop=0; |
298 | node_t node1=~0,node2=~0; |
299 | |
300 | for(i=0;i<segments->number;i++) |
301 | { |
302 | Segment *segment=&segments->segments->segments[i]; |
303 | |
304 | if(segment->node1==node1 && segment->node2==node2) |
305 | { |
306 | duplicate++; |
307 | segment->node1=~0; |
308 | } |
309 | else if(segment->node1==segment->node2) |
310 | { |
311 | loop++; |
312 | segment->node1=~0; |
313 | } |
314 | |
315 | node1=segment->node1; |
316 | node2=segment->node2; |
317 | |
318 | if(!((i+1)%10000)) |
319 | { |
320 | printf("\rChecking: Segments=%d Duplicate=%d Loop=%d",i+1,duplicate,loop); |
321 | fflush(stdout); |
322 | } |
323 | } |
324 | |
325 | printf("\rChecked: Segments=%d Duplicate=%d Loop=%d \n",segments->number,duplicate,loop); |
326 | fflush(stdout); |
327 | } |
328 | |
329 | |
330 | /*++++++++++++++++++++++++++++++++++++++ |
331 | Assign the lengths and durations to all of the segments. |
332 | |
333 | SegmentsMem* segments The set of segments to process. |
334 | |
335 | Nodes *nodes The list of nodes to use. |
336 | |
337 | Ways *ways The list of ways to use. |
338 | ++++++++++++++++++++++++++++++++++++++*/ |
339 | |
340 | void FixupSegmentLengths(SegmentsMem* segments,Nodes *nodes,Ways *ways) |
341 | { |
342 | int i; |
343 | |
344 | assert(segments->sorted); /* Must be sorted */ |
345 | |
346 | for(i=0;i<segments->number;i++) |
347 | { |
348 | Node *node1=FindNode(nodes,segments->segments->segments[i].node1); |
349 | Node *node2=FindNode(nodes,segments->segments->segments[i].node2); |
350 | |
351 | /* Set the distance but preserve the INVALID_DISTANCE flag */ |
352 | |
353 | segments->segments->segments[i].distance|=Distance(node1,node2); |
354 | |
355 | if(!((i+1)%10000)) |
356 | { |
357 | printf("\rMeasuring Segments: Segments=%d",i+1); |
358 | fflush(stdout); |
359 | } |
360 | } |
361 | |
362 | printf("\rMeasured Segments: Segments=%d \n",segments->number); |
363 | fflush(stdout); |
364 | } |
365 | |
366 | |
367 | /*++++++++++++++++++++++++++++++++++++++ |
368 | Calculate the distance between two nodes. |
369 | |
370 | distance_t Distance Returns the distance between the nodes. |
371 | |
372 | Node *node1 The starting node. |
373 | |
374 | Node *node2 The end node. |
375 | ++++++++++++++++++++++++++++++++++++++*/ |
376 | |
377 | distance_t Distance(Node *node1,Node *node2) |
378 | { |
379 | double radiant = M_PI / 180; |
380 | |
381 | double dlon = radiant * (node1->longitude - node2->longitude); |
382 | double dlat = radiant * (node1->latitude - node2->latitude); |
383 | |
384 | double a1,a2,a,sa,c,d; |
385 | |
386 | if(dlon==0 && dlat==0) |
387 | return 0; |
388 | |
389 | a1 = sin (dlat / 2); |
390 | a2 = sin (dlon / 2); |
391 | a = (a1 * a1) + cos (node1->latitude * radiant) * cos (node2->latitude * radiant) * a2 * a2; |
392 | sa = sqrt (a); |
393 | if (sa <= 1.0) |
394 | {c = 2 * asin (sa);} |
395 | else |
396 | {c = 2 * asin (1.0);} |
397 | d = 6378.137 * c; |
398 | |
399 | return km_to_distance(d); |
400 | } |
401 | |
402 | |
403 | /*++++++++++++++++++++++++++++++++++++++ |
404 | Calculate the duration of segment. |
405 | |
406 | duration_t Duration Returns the duration of travel between the nodes. |
407 | |
408 | Segment *segment The segment to traverse. |
409 | |
410 | Way *way The way that the segment belongs to. |
411 | |
412 | Transport transport The type of transport being used. |
413 | ++++++++++++++++++++++++++++++++++++++*/ |
414 | |
415 | duration_t Duration(Segment *segment,Way *way,Transport transport) |
416 | { |
417 | speed_t speed=WaySpeed(way); |
418 | distance_t distance=segment->distance; |
419 | |
420 | if(transport==Transport_Foot) |
421 | speed=5; |
422 | else if(transport==Transport_Horse) |
423 | speed=8; |
424 | else if(transport==Transport_Bicycle) |
425 | speed=20; |
426 | |
427 | return hours_to_duration(distance_to_km(distance)/speed); |
428 | } |
Properties
Name | Value |
---|---|
cvs:description | Segment data type. |