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 96 -
(show annotations)
(download)
(as text)
Sat Jan 31 15:32:42 2009 UTC (16 years, 1 month ago) by amb
File MIME type: text/x-csrc
File size: 15272 byte(s)
Sat Jan 31 15:32:42 2009 UTC (16 years, 1 month ago) by amb
File MIME type: text/x-csrc
File size: 15272 byte(s)
Intermediate version during code cleanup.
1 | /*************************************** |
2 | $Header: /home/amb/CVS/routino/src/segments.c,v 1.25 2009-01-31 15:32:42 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 <unistd.h> |
17 | #include <math.h> |
18 | #include <stdlib.h> |
19 | |
20 | #include "nodes.h" |
21 | #include "segments.h" |
22 | #include "functions.h" |
23 | |
24 | |
25 | /* Constants */ |
26 | |
27 | /*+ The array size increment for segments - expect ~8,000,000 segments. +*/ |
28 | #define INCREMENT_SEGMENTS 1024*1024 |
29 | |
30 | |
31 | /* Functions */ |
32 | |
33 | static int sort_by_id(SegmentEx *a,SegmentEx *b); |
34 | |
35 | |
36 | /*++++++++++++++++++++++++++++++++++++++ |
37 | Allocate a new segment list. |
38 | |
39 | SegmentsMem *NewSegmentList Returns the segment list. |
40 | ++++++++++++++++++++++++++++++++++++++*/ |
41 | |
42 | SegmentsMem *NewSegmentList(void) |
43 | { |
44 | SegmentsMem *segmentsmem; |
45 | |
46 | segmentsmem=(SegmentsMem*)malloc(sizeof(SegmentsMem)); |
47 | |
48 | segmentsmem->sorted=0; |
49 | segmentsmem->alloced=INCREMENT_SEGMENTS; |
50 | segmentsmem->number=0; |
51 | |
52 | segmentsmem->xdata=(SegmentEx*)malloc(segmentsmem->alloced*sizeof(SegmentEx)); |
53 | |
54 | return(segmentsmem); |
55 | } |
56 | |
57 | |
58 | /*++++++++++++++++++++++++++++++++++++++ |
59 | Free a segment list. |
60 | |
61 | SegmentsMem *segmentsmem The list to be freed. |
62 | ++++++++++++++++++++++++++++++++++++++*/ |
63 | |
64 | void FreeSegmentList(SegmentsMem *segmentsmem) |
65 | { |
66 | free(segmentsmem->xdata); |
67 | free(segmentsmem); |
68 | } |
69 | |
70 | |
71 | /*++++++++++++++++++++++++++++++++++++++ |
72 | Load in a segment list from a file. |
73 | |
74 | Segments* SaveSegmentList Returns the segment list that has just been loaded. |
75 | |
76 | const char *filename The name of the file to load. |
77 | ++++++++++++++++++++++++++++++++++++++*/ |
78 | |
79 | Segments *LoadSegmentList(const char *filename) |
80 | { |
81 | void *data; |
82 | Segments *segments; |
83 | |
84 | segments=(Segments*)malloc(sizeof(Segments)); |
85 | |
86 | data=MapFile(filename); |
87 | |
88 | /* Copy the Segments structure from the loaded data */ |
89 | |
90 | *segments=*((Segments*)data); |
91 | |
92 | /* Adjust the pointers in the Segments structure. */ |
93 | |
94 | segments->data =data; |
95 | segments->segments=(Segment*)(data+(off_t)segments->segments); |
96 | |
97 | return(segments); |
98 | } |
99 | |
100 | |
101 | /*++++++++++++++++++++++++++++++++++++++ |
102 | Save the segment list to a file. |
103 | |
104 | SegmentsMem* segmentsmem The set of segments to save. |
105 | |
106 | const char *filename The name of the file to save. |
107 | ++++++++++++++++++++++++++++++++++++++*/ |
108 | |
109 | void SaveSegmentList(SegmentsMem* segmentsmem,const char *filename) |
110 | { |
111 | int i; |
112 | int fd; |
113 | Segments *segments=calloc(1,sizeof(Segments)); |
114 | |
115 | assert(segmentsmem->sorted); /* Must be sorted */ |
116 | |
117 | /* Fill in a Segments structure with the offset of the real data in the file after |
118 | the Segment structure itself. */ |
119 | |
120 | segments->number=segmentsmem->number; |
121 | segments->data=NULL; |
122 | segments->segments=(void*)sizeof(Segments); |
123 | |
124 | /* Write out the Segments structure and then the real data. */ |
125 | |
126 | fd=OpenFile(filename); |
127 | |
128 | write(fd,segments,sizeof(Segments)); |
129 | |
130 | for(i=0;i<segmentsmem->number;i++) |
131 | write(fd,&segmentsmem->xdata[i].segment,sizeof(Segment)); |
132 | |
133 | close(fd); |
134 | |
135 | /* Free the fake Segments */ |
136 | |
137 | free(segments); |
138 | } |
139 | |
140 | |
141 | /*++++++++++++++++++++++++++++++++++++++ |
142 | Find the first segment with a particular starting node. |
143 | |
144 | SegmentEx *FindFirstSegment Returns the first extended segment with the specified id. |
145 | |
146 | SegmentsMem* segmentsmem The set of segments to process. |
147 | |
148 | node_t node The node to look for. |
149 | ++++++++++++++++++++++++++++++++++++++*/ |
150 | |
151 | SegmentEx *FindFirstSegment(SegmentsMem* segmentsmem,node_t node) |
152 | { |
153 | int start=0; |
154 | int end=segmentsmem->number-1; |
155 | int mid; |
156 | int found; |
157 | |
158 | /* Binary search - search key exact match only is required. |
159 | * |
160 | * # <- start | Check mid and move start or end if it doesn't match |
161 | * # | |
162 | * # | Since an exact match is wanted we can set end=mid-1 |
163 | * # <- mid | or start=mid+1 because we know that mid doesn't match. |
164 | * # | |
165 | * # | Eventually either end=start or end=start+1 and one of |
166 | * # <- end | start or end is the wanted one. |
167 | */ |
168 | |
169 | if(end<start) /* There are no nodes */ |
170 | return(NULL); |
171 | else if(node<segmentsmem->xdata[start].node1) /* Check key is not before start */ |
172 | return(NULL); |
173 | else if(node>segmentsmem->xdata[end].node1) /* Check key is not after end */ |
174 | return(NULL); |
175 | else |
176 | { |
177 | do |
178 | { |
179 | mid=(start+end)/2; /* Choose mid point */ |
180 | |
181 | if(segmentsmem->xdata[mid].node1<node) /* Mid point is too low */ |
182 | start=mid; |
183 | else if(segmentsmem->xdata[mid].node1>node) /* Mid point is too high */ |
184 | end=mid; |
185 | else /* Mid point is correct */ |
186 | {found=mid; goto found;} |
187 | } |
188 | while((end-start)>1); |
189 | |
190 | if(segmentsmem->xdata[start].node1==node) /* Start is correct */ |
191 | {found=start; goto found;} |
192 | |
193 | if(segmentsmem->xdata[end].node1==node) /* End is correct */ |
194 | {found=end; goto found;} |
195 | } |
196 | |
197 | return(NULL); |
198 | |
199 | found: |
200 | |
201 | while(found>0 && segmentsmem->xdata[found-1].node1==node) |
202 | found--; |
203 | |
204 | return(&segmentsmem->xdata[found]); |
205 | } |
206 | |
207 | |
208 | /*++++++++++++++++++++++++++++++++++++++ |
209 | Find the next segment with a particular starting node. |
210 | |
211 | SegmentEx *NextSegment Returns a pointer to the next segment with the same id. |
212 | |
213 | SegmentsMem* segments The set of segments to process. |
214 | |
215 | SegmentEx *segmentex The current segment. |
216 | ++++++++++++++++++++++++++++++++++++++*/ |
217 | |
218 | SegmentEx *FindNextSegment(SegmentsMem* segmentsmem,SegmentEx *segmentex) |
219 | { |
220 | SegmentEx *next=segmentex+1; |
221 | |
222 | if(IndexSegmentEx(segmentsmem,next)==segmentsmem->number) |
223 | return(NULL); |
224 | |
225 | if(next->node1==segmentex->node1) |
226 | return(next); |
227 | |
228 | return(NULL); |
229 | } |
230 | |
231 | |
232 | /*++++++++++++++++++++++++++++++++++++++ |
233 | Find the next segment with a particular starting node. |
234 | |
235 | Segment *NextSegment Returns a pointer to the next segment with the same id. |
236 | |
237 | Segments* segments The set of segments to process. |
238 | |
239 | Segment *segment The current segment. |
240 | ++++++++++++++++++++++++++++++++++++++*/ |
241 | |
242 | Segment *NextSegment(Segments* segments,Segment *segment) |
243 | { |
244 | Segment *next=segment+1; |
245 | |
246 | if(IndexSegment(segments,next)==segments->number) |
247 | return(NULL); |
248 | |
249 | if(NODE(next->node1)==NODE(segment->node1)) |
250 | return(next); |
251 | |
252 | return(NULL); |
253 | } |
254 | |
255 | |
256 | /*++++++++++++++++++++++++++++++++++++++ |
257 | Append a segment to a newly created segment list (unsorted). |
258 | |
259 | SegmentEx *AppendSegment Returns the appended segment. |
260 | |
261 | SegmentsMem* segmentsmem The set of segments to process. |
262 | |
263 | node_t node1 The first node in the segment. |
264 | |
265 | node_t node2 The second node in the segment. |
266 | |
267 | index_t way The index of the way that the pair of segments are connected by. |
268 | ++++++++++++++++++++++++++++++++++++++*/ |
269 | |
270 | SegmentEx *AppendSegment(SegmentsMem* segmentsmem,node_t node1,node_t node2,index_t way) |
271 | { |
272 | /* Check that the array has enough space. */ |
273 | |
274 | if(segmentsmem->number==segmentsmem->alloced) |
275 | { |
276 | segmentsmem->alloced+=INCREMENT_SEGMENTS; |
277 | |
278 | segmentsmem->xdata=(SegmentEx*)realloc((void*)segmentsmem->xdata,segmentsmem->alloced*sizeof(SegmentEx)); |
279 | } |
280 | |
281 | /* Insert the segment */ |
282 | |
283 | segmentsmem->xdata[segmentsmem->number].node1=node1; |
284 | segmentsmem->xdata[segmentsmem->number].node2=node2; |
285 | segmentsmem->xdata[segmentsmem->number].segment.way=way; |
286 | segmentsmem->xdata[segmentsmem->number].segment.distance=0; |
287 | |
288 | segmentsmem->number++; |
289 | |
290 | segmentsmem->sorted=0; |
291 | |
292 | return(&segmentsmem->xdata[segmentsmem->number-1]); |
293 | } |
294 | |
295 | |
296 | /*++++++++++++++++++++++++++++++++++++++ |
297 | Sort the segment list. |
298 | |
299 | SegmentsMem* segmentsmem The set of segments to process. |
300 | ++++++++++++++++++++++++++++++++++++++*/ |
301 | |
302 | void SortSegmentList(SegmentsMem* segmentsmem) |
303 | { |
304 | qsort(segmentsmem->xdata,segmentsmem->number,sizeof(SegmentEx),(int (*)(const void*,const void*))sort_by_id); |
305 | |
306 | while(segmentsmem->xdata[segmentsmem->number-1].node1==~0) |
307 | segmentsmem->number--; |
308 | |
309 | segmentsmem->sorted=1; |
310 | } |
311 | |
312 | |
313 | /*++++++++++++++++++++++++++++++++++++++ |
314 | Sort the segments into id order. |
315 | |
316 | int sort_by_id Returns the comparison of the node fields. |
317 | |
318 | SegmentEx *a The first Segment. |
319 | |
320 | SegmentEx *b The second Segment. |
321 | ++++++++++++++++++++++++++++++++++++++*/ |
322 | |
323 | static int sort_by_id(SegmentEx *a,SegmentEx *b) |
324 | { |
325 | node_t a_id1=a->node1,a_id2=a->node2; |
326 | node_t b_id1=b->node1,b_id2=b->node2; |
327 | |
328 | if(a_id1<b_id1) |
329 | return(-1); |
330 | else if(a_id1>b_id1) |
331 | return(1); |
332 | else /* if(a_id1==b_id1) */ |
333 | { |
334 | if(a_id2<b_id2) |
335 | return(-1); |
336 | else |
337 | return(1); |
338 | } |
339 | } |
340 | |
341 | |
342 | /*++++++++++++++++++++++++++++++++++++++ |
343 | Remove bad segments (zero length or duplicated). |
344 | |
345 | SegmentsMem *segmentsmem The segments to modify. |
346 | ++++++++++++++++++++++++++++++++++++++*/ |
347 | |
348 | void RemoveBadSegments(SegmentsMem *segmentsmem) |
349 | { |
350 | int i; |
351 | int duplicate=0,loop=0; |
352 | node_t node1=~0,node2=~0; |
353 | |
354 | for(i=0;i<segmentsmem->number;i++) |
355 | { |
356 | if(segmentsmem->xdata[i].node1==node1 && segmentsmem->xdata[i].node2==node2) |
357 | { |
358 | duplicate++; |
359 | segmentsmem->xdata[i].node1=~0; |
360 | } |
361 | else if(segmentsmem->xdata[i].node1==segmentsmem->xdata[i].node2) |
362 | { |
363 | loop++; |
364 | segmentsmem->xdata[i].node1=~0; |
365 | } |
366 | |
367 | node1=segmentsmem->xdata[i].node1; |
368 | node2=segmentsmem->xdata[i].node2; |
369 | |
370 | if(!((i+1)%10000)) |
371 | { |
372 | printf("\rChecking: Segments=%d Duplicate=%d Loop=%d",i+1,duplicate,loop); |
373 | fflush(stdout); |
374 | } |
375 | } |
376 | |
377 | printf("\rChecked: Segments=%d Duplicate=%d Loop=%d \n",segmentsmem->number,duplicate,loop); |
378 | fflush(stdout); |
379 | } |
380 | |
381 | |
382 | /*++++++++++++++++++++++++++++++++++++++ |
383 | Measure the segments. |
384 | |
385 | SegmentsMem* segmentsmem The set of segments to process. |
386 | |
387 | NodesMem *nodesmem The list of nodes to use. |
388 | ++++++++++++++++++++++++++++++++++++++*/ |
389 | |
390 | void MeasureSegments(SegmentsMem* segmentsmem,NodesMem *nodesmem) |
391 | { |
392 | int i; |
393 | |
394 | assert(segmentsmem->sorted); /* Must be sorted */ |
395 | |
396 | for(i=0;i<segmentsmem->number;i++) |
397 | { |
398 | NodeEx *node1=FindNode(nodesmem,segmentsmem->xdata[i].node1); |
399 | NodeEx *node2=FindNode(nodesmem,segmentsmem->xdata[i].node2); |
400 | |
401 | /* Set the distance but preserve the ONEWAY_OPPOSITE flag */ |
402 | |
403 | segmentsmem->xdata[i].segment.distance|=Distance(&node1->node,&node2->node); |
404 | |
405 | if(!((i+1)%10000)) |
406 | { |
407 | printf("\rMeasuring Segments: Segments=%d",i+1); |
408 | fflush(stdout); |
409 | } |
410 | } |
411 | |
412 | printf("\rMeasured Segments: Segments=%d \n",segmentsmem->number); |
413 | fflush(stdout); |
414 | } |
415 | |
416 | |
417 | /*++++++++++++++++++++++++++++++++++++++ |
418 | Fix the segment indexes to the nodes. |
419 | |
420 | SegmentsMem* segmentsmem The set of segments to process. |
421 | |
422 | NodesMem *nodesmem The list of nodes to use. |
423 | |
424 | SegmentsMem* supersegmentsmem The set of super-segments to append. |
425 | ++++++++++++++++++++++++++++++++++++++*/ |
426 | |
427 | void FixupSegments(SegmentsMem* segmentsmem,NodesMem *nodesmem,SegmentsMem* supersegmentsmem) |
428 | { |
429 | int i,j,n; |
430 | |
431 | assert(segmentsmem->sorted); /* Must be sorted */ |
432 | assert(supersegmentsmem->sorted); /* Must be sorted */ |
433 | |
434 | for(i=0;i<segmentsmem->number;i++) |
435 | { |
436 | NodeEx *node1=FindNode(nodesmem,segmentsmem->xdata[i].node1); |
437 | NodeEx *node2=FindNode(nodesmem,segmentsmem->xdata[i].node2); |
438 | |
439 | segmentsmem->xdata[i].segment.node1=IndexNodeEx(nodesmem,node1)|SUPER_FLAG; |
440 | segmentsmem->xdata[i].segment.node2=IndexNodeEx(nodesmem,node2); |
441 | |
442 | if(!((i+1)%10000)) |
443 | { |
444 | printf("\rFixing Segments: Segments=%d",i+1); |
445 | fflush(stdout); |
446 | } |
447 | } |
448 | |
449 | printf("\rFixed Segments: Segments=%d \n",segmentsmem->number); |
450 | fflush(stdout); |
451 | |
452 | for(i=0;i<supersegmentsmem->number;i++) |
453 | { |
454 | NodeEx *node1=FindNode(nodesmem,supersegmentsmem->xdata[i].node1); |
455 | NodeEx *node2=FindNode(nodesmem,supersegmentsmem->xdata[i].node2); |
456 | |
457 | supersegmentsmem->xdata[i].segment.node1=IndexNodeEx(nodesmem,node1); |
458 | supersegmentsmem->xdata[i].segment.node2=IndexNodeEx(nodesmem,node2)|SUPER_FLAG; |
459 | |
460 | if(!((i+1)%10000)) |
461 | { |
462 | printf("\rFixing Super-Segments: Super-Segments=%d",i+1); |
463 | fflush(stdout); |
464 | } |
465 | } |
466 | |
467 | printf("\rFixed Super-Segments: Super-Segments=%d \n",supersegmentsmem->number); |
468 | fflush(stdout); |
469 | |
470 | n=segmentsmem->number; |
471 | |
472 | for(i=0,j=0;i<n;i++) |
473 | { |
474 | while(j<supersegmentsmem->number) |
475 | { |
476 | if(segmentsmem->xdata[i].node1==supersegmentsmem->xdata[j].node1 && |
477 | segmentsmem->xdata[i].node2==supersegmentsmem->xdata[j].node2) |
478 | { |
479 | segmentsmem->xdata[i].segment.node2|=SUPER_FLAG; |
480 | j++; |
481 | break; |
482 | } |
483 | else if(segmentsmem->xdata[i].node1==supersegmentsmem->xdata[j].node1 && |
484 | segmentsmem->xdata[i].node2>supersegmentsmem->xdata[j].node2) |
485 | { |
486 | SegmentEx *supersegmentex=AppendSegment(segmentsmem,supersegmentsmem->xdata[j].node1,supersegmentsmem->xdata[j].node2,supersegmentsmem->xdata[j].segment.way); |
487 | |
488 | supersegmentex->segment.node1=supersegmentsmem->xdata[j].segment.node1; |
489 | supersegmentex->segment.node2=supersegmentsmem->xdata[j].segment.node2; |
490 | supersegmentex->segment.distance=supersegmentsmem->xdata[j].segment.distance; |
491 | } |
492 | else if(segmentsmem->xdata[i].node1>supersegmentsmem->xdata[j].node1) |
493 | { |
494 | SegmentEx *supersegmentex=AppendSegment(segmentsmem,supersegmentsmem->xdata[j].node1,supersegmentsmem->xdata[j].node2,supersegmentsmem->xdata[j].segment.way); |
495 | |
496 | supersegmentex->segment.node1=supersegmentsmem->xdata[j].segment.node1; |
497 | supersegmentex->segment.node2=supersegmentsmem->xdata[j].segment.node2; |
498 | supersegmentex->segment.distance=supersegmentsmem->xdata[j].segment.distance; |
499 | } |
500 | else |
501 | break; |
502 | |
503 | j++; |
504 | } |
505 | |
506 | if(!((i+1)%10000)) |
507 | { |
508 | printf("\rMerging Segments: Segments=%d Super-Segment=%d Total=%d",i+1,j+1,segmentsmem->number); |
509 | fflush(stdout); |
510 | } |
511 | } |
512 | |
513 | printf("\rMerged Segments: Segments=%d Super-Segment=%d Total=%d \n",n,supersegmentsmem->number,segmentsmem->number); |
514 | fflush(stdout); |
515 | } |
516 | |
517 | |
518 | /*++++++++++++++++++++++++++++++++++++++ |
519 | Calculate the distance between two nodes. |
520 | |
521 | distance_t Distance Returns the distance between the nodes. |
522 | |
523 | Node *node1 The starting node. |
524 | |
525 | Node *node2 The end node. |
526 | ++++++++++++++++++++++++++++++++++++++*/ |
527 | |
528 | distance_t Distance(Node *node1,Node *node2) |
529 | { |
530 | double radiant = M_PI / 180; |
531 | |
532 | double dlon = radiant * (node1->longitude - node2->longitude); |
533 | double dlat = radiant * (node1->latitude - node2->latitude); |
534 | |
535 | double a1,a2,a,sa,c,d; |
536 | |
537 | if(dlon==0 && dlat==0) |
538 | return 0; |
539 | |
540 | a1 = sin (dlat / 2); |
541 | a2 = sin (dlon / 2); |
542 | a = (a1 * a1) + cos (node1->latitude * radiant) * cos (node2->latitude * radiant) * a2 * a2; |
543 | sa = sqrt (a); |
544 | if (sa <= 1.0) |
545 | {c = 2 * asin (sa);} |
546 | else |
547 | {c = 2 * asin (1.0);} |
548 | d = 6378.137 * c; |
549 | |
550 | return km_to_distance(d); |
551 | } |
552 | |
553 | |
554 | /*++++++++++++++++++++++++++++++++++++++ |
555 | Calculate the duration of segment. |
556 | |
557 | duration_t Duration Returns the duration of travel between the nodes. |
558 | |
559 | Segment *segment The segment to traverse. |
560 | |
561 | Way *way The way that the segment belongs to. |
562 | |
563 | Profile *profile The profile of the transport being used. |
564 | ++++++++++++++++++++++++++++++++++++++*/ |
565 | |
566 | duration_t Duration(Segment *segment,Way *way,Profile *profile) |
567 | { |
568 | speed_t speed=profile->speed[HIGHWAY(way->type)]; |
569 | distance_t distance=DISTANCE(segment->distance); |
570 | |
571 | return distance_speed_to_duration(distance,speed); |
572 | } |
Properties
Name | Value |
---|---|
cvs:description | Segment data type. |