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 1442 - (hide annotations) (download) (as text)
Sat Jun 29 18:24:48 2013 UTC (11 years, 9 months ago) by amb
Original Path: trunk/src/prunex.c
File MIME type: text/x-csrc
File size: 42191 byte(s)
Close file and free memory (found by valgrind).

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