Routino SVN Repository Browser

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

ViewVC logotype

Contents of /trunk/src/prunex.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1265 - (show annotations) (download) (as text)
Sun Mar 3 15:55:27 2013 UTC (12 years ago) by amb
File MIME type: text/x-csrc
File size: 41236 byte(s)
Add a test case for pruning straight segments.  Found an error case related to
loops and fixed it.

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