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 970 - (hide annotations) (download) (as text)
Sun Feb 19 16:56:45 2012 UTC (13 years, 1 month ago) by amb
File MIME type: text/x-csrc
File size: 37992 byte(s)
Some fixes to be able to process the whole of the UK.

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