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 1208 - (hide annotations) (download) (as text)
Sat Dec 15 16:43:03 2012 UTC (12 years, 3 months ago) by amb
File MIME type: text/x-csrc
File size: 40312 byte(s)
Stop planetsplitter crashing out in unusual ways if there is no data.

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