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 262 -
(hide annotations)
(download)
(as text)
Thu Sep 17 12:55:15 2009 UTC (15 years, 6 months ago) by amb
File MIME type: text/x-csrc
File size: 26134 byte(s)
Thu Sep 17 12:55:15 2009 UTC (15 years, 6 months ago) by amb
File MIME type: text/x-csrc
File size: 26134 byte(s)
Added the slim mode to Ways as well.
1 | amb | 110 | /*************************************** |
2 | amb | 262 | $Header: /home/amb/CVS/routino/src/segmentsx.c,v 1.36 2009-09-17 12:55:15 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 | 262 | /* Close the files and re-open them */ |
465 | |||
466 | CloseFile(segmentsx->fd); | ||
467 | segmentsx->fd=ReOpenFile(segmentsx->filename); | ||
468 | |||
469 | amb | 256 | /* Allocate the array of indexes */ |
470 | amb | 110 | |
471 | amb | 256 | segmentsx->n1data=(index_t*)malloc(segmentsx->xnumber*sizeof(index_t)); |
472 | amb | 110 | |
473 | amb | 256 | assert(segmentsx->n1data); /* Check malloc() worked */ |
474 | amb | 243 | |
475 | amb | 257 | segmentsx->xdata=MapFile(segmentsx->filename); |
476 | amb | 110 | |
477 | amb | 256 | for(i=0;i<segmentsx->xnumber;i++) |
478 | segmentsx->n1data[i]=i; | ||
479 | amb | 110 | |
480 | amb | 256 | segmentsx->number=segmentsx->xnumber; |
481 | |||
482 | printf("\rSorted Segments (pre-sort) \n"); | ||
483 | fflush(stdout); | ||
484 | |||
485 | ReSortSegmentList(segmentsx); | ||
486 | } | ||
487 | |||
488 | |||
489 | /*+ A temporary file-local variable for use by the sort function. +*/ | ||
490 | static SegmentsX *sortsegmentsx; | ||
491 | |||
492 | |||
493 | /*++++++++++++++++++++++++++++++++++++++ | ||
494 | Sort the segment list again. | ||
495 | |||
496 | SegmentsX* segmentsx The set of segments to process. | ||
497 | ++++++++++++++++++++++++++++++++++++++*/ | ||
498 | |||
499 | void ReSortSegmentList(SegmentsX* segmentsx) | ||
500 | { | ||
501 | assert(segmentsx->n1data); /* Must have n1data filled in => initially sorted */ | ||
502 | amb | 257 | assert(segmentsx->xdata); /* Must have xdata filled in => mapped from file */ |
503 | amb | 256 | |
504 | printf("Sorting Segments"); | ||
505 | fflush(stdout); | ||
506 | |||
507 | sortsegmentsx=segmentsx; | ||
508 | |||
509 | qsort(segmentsx->n1data,segmentsx->number,sizeof(index_t),(int (*)(const void*,const void*))sort_by_id1_and_distance); | ||
510 | |||
511 | while(segmentsx->n1data[segmentsx->number-1]==NO_SEGMENT) | ||
512 | segmentsx->number--; | ||
513 | |||
514 | amb | 227 | printf("\rSorted Segments \n"); |
515 | fflush(stdout); | ||
516 | amb | 110 | } |
517 | |||
518 | |||
519 | /*++++++++++++++++++++++++++++++++++++++ | ||
520 | amb | 256 | Sort the segment list for the first time (i.e. create the sortable indexes). |
521 | |||
522 | SegmentsX* segmentsx The set of segments to process. | ||
523 | ++++++++++++++++++++++++++++++++++++++*/ | ||
524 | |||
525 | void FinalSortSegmentList(SegmentsX* segmentsx) | ||
526 | { | ||
527 | index_t i; | ||
528 | |||
529 | assert(segmentsx->n1data); /* Must have n1data filled in => initially sorted */ | ||
530 | assert(!segmentsx->n2data); /* Must not have n2data filled in => not finally sorted */ | ||
531 | |||
532 | ReSortSegmentList(segmentsx); | ||
533 | |||
534 | printf("Sorting Segments (post-sort)"); | ||
535 | fflush(stdout); | ||
536 | |||
537 | /* Allocate the array of indexes */ | ||
538 | |||
539 | segmentsx->n2data=(index_t*)malloc(segmentsx->xnumber*sizeof(index_t)); | ||
540 | |||
541 | assert(segmentsx->n2data); /* Check malloc() worked */ | ||
542 | |||
543 | for(i=0;i<segmentsx->number;i++) | ||
544 | segmentsx->n2data[i]=segmentsx->n1data[i]; | ||
545 | |||
546 | sortsegmentsx=segmentsx; | ||
547 | |||
548 | qsort(segmentsx->n2data,segmentsx->number,sizeof(index_t),(int (*)(const void*,const void*))sort_by_id2_and_distance); | ||
549 | |||
550 | amb | 258 | if(option_slim) |
551 | segmentsx->xdata=UnmapFile(segmentsx->filename); | ||
552 | |||
553 | amb | 256 | printf("\rSorted Segments (post-sort) \n"); |
554 | fflush(stdout); | ||
555 | } | ||
556 | |||
557 | |||
558 | /*++++++++++++++++++++++++++++++++++++++ | ||
559 | amb | 229 | Sort the segments into id order (node1 then node2) and then distance order. |
560 | amb | 110 | |
561 | amb | 229 | int sort_by_id1_and_distance Returns the comparison of the node fields. |
562 | amb | 110 | |
563 | amb | 256 | index_t *a The first segment index. |
564 | amb | 110 | |
565 | amb | 256 | index_t *b The second segment index. |
566 | amb | 110 | ++++++++++++++++++++++++++++++++++++++*/ |
567 | |||
568 | amb | 256 | static int sort_by_id1_and_distance(index_t *a,index_t *b) |
569 | amb | 110 | { |
570 | amb | 256 | if(*a==NO_SEGMENT) |
571 | return(1); | ||
572 | else if(*b==NO_SEGMENT) | ||
573 | amb | 110 | return(-1); |
574 | amb | 256 | else |
575 | amb | 110 | { |
576 | amb | 257 | SegmentX *segmentx_a=&sortsegmentsx->xdata[*a]; |
577 | SegmentX *segmentx_b=&sortsegmentsx->xdata[*b]; | ||
578 | amb | 110 | |
579 | amb | 256 | node_t a_id1=segmentx_a->node1; |
580 | node_t b_id1=segmentx_b->node1; | ||
581 | |||
582 | if(a_id1<b_id1) | ||
583 | amb | 110 | return(-1); |
584 | amb | 256 | else if(a_id1>b_id1) |
585 | amb | 110 | return(1); |
586 | amb | 256 | else /* if(a_id1==b_id1) */ |
587 | amb | 110 | { |
588 | amb | 256 | node_t a_id2=segmentx_a->node2; |
589 | node_t b_id2=segmentx_b->node2; | ||
590 | amb | 110 | |
591 | amb | 256 | if(a_id2<b_id2) |
592 | amb | 110 | return(-1); |
593 | amb | 256 | else if(a_id2>b_id2) |
594 | amb | 110 | return(1); |
595 | else | ||
596 | amb | 256 | { |
597 | distance_t a_distance=segmentx_a->distance; | ||
598 | distance_t b_distance=segmentx_b->distance; | ||
599 | |||
600 | if(a_distance<b_distance) | ||
601 | return(-1); | ||
602 | else if(a_distance>b_distance) | ||
603 | return(1); | ||
604 | else | ||
605 | return(0); | ||
606 | } | ||
607 | amb | 110 | } |
608 | } | ||
609 | } | ||
610 | |||
611 | |||
612 | /*++++++++++++++++++++++++++++++++++++++ | ||
613 | amb | 229 | Sort the segments into id order (node2 then node1) and then distance order. |
614 | |||
615 | int sort_by_id2_and_distance Returns the comparison of the node fields. | ||
616 | |||
617 | amb | 256 | index_t *a The first segment index. |
618 | amb | 229 | |
619 | amb | 256 | index_t *b The second segment index. |
620 | amb | 229 | ++++++++++++++++++++++++++++++++++++++*/ |
621 | |||
622 | amb | 256 | static int sort_by_id2_and_distance(index_t *a,index_t *b) |
623 | amb | 229 | { |
624 | amb | 257 | SegmentX *segmentx_a=&sortsegmentsx->xdata[*a]; |
625 | SegmentX *segmentx_b=&sortsegmentsx->xdata[*b]; | ||
626 | amb | 229 | |
627 | amb | 256 | node_t a_id2=segmentx_a->node2; |
628 | node_t b_id2=segmentx_b->node2; | ||
629 | |||
630 | amb | 229 | if(a_id2<b_id2) |
631 | return(-1); | ||
632 | else if(a_id2>b_id2) | ||
633 | return(1); | ||
634 | else /* if(a_id2==b_id2) */ | ||
635 | { | ||
636 | amb | 256 | node_t a_id1=segmentx_a->node1; |
637 | node_t b_id1=segmentx_b->node1; | ||
638 | amb | 229 | |
639 | if(a_id1<b_id1) | ||
640 | return(-1); | ||
641 | else if(a_id1>b_id1) | ||
642 | return(1); | ||
643 | else | ||
644 | { | ||
645 | amb | 256 | distance_t a_distance=segmentx_a->distance; |
646 | distance_t b_distance=segmentx_b->distance; | ||
647 | amb | 229 | |
648 | if(a_distance<b_distance) | ||
649 | return(-1); | ||
650 | else if(a_distance>b_distance) | ||
651 | return(1); | ||
652 | else | ||
653 | return(0); | ||
654 | } | ||
655 | } | ||
656 | } | ||
657 | |||
658 | |||
659 | /*++++++++++++++++++++++++++++++++++++++ | ||
660 | amb | 110 | Remove bad segments (zero length or duplicated). |
661 | |||
662 | amb | 195 | NodesX *nodesx The nodes to check. |
663 | |||
664 | amb | 110 | SegmentsX *segmentsx The segments to modify. |
665 | ++++++++++++++++++++++++++++++++++++++*/ | ||
666 | |||
667 | amb | 204 | void RemoveBadSegments(NodesX *nodesx,SegmentsX *segmentsx) |
668 | amb | 110 | { |
669 | amb | 214 | index_t i; |
670 | amb | 195 | int duplicate=0,loop=0,missing=0; |
671 | amb | 256 | SegmentX *prevsegmentx=NULL; |
672 | amb | 110 | |
673 | amb | 243 | assert(segmentsx->n1data); /* Must have n1data filled in => sorted by node 1 */ |
674 | amb | 257 | assert(segmentsx->xdata); /* Must have xdata filled in => mapped from file */ |
675 | amb | 110 | |
676 | amb | 227 | printf("Checking: Segments=0 Duplicate=0 Loop=0 Missing-Node=0"); |
677 | fflush(stdout); | ||
678 | |||
679 | amb | 110 | for(i=0;i<segmentsx->number;i++) |
680 | { | ||
681 | amb | 257 | SegmentX *segmentx=&segmentsx->xdata[segmentsx->n1data[i]]; |
682 | amb | 256 | |
683 | amb | 257 | if(segmentx->node1==segmentx->node2) |
684 | amb | 110 | { |
685 | amb | 257 | loop++; |
686 | segmentsx->n1data[i]=NO_SEGMENT; | ||
687 | } | ||
688 | else if(i && segmentx->node1==prevsegmentx->node1 && | ||
689 | segmentx->node2==prevsegmentx->node2) | ||
690 | { | ||
691 | amb | 110 | duplicate++; |
692 | amb | 256 | segmentsx->n1data[i-1]=NO_SEGMENT; |
693 | amb | 110 | } |
694 | amb | 256 | else if(IndexNodeX(nodesx,segmentx->node1)==NO_NODE || |
695 | IndexNodeX(nodesx,segmentx->node2)==NO_NODE) | ||
696 | amb | 195 | { |
697 | missing++; | ||
698 | amb | 256 | segmentsx->n1data[i]=NO_SEGMENT; |
699 | amb | 195 | } |
700 | amb | 110 | |
701 | amb | 256 | prevsegmentx=segmentx; |
702 | |||
703 | amb | 110 | if(!((i+1)%10000)) |
704 | { | ||
705 | amb | 195 | printf("\rChecking: Segments=%d Duplicate=%d Loop=%d Missing-Node=%d",i+1,duplicate,loop,missing); |
706 | amb | 110 | fflush(stdout); |
707 | } | ||
708 | } | ||
709 | |||
710 | amb | 195 | printf("\rChecked: Segments=%d Duplicate=%d Loop=%d Missing-Node=%d \n",segmentsx->number,duplicate,loop,missing); |
711 | amb | 110 | fflush(stdout); |
712 | } | ||
713 | |||
714 | |||
715 | /*++++++++++++++++++++++++++++++++++++++ | ||
716 | Measure the segments. | ||
717 | |||
718 | SegmentsX* segmentsx The set of segments to process. | ||
719 | |||
720 | NodesX *nodesx The list of nodes to use. | ||
721 | ++++++++++++++++++++++++++++++++++++++*/ | ||
722 | |||
723 | void MeasureSegments(SegmentsX* segmentsx,NodesX *nodesx) | ||
724 | { | ||
725 | amb | 256 | index_t i=0; |
726 | int fd; | ||
727 | SegmentX segmentx; | ||
728 | amb | 110 | |
729 | amb | 227 | printf("Measuring Segments: Segments=0"); |
730 | fflush(stdout); | ||
731 | |||
732 | amb | 257 | if(option_slim) |
733 | nodesx->xdata=MapFile(nodesx->filename); | ||
734 | |||
735 | amb | 258 | if(!option_slim) |
736 | segmentsx->xdata=UnmapFile(segmentsx->filename); | ||
737 | |||
738 | amb | 256 | DeleteFile(segmentsx->filename); |
739 | |||
740 | fd=OpenFile(segmentsx->filename); | ||
741 | SeekFile(segmentsx->fd,0); | ||
742 | |||
743 | while(!ReadFile(segmentsx->fd,&segmentx,sizeof(SegmentX))) | ||
744 | amb | 110 | { |
745 | amb | 257 | index_t index1=IndexNodeX(nodesx,segmentx.node1); |
746 | index_t index2=IndexNodeX(nodesx,segmentx.node2); | ||
747 | amb | 110 | |
748 | amb | 257 | if(index1!=NO_NODE && index2!=NO_NODE) |
749 | { | ||
750 | NodeX *nodex1=&nodesx->xdata[IndexNodeX(nodesx,segmentx.node1)]; | ||
751 | NodeX *nodex2=&nodesx->xdata[IndexNodeX(nodesx,segmentx.node2)]; | ||
752 | amb | 110 | |
753 | amb | 257 | /* Set the distance but preserve the ONEWAY_* flags */ |
754 | |||
755 | amb | 256 | segmentx.distance|=DISTANCE(DistanceX(nodex1,nodex2)); |
756 | amb | 257 | } |
757 | amb | 110 | |
758 | amb | 256 | WriteFile(fd,&segmentx,sizeof(SegmentX)); |
759 | |||
760 | i++; | ||
761 | |||
762 | if(!(i%10000)) | ||
763 | amb | 110 | { |
764 | amb | 256 | printf("\rMeasuring Segments: Segments=%d",i); |
765 | amb | 110 | fflush(stdout); |
766 | } | ||
767 | } | ||
768 | |||
769 | amb | 256 | CloseFile(segmentsx->fd); |
770 | CloseFile(fd); | ||
771 | |||
772 | segmentsx->fd=ReOpenFile(segmentsx->filename); | ||
773 | |||
774 | if(!option_slim) | ||
775 | segmentsx->xdata=MapFile(segmentsx->filename); | ||
776 | |||
777 | amb | 257 | if(option_slim) |
778 | nodesx->xdata=UnmapFile(nodesx->filename); | ||
779 | |||
780 | amb | 256 | printf("\rMeasured Segments: Segments=%d \n",segmentsx->xnumber); |
781 | amb | 110 | fflush(stdout); |
782 | } | ||
783 | |||
784 | |||
785 | /*++++++++++++++++++++++++++++++++++++++ | ||
786 | Mark the duplicate segments. | ||
787 | |||
788 | SegmentsX* segmentsx The set of segments to process. | ||
789 | |||
790 | WaysX *waysx The list of ways to use. | ||
791 | ++++++++++++++++++++++++++++++++++++++*/ | ||
792 | |||
793 | amb | 212 | void DeduplicateSegments(SegmentsX* segmentsx,WaysX *waysx) |
794 | amb | 110 | { |
795 | amb | 214 | index_t i; |
796 | int duplicate=0; | ||
797 | amb | 256 | SegmentX *prevsegmentx; |
798 | amb | 110 | |
799 | amb | 243 | assert(segmentsx->n1data); /* Must have n1data filled in => sorted by node 1 */ |
800 | amb | 257 | assert(segmentsx->xdata); /* Must have xdata filled in => mapped from file */ |
801 | amb | 110 | |
802 | amb | 227 | printf("Deduplicating Segments: Segments=0 Duplicate=0"); |
803 | fflush(stdout); | ||
804 | |||
805 | amb | 257 | prevsegmentx=&segmentsx->xdata[segmentsx->n1data[0]]; |
806 | amb | 256 | |
807 | amb | 110 | for(i=1;i<segmentsx->number;i++) |
808 | { | ||
809 | amb | 257 | SegmentX *segmentx=&segmentsx->xdata[segmentsx->n1data[i]]; |
810 | amb | 256 | |
811 | if(segmentx->node1==prevsegmentx->node1 && | ||
812 | segmentx->node2==prevsegmentx->node2 && | ||
813 | DISTFLAG(segmentx->distance)==DISTFLAG(prevsegmentx->distance)) | ||
814 | amb | 110 | { |
815 | amb | 262 | WayX *wayx1=LookupWayX(waysx,IndexWayX(waysx,prevsegmentx->way),1); |
816 | WayX *wayx2=LookupWayX(waysx,IndexWayX(waysx, segmentx->way),2); | ||
817 | amb | 110 | |
818 | amb | 262 | if(!WaysCompare(&wayx1->way,&wayx2->way)) |
819 | amb | 110 | { |
820 | amb | 256 | segmentsx->n1data[i-1]=NO_SEGMENT; |
821 | amb | 110 | |
822 | duplicate++; | ||
823 | } | ||
824 | } | ||
825 | |||
826 | amb | 256 | prevsegmentx=segmentx; |
827 | |||
828 | amb | 110 | if(!((i+1)%10000)) |
829 | { | ||
830 | printf("\rDeduplicating Segments: Segments=%d Duplicate=%d",i+1,duplicate); | ||
831 | fflush(stdout); | ||
832 | } | ||
833 | } | ||
834 | |||
835 | amb | 229 | printf("\rDeduplicated Segments: Segments=%d Duplicate=%d Unique=%d\n",segmentsx->number,duplicate,segmentsx->number-duplicate); |
836 | amb | 110 | fflush(stdout); |
837 | } | ||
838 | |||
839 | |||
840 | /*++++++++++++++++++++++++++++++++++++++ | ||
841 | amb | 209 | Create the real segments data. |
842 | |||
843 | SegmentsX* segmentsx The set of segments to use. | ||
844 | |||
845 | WaysX* waysx The set of ways to use. | ||
846 | ++++++++++++++++++++++++++++++++++++++*/ | ||
847 | |||
848 | void CreateRealSegments(SegmentsX *segmentsx,WaysX *waysx) | ||
849 | { | ||
850 | amb | 214 | index_t i; |
851 | amb | 209 | |
852 | amb | 243 | assert(segmentsx->n1data); /* Must have n1data filled in => sorted by node 1 */ |
853 | assert(!segmentsx->sdata); /* Must not have sdata filled in => no real segments */ | ||
854 | amb | 213 | |
855 | amb | 227 | printf("Creating Real Segments: Segments=0"); |
856 | fflush(stdout); | ||
857 | |||
858 | amb | 209 | /* Allocate the memory */ |
859 | |||
860 | segmentsx->sdata=(Segment*)malloc(segmentsx->number*sizeof(Segment)); | ||
861 | |||
862 | amb | 243 | assert(segmentsx->sdata); /* Check malloc() worked */ |
863 | |||
864 | amb | 209 | /* Loop through and allocate. */ |
865 | |||
866 | for(i=0;i<segmentsx->number;i++) | ||
867 | { | ||
868 | amb | 257 | SegmentX *segmentx=LookupSegmentX(segmentsx,segmentsx->n1data[i]); |
869 | amb | 262 | WayX *wayx=LookupWayX(waysx,IndexWayX(waysx,segmentx->way),1); |
870 | amb | 209 | |
871 | segmentsx->sdata[i].node1=0; | ||
872 | segmentsx->sdata[i].node2=0; | ||
873 | segmentsx->sdata[i].next2=NO_NODE; | ||
874 | amb | 262 | segmentsx->sdata[i].way=wayx->cid; |
875 | amb | 256 | segmentsx->sdata[i].distance=segmentx->distance; |
876 | amb | 209 | |
877 | if(!((i+1)%10000)) | ||
878 | { | ||
879 | printf("\rCreating Real Segments: Segments=%d",i+1); | ||
880 | fflush(stdout); | ||
881 | } | ||
882 | } | ||
883 | |||
884 | printf("\rCreating Real Segments: Segments=%d \n",segmentsx->number); | ||
885 | fflush(stdout); | ||
886 | } | ||
887 | |||
888 | |||
889 | /*++++++++++++++++++++++++++++++++++++++ | ||
890 | amb | 110 | Assign the nodes indexes to the segments. |
891 | |||
892 | SegmentsX* segmentsx The set of segments to process. | ||
893 | |||
894 | NodesX *nodesx The list of nodes to use. | ||
895 | ++++++++++++++++++++++++++++++++++++++*/ | ||
896 | |||
897 | void IndexSegments(SegmentsX* segmentsx,NodesX *nodesx) | ||
898 | { | ||
899 | amb | 214 | index_t i; |
900 | amb | 110 | |
901 | amb | 243 | assert(segmentsx->n1data); /* Must have n1data filled in => sorted by node 1 */ |
902 | assert(segmentsx->sdata); /* Must have sdata filled in => real segments */ | ||
903 | assert(nodesx->gdata); /* Must have gdata filled in => sorted geographically */ | ||
904 | amb | 110 | |
905 | amb | 227 | printf("Indexing Nodes: Nodes=0"); |
906 | fflush(stdout); | ||
907 | |||
908 | amb | 110 | /* Index the segments */ |
909 | |||
910 | for(i=0;i<nodesx->number;i++) | ||
911 | { | ||
912 | amb | 257 | Node *node =&nodesx->ndata[nodesx->gdata[i]]; |
913 | amb | 212 | index_t index=SEGMENT(node->firstseg); |
914 | amb | 110 | |
915 | do | ||
916 | { | ||
917 | amb | 257 | SegmentX *segmentx=LookupSegmentX(segmentsx,segmentsx->n1data[index]); |
918 | amb | 256 | |
919 | amb | 257 | if(segmentx->node1==nodesx->idata[nodesx->gdata[i]]) |
920 | amb | 110 | { |
921 | amb | 209 | segmentsx->sdata[index].node1=i; |
922 | amb | 110 | |
923 | amb | 209 | index++; |
924 | amb | 128 | |
925 | amb | 256 | if(index>=segmentsx->number) |
926 | amb | 209 | break; |
927 | amb | 256 | |
928 | amb | 257 | segmentx=LookupSegmentX(segmentsx,segmentsx->n1data[index]); |
929 | amb | 256 | |
930 | amb | 257 | if(segmentx->node1!=nodesx->idata[nodesx->gdata[i]]) |
931 | amb | 256 | break; |
932 | amb | 110 | } |
933 | else | ||
934 | { | ||
935 | amb | 209 | segmentsx->sdata[index].node2=i; |
936 | amb | 110 | |
937 | amb | 209 | if(segmentsx->sdata[index].next2==NO_NODE) |
938 | break; | ||
939 | amb | 110 | else |
940 | amb | 209 | index=segmentsx->sdata[index].next2; |
941 | amb | 110 | } |
942 | } | ||
943 | amb | 209 | while(1); |
944 | amb | 110 | |
945 | if(!((i+1)%10000)) | ||
946 | { | ||
947 | printf("\rIndexing Nodes: Nodes=%d",i+1); | ||
948 | fflush(stdout); | ||
949 | } | ||
950 | } | ||
951 | |||
952 | printf("\rIndexed Nodes: Nodes=%d \n",nodesx->number); | ||
953 | fflush(stdout); | ||
954 | } | ||
955 | |||
956 | |||
957 | /*++++++++++++++++++++++++++++++++++++++ | ||
958 | Calculate the distance between two nodes. | ||
959 | |||
960 | distance_t DistanceX Returns the distance between the extended nodes. | ||
961 | |||
962 | NodeX *nodex1 The starting node. | ||
963 | |||
964 | NodeX *nodex2 The end node. | ||
965 | ++++++++++++++++++++++++++++++++++++++*/ | ||
966 | |||
967 | amb | 228 | static distance_t DistanceX(NodeX *nodex1,NodeX *nodex2) |
968 | amb | 110 | { |
969 | amb | 223 | double dlon = latlong_to_radians(nodex1->longitude) - latlong_to_radians(nodex2->longitude); |
970 | double dlat = latlong_to_radians(nodex1->latitude) - latlong_to_radians(nodex2->latitude); | ||
971 | double lat1 = latlong_to_radians(nodex1->latitude); | ||
972 | double lat2 = latlong_to_radians(nodex2->latitude); | ||
973 | amb | 110 | |
974 | amb | 219 | double a1,a2,a,sa,c,d; |
975 | amb | 110 | |
976 | if(dlon==0 && dlat==0) | ||
977 | return 0; | ||
978 | |||
979 | amb | 219 | a1 = sin (dlat / 2); |
980 | a2 = sin (dlon / 2); | ||
981 | a = (a1 * a1) + cos (lat1) * cos (lat2) * a2 * a2; | ||
982 | sa = sqrt (a); | ||
983 | amb | 110 | if (sa <= 1.0) |
984 | amb | 219 | {c = 2 * asin (sa);} |
985 | amb | 110 | else |
986 | amb | 219 | {c = 2 * asin (1.0);} |
987 | amb | 110 | d = 6378.137 * c; |
988 | |||
989 | return km_to_distance(d); | ||
990 | } |
Properties
Name | Value |
---|---|
cvs:description | Extended segments functions. |