Routino SVN Repository Browser

Check out the latest version of Routino: svn co http://routino.org/svn/trunk routino

ViewVC logotype

Contents of /trunk/src/prunex.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1098 - (show annotations) (download) (as text)
Sat Oct 20 12:52:01 2012 UTC (12 years, 5 months ago) by amb
File MIME type: text/x-csrc
File size: 36805 byte(s)
Delete the pruned nodes before searching for super-nodes etc.

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