Routino SVN Repository Browser

Check out the latest version of Routino: svn co http://routino.org/svn/trunk routino

ViewVC logotype

Annotation of /branches/destination-access/src/prunex.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1408 - (hide annotations) (download) (as text)
Fri Jun 21 14:43:37 2013 UTC (11 years, 9 months ago) by amb
Original Path: trunk/src/prunex.c
File MIME type: text/x-csrc
File size: 41357 byte(s)
Use the new functions for buffering while reading when looping through files
other than the ones already done that use the FILESORT_VARINT method of storing
data.

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