Routino SVN Repository Browser

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

ViewVC logotype

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1990 - (show annotations) (download) (as text)
Wed Apr 17 18:01:27 2019 UTC (5 years, 11 months ago) by amb
File MIME type: text/x-csrc
File size: 43261 byte(s)
Merge from trunk (signed/unsigned, sanitizer and name changes).

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