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 1124 - (hide annotations) (download) (as text)
Sat Nov 3 11:31:18 2012 UTC (12 years, 5 months ago) by amb
File MIME type: text/x-csrc
File size: 39573 byte(s)
Append the new ways directly to the end of the existing ways rather than using a
new file.

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