Check out the latest version of Routino: svn co http://routino.org/svn/trunk routino
Contents of /trunk/src/segmentsx.c
Parent Directory
|
Revision Log
Revision 195 -
(show annotations)
(download)
(as text)
Sat Jun 13 13:02:12 2009 UTC (15 years, 9 months ago) by amb
File MIME type: text/x-csrc
File size: 15443 byte(s)
Sat Jun 13 13:02:12 2009 UTC (15 years, 9 months ago) by amb
File MIME type: text/x-csrc
File size: 15443 byte(s)
Handle nodes that are missing from the .osm file (ignore the segment).
1 | /*************************************** |
2 | $Header: /home/amb/CVS/routino/src/segmentsx.c,v 1.9 2009-06-13 13:02:12 amb Exp $ |
3 | |
4 | Extended Segment data type functions. |
5 | |
6 | Part of the Routino routing software. |
7 | ******************/ /****************** |
8 | This file Copyright 2008,2009 Andrew M. Bishop |
9 | |
10 | This program is free software: you can redistribute it and/or modify |
11 | it under the terms of the GNU Affero General Public License as published by |
12 | the Free Software Foundation, either version 3 of the License, or |
13 | (at your option) any later version. |
14 | |
15 | This program is distributed in the hope that it will be useful, |
16 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
18 | GNU Affero General Public License for more details. |
19 | |
20 | You should have received a copy of the GNU Affero General Public License |
21 | along with this program. If not, see <http://www.gnu.org/licenses/>. |
22 | ***************************************/ |
23 | |
24 | |
25 | #include <assert.h> |
26 | #include <math.h> |
27 | #include <string.h> |
28 | #include <stdlib.h> |
29 | #include <stdio.h> |
30 | |
31 | #include "types.h" |
32 | #include "functions.h" |
33 | #include "nodesx.h" |
34 | #include "segmentsx.h" |
35 | #include "waysx.h" |
36 | |
37 | |
38 | /* Constants */ |
39 | |
40 | /*+ The array size increment for segments - expect ~8,000,000 segments. +*/ |
41 | #define INCREMENT_SEGMENTS 1024*1024 |
42 | |
43 | |
44 | /* Functions */ |
45 | |
46 | static int sort_by_id(SegmentX **a,SegmentX **b); |
47 | |
48 | |
49 | /*++++++++++++++++++++++++++++++++++++++ |
50 | Allocate a new segment list. |
51 | |
52 | SegmentsX *NewSegmentList Returns the segment list. |
53 | ++++++++++++++++++++++++++++++++++++++*/ |
54 | |
55 | SegmentsX *NewSegmentList(void) |
56 | { |
57 | SegmentsX *segmentsx; |
58 | |
59 | segmentsx=(SegmentsX*)malloc(sizeof(SegmentsX)); |
60 | |
61 | segmentsx->sorted=0; |
62 | segmentsx->alloced=INCREMENT_SEGMENTS; |
63 | segmentsx->xnumber=0; |
64 | |
65 | segmentsx->xdata=(SegmentX*)malloc(segmentsx->alloced*sizeof(SegmentX)); |
66 | segmentsx->sdata=NULL; |
67 | |
68 | return(segmentsx); |
69 | } |
70 | |
71 | |
72 | /*++++++++++++++++++++++++++++++++++++++ |
73 | Free a segment list. |
74 | |
75 | SegmentsX *segmentsx The list to be freed. |
76 | ++++++++++++++++++++++++++++++++++++++*/ |
77 | |
78 | void FreeSegmentList(SegmentsX *segmentsx) |
79 | { |
80 | free(segmentsx->xdata); |
81 | free(segmentsx->sdata); |
82 | free(segmentsx); |
83 | } |
84 | |
85 | |
86 | /*++++++++++++++++++++++++++++++++++++++ |
87 | Save the segment list to a file. |
88 | |
89 | SegmentsX* segmentsx The set of segments to save. |
90 | |
91 | const char *filename The name of the file to save. |
92 | ++++++++++++++++++++++++++++++++++++++*/ |
93 | |
94 | void SaveSegmentList(SegmentsX* segmentsx,const char *filename) |
95 | { |
96 | int i; |
97 | int fd; |
98 | Segments *segments=calloc(1,sizeof(Segments)); |
99 | |
100 | assert(segmentsx->sorted); /* Must be sorted */ |
101 | |
102 | /* Fill in a Segments structure with the offset of the real data in the file after |
103 | the Segment structure itself. */ |
104 | |
105 | segments->number=segmentsx->number; |
106 | segments->data=NULL; |
107 | segments->segments=(void*)sizeof(Segments); |
108 | |
109 | /* Write out the Segments structure and then the real data. */ |
110 | |
111 | fd=OpenFile(filename); |
112 | |
113 | WriteFile(fd,segments,sizeof(Segments)); |
114 | |
115 | for(i=0;i<segmentsx->number;i++) |
116 | { |
117 | WriteFile(fd,&segmentsx->sdata[i]->segment,sizeof(Segment)); |
118 | |
119 | if(!((i+1)%10000)) |
120 | { |
121 | printf("\rWriting Segments: Segments=%d",i+1); |
122 | fflush(stdout); |
123 | } |
124 | } |
125 | |
126 | printf("\rWrote Segments: Segments=%d \n",segmentsx->number); |
127 | fflush(stdout); |
128 | |
129 | CloseFile(fd); |
130 | |
131 | /* Free the fake Segments */ |
132 | |
133 | free(segments); |
134 | } |
135 | |
136 | |
137 | /*++++++++++++++++++++++++++++++++++++++ |
138 | Find the first segment with a particular starting node. |
139 | |
140 | SegmentX **FindFirstSegmentX Returns a pointer to the first extended segment with the specified id. |
141 | |
142 | SegmentsX* segmentsx The set of segments to process. |
143 | |
144 | node_t node The node to look for. |
145 | ++++++++++++++++++++++++++++++++++++++*/ |
146 | |
147 | SegmentX **FindFirstSegmentX(SegmentsX* segmentsx,node_t node) |
148 | { |
149 | int start=0; |
150 | int end=segmentsx->number-1; |
151 | int mid; |
152 | int found; |
153 | |
154 | assert(segmentsx->sorted); /* Must be sorted */ |
155 | |
156 | /* Binary search - search key exact match only is required. |
157 | * |
158 | * # <- start | Check mid and move start or end if it doesn't match |
159 | * # | |
160 | * # | Since an exact match is wanted we can set end=mid-1 |
161 | * # <- mid | or start=mid+1 because we know that mid doesn't match. |
162 | * # | |
163 | * # | Eventually either end=start or end=start+1 and one of |
164 | * # <- end | start or end is the wanted one. |
165 | */ |
166 | |
167 | if(end<start) /* There are no nodes */ |
168 | return(NULL); |
169 | else if(node<segmentsx->sdata[start]->node1) /* Check key is not before start */ |
170 | return(NULL); |
171 | else if(node>segmentsx->sdata[end]->node1) /* Check key is not after end */ |
172 | return(NULL); |
173 | else |
174 | { |
175 | do |
176 | { |
177 | mid=(start+end)/2; /* Choose mid point */ |
178 | |
179 | if(segmentsx->sdata[mid]->node1<node) /* Mid point is too low */ |
180 | start=mid; |
181 | else if(segmentsx->sdata[mid]->node1>node) /* Mid point is too high */ |
182 | end=mid; |
183 | else /* Mid point is correct */ |
184 | {found=mid; goto found;} |
185 | } |
186 | while((end-start)>1); |
187 | |
188 | if(segmentsx->sdata[start]->node1==node) /* Start is correct */ |
189 | {found=start; goto found;} |
190 | |
191 | if(segmentsx->sdata[end]->node1==node) /* End is correct */ |
192 | {found=end; goto found;} |
193 | } |
194 | |
195 | return(NULL); |
196 | |
197 | found: |
198 | |
199 | while(found>0 && segmentsx->sdata[found-1]->node1==node) |
200 | found--; |
201 | |
202 | return(&segmentsx->sdata[found]); |
203 | } |
204 | |
205 | |
206 | /*++++++++++++++++++++++++++++++++++++++ |
207 | Find the next segment with a particular starting node. |
208 | |
209 | SegmentX **FindNextSegmentX Returns a pointer to the next segment with the same id. |
210 | |
211 | SegmentsX* segmentsx The set of segments to process. |
212 | |
213 | SegmentX **segmentx The current segment. |
214 | ++++++++++++++++++++++++++++++++++++++*/ |
215 | |
216 | SegmentX **FindNextSegmentX(SegmentsX* segmentsx,SegmentX **segmentx) |
217 | { |
218 | SegmentX **next=segmentx+1; |
219 | |
220 | if((next-segmentsx->sdata)==segmentsx->number) |
221 | return(NULL); |
222 | |
223 | if((*next)->node1==(*segmentx)->node1) |
224 | return(next); |
225 | |
226 | return(NULL); |
227 | } |
228 | |
229 | |
230 | /*++++++++++++++++++++++++++++++++++++++ |
231 | Append a segment to a segment list. |
232 | |
233 | Segment *AppendSegment Returns the appended segment. |
234 | |
235 | SegmentsX* segmentsx The set of segments to process. |
236 | |
237 | node_t node1 The first node in the segment. |
238 | |
239 | node_t node2 The second node in the segment. |
240 | ++++++++++++++++++++++++++++++++++++++*/ |
241 | |
242 | Segment *AppendSegment(SegmentsX* segmentsx,node_t node1,node_t node2) |
243 | { |
244 | /* Check that the array has enough space. */ |
245 | |
246 | if(segmentsx->xnumber==segmentsx->alloced) |
247 | { |
248 | segmentsx->alloced+=INCREMENT_SEGMENTS; |
249 | |
250 | segmentsx->xdata=(SegmentX*)realloc((void*)segmentsx->xdata,segmentsx->alloced*sizeof(SegmentX)); |
251 | } |
252 | |
253 | /* Insert the segment */ |
254 | |
255 | segmentsx->xdata[segmentsx->xnumber].node1=node1; |
256 | segmentsx->xdata[segmentsx->xnumber].node2=node2; |
257 | |
258 | memset(&segmentsx->xdata[segmentsx->xnumber].segment,0,sizeof(Segment)); |
259 | |
260 | segmentsx->xnumber++; |
261 | |
262 | segmentsx->sorted=0; |
263 | |
264 | return(&segmentsx->xdata[segmentsx->xnumber-1].segment); |
265 | } |
266 | |
267 | |
268 | /*++++++++++++++++++++++++++++++++++++++ |
269 | Sort the segment list. |
270 | |
271 | SegmentsX* segmentsx The set of segments to process. |
272 | ++++++++++++++++++++++++++++++++++++++*/ |
273 | |
274 | void SortSegmentList(SegmentsX* segmentsx) |
275 | { |
276 | int i; |
277 | |
278 | printf("Sorting Segments"); fflush(stdout); |
279 | |
280 | /* Allocate the arrays of pointers */ |
281 | |
282 | if(segmentsx->sorted) |
283 | segmentsx->sdata=realloc(segmentsx->sdata,segmentsx->xnumber*sizeof(SegmentX*)); |
284 | else |
285 | segmentsx->sdata=malloc(segmentsx->xnumber*sizeof(SegmentX*)); |
286 | |
287 | segmentsx->number=0; |
288 | |
289 | for(i=0;i<segmentsx->xnumber;i++) |
290 | if(segmentsx->xdata[i].node1!=NO_NODE) |
291 | { |
292 | segmentsx->sdata[segmentsx->number]=&segmentsx->xdata[i]; |
293 | segmentsx->number++; |
294 | } |
295 | |
296 | qsort(segmentsx->sdata,segmentsx->number,sizeof(SegmentX*),(int (*)(const void*,const void*))sort_by_id); |
297 | |
298 | segmentsx->sorted=1; |
299 | |
300 | printf("\rSorted Segments \n"); fflush(stdout); |
301 | } |
302 | |
303 | |
304 | /*++++++++++++++++++++++++++++++++++++++ |
305 | Sort the segments into id order. |
306 | |
307 | int sort_by_id Returns the comparison of the node fields. |
308 | |
309 | SegmentX **a The first Segment. |
310 | |
311 | SegmentX **b The second Segment. |
312 | ++++++++++++++++++++++++++++++++++++++*/ |
313 | |
314 | static int sort_by_id(SegmentX **a,SegmentX **b) |
315 | { |
316 | node_t a_id1=(*a)->node1; |
317 | node_t b_id1=(*b)->node1; |
318 | |
319 | if(a_id1<b_id1) |
320 | return(-1); |
321 | else if(a_id1>b_id1) |
322 | return(1); |
323 | else /* if(a_id1==b_id1) */ |
324 | { |
325 | node_t a_id2=(*a)->node2; |
326 | node_t b_id2=(*b)->node2; |
327 | |
328 | if(a_id2<b_id2) |
329 | return(-1); |
330 | else if(a_id2>b_id2) |
331 | return(1); |
332 | else |
333 | { |
334 | distance_t a_distance=(*a)->segment.distance; |
335 | distance_t b_distance=(*b)->segment.distance; |
336 | |
337 | if(a_distance<b_distance) |
338 | return(-1); |
339 | else if(a_distance>b_distance) |
340 | return(1); |
341 | else |
342 | return(0); |
343 | } |
344 | } |
345 | } |
346 | |
347 | |
348 | /*++++++++++++++++++++++++++++++++++++++ |
349 | Remove bad segments (zero length or duplicated). |
350 | |
351 | NodesX *nodesx The nodes to check. |
352 | |
353 | SegmentsX *segmentsx The segments to modify. |
354 | ++++++++++++++++++++++++++++++++++++++*/ |
355 | |
356 | void RemoveBadSegments(NodesX *nodesx,SegmentsX *segmentsx) |
357 | { |
358 | int i; |
359 | int duplicate=0,loop=0,missing=0; |
360 | |
361 | assert(segmentsx->sorted); /* Must be sorted */ |
362 | |
363 | for(i=0;i<segmentsx->number;i++) |
364 | { |
365 | if(i && segmentsx->sdata[i]->node1==segmentsx->sdata[i-1]->node1 && |
366 | segmentsx->sdata[i]->node2==segmentsx->sdata[i-1]->node2) |
367 | { |
368 | duplicate++; |
369 | segmentsx->sdata[i-1]->node1=NO_NODE; |
370 | } |
371 | else if(segmentsx->sdata[i]->node1==segmentsx->sdata[i]->node2) |
372 | { |
373 | loop++; |
374 | segmentsx->sdata[i]->node1=NO_NODE; |
375 | } |
376 | else if(!FindNodeX(nodesx,segmentsx->sdata[i]->node1) || |
377 | !FindNodeX(nodesx,segmentsx->sdata[i]->node2)) |
378 | { |
379 | missing++; |
380 | segmentsx->sdata[i]->node1=NO_NODE; |
381 | } |
382 | |
383 | if(!((i+1)%10000)) |
384 | { |
385 | printf("\rChecking: Segments=%d Duplicate=%d Loop=%d Missing-Node=%d",i+1,duplicate,loop,missing); |
386 | fflush(stdout); |
387 | } |
388 | } |
389 | |
390 | printf("\rChecked: Segments=%d Duplicate=%d Loop=%d Missing-Node=%d \n",segmentsx->number,duplicate,loop,missing); |
391 | fflush(stdout); |
392 | } |
393 | |
394 | |
395 | /*++++++++++++++++++++++++++++++++++++++ |
396 | Measure the segments. |
397 | |
398 | SegmentsX* segmentsx The set of segments to process. |
399 | |
400 | NodesX *nodesx The list of nodes to use. |
401 | ++++++++++++++++++++++++++++++++++++++*/ |
402 | |
403 | void MeasureSegments(SegmentsX* segmentsx,NodesX *nodesx) |
404 | { |
405 | int i; |
406 | |
407 | assert(segmentsx->sorted); /* Must be sorted */ |
408 | |
409 | for(i=0;i<segmentsx->number;i++) |
410 | { |
411 | NodeX *node1=FindNodeX(nodesx,segmentsx->sdata[i]->node1); |
412 | NodeX *node2=FindNodeX(nodesx,segmentsx->sdata[i]->node2); |
413 | |
414 | /* Set the distance but preserve the ONEWAY_* flags */ |
415 | |
416 | segmentsx->sdata[i]->segment.distance|=DistanceX(node1,node2); |
417 | |
418 | if(!((i+1)%10000)) |
419 | { |
420 | printf("\rMeasuring Segments: Segments=%d",i+1); |
421 | fflush(stdout); |
422 | } |
423 | } |
424 | |
425 | printf("\rMeasured Segments: Segments=%d \n",segmentsx->number); |
426 | fflush(stdout); |
427 | } |
428 | |
429 | |
430 | /*++++++++++++++++++++++++++++++++++++++ |
431 | Make the segments all point the same way (node1<node2). |
432 | |
433 | SegmentsX* segmentsx The set of segments to process. |
434 | |
435 | NodesX *nodesx The list of nodes to use. |
436 | ++++++++++++++++++++++++++++++++++++++*/ |
437 | |
438 | void RotateSegments(SegmentsX* segmentsx,NodesX *nodesx) |
439 | { |
440 | int i,rotated=0; |
441 | |
442 | assert(segmentsx->sorted); /* Must be sorted */ |
443 | |
444 | for(i=0;i<segmentsx->number;i++) |
445 | { |
446 | if(segmentsx->sdata[i]->node1>segmentsx->sdata[i]->node2) |
447 | { |
448 | segmentsx->sdata[i]->node1^=segmentsx->sdata[i]->node2; |
449 | segmentsx->sdata[i]->node2^=segmentsx->sdata[i]->node1; |
450 | segmentsx->sdata[i]->node1^=segmentsx->sdata[i]->node2; |
451 | |
452 | if(segmentsx->sdata[i]->segment.distance&(ONEWAY_2TO1|ONEWAY_1TO2)) |
453 | segmentsx->sdata[i]->segment.distance^=ONEWAY_2TO1|ONEWAY_1TO2; |
454 | |
455 | rotated++; |
456 | } |
457 | |
458 | if(!((i+1)%10000)) |
459 | { |
460 | printf("\rRotating Segments: Segments=%d Rotated=%d",i+1,rotated); |
461 | fflush(stdout); |
462 | } |
463 | } |
464 | |
465 | printf("\rRotated Segments: Segments=%d Rotated=%d \n",segmentsx->number,rotated); |
466 | fflush(stdout); |
467 | } |
468 | |
469 | |
470 | /*++++++++++++++++++++++++++++++++++++++ |
471 | Mark the duplicate segments. |
472 | |
473 | SegmentsX* segmentsx The set of segments to process. |
474 | |
475 | NodesX *nodesx The list of nodes to use. |
476 | |
477 | WaysX *waysx The list of ways to use. |
478 | ++++++++++++++++++++++++++++++++++++++*/ |
479 | |
480 | void DeduplicateSegments(SegmentsX* segmentsx,NodesX *nodesx,WaysX *waysx) |
481 | { |
482 | int i,duplicate=0; |
483 | |
484 | assert(segmentsx->sorted); /* Must be sorted */ |
485 | |
486 | for(i=1;i<segmentsx->number;i++) |
487 | { |
488 | if(segmentsx->sdata[i]->node1==segmentsx->sdata[i-1]->node1 && |
489 | segmentsx->sdata[i]->node2==segmentsx->sdata[i-1]->node2 && |
490 | segmentsx->sdata[i]->segment.node1==segmentsx->sdata[i-1]->segment.node1 && |
491 | segmentsx->sdata[i]->segment.node2==segmentsx->sdata[i-1]->segment.node2 && |
492 | segmentsx->sdata[i]->segment.distance==segmentsx->sdata[i-1]->segment.distance) |
493 | { |
494 | WayX *wayx1=LookupWayX(waysx,segmentsx->sdata[i-1]->segment.way); |
495 | WayX *wayx2=LookupWayX(waysx,segmentsx->sdata[i]->segment.way); |
496 | |
497 | if(wayx1==wayx2 || WaysSame(&wayx1->way,&wayx2->way)) |
498 | { |
499 | segmentsx->sdata[i-1]->node1=NO_NODE; |
500 | segmentsx->sdata[i-1]->node2=NO_NODE; |
501 | |
502 | duplicate++; |
503 | } |
504 | } |
505 | |
506 | if(!((i+1)%10000)) |
507 | { |
508 | printf("\rDeduplicating Segments: Segments=%d Duplicate=%d",i+1,duplicate); |
509 | fflush(stdout); |
510 | } |
511 | } |
512 | |
513 | printf("\rDeduplicated Segments: Segments=%d Duplicate=%d \n",segmentsx->number,duplicate); |
514 | fflush(stdout); |
515 | } |
516 | |
517 | |
518 | /*++++++++++++++++++++++++++++++++++++++ |
519 | Assign the nodes indexes to the segments. |
520 | |
521 | SegmentsX* segmentsx The set of segments to process. |
522 | |
523 | NodesX *nodesx The list of nodes to use. |
524 | ++++++++++++++++++++++++++++++++++++++*/ |
525 | |
526 | void IndexSegments(SegmentsX* segmentsx,NodesX *nodesx) |
527 | { |
528 | int i; |
529 | |
530 | assert(segmentsx->sorted); /* Must be sorted */ |
531 | assert(nodesx->sorted); /* Must be sorted */ |
532 | |
533 | /* Index the segments */ |
534 | |
535 | for(i=0;i<nodesx->number;i++) |
536 | { |
537 | SegmentX **segmentx=LookupSegmentX(segmentsx,SEGMENT(nodesx->gdata[i]->node.firstseg)); |
538 | |
539 | do |
540 | { |
541 | if((*segmentx)->node1==nodesx->gdata[i]->id) |
542 | { |
543 | (*segmentx)->segment.node1|=i; |
544 | |
545 | segmentx++; |
546 | |
547 | if((*segmentx)->node1!=nodesx->gdata[i]->id || (segmentx-segmentsx->sdata)>=segmentsx->number) |
548 | segmentx=NULL; |
549 | } |
550 | else |
551 | { |
552 | (*segmentx)->segment.node2|=i; |
553 | |
554 | if((*segmentx)->segment.next2==NO_NODE) |
555 | segmentx=NULL; |
556 | else |
557 | segmentx=LookupSegmentX(segmentsx,(*segmentx)->segment.next2); |
558 | } |
559 | } |
560 | while(segmentx); |
561 | |
562 | if(!((i+1)%10000)) |
563 | { |
564 | printf("\rIndexing Nodes: Nodes=%d",i+1); |
565 | fflush(stdout); |
566 | } |
567 | } |
568 | |
569 | printf("\rIndexed Nodes: Nodes=%d \n",nodesx->number); |
570 | fflush(stdout); |
571 | } |
572 | |
573 | |
574 | /*++++++++++++++++++++++++++++++++++++++ |
575 | Calculate the distance between two nodes. |
576 | |
577 | distance_t DistanceX Returns the distance between the extended nodes. |
578 | |
579 | NodeX *nodex1 The starting node. |
580 | |
581 | NodeX *nodex2 The end node. |
582 | ++++++++++++++++++++++++++++++++++++++*/ |
583 | |
584 | distance_t DistanceX(NodeX *nodex1,NodeX *nodex2) |
585 | { |
586 | float dlon = nodex1->longitude - nodex2->longitude; |
587 | float dlat = nodex1->latitude - nodex2->latitude; |
588 | |
589 | float a1,a2,a,sa,c,d; |
590 | |
591 | if(dlon==0 && dlat==0) |
592 | return 0; |
593 | |
594 | a1 = sinf (dlat / 2); |
595 | a2 = sinf (dlon / 2); |
596 | a = (a1 * a1) + cosf (nodex1->latitude) * cosf (nodex2->latitude) * a2 * a2; |
597 | sa = sqrtf (a); |
598 | if (sa <= 1.0) |
599 | {c = 2 * asinf (sa);} |
600 | else |
601 | {c = 2 * asinf (1.0);} |
602 | d = 6378.137 * c; |
603 | |
604 | return km_to_distance(d); |
605 | } |
Properties
Name | Value |
---|---|
cvs:description | Extended segments functions. |