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 966 - (hide annotations) (download) (as text)
Sat Feb 18 10:36:35 2012 UTC (13 years, 1 month ago) by amb
File MIME type: text/x-csrc
File size: 36026 byte(s)
Prune nodes in the middle of straight highways.

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