Routino SVN Repository Browser

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

ViewVC logotype

Annotation of /trunk/src/prunex.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1017 - (hide annotations) (download) (as text)
Wed Jul 11 18:29:05 2012 UTC (12 years, 8 months ago) by amb
File MIME type: text/x-csrc
File size: 37850 byte(s)
Fix bug with pruning straight highways (uninitialised data).

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