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 967 - (hide annotations) (download) (as text)
Sat Feb 18 13:24:41 2012 UTC (13 years, 1 month ago) by amb
File MIME type: text/x-csrc
File size: 36352 byte(s)
Refactored the code for straight highways and made improvements.

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 amb 967 int nalloc;
778 amb 966 index_t *nodes,*segments;
779 amb 967 double *lats,*lons;
780 amb 966 double maximumf;
781    
782     if(nodesx->number==0 || segmentsx->number==0 || waysx->number==0)
783     return;
784    
785     maximumf=distance_to_km(maximum);
786    
787     /* Print the start message */
788    
789     printf_first("Pruning Straight Highway Nodes: Nodes=0 Pruned=0");
790    
791     /* Map into memory / open the files */
792    
793     #if !SLIM
794     nodesx->data=MapFile(nodesx->filename);
795     segmentsx->data=MapFileWriteable(segmentsx->filename);
796     waysx->data=MapFile(waysx->filename);
797     #else
798     nodesx->fd=ReOpenFile(nodesx->filename);
799     segmentsx->fd=ReOpenFileWriteable(segmentsx->filename);
800     waysx->fd=ReOpenFile(waysx->filename);
801     #endif
802    
803     checked=AllocBitMask(nodesx->number);
804    
805     assert(checked); /* Check AllocBitMask() worked */
806    
807     nodes =(index_t*)malloc((nalloc=1024)*sizeof(index_t));
808     segments=(index_t*)malloc( nalloc *sizeof(index_t));
809    
810     assert(nodes); /* Check malloc() worked */
811     assert(segments); /* Check malloc() worked */
812    
813 amb 967 lats=(double*)malloc(nalloc*sizeof(double));
814     lons=(double*)malloc(nalloc*sizeof(double));
815    
816     assert(lats); /* Check malloc() worked */
817     assert(lons); /* Check malloc() worked */
818    
819 amb 966 /* Loop through the nodes and find stretchs of simple highway for possible modification */
820    
821     for(i=0;i<nodesx->number;i++)
822     {
823     int lowerbounded=0,upperbounded=0,loop=0;
824     index_t lower=nalloc/2,current=nalloc/2,upper=nalloc/2;
825    
826     if(segmentsx->firstnode[i]==NO_SEGMENT)
827     goto endloop;
828    
829     if(IsBitSet(checked,i))
830     goto endloop;
831    
832     /* Find all connected nodes */
833    
834     nodes[current]=i;
835    
836     do
837     {
838     index_t node1=NO_NODE,node2=NO_NODE;
839     index_t segment1,segment2;
840     index_t way1,way2;
841     int segcount=0;
842 amb 967 NodeX *nodex;
843 amb 966
844     if(!IsBitSet(checked,nodes[current]))
845     {
846     SegmentX *segmentx;
847    
848     /* Count the segments connected to the node */
849    
850     segmentx=FirstSegmentX(segmentsx,nodes[current],1);
851    
852     while(segmentx)
853     {
854     segcount++;
855    
856     if(node1==NO_NODE)
857     {
858     segment1=IndexSegmentX(segmentsx,segmentx);
859     node1=OtherNode(segmentx,nodes[current]);
860     way1=segmentx->way;
861     }
862     else if(node2==NO_NODE)
863     {
864     segment2=IndexSegmentX(segmentsx,segmentx);
865     node2=OtherNode(segmentx,nodes[current]);
866     way2=segmentx->way;
867     }
868    
869     segmentx=NextSegmentX(segmentsx,segmentx,nodes[current]);
870     }
871     }
872    
873     /* Perform more checks */
874    
875 amb 967 nodex=LookupNodeX(nodesx,nodes[current],1);
876    
877     lats[current]=latlong_to_radians(nodex->latitude);
878     lons[current]=latlong_to_radians(nodex->longitude);
879    
880     /* Check if allowed due to mini-roundabout and turn restriction */
881    
882     if(nodex->flags&NODE_MINIRNDBT)
883     segcount=0;
884    
885     if(nodex->flags&NODE_TURNRSTRCT2 || nodex->flags&NODE_TURNRSTRCT)
886     segcount=0;
887    
888     /* Check if allowed due to one-way properties */
889    
890 amb 966 if(segcount==2)
891     {
892     SegmentX *segmentx1,*segmentx2;
893    
894     segmentx1=LookupSegmentX(segmentsx,segment1,1);
895     segmentx2=LookupSegmentX(segmentsx,segment2,2);
896    
897     if(!IsOneway(segmentx1) && !IsOneway(segmentx2))
898     ;
899     else if(IsOneway(segmentx1) && IsOneway(segmentx2))
900     {
901     if(IsOnewayTo(segmentx1,nodes[current]) && !IsOnewayFrom(segmentx2,nodes[current])) /* S1 is one-way but S2 doesn't continue */
902     segcount=0;
903    
904     if(IsOnewayFrom(segmentx1,nodes[current]) && !IsOnewayTo(segmentx2,nodes[current])) /* S1 is one-way but S2 doesn't continue */
905     segcount=0;
906     }
907     else
908     segcount=0;
909     }
910    
911 amb 967 /* Check if allowed due to highway properties and node restrictions */
912    
913 amb 966 if(segcount==2)
914     {
915     WayX *wayx1,*wayx2;
916    
917     wayx1=LookupWayX(waysx,way1,1);
918     wayx2=LookupWayX(waysx,way2,2);
919    
920     if(WaysCompare(&wayx1->way,&wayx2->way))
921     segcount=0;
922    
923     if((nodex->allow&wayx1->way.allow)!=wayx1->way.allow)
924     segcount=0;
925    
926     if((nodex->allow&wayx2->way.allow)!=wayx2->way.allow)
927     segcount=0;
928     }
929    
930     /* Update the lists */
931    
932     if(segcount==2)
933     {
934     if((upper-lower)==(nalloc-1))
935     {
936     nodes =(index_t*)realloc(nodes ,(nalloc+=1024)*sizeof(index_t));
937     segments=(index_t*)realloc(segments, nalloc *sizeof(index_t));
938 amb 967
939     lats=(double*)realloc(lats,nalloc*sizeof(double));
940     lons=(double*)realloc(lons,nalloc*sizeof(double));
941 amb 966 }
942    
943     if(lower==0) /* move everything up by one */
944     {
945     memmove(nodes+1 ,nodes ,(upper-lower)*sizeof(index_t));
946     memmove(segments+1,segments,(upper-lower)*sizeof(index_t));
947    
948 amb 967 memmove(lats+1,lats,(upper-lower)*sizeof(double));
949     memmove(lons+1,lons,(upper-lower)*sizeof(double));
950    
951 amb 966 current++;
952     lower++;
953     upper++;
954     }
955    
956     if(lower==upper) /* first */
957     {
958     lower--;
959    
960     nodes[lower]=node1;
961     segments[lower]=segment1;
962    
963     upper++;
964    
965     nodes[upper]=node2;
966     segments[upper-1]=segment2;
967    
968     current--;
969     }
970     else if(current==lower)
971     {
972     lower--;
973    
974     if(nodes[current+1]==node2)
975     {
976     nodes[lower]=node1;
977     segments[lower]=segment1;
978     }
979     else /* if(nodes[current+1]==node1) */
980     {
981     nodes[lower]=node2;
982     segments[lower]=segment2;
983     }
984    
985     current--;
986     }
987     else /* if(current==upper) */
988     {
989     upper++;
990    
991     if(nodes[current-1]==node2)
992     {
993     nodes[upper]=node1;
994     segments[upper-1]=segment1;
995     }
996     else /* if(nodes[current-1]==node1) */
997     {
998     nodes[upper]=node2;
999     segments[upper-1]=segment2;
1000     }
1001    
1002     current++;
1003     }
1004    
1005     if(nodes[upper]==nodes[lower])
1006     {
1007     loop=1;
1008     if(lowerbounded)
1009     loop++;
1010    
1011     lowerbounded=1;
1012     upperbounded=1;
1013     }
1014     }
1015     else
1016     {
1017     if(current==upper)
1018     upperbounded=1;
1019    
1020     if(current==lower)
1021     {
1022     lowerbounded=1;
1023     current=upper;
1024     }
1025     }
1026     }
1027     while(!(lowerbounded && upperbounded));
1028    
1029 amb 967 /* Mark the nodes */
1030    
1031     for(current=lower;current<=upper;current++)
1032     SetBit(checked,nodes[current]);
1033    
1034 amb 966 /* Check for straight highway */
1035    
1036     while((upper-lower)>=2)
1037     {
1038 amb 967 index_t bestc=lower;
1039 amb 966
1040 amb 967 for(current=lower+2;current<=upper;current++)
1041 amb 966 {
1042 amb 967 double dist1,dist2,dist3,dist3a,dist3b,distp;
1043     index_t c;
1044 amb 966
1045 amb 967 dist3=distance(lats[lower],lons[lower],lats[current],lons[current]);
1046 amb 966
1047 amb 967 for(c=lower+1;c<current;c++)
1048 amb 966 {
1049 amb 967 dist1=distance(lats[lower] ,lons[lower] ,lats[c],lons[c]);
1050     dist2=distance(lats[current],lons[current],lats[c],lons[c]);
1051 amb 966
1052 amb 967 /* Use law of cosines (assume flat Earth) */
1053 amb 966
1054 amb 967 dist3a=(dist1*dist1-dist2*dist2+dist3*dist3)/(2.0*dist3);
1055     dist3b=dist3-dist3a;
1056 amb 966
1057 amb 967 if((dist1+dist2)<dist3)
1058     distp=0;
1059     else if(dist3a>=0 && dist3b>=0)
1060     distp=sqrt(dist1*dist1-dist3a*dist3a);
1061     else if(dist3a>0)
1062     distp=dist2;
1063     else /* if(dist3b>0) */
1064     distp=dist1;
1065 amb 966
1066 amb 967 if(distp>maximumf) /* gone too far */
1067     break;
1068     }
1069 amb 966
1070 amb 967 if(c>bestc)
1071     bestc=c;
1072 amb 966
1073 amb 967 if(bestc>c)
1074     c=bestc;
1075 amb 966
1076 amb 967 if(c==current && current!=upper) /* Can replace at least this far (not finished yet) */
1077     continue;
1078 amb 966
1079 amb 967 if((c-lower)<2) /* first three points are not straight */
1080     {
1081     lower=c;
1082     break;
1083     }
1084     else /* delete some segments and shift along */
1085     {
1086     SegmentX *segmentx;
1087     distance_t distance=0;
1088 amb 966
1089 amb 967 current=c;
1090 amb 966
1091 amb 967 for(c=lower+1;c<current;c++)
1092     {
1093     segmentx=LookupSegmentX(segmentsx,segments[c],1);
1094 amb 966
1095 amb 967 distance+=DISTANCE(segmentx->distance);
1096 amb 966
1097 amb 967 prune_segment(segmentsx,segmentx);
1098 amb 966
1099 amb 967 npruned++;
1100     }
1101 amb 966
1102 amb 967 segmentx=LookupSegmentX(segmentsx,segments[lower],1);
1103 amb 966
1104 amb 967 segmentx->distance+=distance;
1105 amb 966
1106 amb 967 if(segmentx->node1==nodes[lower])
1107     modify_segment(segmentsx,segmentx,nodes[lower],nodes[current]);
1108     else /* if(segmentx->node2==nodes[lower]) */
1109     modify_segment(segmentsx,segmentx,nodes[current],nodes[lower]);
1110 amb 966
1111 amb 967 lower=current;
1112     break;
1113 amb 966 }
1114     }
1115     }
1116    
1117     endloop:
1118    
1119     SetBit(checked,i);
1120    
1121     if(!((i+1)%10000))
1122     printf_middle("Pruning Straight Highway Nodes: Nodes=%"Pindex_t" Pruned=%"Pindex_t,i+1,npruned);
1123     }
1124    
1125     /* Unmap from memory / close the files */
1126    
1127     free(checked);
1128    
1129     free(nodes);
1130     free(segments);
1131    
1132 amb 967 free(lats);
1133     free(lons);
1134    
1135 amb 966 #if !SLIM
1136     nodesx->data=UnmapFile(nodesx->filename);
1137     segmentsx->data=UnmapFile(segmentsx->filename);
1138     waysx->data=UnmapFile(waysx->filename);
1139     #else
1140     nodesx->fd=CloseFile(nodesx->fd);
1141     segmentsx->fd=CloseFile(segmentsx->fd);
1142     waysx->fd=CloseFile(waysx->fd);
1143     #endif
1144    
1145     /* Print the final message */
1146    
1147     printf_last("Pruned Straight Highway Nodes: Nodes=%"Pindex_t" Pruned=%"Pindex_t,nodesx->number,npruned);
1148     }
1149    
1150    
1151     /*++++++++++++++++++++++++++++++++++++++
1152 amb 960 Prune a segment; unused nodes and ways will get marked for pruning later.
1153 amb 953
1154     SegmentsX *segmentsx The set of segments to use.
1155    
1156     SegmentX *segmentx The segment to be pruned.
1157     ++++++++++++++++++++++++++++++++++++++*/
1158    
1159 amb 960 static void prune_segment(SegmentsX *segmentsx,SegmentX *segmentx)
1160 amb 953 {
1161     unlink_segment_node_refs(segmentsx,segmentx,segmentx->node1);
1162     unlink_segment_node_refs(segmentsx,segmentx,segmentx->node2);
1163    
1164     segmentx->node1=NO_NODE;
1165     segmentx->node2=NO_NODE;
1166     segmentx->next2=NO_SEGMENT;
1167    
1168     PutBackSegmentX(segmentsx,segmentx);
1169     }
1170    
1171    
1172     /*++++++++++++++++++++++++++++++++++++++
1173 amb 960 Modify a segment's nodes; unused nodes will get marked for pruning later.
1174 amb 949
1175     SegmentsX *segmentsx The set of segments to use.
1176    
1177     SegmentX *segmentx The segment to be modified.
1178    
1179     index_t newnode1 The new value of node1.
1180    
1181     index_t newnode2 The new value of node2.
1182     ++++++++++++++++++++++++++++++++++++++*/
1183    
1184     static void modify_segment(SegmentsX *segmentsx,SegmentX *segmentx,index_t newnode1,index_t newnode2)
1185     {
1186     index_t thissegment=IndexSegmentX(segmentsx,segmentx);
1187    
1188 amb 964 assert(newnode1!=newnode2);
1189    
1190 amb 949 if(newnode1!=segmentx->node1)
1191     {
1192     unlink_segment_node_refs(segmentsx,segmentx,segmentx->node1);
1193    
1194     segmentx->node1=newnode1;
1195    
1196     segmentsx->next1[thissegment]=segmentsx->firstnode[newnode1];
1197     segmentsx->firstnode[newnode1]=thissegment;
1198     }
1199    
1200 amb 964 if(newnode2!=segmentx->node2)
1201 amb 949 {
1202     unlink_segment_node_refs(segmentsx,segmentx,segmentx->node2);
1203    
1204     segmentx->node2=newnode2;
1205    
1206     segmentx->next2=segmentsx->firstnode[newnode2];
1207     segmentsx->firstnode[newnode2]=thissegment;
1208     }
1209    
1210     PutBackSegmentX(segmentsx,segmentx);
1211     }
1212    
1213    
1214     /*++++++++++++++++++++++++++++++++++++++
1215     Unlink one node from a segment by modifying the linked list type arrangement of node references.
1216    
1217     SegmentsX *segmentsx The set of segments to use.
1218    
1219     SegmentX *segmentx The segment to be pruned.
1220    
1221     index_t node The node index of the end of the segment being modified here.
1222     ++++++++++++++++++++++++++++++++++++++*/
1223    
1224     static void unlink_segment_node_refs(SegmentsX *segmentsx,SegmentX *segmentx,index_t node)
1225     {
1226     index_t thissegment=IndexSegmentX(segmentsx,segmentx);
1227     index_t segment=segmentsx->firstnode[node];
1228    
1229 amb 953 if(segment==NO_SEGMENT)
1230     return;
1231    
1232 amb 949 if(segment==thissegment)
1233     {
1234     if(segmentx->node1==node)
1235     segmentsx->firstnode[node]=segmentsx->next1[thissegment];
1236     else
1237     segmentsx->firstnode[node]=segmentx->next2;
1238     }
1239     else
1240     {
1241     index_t nextsegment;
1242    
1243     do
1244     {
1245 amb 964 SegmentX *segx=LookupSegmentX(segmentsx,segment,4);
1246 amb 949
1247     if(segx->node1==node)
1248     {
1249     nextsegment=segmentsx->next1[segment];
1250    
1251     if(thissegment==nextsegment)
1252     {
1253     if(segmentx->node1==node)
1254     segmentsx->next1[segment]=segmentsx->next1[thissegment];
1255     else
1256     segmentsx->next1[segment]=segmentx->next2;
1257     }
1258     }
1259     else
1260     {
1261     nextsegment=segx->next2;
1262    
1263     if(thissegment==nextsegment)
1264     {
1265     if(segmentx->node1==node)
1266     segx->next2=segmentsx->next1[thissegment];
1267     else
1268     segx->next2=segmentx->next2;
1269    
1270     PutBackSegmentX(segmentsx,segx);
1271     }
1272     }
1273    
1274     segment=nextsegment;
1275     }
1276 amb 953 while(segment!=thissegment && segment!=NO_SEGMENT);
1277 amb 949 }
1278     }
1279 amb 966
1280    
1281     /*++++++++++++++++++++++++++++++++++++++
1282     Calculate the distance between two locations.
1283    
1284     double distance Returns the distance between the locations.
1285    
1286     double lat1 The latitude of the first location.
1287    
1288     double lon1 The longitude of the first location.
1289    
1290     double lat2 The latitude of the second location.
1291    
1292     double lon2 The longitude of the second location.
1293     ++++++++++++++++++++++++++++++++++++++*/
1294    
1295     static double distance(double lat1,double lon1,double lat2,double lon2)
1296     {
1297     double dlon = lon1 - lon2;
1298     double dlat = lat1 - lat2;
1299    
1300     double a1,a2,a,sa,c,d;
1301    
1302     if(dlon==0 && dlat==0)
1303     return 0;
1304    
1305     a1 = sin (dlat / 2);
1306     a2 = sin (dlon / 2);
1307     a = (a1 * a1) + cos (lat1) * cos (lat2) * a2 * a2;
1308     sa = sqrt (a);
1309     if (sa <= 1.0)
1310     {c = 2 * asin (sa);}
1311     else
1312     {c = 2 * asin (1.0);}
1313     d = 6378.137 * c;
1314    
1315     return(d);
1316     }