Check out the latest version of Routino: svn co http://routino.org/svn/trunk routino
Annotation of /trunk/src/prunex.c
Parent Directory
|
Revision Log
Revision 970 -
(hide annotations)
(download)
(as text)
Sun Feb 19 16:56:45 2012 UTC (13 years, 1 month ago) by amb
File MIME type: text/x-csrc
File size: 37992 byte(s)
Sun Feb 19 16:56:45 2012 UTC (13 years, 1 month ago) by amb
File MIME type: text/x-csrc
File size: 37992 byte(s)
Some fixes to be able to process the whole of the UK.
1 | amb | 949 | /*************************************** |
2 | Data pruning functions. | ||
3 | |||
4 | Part of the Routino routing software. | ||
5 | ******************/ /****************** | ||
6 | This file Copyright 2011-2012 Andrew M. Bishop | ||
7 | |||
8 | This program is free software: you can redistribute it and/or modify | ||
9 | it under the terms of the GNU Affero General Public License as published by | ||
10 | the Free Software Foundation, either version 3 of the License, or | ||
11 | (at your option) any later version. | ||
12 | |||
13 | This program is distributed in the hope that it will be useful, | ||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | GNU Affero General Public License for more details. | ||
17 | |||
18 | You should have received a copy of the GNU Affero General Public License | ||
19 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
20 | ***************************************/ | ||
21 | |||
22 | |||
23 | #include <stdlib.h> | ||
24 | #include <assert.h> | ||
25 | |||
26 | amb | 964 | #include "types.h" |
27 | #include "segments.h" | ||
28 | |||
29 | amb | 955 | #include "typesx.h" |
30 | amb | 949 | #include "nodesx.h" |
31 | #include "segmentsx.h" | ||
32 | #include "waysx.h" | ||
33 | amb | 955 | |
34 | amb | 949 | #include "prunex.h" |
35 | |||
36 | #include "files.h" | ||
37 | #include "logging.h" | ||
38 | |||
39 | |||
40 | /* Local functions */ | ||
41 | |||
42 | amb | 960 | static void prune_segment(SegmentsX *segmentsx,SegmentX *segmentx); |
43 | amb | 949 | static void modify_segment(SegmentsX *segmentsx,SegmentX *segmentx,index_t newnode1,index_t newnode2); |
44 | |||
45 | amb | 970 | static void unlink_segment_node1_refs(SegmentsX *segmentsx,SegmentX *segmentx); |
46 | static void unlink_segment_node2_refs(SegmentsX *segmentsx,SegmentX *segmentx); | ||
47 | amb | 949 | |
48 | amb | 966 | static double distance(double lat1,double lon1,double lat2,double lon2); |
49 | amb | 949 | |
50 | amb | 966 | |
51 | amb | 949 | /*++++++++++++++++++++++++++++++++++++++ |
52 | Initialise the data structures needed for pruning. | ||
53 | |||
54 | NodesX *nodesx The set of nodes to use. | ||
55 | |||
56 | SegmentsX *segmentsx The set of segments to use. | ||
57 | |||
58 | WaysX *waysx The set of ways to use. | ||
59 | ++++++++++++++++++++++++++++++++++++++*/ | ||
60 | |||
61 | void StartPruning(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx) | ||
62 | { | ||
63 | SegmentX segmentx; | ||
64 | index_t index=0,lastnode1=NO_NODE; | ||
65 | |||
66 | /* Print the start message */ | ||
67 | |||
68 | printf_first("Adding Extra Segment Indexes: Segments=0"); | ||
69 | |||
70 | /* Allocate the array of next segment */ | ||
71 | |||
72 | segmentsx->next1=(index_t*)calloc(segmentsx->number,sizeof(index_t)); | ||
73 | |||
74 | assert(segmentsx->next1); /* Check malloc() worked */ | ||
75 | |||
76 | /* Open the file read-only */ | ||
77 | |||
78 | segmentsx->fd=ReOpenFile(segmentsx->filename); | ||
79 | |||
80 | /* Read the on-disk image */ | ||
81 | |||
82 | while(!ReadFile(segmentsx->fd,&segmentx,sizeof(SegmentX))) | ||
83 | { | ||
84 | index_t node1=segmentx.node1; | ||
85 | |||
86 | amb | 953 | if(index==0) |
87 | ; | ||
88 | else if(lastnode1==node1) | ||
89 | segmentsx->next1[index-1]=index; | ||
90 | amb | 949 | else |
91 | amb | 953 | segmentsx->next1[index-1]=NO_SEGMENT; |
92 | amb | 949 | |
93 | lastnode1=node1; | ||
94 | index++; | ||
95 | |||
96 | if(!(index%10000)) | ||
97 | printf_middle("Added Extra Segment Indexes: Segments=%"Pindex_t,index); | ||
98 | } | ||
99 | |||
100 | amb | 953 | segmentsx->next1[index-1]=NO_SEGMENT; |
101 | amb | 949 | |
102 | /* Close the file */ | ||
103 | |||
104 | segmentsx->fd=CloseFile(segmentsx->fd); | ||
105 | |||
106 | /* Print the final message */ | ||
107 | |||
108 | printf_last("Added Extra Segment Indexes: Segments=%"Pindex_t,segmentsx->number); | ||
109 | } | ||
110 | |||
111 | |||
112 | /*++++++++++++++++++++++++++++++++++++++ | ||
113 | Delete the data structures needed for pruning. | ||
114 | |||
115 | NodesX *nodesx The set of nodes to use. | ||
116 | |||
117 | SegmentsX *segmentsx The set of segments to use. | ||
118 | |||
119 | WaysX *waysx The set of ways to use. | ||
120 | ++++++++++++++++++++++++++++++++++++++*/ | ||
121 | |||
122 | void FinishPruning(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx) | ||
123 | { | ||
124 | amb | 960 | index_t i,pruned=0; |
125 | int fd; | ||
126 | |||
127 | amb | 963 | |
128 | /* Delete the pruned segments */ | ||
129 | |||
130 | amb | 949 | free(segmentsx->next1); |
131 | segmentsx->next1=NULL; | ||
132 | |||
133 | SortSegmentList(segmentsx,1); | ||
134 | |||
135 | IndexSegments(segmentsx,nodesx); | ||
136 | amb | 960 | |
137 | |||
138 | amb | 963 | /* Delete the pruned nodes */ |
139 | |||
140 | amb | 960 | printf_first("Marking Pruned Nodes: Nodes=0 Pruned=0"); |
141 | |||
142 | /* Re-open the file read-only and a new file writeable */ | ||
143 | |||
144 | nodesx->fd=ReOpenFile(nodesx->filename); | ||
145 | |||
146 | DeleteFile(nodesx->filename); | ||
147 | |||
148 | fd=OpenFileNew(nodesx->filename); | ||
149 | |||
150 | /* Modify the on-disk image */ | ||
151 | |||
152 | for(i=0;i<nodesx->number;i++) | ||
153 | { | ||
154 | NodeX nodex; | ||
155 | |||
156 | ReadFile(nodesx->fd,&nodex,sizeof(NodeX)); | ||
157 | |||
158 | if(segmentsx->firstnode[i]==NO_SEGMENT) | ||
159 | { | ||
160 | pruned++; | ||
161 | amb | 961 | nodex.latitude=NO_LATLONG; |
162 | nodex.longitude=NO_LATLONG; | ||
163 | amb | 960 | } |
164 | |||
165 | WriteFile(fd,&nodex,sizeof(NodeX)); | ||
166 | |||
167 | if(!((i+1)%10000)) | ||
168 | printf_middle("Marking Pruned Nodes: Nodes=%"Pindex_t" Pruned=%"Pindex_t,i+1,pruned); | ||
169 | } | ||
170 | |||
171 | /* Close the files */ | ||
172 | |||
173 | nodesx->fd=CloseFile(nodesx->fd); | ||
174 | CloseFile(fd); | ||
175 | |||
176 | /* Print the final message */ | ||
177 | |||
178 | printf_last("Marked Pruned Nodes: Nodes=%"Pindex_t" Pruned=%"Pindex_t,nodesx->number,pruned); | ||
179 | amb | 949 | } |
180 | |||
181 | |||
182 | /*++++++++++++++++++++++++++++++++++++++ | ||
183 | amb | 953 | Prune out any groups of nodes and segments whose total length is less than a |
184 | specified minimum. | ||
185 | |||
186 | NodesX *nodesx The set of nodes to use. | ||
187 | |||
188 | SegmentsX *segmentsx The set of segments to use. | ||
189 | |||
190 | amb | 963 | WaysX *waysx The set of ways to use. |
191 | |||
192 | amb | 953 | distance_t minimum The minimum distance to keep. |
193 | ++++++++++++++++++++++++++++++++++++++*/ | ||
194 | |||
195 | amb | 963 | void PruneIsolatedRegions(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx,distance_t minimum) |
196 | amb | 953 | { |
197 | index_t i,j; | ||
198 | index_t nregions=0,npruned=0; | ||
199 | BitMask *connected,*region; | ||
200 | index_t *regionsegments,*othersegments; | ||
201 | int nallocregionsegments,nallocothersegments; | ||
202 | |||
203 | if(nodesx->number==0 || segmentsx->number==0) | ||
204 | return; | ||
205 | |||
206 | /* Print the start message */ | ||
207 | |||
208 | printf_first("Pruning Isolated Regions: Segments=0 Pruned=0"); | ||
209 | |||
210 | /* Map into memory / open the files */ | ||
211 | |||
212 | #if !SLIM | ||
213 | nodesx->data=MapFileWriteable(nodesx->filename); | ||
214 | segmentsx->data=MapFileWriteable(segmentsx->filename); | ||
215 | amb | 963 | waysx->data=MapFile(waysx->filename); |
216 | amb | 953 | #else |
217 | nodesx->fd=ReOpenFileWriteable(nodesx->filename); | ||
218 | segmentsx->fd=ReOpenFileWriteable(segmentsx->filename); | ||
219 | amb | 963 | waysx->fd=ReOpenFile(waysx->filename); |
220 | amb | 953 | #endif |
221 | |||
222 | connected=AllocBitMask(segmentsx->number); | ||
223 | region =AllocBitMask(segmentsx->number); | ||
224 | |||
225 | assert(connected); /* Check AllocBitMask() worked */ | ||
226 | assert(region); /* Check AllocBitMask() worked */ | ||
227 | |||
228 | regionsegments=(index_t*)malloc((nallocregionsegments=1024)*sizeof(index_t)); | ||
229 | othersegments =(index_t*)malloc((nallocothersegments =1024)*sizeof(index_t)); | ||
230 | |||
231 | assert(regionsegments); /* Check malloc() worked */ | ||
232 | assert(othersegments); /* Check malloc() worked */ | ||
233 | |||
234 | /* Loop through the segments and find the disconnected ones */ | ||
235 | |||
236 | for(i=0;i<segmentsx->number;i++) | ||
237 | { | ||
238 | if(!IsBitSet(connected,i)) | ||
239 | { | ||
240 | int nregionsegments=0,nothersegments=0; | ||
241 | distance_t total=0; | ||
242 | |||
243 | othersegments[nothersegments++]=i; | ||
244 | SetBit(region,i); | ||
245 | |||
246 | do | ||
247 | { | ||
248 | SegmentX *segmentx; | ||
249 | index_t thissegment,nodes[2]; | ||
250 | amb | 963 | WayX *wayx; |
251 | amb | 953 | |
252 | thissegment=othersegments[--nothersegments]; | ||
253 | |||
254 | if(nregionsegments==nallocregionsegments) | ||
255 | regionsegments=(index_t*)realloc(regionsegments,(nallocregionsegments+=1024)*sizeof(index_t)); | ||
256 | |||
257 | regionsegments[nregionsegments++]=thissegment; | ||
258 | |||
259 | segmentx=LookupSegmentX(segmentsx,thissegment,1); | ||
260 | |||
261 | nodes[0]=segmentx->node1; | ||
262 | nodes[1]=segmentx->node2; | ||
263 | total+=DISTANCE(segmentx->distance); | ||
264 | |||
265 | amb | 963 | wayx=LookupWayX(waysx,segmentx->way,1); |
266 | |||
267 | amb | 953 | for(j=0;j<2;j++) |
268 | { | ||
269 | amb | 963 | NodeX *nodex=LookupNodeX(nodesx,nodes[j],1); |
270 | |||
271 | if(!(nodex->allow&wayx->way.allow)) /* some type of traffic must be allowed */ | ||
272 | continue; | ||
273 | |||
274 | amb | 953 | segmentx=FirstSegmentX(segmentsx,nodes[j],1); |
275 | |||
276 | while(segmentx) | ||
277 | { | ||
278 | index_t segment=IndexSegmentX(segmentsx,segmentx); | ||
279 | |||
280 | if(segment!=thissegment) | ||
281 | { | ||
282 | amb | 963 | WayX *way2x=LookupWayX(waysx,segmentx->way,2); |
283 | amb | 953 | |
284 | amb | 963 | if(wayx->way.allow&way2x->way.allow) /* some type of traffic must be allowed */ |
285 | amb | 953 | { |
286 | amb | 963 | /* Already connected - finish */ |
287 | amb | 953 | |
288 | amb | 963 | if(IsBitSet(connected,segment)) |
289 | { | ||
290 | total=minimum; | ||
291 | goto foundconnection; | ||
292 | } | ||
293 | |||
294 | /* Not in region - add to list */ | ||
295 | |||
296 | if(!IsBitSet(region,segment)) | ||
297 | { | ||
298 | if(nothersegments==nallocothersegments) | ||
299 | othersegments=(index_t*)realloc(othersegments,(nallocothersegments+=1024)*sizeof(index_t)); | ||
300 | |||
301 | othersegments[nothersegments++]=segment; | ||
302 | SetBit(region,segment); | ||
303 | } | ||
304 | amb | 953 | } |
305 | } | ||
306 | |||
307 | segmentx=NextSegmentX(segmentsx,segmentx,nodes[j]); | ||
308 | } | ||
309 | } | ||
310 | } | ||
311 | while(nothersegments>0 && total<minimum); | ||
312 | |||
313 | foundconnection: | ||
314 | |||
315 | /* Prune the segments or mark them as connected */ | ||
316 | |||
317 | if(total<minimum) | ||
318 | { | ||
319 | nregions++; | ||
320 | |||
321 | for(j=0;j<nregionsegments;j++) | ||
322 | { | ||
323 | SegmentX *segmentx=LookupSegmentX(segmentsx,regionsegments[j],1); | ||
324 | |||
325 | SetBit(connected,regionsegments[j]); | ||
326 | |||
327 | amb | 960 | prune_segment(segmentsx,segmentx); |
328 | amb | 953 | |
329 | npruned++; | ||
330 | } | ||
331 | } | ||
332 | else | ||
333 | { | ||
334 | for(j=0;j<nregionsegments;j++) | ||
335 | { | ||
336 | SetBit(connected,regionsegments[j]); | ||
337 | ClearBit(region,regionsegments[j]); | ||
338 | } | ||
339 | |||
340 | for(j=0;j<nothersegments;j++) | ||
341 | { | ||
342 | SetBit(connected,othersegments[j]); | ||
343 | ClearBit(region,othersegments[j]); | ||
344 | } | ||
345 | } | ||
346 | } | ||
347 | |||
348 | if(!((i+1)%10000)) | ||
349 | printf_middle("Pruning Isolated Regions: Segments=%"Pindex_t" Pruned=%"Pindex_t" (%"Pindex_t" Regions)",i+1,npruned,nregions); | ||
350 | } | ||
351 | |||
352 | /* Unmap from memory / close the files */ | ||
353 | |||
354 | free(region); | ||
355 | free(connected); | ||
356 | |||
357 | free(regionsegments); | ||
358 | free(othersegments); | ||
359 | |||
360 | #if !SLIM | ||
361 | nodesx->data=UnmapFile(nodesx->filename); | ||
362 | segmentsx->data=UnmapFile(segmentsx->filename); | ||
363 | amb | 963 | waysx->data=UnmapFile(waysx->filename); |
364 | amb | 953 | #else |
365 | nodesx->fd=CloseFile(nodesx->fd); | ||
366 | segmentsx->fd=CloseFile(segmentsx->fd); | ||
367 | amb | 963 | waysx->fd=CloseFile(waysx->fd); |
368 | amb | 953 | #endif |
369 | |||
370 | /* Print the final message */ | ||
371 | |||
372 | printf_last("Pruned Isolated Regions: Segments=%"Pindex_t" Pruned=%"Pindex_t" (%"Pindex_t" Regions)",segmentsx->number,npruned,nregions); | ||
373 | } | ||
374 | |||
375 | |||
376 | /*++++++++++++++++++++++++++++++++++++++ | ||
377 | amb | 964 | Prune out any segments that are shorter than a specified minimum. |
378 | |||
379 | NodesX *nodesx The set of nodes to use. | ||
380 | |||
381 | SegmentsX *segmentsx The set of segments to use. | ||
382 | |||
383 | WaysX *waysx The set of ways to use. | ||
384 | |||
385 | amb | 966 | distance_t minimum The maximum length to remove or one less than the minimum length to keep. |
386 | amb | 964 | ++++++++++++++++++++++++++++++++++++++*/ |
387 | |||
388 | void PruneShortSegments(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx,distance_t minimum) | ||
389 | { | ||
390 | index_t i; | ||
391 | index_t nshort=0,npruned=0; | ||
392 | |||
393 | if(nodesx->number==0 || segmentsx->number==0 || waysx->number==0) | ||
394 | return; | ||
395 | |||
396 | /* Print the start message */ | ||
397 | |||
398 | printf_first("Pruning Short Segments: Segments=0 Short=0 Pruned=0"); | ||
399 | |||
400 | /* Map into memory / open the files */ | ||
401 | |||
402 | #if !SLIM | ||
403 | nodesx->data=MapFileWriteable(nodesx->filename); | ||
404 | segmentsx->data=MapFileWriteable(segmentsx->filename); | ||
405 | waysx->data=MapFile(waysx->filename); | ||
406 | #else | ||
407 | nodesx->fd=ReOpenFileWriteable(nodesx->filename); | ||
408 | segmentsx->fd=ReOpenFileWriteable(segmentsx->filename); | ||
409 | waysx->fd=ReOpenFile(waysx->filename); | ||
410 | #endif | ||
411 | |||
412 | /* Loop through the segments and find the short ones for possible modification */ | ||
413 | |||
414 | for(i=0;i<segmentsx->number;i++) | ||
415 | { | ||
416 | SegmentX *segmentx2=LookupSegmentX(segmentsx,i,2); | ||
417 | |||
418 | if(IsPrunedSegmentX(segmentx2)) | ||
419 | amb | 966 | goto endloop; |
420 | amb | 964 | |
421 | /* | ||
422 | : | ||
423 | Initial state: ..N3 -------- N2 | ||
424 | : S2 | ||
425 | |||
426 | : | ||
427 | Final state: ..N3 N2 -- | ||
428 | : S2 | ||
429 | |||
430 | = OR = | ||
431 | |||
432 | : : | ||
433 | Initial state: ..N1 -------- N2 ---- N3 -------- N4.. | ||
434 | : S1 S2 S3 : | ||
435 | |||
436 | : : | ||
437 | Final state: ..N1 ------------ N3 ------------ N4.. N2 -- | ||
438 | : S1 S3 : S2 | ||
439 | |||
440 | Not if N1 is the same as N4. | ||
441 | Not if S2 has different one-way properties from S1 and S3. | ||
442 | Must combine N2, S2 and N3 disallowed transports into new N3. | ||
443 | Must not delete N2 or N3 if they are mini-roundabouts. | ||
444 | Must not delete N2 or N3 if they are part of turn relations. | ||
445 | |||
446 | = OR = | ||
447 | |||
448 | : : | ||
449 | Initial state: ..N1 -------- N2 ---- N3.. | ||
450 | : S1 S2 : | ||
451 | |||
452 | : : | ||
453 | Final state: ..N1 ------------ N3.. N2 -- | ||
454 | : S1 : S2 | ||
455 | |||
456 | Not if N1 is the same as N3. | ||
457 | Not if S1 has different one-way properties from S2. | ||
458 | Not if S1 has different highway properties from S2. | ||
459 | Not if N2 disallows transports allowed on S1 and S2. | ||
460 | Not if N2 is a mini-roundabouts. | ||
461 | Not if N2 is involved in a turn restriction. | ||
462 | */ | ||
463 | |||
464 | if(DISTANCE(segmentx2->distance)<=minimum) | ||
465 | { | ||
466 | index_t node1,node2,node3,node4; | ||
467 | index_t segment1=NO_SEGMENT,segment2=i,segment3=NO_SEGMENT; | ||
468 | SegmentX *segmentx; | ||
469 | int segcount2=0,segcount3=0; | ||
470 | |||
471 | nshort++; | ||
472 | |||
473 | node2=segmentx2->node1; | ||
474 | node3=segmentx2->node2; | ||
475 | |||
476 | /* Count the segments connected to N2 and N3 */ | ||
477 | |||
478 | segmentx=FirstSegmentX(segmentsx,node2,4); | ||
479 | |||
480 | while(segmentx) | ||
481 | { | ||
482 | segcount2++; | ||
483 | |||
484 | if(segment1==NO_SEGMENT) | ||
485 | { | ||
486 | index_t segment=IndexSegmentX(segmentsx,segmentx); | ||
487 | |||
488 | if(segment!=segment2) | ||
489 | { | ||
490 | segment1=segment; | ||
491 | node1=OtherNode(segmentx,node2); | ||
492 | } | ||
493 | } | ||
494 | |||
495 | segmentx=NextSegmentX(segmentsx,segmentx,node2); | ||
496 | } | ||
497 | |||
498 | segmentx=FirstSegmentX(segmentsx,node3,4); | ||
499 | |||
500 | while(segmentx) | ||
501 | { | ||
502 | segcount3++; | ||
503 | |||
504 | if(segment3==NO_SEGMENT) | ||
505 | { | ||
506 | index_t segment=IndexSegmentX(segmentsx,segmentx); | ||
507 | |||
508 | if(segment!=segment2) | ||
509 | { | ||
510 | segment3=segment; | ||
511 | node4=OtherNode(segmentx,node3); | ||
512 | } | ||
513 | } | ||
514 | |||
515 | segmentx=NextSegmentX(segmentsx,segmentx,node3); | ||
516 | } | ||
517 | |||
518 | /* Check which case we are handling (and canonicalise) */ | ||
519 | |||
520 | if(segcount2>2 && segcount3>2) /* none of the cases in diagram - too complicated */ | ||
521 | { | ||
522 | goto endloop; | ||
523 | } | ||
524 | else if(segcount2==1 || segcount3==1) /* first case in diagram - prune segment */ | ||
525 | { | ||
526 | prune_segment(segmentsx,segmentx2); | ||
527 | } | ||
528 | else if(segcount2==2 && segcount3==2) /* second case in diagram - modify one segment and prune segment */ | ||
529 | { | ||
530 | SegmentX *segmentx1,*segmentx3; | ||
531 | WayX *wayx1,*wayx2,*wayx3; | ||
532 | NodeX *nodex2,*nodex3,*newnodex; | ||
533 | index_t newnode; | ||
534 | int join12=1,join23=1; | ||
535 | |||
536 | /* Check if pruning would collapse a loop */ | ||
537 | |||
538 | if(node1==node4) | ||
539 | goto endloop; | ||
540 | |||
541 | /* Check if allowed due to one-way properties */ | ||
542 | |||
543 | segmentx1=LookupSegmentX(segmentsx,segment1,1); | ||
544 | segmentx3=LookupSegmentX(segmentsx,segment3,3); | ||
545 | |||
546 | if(!IsOneway(segmentx1) && !IsOneway(segmentx2)) | ||
547 | ; | ||
548 | else if(IsOneway(segmentx1) && IsOneway(segmentx2)) | ||
549 | { | ||
550 | if(IsOnewayTo(segmentx1,node2) && !IsOnewayFrom(segmentx2,node2)) /* S1 is one-way but S2 doesn't continue */ | ||
551 | join12=0; | ||
552 | |||
553 | if(IsOnewayFrom(segmentx1,node2) && !IsOnewayTo(segmentx2,node2)) /* S1 is one-way but S2 doesn't continue */ | ||
554 | join12=0; | ||
555 | } | ||
556 | else | ||
557 | join12=0; | ||
558 | |||
559 | if(!IsOneway(segmentx3) && !IsOneway(segmentx2)) | ||
560 | ; | ||
561 | else if(IsOneway(segmentx3) && IsOneway(segmentx2)) | ||
562 | { | ||
563 | if(IsOnewayTo(segmentx3,node3) && !IsOnewayFrom(segmentx2,node3)) /* S3 is one-way but S2 doesn't continue */ | ||
564 | join23=0; | ||
565 | |||
566 | if(IsOnewayFrom(segmentx3,node3) && !IsOnewayTo(segmentx2,node3)) /* S3 is one-way but S2 doesn't continue */ | ||
567 | join23=0; | ||
568 | } | ||
569 | else | ||
570 | join23=0; | ||
571 | |||
572 | if(!join12 && !join23) | ||
573 | goto endloop; | ||
574 | |||
575 | /* Check if allowed due to mini-roundabout and turn restriction */ | ||
576 | |||
577 | nodex2=LookupNodeX(nodesx,node2,2); | ||
578 | nodex3=LookupNodeX(nodesx,node3,3); | ||
579 | |||
580 | if(nodex2->flags&NODE_MINIRNDBT) | ||
581 | join12=0; | ||
582 | |||
583 | if(nodex3->flags&NODE_MINIRNDBT) | ||
584 | join23=0; | ||
585 | |||
586 | if(nodex2->flags&NODE_TURNRSTRCT2 || nodex2->flags&NODE_TURNRSTRCT) | ||
587 | join12=0; | ||
588 | |||
589 | if(nodex3->flags&NODE_TURNRSTRCT2 || nodex3->flags&NODE_TURNRSTRCT) | ||
590 | join23=0; | ||
591 | |||
592 | if(!join12 && !join23) | ||
593 | goto endloop; | ||
594 | |||
595 | /* New node properties */ | ||
596 | |||
597 | if(join12) | ||
598 | { | ||
599 | newnode=node3; | ||
600 | newnodex=nodex3; | ||
601 | } | ||
602 | else /* if(join23) */ | ||
603 | { | ||
604 | newnode=node2; | ||
605 | newnodex=nodex2; | ||
606 | } | ||
607 | |||
608 | wayx1=LookupWayX(waysx,segmentx1->way,1); | ||
609 | wayx2=LookupWayX(waysx,segmentx2->way,2); | ||
610 | wayx3=LookupWayX(waysx,segmentx3->way,3); | ||
611 | |||
612 | newnodex->allow=nodex2->allow&nodex3->allow; /* combine the restrictions of the two nodes */ | ||
613 | newnodex->allow&=~((~wayx2->way.allow)&wayx3->way.allow); /* disallow anything blocked by segment2 */ | ||
614 | newnodex->allow&=~((~wayx2->way.allow)&wayx1->way.allow); /* disallow anything blocked by segment2 */ | ||
615 | |||
616 | newnodex->latitude =(nodex2->latitude +nodex3->latitude )/2; | ||
617 | newnodex->longitude=(nodex2->longitude+nodex3->longitude)/2; | ||
618 | |||
619 | PutBackNodeX(nodesx,newnodex); | ||
620 | |||
621 | /* Modify segments */ | ||
622 | |||
623 | segmentx1->distance+=DISTANCE(segmentx2->distance)/2; | ||
624 | segmentx3->distance+=DISTANCE(segmentx2->distance)-DISTANCE(segmentx2->distance)/2; | ||
625 | |||
626 | PutBackSegmentX(segmentsx,segmentx1); | ||
627 | PutBackSegmentX(segmentsx,segmentx3); | ||
628 | |||
629 | prune_segment(segmentsx,segmentx2); | ||
630 | |||
631 | if(segmentx1->node1==node1) | ||
632 | { | ||
633 | if(segmentx1->node2!=newnode) | ||
634 | modify_segment(segmentsx,segmentx1,node1,newnode); | ||
635 | } | ||
636 | else /* if(segmentx1->node2==node1) */ | ||
637 | { | ||
638 | if(segmentx1->node1!=newnode) | ||
639 | modify_segment(segmentsx,segmentx1,newnode,node1); | ||
640 | } | ||
641 | |||
642 | if(segmentx3->node1==node4) | ||
643 | { | ||
644 | if(segmentx3->node2!=newnode) | ||
645 | modify_segment(segmentsx,segmentx3,node4,newnode); | ||
646 | } | ||
647 | else /* if(segmentx3->node2==node4) */ | ||
648 | { | ||
649 | if(segmentx3->node1!=newnode) | ||
650 | modify_segment(segmentsx,segmentx3,newnode,node4); | ||
651 | } | ||
652 | } | ||
653 | else /* third case in diagram - prune one segment */ | ||
654 | { | ||
655 | SegmentX *segmentx1; | ||
656 | WayX *wayx1,*wayx2; | ||
657 | NodeX *nodex2; | ||
658 | |||
659 | if(segcount3==2) /* not as in diagram, shuffle things round */ | ||
660 | { | ||
661 | index_t temp; | ||
662 | |||
663 | temp=segment1; segment1=segment3; segment3=temp; | ||
664 | temp=node1; node1=node4; node4=temp; | ||
665 | temp=node2; node2=node3; node3=temp; | ||
666 | } | ||
667 | |||
668 | /* Check if pruning would collapse a loop */ | ||
669 | |||
670 | if(node1==node3) | ||
671 | goto endloop; | ||
672 | |||
673 | /* Check if allowed due to one-way properties */ | ||
674 | |||
675 | segmentx1=LookupSegmentX(segmentsx,segment1,1); | ||
676 | |||
677 | if(!IsOneway(segmentx1) && !IsOneway(segmentx2)) | ||
678 | ; | ||
679 | else if(IsOneway(segmentx1) && IsOneway(segmentx2)) | ||
680 | { | ||
681 | if(IsOnewayTo(segmentx1,node2) && !IsOnewayFrom(segmentx2,node2)) /* S1 is one-way but S2 doesn't continue */ | ||
682 | goto endloop; | ||
683 | |||
684 | if(IsOnewayFrom(segmentx1,node2) && !IsOnewayTo(segmentx2,node2)) /* S1 is one-way but S2 doesn't continue */ | ||
685 | goto endloop; | ||
686 | } | ||
687 | else | ||
688 | goto endloop; | ||
689 | |||
690 | /* Check if allowed due to mini-roundabout and turn restriction */ | ||
691 | |||
692 | nodex2=LookupNodeX(nodesx,node2,2); | ||
693 | |||
694 | if(nodex2->flags&NODE_MINIRNDBT) | ||
695 | goto endloop; | ||
696 | |||
697 | if(nodex2->flags&NODE_TURNRSTRCT2 || nodex2->flags&NODE_TURNRSTRCT) | ||
698 | goto endloop; | ||
699 | |||
700 | /* Check if allowed due to highway properties */ | ||
701 | |||
702 | wayx1=LookupWayX(waysx,segmentx1->way,1); | ||
703 | wayx2=LookupWayX(waysx,segmentx2->way,2); | ||
704 | |||
705 | if(WaysCompare(&wayx1->way,&wayx2->way)) | ||
706 | goto endloop; | ||
707 | |||
708 | /* Check if allowed due to node restrictions */ | ||
709 | |||
710 | if((nodex2->allow&wayx1->way.allow)!=wayx1->way.allow) | ||
711 | goto endloop; | ||
712 | |||
713 | if((nodex2->allow&wayx2->way.allow)!=wayx2->way.allow) | ||
714 | goto endloop; | ||
715 | |||
716 | /* Modify segments */ | ||
717 | |||
718 | segmentx1->distance+=DISTANCE(segmentx2->distance); | ||
719 | |||
720 | PutBackSegmentX(segmentsx,segmentx1); | ||
721 | |||
722 | prune_segment(segmentsx,segmentx2); | ||
723 | |||
724 | if(segmentx1->node1==node1) | ||
725 | modify_segment(segmentsx,segmentx1,node1,node3); | ||
726 | else /* if(segmentx1->node2==node1) */ | ||
727 | modify_segment(segmentsx,segmentx1,node3,node1); | ||
728 | } | ||
729 | |||
730 | npruned++; | ||
731 | } | ||
732 | |||
733 | endloop: | ||
734 | |||
735 | if(!((i+1)%10000)) | ||
736 | printf_middle("Pruning Short Segments: Segments=%"Pindex_t" Short=%"Pindex_t" Pruned=%"Pindex_t,i+1,nshort,npruned); | ||
737 | } | ||
738 | |||
739 | /* Unmap from memory / close the files */ | ||
740 | |||
741 | #if !SLIM | ||
742 | nodesx->data=UnmapFile(nodesx->filename); | ||
743 | segmentsx->data=UnmapFile(segmentsx->filename); | ||
744 | waysx->data=UnmapFile(waysx->filename); | ||
745 | #else | ||
746 | nodesx->fd=CloseFile(nodesx->fd); | ||
747 | segmentsx->fd=CloseFile(segmentsx->fd); | ||
748 | waysx->fd=CloseFile(waysx->fd); | ||
749 | #endif | ||
750 | |||
751 | /* Print the final message */ | ||
752 | |||
753 | printf_last("Pruned Short Segments: Segments=%"Pindex_t" Short=%"Pindex_t" Pruned=%"Pindex_t,segmentsx->number,nshort,npruned); | ||
754 | } | ||
755 | |||
756 | |||
757 | /*++++++++++++++++++++++++++++++++++++++ | ||
758 | amb | 966 | Prune out any nodes from straight highways where the introduced error is smaller than a specified maximum. |
759 | |||
760 | NodesX *nodesx The set of nodes to use. | ||
761 | |||
762 | SegmentsX *segmentsx The set of segments to use. | ||
763 | |||
764 | WaysX *waysx The set of ways to use. | ||
765 | |||
766 | distance_t maximum The maximum error to introduce. | ||
767 | ++++++++++++++++++++++++++++++++++++++*/ | ||
768 | |||
769 | void PruneStraightHighwayNodes(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx,distance_t maximum) | ||
770 | { | ||
771 | index_t i; | ||
772 | index_t npruned=0; | ||
773 | BitMask *checked; | ||
774 | amb | 967 | int nalloc; |
775 | amb | 966 | index_t *nodes,*segments; |
776 | amb | 967 | double *lats,*lons; |
777 | amb | 966 | double maximumf; |
778 | |||
779 | if(nodesx->number==0 || segmentsx->number==0 || waysx->number==0) | ||
780 | return; | ||
781 | |||
782 | maximumf=distance_to_km(maximum); | ||
783 | |||
784 | /* Print the start message */ | ||
785 | |||
786 | printf_first("Pruning Straight Highway Nodes: Nodes=0 Pruned=0"); | ||
787 | |||
788 | /* Map into memory / open the files */ | ||
789 | |||
790 | #if !SLIM | ||
791 | nodesx->data=MapFile(nodesx->filename); | ||
792 | segmentsx->data=MapFileWriteable(segmentsx->filename); | ||
793 | waysx->data=MapFile(waysx->filename); | ||
794 | #else | ||
795 | nodesx->fd=ReOpenFile(nodesx->filename); | ||
796 | segmentsx->fd=ReOpenFileWriteable(segmentsx->filename); | ||
797 | waysx->fd=ReOpenFile(waysx->filename); | ||
798 | #endif | ||
799 | |||
800 | checked=AllocBitMask(nodesx->number); | ||
801 | |||
802 | assert(checked); /* Check AllocBitMask() worked */ | ||
803 | |||
804 | nodes =(index_t*)malloc((nalloc=1024)*sizeof(index_t)); | ||
805 | segments=(index_t*)malloc( nalloc *sizeof(index_t)); | ||
806 | |||
807 | assert(nodes); /* Check malloc() worked */ | ||
808 | assert(segments); /* Check malloc() worked */ | ||
809 | |||
810 | amb | 967 | lats=(double*)malloc(nalloc*sizeof(double)); |
811 | lons=(double*)malloc(nalloc*sizeof(double)); | ||
812 | |||
813 | assert(lats); /* Check malloc() worked */ | ||
814 | assert(lons); /* Check malloc() worked */ | ||
815 | |||
816 | amb | 966 | /* Loop through the nodes and find stretchs of simple highway for possible modification */ |
817 | |||
818 | for(i=0;i<nodesx->number;i++) | ||
819 | { | ||
820 | int lowerbounded=0,upperbounded=0,loop=0; | ||
821 | index_t lower=nalloc/2,current=nalloc/2,upper=nalloc/2; | ||
822 | |||
823 | if(segmentsx->firstnode[i]==NO_SEGMENT) | ||
824 | goto endloop; | ||
825 | |||
826 | if(IsBitSet(checked,i)) | ||
827 | goto endloop; | ||
828 | |||
829 | /* Find all connected nodes */ | ||
830 | |||
831 | nodes[current]=i; | ||
832 | |||
833 | do | ||
834 | { | ||
835 | index_t node1=NO_NODE,node2=NO_NODE; | ||
836 | index_t segment1,segment2; | ||
837 | index_t way1,way2; | ||
838 | int segcount=0; | ||
839 | amb | 967 | NodeX *nodex; |
840 | amb | 966 | |
841 | if(!IsBitSet(checked,nodes[current])) | ||
842 | { | ||
843 | SegmentX *segmentx; | ||
844 | |||
845 | /* Count the segments connected to the node */ | ||
846 | |||
847 | segmentx=FirstSegmentX(segmentsx,nodes[current],1); | ||
848 | |||
849 | while(segmentx) | ||
850 | { | ||
851 | segcount++; | ||
852 | |||
853 | if(node1==NO_NODE) | ||
854 | { | ||
855 | segment1=IndexSegmentX(segmentsx,segmentx); | ||
856 | node1=OtherNode(segmentx,nodes[current]); | ||
857 | way1=segmentx->way; | ||
858 | } | ||
859 | else if(node2==NO_NODE) | ||
860 | { | ||
861 | segment2=IndexSegmentX(segmentsx,segmentx); | ||
862 | node2=OtherNode(segmentx,nodes[current]); | ||
863 | way2=segmentx->way; | ||
864 | } | ||
865 | |||
866 | segmentx=NextSegmentX(segmentsx,segmentx,nodes[current]); | ||
867 | } | ||
868 | } | ||
869 | |||
870 | /* Perform more checks */ | ||
871 | |||
872 | amb | 967 | nodex=LookupNodeX(nodesx,nodes[current],1); |
873 | |||
874 | lats[current]=latlong_to_radians(nodex->latitude); | ||
875 | lons[current]=latlong_to_radians(nodex->longitude); | ||
876 | |||
877 | /* Check if allowed due to mini-roundabout and turn restriction */ | ||
878 | |||
879 | if(nodex->flags&NODE_MINIRNDBT) | ||
880 | segcount=0; | ||
881 | |||
882 | if(nodex->flags&NODE_TURNRSTRCT2 || nodex->flags&NODE_TURNRSTRCT) | ||
883 | segcount=0; | ||
884 | |||
885 | /* Check if allowed due to one-way properties */ | ||
886 | |||
887 | amb | 966 | if(segcount==2) |
888 | { | ||
889 | SegmentX *segmentx1,*segmentx2; | ||
890 | |||
891 | segmentx1=LookupSegmentX(segmentsx,segment1,1); | ||
892 | segmentx2=LookupSegmentX(segmentsx,segment2,2); | ||
893 | |||
894 | if(!IsOneway(segmentx1) && !IsOneway(segmentx2)) | ||
895 | ; | ||
896 | else if(IsOneway(segmentx1) && IsOneway(segmentx2)) | ||
897 | { | ||
898 | if(IsOnewayTo(segmentx1,nodes[current]) && !IsOnewayFrom(segmentx2,nodes[current])) /* S1 is one-way but S2 doesn't continue */ | ||
899 | segcount=0; | ||
900 | |||
901 | if(IsOnewayFrom(segmentx1,nodes[current]) && !IsOnewayTo(segmentx2,nodes[current])) /* S1 is one-way but S2 doesn't continue */ | ||
902 | segcount=0; | ||
903 | } | ||
904 | else | ||
905 | segcount=0; | ||
906 | } | ||
907 | |||
908 | amb | 967 | /* Check if allowed due to highway properties and node restrictions */ |
909 | |||
910 | amb | 966 | if(segcount==2) |
911 | { | ||
912 | WayX *wayx1,*wayx2; | ||
913 | |||
914 | wayx1=LookupWayX(waysx,way1,1); | ||
915 | wayx2=LookupWayX(waysx,way2,2); | ||
916 | |||
917 | if(WaysCompare(&wayx1->way,&wayx2->way)) | ||
918 | segcount=0; | ||
919 | |||
920 | if((nodex->allow&wayx1->way.allow)!=wayx1->way.allow) | ||
921 | segcount=0; | ||
922 | |||
923 | if((nodex->allow&wayx2->way.allow)!=wayx2->way.allow) | ||
924 | segcount=0; | ||
925 | } | ||
926 | |||
927 | /* Update the lists */ | ||
928 | |||
929 | if(segcount==2) | ||
930 | { | ||
931 | amb | 970 | if(upper==(nalloc-1)) |
932 | amb | 966 | { |
933 | nodes =(index_t*)realloc(nodes ,(nalloc+=1024)*sizeof(index_t)); | ||
934 | segments=(index_t*)realloc(segments, nalloc *sizeof(index_t)); | ||
935 | amb | 967 | |
936 | lats=(double*)realloc(lats,nalloc*sizeof(double)); | ||
937 | lons=(double*)realloc(lons,nalloc*sizeof(double)); | ||
938 | amb | 966 | } |
939 | |||
940 | if(lower==0) /* move everything up by one */ | ||
941 | { | ||
942 | memmove(nodes+1 ,nodes ,(upper-lower)*sizeof(index_t)); | ||
943 | memmove(segments+1,segments,(upper-lower)*sizeof(index_t)); | ||
944 | |||
945 | amb | 967 | memmove(lats+1,lats,(upper-lower)*sizeof(double)); |
946 | memmove(lons+1,lons,(upper-lower)*sizeof(double)); | ||
947 | |||
948 | amb | 966 | current++; |
949 | lower++; | ||
950 | upper++; | ||
951 | } | ||
952 | |||
953 | if(lower==upper) /* first */ | ||
954 | { | ||
955 | lower--; | ||
956 | |||
957 | nodes[lower]=node1; | ||
958 | segments[lower]=segment1; | ||
959 | |||
960 | upper++; | ||
961 | |||
962 | nodes[upper]=node2; | ||
963 | segments[upper-1]=segment2; | ||
964 | |||
965 | current--; | ||
966 | } | ||
967 | else if(current==lower) | ||
968 | { | ||
969 | lower--; | ||
970 | |||
971 | if(nodes[current+1]==node2) | ||
972 | { | ||
973 | nodes[lower]=node1; | ||
974 | segments[lower]=segment1; | ||
975 | } | ||
976 | else /* if(nodes[current+1]==node1) */ | ||
977 | { | ||
978 | nodes[lower]=node2; | ||
979 | segments[lower]=segment2; | ||
980 | } | ||
981 | |||
982 | current--; | ||
983 | } | ||
984 | else /* if(current==upper) */ | ||
985 | { | ||
986 | upper++; | ||
987 | |||
988 | if(nodes[current-1]==node2) | ||
989 | { | ||
990 | nodes[upper]=node1; | ||
991 | segments[upper-1]=segment1; | ||
992 | } | ||
993 | else /* if(nodes[current-1]==node1) */ | ||
994 | { | ||
995 | nodes[upper]=node2; | ||
996 | segments[upper-1]=segment2; | ||
997 | } | ||
998 | |||
999 | current++; | ||
1000 | } | ||
1001 | |||
1002 | if(nodes[upper]==nodes[lower]) | ||
1003 | { | ||
1004 | loop=1; | ||
1005 | if(lowerbounded) | ||
1006 | loop++; | ||
1007 | |||
1008 | lowerbounded=1; | ||
1009 | upperbounded=1; | ||
1010 | } | ||
1011 | } | ||
1012 | else | ||
1013 | { | ||
1014 | if(current==upper) | ||
1015 | upperbounded=1; | ||
1016 | |||
1017 | if(current==lower) | ||
1018 | { | ||
1019 | lowerbounded=1; | ||
1020 | current=upper; | ||
1021 | } | ||
1022 | } | ||
1023 | } | ||
1024 | while(!(lowerbounded && upperbounded)); | ||
1025 | |||
1026 | amb | 967 | /* Mark the nodes */ |
1027 | |||
1028 | for(current=lower;current<=upper;current++) | ||
1029 | SetBit(checked,nodes[current]); | ||
1030 | |||
1031 | amb | 966 | /* Check for straight highway */ |
1032 | |||
1033 | while((upper-lower)>=2) | ||
1034 | { | ||
1035 | amb | 967 | index_t bestc=lower; |
1036 | amb | 966 | |
1037 | amb | 967 | for(current=lower+2;current<=upper;current++) |
1038 | amb | 966 | { |
1039 | amb | 967 | double dist1,dist2,dist3,dist3a,dist3b,distp; |
1040 | index_t c; | ||
1041 | amb | 966 | |
1042 | amb | 967 | dist3=distance(lats[lower],lons[lower],lats[current],lons[current]); |
1043 | amb | 966 | |
1044 | amb | 967 | for(c=lower+1;c<current;c++) |
1045 | amb | 966 | { |
1046 | amb | 967 | dist1=distance(lats[lower] ,lons[lower] ,lats[c],lons[c]); |
1047 | dist2=distance(lats[current],lons[current],lats[c],lons[c]); | ||
1048 | amb | 966 | |
1049 | amb | 967 | /* Use law of cosines (assume flat Earth) */ |
1050 | amb | 966 | |
1051 | amb | 967 | dist3a=(dist1*dist1-dist2*dist2+dist3*dist3)/(2.0*dist3); |
1052 | dist3b=dist3-dist3a; | ||
1053 | amb | 966 | |
1054 | amb | 967 | if((dist1+dist2)<dist3) |
1055 | distp=0; | ||
1056 | else if(dist3a>=0 && dist3b>=0) | ||
1057 | distp=sqrt(dist1*dist1-dist3a*dist3a); | ||
1058 | else if(dist3a>0) | ||
1059 | distp=dist2; | ||
1060 | else /* if(dist3b>0) */ | ||
1061 | distp=dist1; | ||
1062 | amb | 966 | |
1063 | amb | 967 | if(distp>maximumf) /* gone too far */ |
1064 | break; | ||
1065 | } | ||
1066 | amb | 966 | |
1067 | amb | 967 | if(c>bestc) |
1068 | bestc=c; | ||
1069 | amb | 966 | |
1070 | amb | 967 | if(bestc>c) |
1071 | c=bestc; | ||
1072 | amb | 966 | |
1073 | amb | 967 | if(c==current && current!=upper) /* Can replace at least this far (not finished yet) */ |
1074 | continue; | ||
1075 | amb | 966 | |
1076 | amb | 967 | if((c-lower)<2) /* first three points are not straight */ |
1077 | { | ||
1078 | lower=c; | ||
1079 | break; | ||
1080 | } | ||
1081 | else /* delete some segments and shift along */ | ||
1082 | { | ||
1083 | SegmentX *segmentx; | ||
1084 | distance_t distance=0; | ||
1085 | amb | 966 | |
1086 | amb | 967 | current=c; |
1087 | amb | 966 | |
1088 | amb | 967 | for(c=lower+1;c<current;c++) |
1089 | { | ||
1090 | segmentx=LookupSegmentX(segmentsx,segments[c],1); | ||
1091 | amb | 966 | |
1092 | amb | 967 | distance+=DISTANCE(segmentx->distance); |
1093 | amb | 966 | |
1094 | amb | 967 | prune_segment(segmentsx,segmentx); |
1095 | amb | 966 | |
1096 | amb | 967 | npruned++; |
1097 | } | ||
1098 | amb | 966 | |
1099 | amb | 967 | segmentx=LookupSegmentX(segmentsx,segments[lower],1); |
1100 | amb | 966 | |
1101 | amb | 970 | if(nodes[lower]==nodes[current]) /* loop; all within maximum distance */ |
1102 | { | ||
1103 | prune_segment(segmentsx,segmentx); | ||
1104 | amb | 966 | |
1105 | amb | 970 | npruned++; |
1106 | } | ||
1107 | else | ||
1108 | { | ||
1109 | segmentx->distance+=distance; | ||
1110 | amb | 966 | |
1111 | amb | 970 | PutBackSegmentX(segmentsx,segmentx); |
1112 | |||
1113 | if(segmentx->node1==nodes[lower]) | ||
1114 | modify_segment(segmentsx,segmentx,nodes[lower],nodes[current]); | ||
1115 | else /* if(segmentx->node2==nodes[lower]) */ | ||
1116 | modify_segment(segmentsx,segmentx,nodes[current],nodes[lower]); | ||
1117 | } | ||
1118 | |||
1119 | amb | 967 | lower=current; |
1120 | break; | ||
1121 | amb | 966 | } |
1122 | } | ||
1123 | } | ||
1124 | |||
1125 | endloop: | ||
1126 | |||
1127 | SetBit(checked,i); | ||
1128 | |||
1129 | if(!((i+1)%10000)) | ||
1130 | printf_middle("Pruning Straight Highway Nodes: Nodes=%"Pindex_t" Pruned=%"Pindex_t,i+1,npruned); | ||
1131 | } | ||
1132 | |||
1133 | /* Unmap from memory / close the files */ | ||
1134 | |||
1135 | free(checked); | ||
1136 | |||
1137 | free(nodes); | ||
1138 | free(segments); | ||
1139 | |||
1140 | amb | 967 | free(lats); |
1141 | free(lons); | ||
1142 | |||
1143 | amb | 966 | #if !SLIM |
1144 | nodesx->data=UnmapFile(nodesx->filename); | ||
1145 | segmentsx->data=UnmapFile(segmentsx->filename); | ||
1146 | waysx->data=UnmapFile(waysx->filename); | ||
1147 | #else | ||
1148 | nodesx->fd=CloseFile(nodesx->fd); | ||
1149 | segmentsx->fd=CloseFile(segmentsx->fd); | ||
1150 | waysx->fd=CloseFile(waysx->fd); | ||
1151 | #endif | ||
1152 | |||
1153 | /* Print the final message */ | ||
1154 | |||
1155 | printf_last("Pruned Straight Highway Nodes: Nodes=%"Pindex_t" Pruned=%"Pindex_t,nodesx->number,npruned); | ||
1156 | } | ||
1157 | |||
1158 | |||
1159 | /*++++++++++++++++++++++++++++++++++++++ | ||
1160 | amb | 960 | Prune a segment; unused nodes and ways will get marked for pruning later. |
1161 | amb | 953 | |
1162 | SegmentsX *segmentsx The set of segments to use. | ||
1163 | |||
1164 | SegmentX *segmentx The segment to be pruned. | ||
1165 | ++++++++++++++++++++++++++++++++++++++*/ | ||
1166 | |||
1167 | amb | 960 | static void prune_segment(SegmentsX *segmentsx,SegmentX *segmentx) |
1168 | amb | 953 | { |
1169 | amb | 970 | unlink_segment_node1_refs(segmentsx,segmentx); |
1170 | unlink_segment_node2_refs(segmentsx,segmentx); | ||
1171 | amb | 953 | |
1172 | segmentx->node1=NO_NODE; | ||
1173 | segmentx->node2=NO_NODE; | ||
1174 | segmentx->next2=NO_SEGMENT; | ||
1175 | |||
1176 | PutBackSegmentX(segmentsx,segmentx); | ||
1177 | } | ||
1178 | |||
1179 | |||
1180 | /*++++++++++++++++++++++++++++++++++++++ | ||
1181 | amb | 960 | Modify a segment's nodes; unused nodes will get marked for pruning later. |
1182 | amb | 949 | |
1183 | SegmentsX *segmentsx The set of segments to use. | ||
1184 | |||
1185 | SegmentX *segmentx The segment to be modified. | ||
1186 | |||
1187 | index_t newnode1 The new value of node1. | ||
1188 | |||
1189 | index_t newnode2 The new value of node2. | ||
1190 | ++++++++++++++++++++++++++++++++++++++*/ | ||
1191 | |||
1192 | static void modify_segment(SegmentsX *segmentsx,SegmentX *segmentx,index_t newnode1,index_t newnode2) | ||
1193 | { | ||
1194 | index_t thissegment=IndexSegmentX(segmentsx,segmentx); | ||
1195 | |||
1196 | amb | 964 | assert(newnode1!=newnode2); |
1197 | |||
1198 | amb | 970 | if(newnode1>newnode2) /* rotate the segment around */ |
1199 | amb | 949 | { |
1200 | amb | 968 | index_t temp; |
1201 | |||
1202 | if(segmentx->distance&(ONEWAY_2TO1|ONEWAY_1TO2)) | ||
1203 | segmentx->distance^=ONEWAY_2TO1|ONEWAY_1TO2; | ||
1204 | |||
1205 | amb | 970 | PutBackSegmentX(segmentsx,segmentx); |
1206 | |||
1207 | amb | 968 | temp=newnode1; |
1208 | newnode1=newnode2; | ||
1209 | newnode2=temp; | ||
1210 | amb | 970 | } |
1211 | amb | 968 | |
1212 | amb | 970 | if(newnode1!=segmentx->node1) |
1213 | unlink_segment_node1_refs(segmentsx,segmentx); | ||
1214 | amb | 968 | |
1215 | amb | 970 | if(newnode2!=segmentx->node2) |
1216 | unlink_segment_node2_refs(segmentsx,segmentx); | ||
1217 | amb | 949 | |
1218 | amb | 968 | if(newnode1!=segmentx->node1) /* only modify it if the node has changed */ |
1219 | { | ||
1220 | amb | 949 | segmentx->node1=newnode1; |
1221 | |||
1222 | segmentsx->next1[thissegment]=segmentsx->firstnode[newnode1]; | ||
1223 | segmentsx->firstnode[newnode1]=thissegment; | ||
1224 | amb | 970 | |
1225 | PutBackSegmentX(segmentsx,segmentx); | ||
1226 | amb | 949 | } |
1227 | |||
1228 | amb | 968 | if(newnode2!=segmentx->node2) /* only modify it if the node has changed */ |
1229 | amb | 949 | { |
1230 | segmentx->node2=newnode2; | ||
1231 | |||
1232 | segmentx->next2=segmentsx->firstnode[newnode2]; | ||
1233 | segmentsx->firstnode[newnode2]=thissegment; | ||
1234 | amb | 970 | |
1235 | PutBackSegmentX(segmentsx,segmentx); | ||
1236 | amb | 949 | } |
1237 | } | ||
1238 | |||
1239 | |||
1240 | /*++++++++++++++++++++++++++++++++++++++ | ||
1241 | amb | 970 | Unlink a node1 from a segment by modifying the linked list type arrangement of node references. |
1242 | amb | 949 | |
1243 | SegmentsX *segmentsx The set of segments to use. | ||
1244 | |||
1245 | amb | 970 | SegmentX *segmentx The segment to be modified. |
1246 | amb | 949 | ++++++++++++++++++++++++++++++++++++++*/ |
1247 | |||
1248 | amb | 970 | static void unlink_segment_node1_refs(SegmentsX *segmentsx,SegmentX *segmentx) |
1249 | amb | 949 | { |
1250 | amb | 970 | index_t segment,thissegment; |
1251 | amb | 949 | |
1252 | amb | 970 | thissegment=IndexSegmentX(segmentsx,segmentx); |
1253 | amb | 953 | |
1254 | amb | 970 | segment=segmentsx->firstnode[segmentx->node1]; |
1255 | |||
1256 | amb | 949 | if(segment==thissegment) |
1257 | amb | 970 | segmentsx->firstnode[segmentx->node1]=segmentsx->next1[thissegment]; |
1258 | amb | 949 | else |
1259 | { | ||
1260 | do | ||
1261 | { | ||
1262 | amb | 970 | index_t nextsegment; |
1263 | amb | 964 | SegmentX *segx=LookupSegmentX(segmentsx,segment,4); |
1264 | amb | 949 | |
1265 | amb | 970 | if(segx->node1==segmentx->node1) |
1266 | amb | 949 | { |
1267 | nextsegment=segmentsx->next1[segment]; | ||
1268 | |||
1269 | amb | 970 | if(nextsegment==thissegment) |
1270 | segmentsx->next1[segment]=segmentsx->next1[thissegment]; | ||
1271 | } | ||
1272 | else /* if(segx->node2==segmentx->node1) */ | ||
1273 | { | ||
1274 | nextsegment=segx->next2; | ||
1275 | |||
1276 | if(nextsegment==thissegment) | ||
1277 | amb | 949 | { |
1278 | amb | 970 | segx->next2=segmentsx->next1[thissegment]; |
1279 | |||
1280 | PutBackSegmentX(segmentsx,segx); | ||
1281 | amb | 949 | } |
1282 | } | ||
1283 | amb | 970 | |
1284 | segment=nextsegment; | ||
1285 | } | ||
1286 | while(segment!=thissegment && segment!=NO_SEGMENT); | ||
1287 | } | ||
1288 | } | ||
1289 | |||
1290 | |||
1291 | /*++++++++++++++++++++++++++++++++++++++ | ||
1292 | Unlink a node2 from a segment by modifying the linked list type arrangement of node references. | ||
1293 | |||
1294 | SegmentsX *segmentsx The set of segments to use. | ||
1295 | |||
1296 | SegmentX *segmentx The segment to be modified. | ||
1297 | ++++++++++++++++++++++++++++++++++++++*/ | ||
1298 | |||
1299 | static void unlink_segment_node2_refs(SegmentsX *segmentsx,SegmentX *segmentx) | ||
1300 | { | ||
1301 | index_t segment,thissegment; | ||
1302 | |||
1303 | thissegment=IndexSegmentX(segmentsx,segmentx); | ||
1304 | |||
1305 | segment=segmentsx->firstnode[segmentx->node2]; | ||
1306 | |||
1307 | if(segment==thissegment) | ||
1308 | segmentsx->firstnode[segmentx->node2]=segmentx->next2; | ||
1309 | else | ||
1310 | { | ||
1311 | do | ||
1312 | { | ||
1313 | index_t nextsegment; | ||
1314 | SegmentX *segx=LookupSegmentX(segmentsx,segment,4); | ||
1315 | |||
1316 | if(segx->node1==segmentx->node2) | ||
1317 | amb | 949 | { |
1318 | amb | 970 | nextsegment=segmentsx->next1[segment]; |
1319 | |||
1320 | if(nextsegment==thissegment) | ||
1321 | segmentsx->next1[segment]=segmentx->next2; | ||
1322 | } | ||
1323 | else /* if(segx->node2==segmentx->node2) */ | ||
1324 | { | ||
1325 | amb | 949 | nextsegment=segx->next2; |
1326 | |||
1327 | amb | 970 | if(nextsegment==thissegment) |
1328 | amb | 949 | { |
1329 | amb | 970 | segx->next2=segmentx->next2; |
1330 | amb | 949 | |
1331 | PutBackSegmentX(segmentsx,segx); | ||
1332 | } | ||
1333 | } | ||
1334 | |||
1335 | segment=nextsegment; | ||
1336 | } | ||
1337 | amb | 953 | while(segment!=thissegment && segment!=NO_SEGMENT); |
1338 | amb | 949 | } |
1339 | } | ||
1340 | amb | 966 | |
1341 | |||
1342 | /*++++++++++++++++++++++++++++++++++++++ | ||
1343 | Calculate the distance between two locations. | ||
1344 | |||
1345 | double distance Returns the distance between the locations. | ||
1346 | |||
1347 | double lat1 The latitude of the first location. | ||
1348 | |||
1349 | double lon1 The longitude of the first location. | ||
1350 | |||
1351 | double lat2 The latitude of the second location. | ||
1352 | |||
1353 | double lon2 The longitude of the second location. | ||
1354 | ++++++++++++++++++++++++++++++++++++++*/ | ||
1355 | |||
1356 | static double distance(double lat1,double lon1,double lat2,double lon2) | ||
1357 | { | ||
1358 | double dlon = lon1 - lon2; | ||
1359 | double dlat = lat1 - lat2; | ||
1360 | |||
1361 | double a1,a2,a,sa,c,d; | ||
1362 | |||
1363 | if(dlon==0 && dlat==0) | ||
1364 | return 0; | ||
1365 | |||
1366 | a1 = sin (dlat / 2); | ||
1367 | a2 = sin (dlon / 2); | ||
1368 | a = (a1 * a1) + cos (lat1) * cos (lat2) * a2 * a2; | ||
1369 | sa = sqrt (a); | ||
1370 | if (sa <= 1.0) | ||
1371 | {c = 2 * asin (sa);} | ||
1372 | else | ||
1373 | {c = 2 * asin (1.0);} | ||
1374 | d = 6378.137 * c; | ||
1375 | |||
1376 | return(d); | ||
1377 | } |