Routino SVN Repository Browser

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

ViewVC logotype

Annotation of /trunk/src/prunex.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1448 - (hide annotations) (download) (as text)
Tue Jul 2 17:52:01 2013 UTC (11 years, 9 months ago) by amb
File MIME type: text/x-csrc
File size: 41956 byte(s)
Revert r1432 because even though it seemed like it should have been faster in
slim mode it was actually much slower on the routino.org virtual server.

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