Check out the latest version of Routino: svn co http://routino.org/svn/trunk routino
Annotation of /trunk/src/segmentsx.c
Parent Directory
|
Revision Log
Revision 257 -
(hide annotations)
(download)
(as text)
Mon Sep 7 19:01:59 2009 UTC (15 years, 6 months ago) by amb
File MIME type: text/x-csrc
File size: 25949 byte(s)
Mon Sep 7 19:01:59 2009 UTC (15 years, 6 months ago) by amb
File MIME type: text/x-csrc
File size: 25949 byte(s)
Fixed slim mode for segments and nodes (slim now means mapping only one file into RAM at a time and none when creating the final output).
1 | amb | 110 | /*************************************** |
2 | amb | 257 | $Header: /home/amb/CVS/routino/src/segmentsx.c,v 1.34 2009-09-07 19:01:58 amb Exp $ |
3 | amb | 110 | |
4 | Extended Segment data type functions. | ||
5 | amb | 151 | |
6 | Part of the Routino routing software. | ||
7 | amb | 110 | ******************/ /****************** |
8 | amb | 151 | This file Copyright 2008,2009 Andrew M. Bishop |
9 | amb | 110 | |
10 | amb | 151 | 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 | amb | 110 | ***************************************/ |
23 | |||
24 | |||
25 | #include <assert.h> | ||
26 | #include <math.h> | ||
27 | #include <stdlib.h> | ||
28 | #include <stdio.h> | ||
29 | amb | 256 | #include <string.h> |
30 | amb | 110 | |
31 | #include "types.h" | ||
32 | #include "functions.h" | ||
33 | #include "nodesx.h" | ||
34 | #include "segmentsx.h" | ||
35 | #include "waysx.h" | ||
36 | amb | 228 | #include "nodes.h" |
37 | #include "segments.h" | ||
38 | #include "ways.h" | ||
39 | amb | 110 | |
40 | |||
41 | amb | 256 | /* Variables */ |
42 | amb | 110 | |
43 | amb | 256 | extern int option_slim; |
44 | extern char *tmpdirname; | ||
45 | amb | 110 | |
46 | amb | 228 | /* Local Functions */ |
47 | amb | 110 | |
48 | amb | 256 | static int sort_by_id1_and_distance(index_t *a,index_t *b); |
49 | static int sort_by_id2_and_distance(index_t *a,index_t *b); | ||
50 | static index_t *index_first1_segmentx(SegmentsX* segmentsx,node_t node); | ||
51 | static index_t *index_first2_segmentx(SegmentsX* segmentsx,node_t node); | ||
52 | amb | 228 | static distance_t DistanceX(NodeX *nodex1,NodeX *nodex2); |
53 | amb | 110 | |
54 | |||
55 | /*++++++++++++++++++++++++++++++++++++++ | ||
56 | Allocate a new segment list. | ||
57 | |||
58 | SegmentsX *NewSegmentList Returns the segment list. | ||
59 | ++++++++++++++++++++++++++++++++++++++*/ | ||
60 | |||
61 | SegmentsX *NewSegmentList(void) | ||
62 | { | ||
63 | SegmentsX *segmentsx; | ||
64 | |||
65 | amb | 213 | segmentsx=(SegmentsX*)calloc(1,sizeof(SegmentsX)); |
66 | amb | 110 | |
67 | amb | 243 | assert(segmentsx); /* Check calloc() worked */ |
68 | |||
69 | amb | 256 | segmentsx->filename=(char*)malloc(strlen(tmpdirname)+24); |
70 | sprintf(segmentsx->filename,"%s/segments.%p.tmp",tmpdirname,segmentsx); | ||
71 | amb | 216 | |
72 | amb | 256 | segmentsx->fd=OpenFile(segmentsx->filename); |
73 | |||
74 | amb | 110 | return(segmentsx); |
75 | } | ||
76 | |||
77 | |||
78 | /*++++++++++++++++++++++++++++++++++++++ | ||
79 | amb | 226 | Free a segment list. |
80 | amb | 110 | |
81 | SegmentsX *segmentsx The list to be freed. | ||
82 | ++++++++++++++++++++++++++++++++++++++*/ | ||
83 | |||
84 | void FreeSegmentList(SegmentsX *segmentsx) | ||
85 | { | ||
86 | amb | 213 | if(segmentsx->xdata) |
87 | amb | 256 | UnmapFile(segmentsx->filename); |
88 | amb | 226 | |
89 | amb | 256 | DeleteFile(segmentsx->filename); |
90 | |||
91 | amb | 229 | if(segmentsx->n1data) |
92 | free(segmentsx->n1data); | ||
93 | amb | 226 | |
94 | amb | 229 | if(segmentsx->n2data) |
95 | free(segmentsx->n2data); | ||
96 | |||
97 | amb | 226 | if(segmentsx->sdata) |
98 | free(segmentsx->sdata); | ||
99 | |||
100 | amb | 110 | free(segmentsx); |
101 | } | ||
102 | |||
103 | |||
104 | /*++++++++++++++++++++++++++++++++++++++ | ||
105 | Save the segment list to a file. | ||
106 | |||
107 | SegmentsX* segmentsx The set of segments to save. | ||
108 | |||
109 | const char *filename The name of the file to save. | ||
110 | ++++++++++++++++++++++++++++++++++++++*/ | ||
111 | |||
112 | void SaveSegmentList(SegmentsX* segmentsx,const char *filename) | ||
113 | { | ||
114 | amb | 214 | index_t i; |
115 | amb | 110 | int fd; |
116 | amb | 243 | Segments *segments; |
117 | amb | 232 | int super_number=0,normal_number=0; |
118 | amb | 110 | |
119 | amb | 243 | assert(segmentsx->sdata); /* Must have sdata filled in => real segments */ |
120 | amb | 110 | |
121 | amb | 227 | printf("Writing Segments: Segments=0"); |
122 | fflush(stdout); | ||
123 | |||
124 | amb | 232 | for(i=0;i<segmentsx->number;i++) |
125 | { | ||
126 | if(IsSuperSegment(&segmentsx->sdata[i])) | ||
127 | super_number++; | ||
128 | if(IsNormalSegment(&segmentsx->sdata[i])) | ||
129 | normal_number++; | ||
130 | } | ||
131 | |||
132 | amb | 110 | /* Fill in a Segments structure with the offset of the real data in the file after |
133 | the Segment structure itself. */ | ||
134 | |||
135 | amb | 243 | segments=calloc(1,sizeof(Segments)); |
136 | |||
137 | assert(segments); /* Check calloc() worked */ | ||
138 | |||
139 | amb | 110 | segments->number=segmentsx->number; |
140 | amb | 232 | segments->snumber=super_number; |
141 | segments->nnumber=normal_number; | ||
142 | |||
143 | amb | 110 | segments->data=NULL; |
144 | amb | 232 | |
145 | amb | 110 | segments->segments=(void*)sizeof(Segments); |
146 | |||
147 | /* Write out the Segments structure and then the real data. */ | ||
148 | |||
149 | fd=OpenFile(filename); | ||
150 | |||
151 | WriteFile(fd,segments,sizeof(Segments)); | ||
152 | |||
153 | amb | 203 | for(i=0;i<segments->number;i++) |
154 | amb | 132 | { |
155 | amb | 209 | WriteFile(fd,&segmentsx->sdata[i],sizeof(Segment)); |
156 | amb | 110 | |
157 | amb | 132 | if(!((i+1)%10000)) |
158 | { | ||
159 | printf("\rWriting Segments: Segments=%d",i+1); | ||
160 | fflush(stdout); | ||
161 | } | ||
162 | } | ||
163 | |||
164 | amb | 203 | printf("\rWrote Segments: Segments=%d \n",segments->number); |
165 | amb | 132 | fflush(stdout); |
166 | |||
167 | amb | 110 | CloseFile(fd); |
168 | |||
169 | /* Free the fake Segments */ | ||
170 | |||
171 | free(segments); | ||
172 | } | ||
173 | |||
174 | |||
175 | /*++++++++++++++++++++++++++++++++++++++ | ||
176 | amb | 257 | Lookup a particular segment. |
177 | amb | 110 | |
178 | amb | 257 | SegmentX *LookupSegmentX Returns a pointer to the extended segment with the specified id. |
179 | amb | 110 | |
180 | SegmentsX* segmentsx The set of segments to process. | ||
181 | |||
182 | amb | 256 | index_t index The segment index to look for. |
183 | ++++++++++++++++++++++++++++++++++++++*/ | ||
184 | |||
185 | amb | 257 | SegmentX *LookupSegmentX(SegmentsX* segmentsx,index_t index) |
186 | amb | 256 | { |
187 | assert(index!=NO_SEGMENT); /* Must be a valid segment */ | ||
188 | |||
189 | if(option_slim) | ||
190 | { | ||
191 | SeekFile(segmentsx->fd,index*sizeof(SegmentX)); | ||
192 | |||
193 | amb | 257 | ReadFile(segmentsx->fd,&segmentsx->cached,sizeof(SegmentX)); |
194 | amb | 256 | |
195 | amb | 257 | return(&segmentsx->cached); |
196 | amb | 256 | } |
197 | else | ||
198 | { | ||
199 | return(&segmentsx->xdata[index]); | ||
200 | } | ||
201 | } | ||
202 | |||
203 | |||
204 | /*++++++++++++++++++++++++++++++++++++++ | ||
205 | Find the first segment index with a particular starting node in either n1data or n2data. | ||
206 | amb | 257 | |
207 | amb | 256 | index_t *IndexFirstSegmentX Returns a pointer to the index of the first extended segment with the specified id. |
208 | |||
209 | SegmentsX* segmentsx The set of segments to process. | ||
210 | |||
211 | amb | 110 | node_t node The node to look for. |
212 | ++++++++++++++++++++++++++++++++++++++*/ | ||
213 | |||
214 | amb | 256 | index_t *IndexFirstSegmentX(SegmentsX* segmentsx,node_t node) |
215 | amb | 110 | { |
216 | amb | 256 | index_t *first=index_first1_segmentx(segmentsx,node); |
217 | amb | 229 | |
218 | if(first) | ||
219 | return(first); | ||
220 | |||
221 | amb | 256 | return(index_first2_segmentx(segmentsx,node)); |
222 | amb | 229 | } |
223 | |||
224 | |||
225 | /*++++++++++++++++++++++++++++++++++++++ | ||
226 | amb | 256 | Find the first segment index with a particular starting node in n1data. |
227 | amb | 257 | |
228 | amb | 256 | index_t *index_first1_segmentx Returns a pointer to the index of the first extended segment with the specified id. |
229 | amb | 229 | |
230 | SegmentsX* segmentsx The set of segments to process. | ||
231 | |||
232 | node_t node The node to look for. | ||
233 | ++++++++++++++++++++++++++++++++++++++*/ | ||
234 | |||
235 | amb | 256 | static index_t *index_first1_segmentx(SegmentsX* segmentsx,node_t node) |
236 | amb | 229 | { |
237 | amb | 110 | int start=0; |
238 | int end=segmentsx->number-1; | ||
239 | int mid; | ||
240 | int found; | ||
241 | |||
242 | amb | 243 | assert(segmentsx->n1data); /* Must have n1data filled in => sorted by node 1 */ |
243 | amb | 257 | assert(segmentsx->xdata); /* Must have xdata filled in => mapped from file */ |
244 | amb | 110 | |
245 | /* Binary search - search key exact match only is required. | ||
246 | * | ||
247 | * # <- start | Check mid and move start or end if it doesn't match | ||
248 | * # | | ||
249 | * # | Since an exact match is wanted we can set end=mid-1 | ||
250 | * # <- mid | or start=mid+1 because we know that mid doesn't match. | ||
251 | * # | | ||
252 | * # | Eventually either end=start or end=start+1 and one of | ||
253 | * # <- end | start or end is the wanted one. | ||
254 | */ | ||
255 | |||
256 | amb | 257 | if(end<start) /* There are no nodes */ |
257 | amb | 110 | return(NULL); |
258 | amb | 257 | else if(node<segmentsx->xdata[segmentsx->n1data[start]].node1) /* Check key is not before start */ |
259 | amb | 110 | return(NULL); |
260 | amb | 257 | else if(node>segmentsx->xdata[segmentsx->n1data[end]].node1) /* Check key is not after end */ |
261 | amb | 110 | return(NULL); |
262 | amb | 257 | else |
263 | amb | 110 | { |
264 | amb | 257 | do |
265 | { | ||
266 | mid=(start+end)/2; /* Choose mid point */ | ||
267 | amb | 110 | |
268 | amb | 257 | if(segmentsx->xdata[segmentsx->n1data[mid]].node1<node) /* Mid point is too low */ |
269 | start=mid; | ||
270 | else if(segmentsx->xdata[segmentsx->n1data[mid]].node1>node) /* Mid point is too high */ | ||
271 | end=mid; | ||
272 | else /* Mid point is correct */ | ||
273 | {found=mid; goto found;} | ||
274 | } | ||
275 | while((end-start)>1); | ||
276 | amb | 110 | |
277 | amb | 257 | if(segmentsx->xdata[segmentsx->n1data[start]].node1==node) /* Start is correct */ |
278 | {found=start; goto found;} | ||
279 | |||
280 | if(segmentsx->xdata[segmentsx->n1data[end]].node1==node) /* End is correct */ | ||
281 | {found=end; goto found;} | ||
282 | amb | 110 | } |
283 | |||
284 | return(NULL); | ||
285 | |||
286 | found: | ||
287 | |||
288 | amb | 257 | while(found>0 && segmentsx->xdata[segmentsx->n1data[found-1]].node1==node) |
289 | amb | 110 | found--; |
290 | |||
291 | amb | 229 | return(&segmentsx->n1data[found]); |
292 | amb | 110 | } |
293 | |||
294 | |||
295 | /*++++++++++++++++++++++++++++++++++++++ | ||
296 | amb | 256 | Find the first segment index with a particular starting node in n1data. |
297 | amb | 257 | |
298 | amb | 256 | index_t *index_first2_segmentx Returns a pointer to the index of the first extended segment with the specified id. |
299 | amb | 229 | |
300 | SegmentsX* segmentsx The set of segments to process. | ||
301 | |||
302 | node_t node The node to look for. | ||
303 | ++++++++++++++++++++++++++++++++++++++*/ | ||
304 | |||
305 | amb | 256 | static index_t *index_first2_segmentx(SegmentsX* segmentsx,node_t node) |
306 | amb | 229 | { |
307 | int start=0; | ||
308 | int end=segmentsx->number-1; | ||
309 | int mid; | ||
310 | int found; | ||
311 | |||
312 | amb | 257 | assert(segmentsx->n2data); /* Must have n2data filled in => sorted by node 2 */ |
313 | assert(segmentsx->xdata); /* Must have xdata filled in => mapped from file */ | ||
314 | amb | 229 | |
315 | /* Binary search - search key exact match only is required. | ||
316 | * | ||
317 | * # <- start | Check mid and move start or end if it doesn't match | ||
318 | * # | | ||
319 | * # | Since an exact match is wanted we can set end=mid-1 | ||
320 | * # <- mid | or start=mid+1 because we know that mid doesn't match. | ||
321 | * # | | ||
322 | * # | Eventually either end=start or end=start+1 and one of | ||
323 | * # <- end | start or end is the wanted one. | ||
324 | */ | ||
325 | |||
326 | amb | 257 | if(end<start) /* There are no nodes */ |
327 | amb | 229 | return(NULL); |
328 | amb | 257 | else if(node<segmentsx->xdata[segmentsx->n2data[start]].node2) /* Check key is not before start */ |
329 | amb | 229 | return(NULL); |
330 | amb | 257 | else if(node>segmentsx->xdata[segmentsx->n2data[end]].node2) /* Check key is not after end */ |
331 | amb | 229 | return(NULL); |
332 | amb | 257 | else |
333 | amb | 229 | { |
334 | amb | 257 | do |
335 | { | ||
336 | mid=(start+end)/2; /* Choose mid point */ | ||
337 | amb | 229 | |
338 | amb | 257 | if(segmentsx->xdata[segmentsx->n2data[mid]].node2<node) /* Mid point is too low */ |
339 | start=mid; | ||
340 | else if(segmentsx->xdata[segmentsx->n2data[mid]].node2>node) /* Mid point is too high */ | ||
341 | end=mid; | ||
342 | else /* Mid point is correct */ | ||
343 | {found=mid; goto found;} | ||
344 | } | ||
345 | while((end-start)>1); | ||
346 | amb | 229 | |
347 | amb | 257 | if(segmentsx->xdata[segmentsx->n2data[start]].node2==node) /* Start is correct */ |
348 | {found=start; goto found;} | ||
349 | |||
350 | if(segmentsx->xdata[segmentsx->n2data[end]].node2==node) /* End is correct */ | ||
351 | {found=end; goto found;} | ||
352 | amb | 229 | } |
353 | |||
354 | return(NULL); | ||
355 | |||
356 | found: | ||
357 | |||
358 | amb | 257 | while(found>0 && segmentsx->xdata[segmentsx->n2data[found-1]].node2==node) |
359 | amb | 229 | found--; |
360 | |||
361 | return(&segmentsx->n2data[found]); | ||
362 | } | ||
363 | |||
364 | |||
365 | /*++++++++++++++++++++++++++++++++++++++ | ||
366 | amb | 257 | Find the next segment index with a particular starting node. |
367 | amb | 110 | |
368 | amb | 256 | index_t *IndexNextSegmentX Returns a pointer to the index of the next segment with the same id. |
369 | amb | 110 | |
370 | SegmentsX* segmentsx The set of segments to process. | ||
371 | |||
372 | amb | 257 | SegmentX *segmentx The current segment. |
373 | |||
374 | node_t node The node to look for. | ||
375 | amb | 110 | ++++++++++++++++++++++++++++++++++++++*/ |
376 | |||
377 | amb | 257 | index_t *IndexNextSegmentX(SegmentsX* segmentsx,index_t *index,node_t node) |
378 | amb | 110 | { |
379 | amb | 256 | if((segmentsx->n1data<segmentsx->n2data && index< segmentsx->n2data) || |
380 | (segmentsx->n1data>segmentsx->n2data && index>=segmentsx->n1data)) | ||
381 | amb | 229 | { |
382 | amb | 257 | index++; |
383 | amb | 110 | |
384 | amb | 257 | if((index-segmentsx->n1data)==segmentsx->number) |
385 | return(index_first2_segmentx(segmentsx,node)); | ||
386 | amb | 256 | |
387 | amb | 257 | if(segmentsx->xdata[*index].node1==node) |
388 | return(index); | ||
389 | amb | 110 | |
390 | amb | 257 | return(index_first2_segmentx(segmentsx,node)); |
391 | amb | 229 | } |
392 | else | ||
393 | { | ||
394 | amb | 257 | index++; |
395 | amb | 229 | |
396 | amb | 257 | if((index-segmentsx->n2data)==segmentsx->number) |
397 | amb | 229 | return(NULL); |
398 | |||
399 | amb | 257 | if(segmentsx->xdata[*index].node2==node) |
400 | return(index); | ||
401 | amb | 256 | |
402 | amb | 229 | return(NULL); |
403 | } | ||
404 | amb | 110 | } |
405 | |||
406 | |||
407 | /*++++++++++++++++++++++++++++++++++++++ | ||
408 | Append a segment to a segment list. | ||
409 | |||
410 | SegmentsX* segmentsx The set of segments to process. | ||
411 | |||
412 | amb | 203 | way_t way The way that the segment belongs to. |
413 | |||
414 | amb | 110 | node_t node1 The first node in the segment. |
415 | |||
416 | node_t node2 The second node in the segment. | ||
417 | amb | 228 | |
418 | distance_t distance The distance between the nodes (or just the flags). | ||
419 | amb | 110 | ++++++++++++++++++++++++++++++++++++++*/ |
420 | |||
421 | amb | 209 | void AppendSegment(SegmentsX* segmentsx,way_t way,node_t node1,node_t node2,distance_t distance) |
422 | amb | 110 | { |
423 | amb | 256 | SegmentX segmentx; |
424 | amb | 110 | |
425 | amb | 256 | assert(!segmentsx->n1data); /* Must not have n1data filled in => unsorted */ |
426 | amb | 110 | |
427 | amb | 256 | segmentx.way=way; |
428 | segmentx.distance=distance; | ||
429 | amb | 216 | |
430 | amb | 229 | if(node1>node2) |
431 | { | ||
432 | amb | 256 | segmentx.node1=node2; |
433 | segmentx.node2=node1; | ||
434 | amb | 229 | if(distance&(ONEWAY_2TO1|ONEWAY_1TO2)) |
435 | amb | 256 | segmentx.distance^=(ONEWAY_2TO1|ONEWAY_1TO2); |
436 | amb | 229 | } |
437 | else | ||
438 | { | ||
439 | amb | 256 | segmentx.node1=node1; |
440 | segmentx.node2=node2; | ||
441 | amb | 229 | } |
442 | |||
443 | amb | 256 | WriteFile(segmentsx->fd,&segmentx,sizeof(SegmentX)); |
444 | |||
445 | segmentsx->xnumber++; | ||
446 | amb | 110 | } |
447 | |||
448 | |||
449 | /*++++++++++++++++++++++++++++++++++++++ | ||
450 | amb | 256 | Sort the segment list for the first time (i.e. create the sortable indexes). |
451 | amb | 110 | |
452 | SegmentsX* segmentsx The set of segments to process. | ||
453 | ++++++++++++++++++++++++++++++++++++++*/ | ||
454 | |||
455 | amb | 256 | void InitialSortSegmentList(SegmentsX* segmentsx) |
456 | amb | 110 | { |
457 | amb | 214 | index_t i; |
458 | amb | 110 | |
459 | amb | 256 | assert(!segmentsx->n1data); /* Must not have n1data filled in => unsorted */ |
460 | amb | 213 | |
461 | amb | 256 | printf("Sorting Segments (pre-sort)"); |
462 | amb | 227 | fflush(stdout); |
463 | amb | 132 | |
464 | amb | 256 | /* Allocate the array of indexes */ |
465 | amb | 110 | |
466 | amb | 256 | segmentsx->n1data=(index_t*)malloc(segmentsx->xnumber*sizeof(index_t)); |
467 | amb | 110 | |
468 | amb | 256 | assert(segmentsx->n1data); /* Check malloc() worked */ |
469 | amb | 243 | |
470 | amb | 256 | CloseFile(segmentsx->fd); |
471 | segmentsx->fd=ReOpenFile(segmentsx->filename); | ||
472 | amb | 110 | |
473 | amb | 257 | segmentsx->xdata=MapFile(segmentsx->filename); |
474 | amb | 110 | |
475 | amb | 256 | for(i=0;i<segmentsx->xnumber;i++) |
476 | segmentsx->n1data[i]=i; | ||
477 | amb | 110 | |
478 | amb | 256 | segmentsx->number=segmentsx->xnumber; |
479 | |||
480 | printf("\rSorted Segments (pre-sort) \n"); | ||
481 | fflush(stdout); | ||
482 | |||
483 | ReSortSegmentList(segmentsx); | ||
484 | } | ||
485 | |||
486 | |||
487 | /*+ A temporary file-local variable for use by the sort function. +*/ | ||
488 | static SegmentsX *sortsegmentsx; | ||
489 | |||
490 | |||
491 | /*++++++++++++++++++++++++++++++++++++++ | ||
492 | Sort the segment list again. | ||
493 | |||
494 | SegmentsX* segmentsx The set of segments to process. | ||
495 | ++++++++++++++++++++++++++++++++++++++*/ | ||
496 | |||
497 | void ReSortSegmentList(SegmentsX* segmentsx) | ||
498 | { | ||
499 | assert(segmentsx->n1data); /* Must have n1data filled in => initially sorted */ | ||
500 | amb | 257 | assert(segmentsx->xdata); /* Must have xdata filled in => mapped from file */ |
501 | amb | 256 | |
502 | printf("Sorting Segments"); | ||
503 | fflush(stdout); | ||
504 | |||
505 | sortsegmentsx=segmentsx; | ||
506 | |||
507 | qsort(segmentsx->n1data,segmentsx->number,sizeof(index_t),(int (*)(const void*,const void*))sort_by_id1_and_distance); | ||
508 | |||
509 | while(segmentsx->n1data[segmentsx->number-1]==NO_SEGMENT) | ||
510 | segmentsx->number--; | ||
511 | |||
512 | amb | 227 | printf("\rSorted Segments \n"); |
513 | fflush(stdout); | ||
514 | amb | 110 | } |
515 | |||
516 | |||
517 | /*++++++++++++++++++++++++++++++++++++++ | ||
518 | amb | 256 | Sort the segment list for the first time (i.e. create the sortable indexes). |
519 | |||
520 | SegmentsX* segmentsx The set of segments to process. | ||
521 | ++++++++++++++++++++++++++++++++++++++*/ | ||
522 | |||
523 | void FinalSortSegmentList(SegmentsX* segmentsx) | ||
524 | { | ||
525 | index_t i; | ||
526 | |||
527 | assert(segmentsx->n1data); /* Must have n1data filled in => initially sorted */ | ||
528 | assert(!segmentsx->n2data); /* Must not have n2data filled in => not finally sorted */ | ||
529 | |||
530 | ReSortSegmentList(segmentsx); | ||
531 | |||
532 | printf("Sorting Segments (post-sort)"); | ||
533 | fflush(stdout); | ||
534 | |||
535 | /* Allocate the array of indexes */ | ||
536 | |||
537 | segmentsx->n2data=(index_t*)malloc(segmentsx->xnumber*sizeof(index_t)); | ||
538 | |||
539 | assert(segmentsx->n2data); /* Check malloc() worked */ | ||
540 | |||
541 | for(i=0;i<segmentsx->number;i++) | ||
542 | segmentsx->n2data[i]=segmentsx->n1data[i]; | ||
543 | |||
544 | sortsegmentsx=segmentsx; | ||
545 | |||
546 | qsort(segmentsx->n2data,segmentsx->number,sizeof(index_t),(int (*)(const void*,const void*))sort_by_id2_and_distance); | ||
547 | |||
548 | printf("\rSorted Segments (post-sort) \n"); | ||
549 | fflush(stdout); | ||
550 | } | ||
551 | |||
552 | |||
553 | /*++++++++++++++++++++++++++++++++++++++ | ||
554 | amb | 229 | Sort the segments into id order (node1 then node2) and then distance order. |
555 | amb | 110 | |
556 | amb | 229 | int sort_by_id1_and_distance Returns the comparison of the node fields. |
557 | amb | 110 | |
558 | amb | 256 | index_t *a The first segment index. |
559 | amb | 110 | |
560 | amb | 256 | index_t *b The second segment index. |
561 | amb | 110 | ++++++++++++++++++++++++++++++++++++++*/ |
562 | |||
563 | amb | 256 | static int sort_by_id1_and_distance(index_t *a,index_t *b) |
564 | amb | 110 | { |
565 | amb | 256 | if(*a==NO_SEGMENT) |
566 | return(1); | ||
567 | else if(*b==NO_SEGMENT) | ||
568 | amb | 110 | return(-1); |
569 | amb | 256 | else |
570 | amb | 110 | { |
571 | amb | 257 | SegmentX *segmentx_a=&sortsegmentsx->xdata[*a]; |
572 | SegmentX *segmentx_b=&sortsegmentsx->xdata[*b]; | ||
573 | amb | 110 | |
574 | amb | 256 | node_t a_id1=segmentx_a->node1; |
575 | node_t b_id1=segmentx_b->node1; | ||
576 | |||
577 | if(a_id1<b_id1) | ||
578 | amb | 110 | return(-1); |
579 | amb | 256 | else if(a_id1>b_id1) |
580 | amb | 110 | return(1); |
581 | amb | 256 | else /* if(a_id1==b_id1) */ |
582 | amb | 110 | { |
583 | amb | 256 | node_t a_id2=segmentx_a->node2; |
584 | node_t b_id2=segmentx_b->node2; | ||
585 | amb | 110 | |
586 | amb | 256 | if(a_id2<b_id2) |
587 | amb | 110 | return(-1); |
588 | amb | 256 | else if(a_id2>b_id2) |
589 | amb | 110 | return(1); |
590 | else | ||
591 | amb | 256 | { |
592 | distance_t a_distance=segmentx_a->distance; | ||
593 | distance_t b_distance=segmentx_b->distance; | ||
594 | |||
595 | if(a_distance<b_distance) | ||
596 | return(-1); | ||
597 | else if(a_distance>b_distance) | ||
598 | return(1); | ||
599 | else | ||
600 | return(0); | ||
601 | } | ||
602 | amb | 110 | } |
603 | } | ||
604 | } | ||
605 | |||
606 | |||
607 | /*++++++++++++++++++++++++++++++++++++++ | ||
608 | amb | 229 | Sort the segments into id order (node2 then node1) and then distance order. |
609 | |||
610 | int sort_by_id2_and_distance Returns the comparison of the node fields. | ||
611 | |||
612 | amb | 256 | index_t *a The first segment index. |
613 | amb | 229 | |
614 | amb | 256 | index_t *b The second segment index. |
615 | amb | 229 | ++++++++++++++++++++++++++++++++++++++*/ |
616 | |||
617 | amb | 256 | static int sort_by_id2_and_distance(index_t *a,index_t *b) |
618 | amb | 229 | { |
619 | amb | 257 | SegmentX *segmentx_a=&sortsegmentsx->xdata[*a]; |
620 | SegmentX *segmentx_b=&sortsegmentsx->xdata[*b]; | ||
621 | amb | 229 | |
622 | amb | 256 | node_t a_id2=segmentx_a->node2; |
623 | node_t b_id2=segmentx_b->node2; | ||
624 | |||
625 | amb | 229 | if(a_id2<b_id2) |
626 | return(-1); | ||
627 | else if(a_id2>b_id2) | ||
628 | return(1); | ||
629 | else /* if(a_id2==b_id2) */ | ||
630 | { | ||
631 | amb | 256 | node_t a_id1=segmentx_a->node1; |
632 | node_t b_id1=segmentx_b->node1; | ||
633 | amb | 229 | |
634 | if(a_id1<b_id1) | ||
635 | return(-1); | ||
636 | else if(a_id1>b_id1) | ||
637 | return(1); | ||
638 | else | ||
639 | { | ||
640 | amb | 256 | distance_t a_distance=segmentx_a->distance; |
641 | distance_t b_distance=segmentx_b->distance; | ||
642 | amb | 229 | |
643 | if(a_distance<b_distance) | ||
644 | return(-1); | ||
645 | else if(a_distance>b_distance) | ||
646 | return(1); | ||
647 | else | ||
648 | return(0); | ||
649 | } | ||
650 | } | ||
651 | } | ||
652 | |||
653 | |||
654 | /*++++++++++++++++++++++++++++++++++++++ | ||
655 | amb | 110 | Remove bad segments (zero length or duplicated). |
656 | |||
657 | amb | 195 | NodesX *nodesx The nodes to check. |
658 | |||
659 | amb | 110 | SegmentsX *segmentsx The segments to modify. |
660 | ++++++++++++++++++++++++++++++++++++++*/ | ||
661 | |||
662 | amb | 204 | void RemoveBadSegments(NodesX *nodesx,SegmentsX *segmentsx) |
663 | amb | 110 | { |
664 | amb | 214 | index_t i; |
665 | amb | 195 | int duplicate=0,loop=0,missing=0; |
666 | amb | 256 | SegmentX *prevsegmentx=NULL; |
667 | amb | 110 | |
668 | amb | 243 | assert(segmentsx->n1data); /* Must have n1data filled in => sorted by node 1 */ |
669 | amb | 257 | assert(segmentsx->xdata); /* Must have xdata filled in => mapped from file */ |
670 | amb | 110 | |
671 | amb | 227 | printf("Checking: Segments=0 Duplicate=0 Loop=0 Missing-Node=0"); |
672 | fflush(stdout); | ||
673 | |||
674 | amb | 110 | for(i=0;i<segmentsx->number;i++) |
675 | { | ||
676 | amb | 257 | SegmentX *segmentx=&segmentsx->xdata[segmentsx->n1data[i]]; |
677 | amb | 256 | |
678 | amb | 257 | if(segmentx->node1==segmentx->node2) |
679 | amb | 110 | { |
680 | amb | 257 | loop++; |
681 | segmentsx->n1data[i]=NO_SEGMENT; | ||
682 | } | ||
683 | else if(i && segmentx->node1==prevsegmentx->node1 && | ||
684 | segmentx->node2==prevsegmentx->node2) | ||
685 | { | ||
686 | amb | 110 | duplicate++; |
687 | amb | 256 | segmentsx->n1data[i-1]=NO_SEGMENT; |
688 | amb | 110 | } |
689 | amb | 256 | else if(IndexNodeX(nodesx,segmentx->node1)==NO_NODE || |
690 | IndexNodeX(nodesx,segmentx->node2)==NO_NODE) | ||
691 | amb | 195 | { |
692 | missing++; | ||
693 | amb | 256 | segmentsx->n1data[i]=NO_SEGMENT; |
694 | amb | 195 | } |
695 | amb | 110 | |
696 | amb | 256 | prevsegmentx=segmentx; |
697 | |||
698 | amb | 110 | if(!((i+1)%10000)) |
699 | { | ||
700 | amb | 195 | printf("\rChecking: Segments=%d Duplicate=%d Loop=%d Missing-Node=%d",i+1,duplicate,loop,missing); |
701 | amb | 110 | fflush(stdout); |
702 | } | ||
703 | } | ||
704 | |||
705 | amb | 195 | printf("\rChecked: Segments=%d Duplicate=%d Loop=%d Missing-Node=%d \n",segmentsx->number,duplicate,loop,missing); |
706 | amb | 110 | fflush(stdout); |
707 | } | ||
708 | |||
709 | |||
710 | /*++++++++++++++++++++++++++++++++++++++ | ||
711 | Measure the segments. | ||
712 | |||
713 | SegmentsX* segmentsx The set of segments to process. | ||
714 | |||
715 | NodesX *nodesx The list of nodes to use. | ||
716 | ++++++++++++++++++++++++++++++++++++++*/ | ||
717 | |||
718 | void MeasureSegments(SegmentsX* segmentsx,NodesX *nodesx) | ||
719 | { | ||
720 | amb | 256 | index_t i=0; |
721 | int fd; | ||
722 | SegmentX segmentx; | ||
723 | amb | 110 | |
724 | amb | 227 | printf("Measuring Segments: Segments=0"); |
725 | fflush(stdout); | ||
726 | |||
727 | amb | 257 | if(option_slim) |
728 | nodesx->xdata=MapFile(nodesx->filename); | ||
729 | |||
730 | amb | 256 | DeleteFile(segmentsx->filename); |
731 | |||
732 | fd=OpenFile(segmentsx->filename); | ||
733 | SeekFile(segmentsx->fd,0); | ||
734 | |||
735 | while(!ReadFile(segmentsx->fd,&segmentx,sizeof(SegmentX))) | ||
736 | amb | 110 | { |
737 | amb | 257 | index_t index1=IndexNodeX(nodesx,segmentx.node1); |
738 | index_t index2=IndexNodeX(nodesx,segmentx.node2); | ||
739 | amb | 110 | |
740 | amb | 257 | if(index1!=NO_NODE && index2!=NO_NODE) |
741 | { | ||
742 | NodeX *nodex1=&nodesx->xdata[IndexNodeX(nodesx,segmentx.node1)]; | ||
743 | NodeX *nodex2=&nodesx->xdata[IndexNodeX(nodesx,segmentx.node2)]; | ||
744 | amb | 110 | |
745 | amb | 257 | /* Set the distance but preserve the ONEWAY_* flags */ |
746 | |||
747 | amb | 256 | segmentx.distance|=DISTANCE(DistanceX(nodex1,nodex2)); |
748 | amb | 257 | } |
749 | amb | 110 | |
750 | amb | 256 | WriteFile(fd,&segmentx,sizeof(SegmentX)); |
751 | |||
752 | i++; | ||
753 | |||
754 | if(!(i%10000)) | ||
755 | amb | 110 | { |
756 | amb | 256 | printf("\rMeasuring Segments: Segments=%d",i); |
757 | amb | 110 | fflush(stdout); |
758 | } | ||
759 | } | ||
760 | |||
761 | amb | 256 | CloseFile(segmentsx->fd); |
762 | CloseFile(fd); | ||
763 | |||
764 | segmentsx->fd=ReOpenFile(segmentsx->filename); | ||
765 | |||
766 | if(!option_slim) | ||
767 | { | ||
768 | UnmapFile(segmentsx->filename); | ||
769 | segmentsx->xdata=MapFile(segmentsx->filename); | ||
770 | } | ||
771 | |||
772 | amb | 257 | if(option_slim) |
773 | nodesx->xdata=UnmapFile(nodesx->filename); | ||
774 | |||
775 | amb | 256 | printf("\rMeasured Segments: Segments=%d \n",segmentsx->xnumber); |
776 | amb | 110 | fflush(stdout); |
777 | } | ||
778 | |||
779 | |||
780 | /*++++++++++++++++++++++++++++++++++++++ | ||
781 | Mark the duplicate segments. | ||
782 | |||
783 | SegmentsX* segmentsx The set of segments to process. | ||
784 | |||
785 | WaysX *waysx The list of ways to use. | ||
786 | ++++++++++++++++++++++++++++++++++++++*/ | ||
787 | |||
788 | amb | 212 | void DeduplicateSegments(SegmentsX* segmentsx,WaysX *waysx) |
789 | amb | 110 | { |
790 | amb | 214 | index_t i; |
791 | int duplicate=0; | ||
792 | amb | 256 | SegmentX *prevsegmentx; |
793 | amb | 110 | |
794 | amb | 243 | assert(segmentsx->n1data); /* Must have n1data filled in => sorted by node 1 */ |
795 | amb | 257 | assert(segmentsx->xdata); /* Must have xdata filled in => mapped from file */ |
796 | amb | 110 | |
797 | amb | 227 | printf("Deduplicating Segments: Segments=0 Duplicate=0"); |
798 | fflush(stdout); | ||
799 | |||
800 | amb | 257 | prevsegmentx=&segmentsx->xdata[segmentsx->n1data[0]]; |
801 | amb | 256 | |
802 | amb | 110 | for(i=1;i<segmentsx->number;i++) |
803 | { | ||
804 | amb | 257 | SegmentX *segmentx=&segmentsx->xdata[segmentsx->n1data[i]]; |
805 | amb | 256 | |
806 | if(segmentx->node1==prevsegmentx->node1 && | ||
807 | segmentx->node2==prevsegmentx->node2 && | ||
808 | DISTFLAG(segmentx->distance)==DISTFLAG(prevsegmentx->distance)) | ||
809 | amb | 110 | { |
810 | amb | 256 | WayX *wayx1=FindWayX(waysx,prevsegmentx->way); |
811 | WayX *wayx2=FindWayX(waysx, segmentx->way); | ||
812 | amb | 110 | |
813 | amb | 204 | if(!WaysCompare(wayx1->way,wayx2->way)) |
814 | amb | 110 | { |
815 | amb | 256 | segmentsx->n1data[i-1]=NO_SEGMENT; |
816 | amb | 110 | |
817 | duplicate++; | ||
818 | } | ||
819 | } | ||
820 | |||
821 | amb | 256 | prevsegmentx=segmentx; |
822 | |||
823 | amb | 110 | if(!((i+1)%10000)) |
824 | { | ||
825 | printf("\rDeduplicating Segments: Segments=%d Duplicate=%d",i+1,duplicate); | ||
826 | fflush(stdout); | ||
827 | } | ||
828 | } | ||
829 | |||
830 | amb | 229 | printf("\rDeduplicated Segments: Segments=%d Duplicate=%d Unique=%d\n",segmentsx->number,duplicate,segmentsx->number-duplicate); |
831 | amb | 110 | fflush(stdout); |
832 | } | ||
833 | |||
834 | |||
835 | /*++++++++++++++++++++++++++++++++++++++ | ||
836 | amb | 209 | Create the real segments data. |
837 | |||
838 | SegmentsX* segmentsx The set of segments to use. | ||
839 | |||
840 | WaysX* waysx The set of ways to use. | ||
841 | ++++++++++++++++++++++++++++++++++++++*/ | ||
842 | |||
843 | void CreateRealSegments(SegmentsX *segmentsx,WaysX *waysx) | ||
844 | { | ||
845 | amb | 214 | index_t i; |
846 | amb | 209 | |
847 | amb | 243 | assert(segmentsx->n1data); /* Must have n1data filled in => sorted by node 1 */ |
848 | assert(!segmentsx->sdata); /* Must not have sdata filled in => no real segments */ | ||
849 | amb | 213 | |
850 | amb | 227 | printf("Creating Real Segments: Segments=0"); |
851 | fflush(stdout); | ||
852 | |||
853 | amb | 209 | /* Allocate the memory */ |
854 | |||
855 | segmentsx->sdata=(Segment*)malloc(segmentsx->number*sizeof(Segment)); | ||
856 | |||
857 | amb | 243 | assert(segmentsx->sdata); /* Check malloc() worked */ |
858 | |||
859 | amb | 209 | /* Loop through and allocate. */ |
860 | |||
861 | for(i=0;i<segmentsx->number;i++) | ||
862 | { | ||
863 | amb | 257 | SegmentX *segmentx=LookupSegmentX(segmentsx,segmentsx->n1data[i]); |
864 | amb | 256 | WayX *wayx=FindWayX(waysx,segmentx->way); |
865 | amb | 209 | |
866 | segmentsx->sdata[i].node1=0; | ||
867 | segmentsx->sdata[i].node2=0; | ||
868 | segmentsx->sdata[i].next2=NO_NODE; | ||
869 | amb | 216 | segmentsx->sdata[i].way=IndexWayInWaysX(waysx,wayx); |
870 | amb | 256 | segmentsx->sdata[i].distance=segmentx->distance; |
871 | amb | 209 | |
872 | if(!((i+1)%10000)) | ||
873 | { | ||
874 | printf("\rCreating Real Segments: Segments=%d",i+1); | ||
875 | fflush(stdout); | ||
876 | } | ||
877 | } | ||
878 | |||
879 | printf("\rCreating Real Segments: Segments=%d \n",segmentsx->number); | ||
880 | fflush(stdout); | ||
881 | } | ||
882 | |||
883 | |||
884 | /*++++++++++++++++++++++++++++++++++++++ | ||
885 | amb | 110 | Assign the nodes indexes to the segments. |
886 | |||
887 | SegmentsX* segmentsx The set of segments to process. | ||
888 | |||
889 | NodesX *nodesx The list of nodes to use. | ||
890 | ++++++++++++++++++++++++++++++++++++++*/ | ||
891 | |||
892 | void IndexSegments(SegmentsX* segmentsx,NodesX *nodesx) | ||
893 | { | ||
894 | amb | 214 | index_t i; |
895 | amb | 110 | |
896 | amb | 243 | assert(segmentsx->n1data); /* Must have n1data filled in => sorted by node 1 */ |
897 | assert(segmentsx->sdata); /* Must have sdata filled in => real segments */ | ||
898 | assert(nodesx->gdata); /* Must have gdata filled in => sorted geographically */ | ||
899 | amb | 110 | |
900 | amb | 227 | printf("Indexing Nodes: Nodes=0"); |
901 | fflush(stdout); | ||
902 | |||
903 | amb | 110 | /* Index the segments */ |
904 | |||
905 | for(i=0;i<nodesx->number;i++) | ||
906 | { | ||
907 | amb | 257 | Node *node =&nodesx->ndata[nodesx->gdata[i]]; |
908 | amb | 212 | index_t index=SEGMENT(node->firstseg); |
909 | amb | 110 | |
910 | do | ||
911 | { | ||
912 | amb | 257 | SegmentX *segmentx=LookupSegmentX(segmentsx,segmentsx->n1data[index]); |
913 | amb | 256 | |
914 | amb | 257 | if(segmentx->node1==nodesx->idata[nodesx->gdata[i]]) |
915 | amb | 110 | { |
916 | amb | 209 | segmentsx->sdata[index].node1=i; |
917 | amb | 110 | |
918 | amb | 209 | index++; |
919 | amb | 128 | |
920 | amb | 256 | if(index>=segmentsx->number) |
921 | amb | 209 | break; |
922 | amb | 256 | |
923 | amb | 257 | segmentx=LookupSegmentX(segmentsx,segmentsx->n1data[index]); |
924 | amb | 256 | |
925 | amb | 257 | if(segmentx->node1!=nodesx->idata[nodesx->gdata[i]]) |
926 | amb | 256 | break; |
927 | amb | 110 | } |
928 | else | ||
929 | { | ||
930 | amb | 209 | segmentsx->sdata[index].node2=i; |
931 | amb | 110 | |
932 | amb | 209 | if(segmentsx->sdata[index].next2==NO_NODE) |
933 | break; | ||
934 | amb | 110 | else |
935 | amb | 209 | index=segmentsx->sdata[index].next2; |
936 | amb | 110 | } |
937 | } | ||
938 | amb | 209 | while(1); |
939 | amb | 110 | |
940 | if(!((i+1)%10000)) | ||
941 | { | ||
942 | printf("\rIndexing Nodes: Nodes=%d",i+1); | ||
943 | fflush(stdout); | ||
944 | } | ||
945 | } | ||
946 | |||
947 | printf("\rIndexed Nodes: Nodes=%d \n",nodesx->number); | ||
948 | fflush(stdout); | ||
949 | } | ||
950 | |||
951 | |||
952 | /*++++++++++++++++++++++++++++++++++++++ | ||
953 | Calculate the distance between two nodes. | ||
954 | |||
955 | distance_t DistanceX Returns the distance between the extended nodes. | ||
956 | |||
957 | NodeX *nodex1 The starting node. | ||
958 | |||
959 | NodeX *nodex2 The end node. | ||
960 | ++++++++++++++++++++++++++++++++++++++*/ | ||
961 | |||
962 | amb | 228 | static distance_t DistanceX(NodeX *nodex1,NodeX *nodex2) |
963 | amb | 110 | { |
964 | amb | 223 | double dlon = latlong_to_radians(nodex1->longitude) - latlong_to_radians(nodex2->longitude); |
965 | double dlat = latlong_to_radians(nodex1->latitude) - latlong_to_radians(nodex2->latitude); | ||
966 | double lat1 = latlong_to_radians(nodex1->latitude); | ||
967 | double lat2 = latlong_to_radians(nodex2->latitude); | ||
968 | amb | 110 | |
969 | amb | 219 | double a1,a2,a,sa,c,d; |
970 | amb | 110 | |
971 | if(dlon==0 && dlat==0) | ||
972 | return 0; | ||
973 | |||
974 | amb | 219 | a1 = sin (dlat / 2); |
975 | a2 = sin (dlon / 2); | ||
976 | a = (a1 * a1) + cos (lat1) * cos (lat2) * a2 * a2; | ||
977 | sa = sqrt (a); | ||
978 | amb | 110 | if (sa <= 1.0) |
979 | amb | 219 | {c = 2 * asin (sa);} |
980 | amb | 110 | else |
981 | amb | 219 | {c = 2 * asin (1.0);} |
982 | amb | 110 | d = 6378.137 * c; |
983 | |||
984 | return km_to_distance(d); | ||
985 | } |
Properties
Name | Value |
---|---|
cvs:description | Extended segments functions. |