Routino SVN Repository Browser

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

ViewVC logotype

Contents of /branches/2.4.1-dev/src/prunex.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1213 - (show annotations) (download) (as text)
Mon Dec 17 09:25:17 2012 UTC (12 years, 3 months ago) by amb
File MIME type: text/x-csrc
File size: 40312 byte(s)
Merge revisions 1191, 1193, 1198, 1208 and 1210 from trunk into 2.4.1 branch.

1 /***************************************
2 Data pruning functions.
3
4 Part of the Routino routing software.
5 ******************/ /******************
6 This file Copyright 2011-2012 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 N2 --
457 : S2
458
459 = OR =
460
461 : :
462 Initial state: ..N1 -------- N2 ---- N3 -------- N4..
463 : S1 S2 S3 :
464
465 : :
466 Final state: ..N1 ------------ N3 ------------ N4.. N2 --
467 : S1 S3 : S2
468
469 Not if N1 is the same as N4.
470 Not if S2 has different one-way properties from S1 and S3.
471 Must combine N2, S2 and N3 disallowed transports into new N3.
472 Must not delete N2 or N3 if they are mini-roundabouts.
473 Must not delete N2 or N3 if they are part of turn relations.
474
475 = OR =
476
477 : :
478 Initial state: ..N1 -------- N2 ---- N3..
479 : S1 S2 :
480
481 : :
482 Final state: ..N1 ------------ N3.. N2 --
483 : S1 : S2
484
485 Not if N1 is the same as N3.
486 Not if S1 has different one-way properties from S2.
487 Not if S1 has different highway properties from S2.
488 Not if N2 disallows transports allowed on S1 and S2.
489 Not if N2 is a mini-roundabouts.
490 Not if N2 is involved in a turn restriction.
491 */
492
493 if(DISTANCE(segmentx2->distance)<=minimum)
494 {
495 index_t node1=NO_NODE,node2,node3,node4=NO_NODE;
496 index_t segment1=NO_SEGMENT,segment2=i,segment3=NO_SEGMENT;
497 SegmentX *segmentx;
498 int segcount2=0,segcount3=0;
499
500 nshort++;
501
502 node2=segmentx2->node1;
503 node3=segmentx2->node2;
504
505 /* Count the segments connected to N2 and N3 */
506
507 segmentx=FirstSegmentX(segmentsx,node2,4);
508
509 while(segmentx)
510 {
511 segcount2++;
512
513 if(segment1==NO_SEGMENT)
514 {
515 index_t segment=IndexSegmentX(segmentsx,segmentx);
516
517 if(segment!=segment2)
518 {
519 segment1=segment;
520 node1=OtherNode(segmentx,node2);
521 }
522 }
523 else if(segcount2>2)
524 break;
525
526 segmentx=NextSegmentX(segmentsx,segmentx,node2);
527 }
528
529 segmentx=FirstSegmentX(segmentsx,node3,4);
530
531 while(segmentx)
532 {
533 segcount3++;
534
535 if(segment3==NO_SEGMENT)
536 {
537 index_t segment=IndexSegmentX(segmentsx,segmentx);
538
539 if(segment!=segment2)
540 {
541 segment3=segment;
542 node4=OtherNode(segmentx,node3);
543 }
544 }
545 else if(segcount3>2)
546 break;
547
548 segmentx=NextSegmentX(segmentsx,segmentx,node3);
549 }
550
551 /* Check which case we are handling (and canonicalise) */
552
553 if(segcount2>2 && segcount3>2) /* none of the cases in diagram - too complicated */
554 {
555 goto endloop;
556 }
557 else if(segcount2==1 || segcount3==1) /* first case in diagram - prune segment */
558 {
559 prune_segment(segmentsx,segmentx2);
560 }
561 else if(segcount2==2 && segcount3==2) /* second case in diagram - modify one segment and prune segment */
562 {
563 SegmentX *segmentx1,*segmentx3;
564 WayX *wayx1,*wayx2,*wayx3;
565 NodeX *nodex2,*nodex3,*newnodex;
566 index_t newnode;
567 int join12=1,join23=1;
568
569 /* Check if pruning would collapse a loop */
570
571 if(node1==node4)
572 goto endloop;
573
574 /* Check if allowed due to one-way properties */
575
576 segmentx1=LookupSegmentX(segmentsx,segment1,1);
577 segmentx3=LookupSegmentX(segmentsx,segment3,3);
578
579 if(!IsOneway(segmentx1) && !IsOneway(segmentx2))
580 ;
581 else if(IsOneway(segmentx1) && IsOneway(segmentx2))
582 {
583 if(IsOnewayTo(segmentx1,node2) && !IsOnewayFrom(segmentx2,node2)) /* S1 is one-way but S2 doesn't continue */
584 join12=0;
585
586 if(IsOnewayFrom(segmentx1,node2) && !IsOnewayTo(segmentx2,node2)) /* S1 is one-way but S2 doesn't continue */
587 join12=0;
588 }
589 else
590 join12=0;
591
592 if(!IsOneway(segmentx3) && !IsOneway(segmentx2))
593 ;
594 else if(IsOneway(segmentx3) && IsOneway(segmentx2))
595 {
596 if(IsOnewayTo(segmentx3,node3) && !IsOnewayFrom(segmentx2,node3)) /* S3 is one-way but S2 doesn't continue */
597 join23=0;
598
599 if(IsOnewayFrom(segmentx3,node3) && !IsOnewayTo(segmentx2,node3)) /* S3 is one-way but S2 doesn't continue */
600 join23=0;
601 }
602 else
603 join23=0;
604
605 if(!join12 && !join23)
606 goto endloop;
607
608 /* Check if allowed due to mini-roundabout and turn restriction */
609
610 nodex2=LookupNodeX(nodesx,node2,2);
611 nodex3=LookupNodeX(nodesx,node3,3);
612
613 if(nodex2->flags&NODE_MINIRNDBT)
614 join12=0;
615
616 if(nodex3->flags&NODE_MINIRNDBT)
617 join23=0;
618
619 if(nodex2->flags&NODE_TURNRSTRCT2 || nodex2->flags&NODE_TURNRSTRCT)
620 join12=0;
621
622 if(nodex3->flags&NODE_TURNRSTRCT2 || nodex3->flags&NODE_TURNRSTRCT)
623 join23=0;
624
625 if(!join12 && !join23)
626 goto endloop;
627
628 /* New node properties */
629
630 if(join12)
631 {
632 newnode=node3;
633 newnodex=nodex3;
634 }
635 else /* if(join23) */
636 {
637 newnode=node2;
638 newnodex=nodex2;
639 }
640
641 wayx1=LookupWayX(waysx,segmentx1->way,1);
642 wayx2=LookupWayX(waysx,segmentx2->way,2);
643 wayx3=LookupWayX(waysx,segmentx3->way,3);
644
645 newnodex->allow=nodex2->allow&nodex3->allow; /* combine the restrictions of the two nodes */
646 newnodex->allow&=~((~wayx2->way.allow)&wayx3->way.allow); /* disallow anything blocked by segment2 */
647 newnodex->allow&=~((~wayx2->way.allow)&wayx1->way.allow); /* disallow anything blocked by segment2 */
648
649 newnodex->latitude =(nodex2->latitude +nodex3->latitude )/2;
650 newnodex->longitude=(nodex2->longitude+nodex3->longitude)/2;
651
652 PutBackNodeX(nodesx,newnodex);
653
654 /* Modify segments */
655
656 segmentx1->distance+=DISTANCE(segmentx2->distance)/2;
657 segmentx3->distance+=DISTANCE(segmentx2->distance)-DISTANCE(segmentx2->distance)/2;
658
659 if(segmentx1->node1==node1)
660 {
661 if(segmentx1->node2!=newnode)
662 modify_segment(segmentsx,segmentx1,node1,newnode);
663 else
664 PutBackSegmentX(segmentsx,segmentx1);
665 }
666 else /* if(segmentx1->node2==node1) */
667 {
668 if(segmentx1->node1!=newnode)
669 modify_segment(segmentsx,segmentx1,newnode,node1);
670 else
671 PutBackSegmentX(segmentsx,segmentx1);
672 }
673
674 if(segmentx3->node1==node4)
675 {
676 if(segmentx3->node2!=newnode)
677 modify_segment(segmentsx,segmentx3,node4,newnode);
678 else
679 PutBackSegmentX(segmentsx,segmentx3);
680 }
681 else /* if(segmentx3->node2==node4) */
682 {
683 if(segmentx3->node1!=newnode)
684 modify_segment(segmentsx,segmentx3,newnode,node4);
685 else
686 PutBackSegmentX(segmentsx,segmentx3);
687 }
688
689 ReLookupSegmentX(segmentsx,segmentx2);
690
691 prune_segment(segmentsx,segmentx2);
692 }
693 else /* third case in diagram - prune one segment */
694 {
695 SegmentX *segmentx1;
696 WayX *wayx1,*wayx2;
697 NodeX *nodex2;
698
699 if(segcount3==2) /* not as in diagram, shuffle things round */
700 {
701 index_t temp;
702
703 temp=segment1; segment1=segment3; segment3=temp;
704 temp=node1; node1=node4; node4=temp;
705 temp=node2; node2=node3; node3=temp;
706 }
707
708 /* Check if pruning would collapse a loop */
709
710 if(node1==node3)
711 goto endloop;
712
713 /* Check if allowed due to one-way properties */
714
715 segmentx1=LookupSegmentX(segmentsx,segment1,1);
716
717 if(!IsOneway(segmentx1) && !IsOneway(segmentx2))
718 ;
719 else if(IsOneway(segmentx1) && IsOneway(segmentx2))
720 {
721 if(IsOnewayTo(segmentx1,node2) && !IsOnewayFrom(segmentx2,node2)) /* S1 is one-way but S2 doesn't continue */
722 goto endloop;
723
724 if(IsOnewayFrom(segmentx1,node2) && !IsOnewayTo(segmentx2,node2)) /* S1 is one-way but S2 doesn't continue */
725 goto endloop;
726 }
727 else
728 goto endloop;
729
730 /* Check if allowed due to highway properties */
731
732 wayx1=LookupWayX(waysx,segmentx1->way,1);
733 wayx2=LookupWayX(waysx,segmentx2->way,2);
734
735 if(WaysCompare(&wayx1->way,&wayx2->way))
736 goto endloop;
737
738 /* Check if allowed due to mini-roundabout and turn restriction */
739
740 nodex2=LookupNodeX(nodesx,node2,2);
741
742 if(nodex2->flags&NODE_MINIRNDBT)
743 goto endloop;
744
745 if(nodex2->flags&NODE_TURNRSTRCT2 || nodex2->flags&NODE_TURNRSTRCT)
746 goto endloop;
747
748 /* Check if allowed due to node restrictions */
749
750 if((nodex2->allow&wayx1->way.allow)!=wayx1->way.allow)
751 goto endloop;
752
753 if((nodex2->allow&wayx2->way.allow)!=wayx2->way.allow)
754 goto endloop;
755
756 /* Modify segments */
757
758 segmentx1->distance+=DISTANCE(segmentx2->distance);
759
760 if(segmentx1->node1==node1)
761 modify_segment(segmentsx,segmentx1,node1,node3);
762 else /* if(segmentx1->node2==node1) */
763 modify_segment(segmentsx,segmentx1,node3,node1);
764
765 ReLookupSegmentX(segmentsx,segmentx2);
766
767 prune_segment(segmentsx,segmentx2);
768 }
769
770 npruned++;
771 }
772
773 endloop:
774
775 if(!((i+1)%10000))
776 printf_middle("Pruning Short Segments: Segments=%"Pindex_t" Short=%"Pindex_t" Pruned=%"Pindex_t,i+1,nshort,npruned);
777 }
778
779 /* Unmap from memory / close the files */
780
781 #if !SLIM
782 nodesx->data=UnmapFile(nodesx->data);
783 segmentsx->data=UnmapFile(segmentsx->data);
784 waysx->data=UnmapFile(waysx->data);
785 #else
786 nodesx->fd=CloseFile(nodesx->fd);
787 segmentsx->fd=CloseFile(segmentsx->fd);
788 waysx->fd=CloseFile(waysx->fd);
789 #endif
790
791 /* Print the final message */
792
793 printf_last("Pruned Short Segments: Segments=%"Pindex_t" Short=%"Pindex_t" Pruned=%"Pindex_t,segmentsx->number,nshort,npruned);
794 }
795
796
797 /*++++++++++++++++++++++++++++++++++++++
798 Prune out any nodes from straight highways where the introduced error is smaller than a specified maximum.
799
800 NodesX *nodesx The set of nodes to use.
801
802 SegmentsX *segmentsx The set of segments to use.
803
804 WaysX *waysx The set of ways to use.
805
806 distance_t maximum The maximum error to introduce.
807 ++++++++++++++++++++++++++++++++++++++*/
808
809 void PruneStraightHighwayNodes(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx,distance_t maximum)
810 {
811 index_t i;
812 index_t npruned=0;
813 BitMask *checked;
814 int nalloc;
815 index_t *nodes,*segments;
816 double *lats,*lons;
817 double maximumf;
818
819 if(nodesx->number==0 || segmentsx->number==0 || waysx->number==0)
820 return;
821
822 maximumf=distance_to_km(maximum);
823
824 /* Print the start message */
825
826 printf_first("Pruning Straight Highway Nodes: Nodes=0 Pruned=0");
827
828 /* Map into memory / open the files */
829
830 #if !SLIM
831 nodesx->data=MapFile(nodesx->filename_tmp);
832 segmentsx->data=MapFileWriteable(segmentsx->filename_tmp);
833 waysx->data=MapFile(waysx->filename_tmp);
834 #else
835 nodesx->fd=ReOpenFile(nodesx->filename_tmp);
836 segmentsx->fd=ReOpenFileWriteable(segmentsx->filename_tmp);
837 waysx->fd=ReOpenFile(waysx->filename_tmp);
838 #endif
839
840 checked=AllocBitMask(nodesx->number);
841
842 logassert(checked,"Failed to allocate memory (try using slim mode?)"); /* Check AllocBitMask() worked */
843
844 nodes =(index_t*)malloc((nalloc=1024)*sizeof(index_t));
845 segments=(index_t*)malloc( nalloc *sizeof(index_t));
846
847 logassert(nodes,"Failed to allocate memory (try using slim mode?)"); /* Check malloc() worked */
848 logassert(segments,"Failed to allocate memory (try using slim mode?)"); /* Check malloc() worked */
849
850 lats=(double*)malloc(nalloc*sizeof(double));
851 lons=(double*)malloc(nalloc*sizeof(double));
852
853 logassert(lats,"Failed to allocate memory (try using slim mode?)"); /* Check malloc() worked */
854 logassert(lons,"Failed to allocate memory (try using slim mode?)"); /* Check malloc() worked */
855
856 /* Loop through the nodes and find stretchs of simple highway for possible modification */
857
858 for(i=0;i<nodesx->number;i++)
859 {
860 int lowerbounded=0,upperbounded=0;
861 index_t lower=nalloc/2,current=nalloc/2,upper=nalloc/2;
862
863 if(IsBitSet(checked,i))
864 goto endloop;
865
866 if(segmentsx->firstnode[i]==NO_SEGMENT)
867 goto endloop;
868
869 /* Find all connected nodes */
870
871 nodes[current]=i;
872
873 do
874 {
875 index_t node1=NO_NODE,node2=NO_NODE;
876 index_t segment1=NO_SEGMENT,segment2=NO_SEGMENT;
877 index_t way1=NO_WAY,way2=NO_WAY;
878 int segcount=0;
879 NodeX *nodex;
880
881 /* Get the node data */
882
883 nodex=LookupNodeX(nodesx,nodes[current],1);
884
885 lats[current]=latlong_to_radians(nodex->latitude);
886 lons[current]=latlong_to_radians(nodex->longitude);
887
888 /* Count the segments at the node if not forced to be an end node */
889
890 if(IsBitSet(checked,nodes[current]))
891 ;
892 else if(nodex->flags&NODE_MINIRNDBT)
893 ;
894 else if(nodex->flags&NODE_TURNRSTRCT2 || nodex->flags&NODE_TURNRSTRCT)
895 ;
896 else
897 {
898 SegmentX *segmentx;
899
900 /* Count the segments connected to the node */
901
902 segmentx=FirstSegmentX(segmentsx,nodes[current],1);
903
904 while(segmentx)
905 {
906 segcount++;
907
908 if(node1==NO_NODE)
909 {
910 segment1=IndexSegmentX(segmentsx,segmentx);
911 node1=OtherNode(segmentx,nodes[current]);
912 way1=segmentx->way;
913 }
914 else if(node2==NO_NODE)
915 {
916 segment2=IndexSegmentX(segmentsx,segmentx);
917 node2=OtherNode(segmentx,nodes[current]);
918 way2=segmentx->way;
919 }
920 else
921 break;
922
923 segmentx=NextSegmentX(segmentsx,segmentx,nodes[current]);
924 }
925 }
926
927 /* Check if allowed due to one-way properties */
928
929 if(segcount==2)
930 {
931 SegmentX *segmentx1,*segmentx2;
932
933 segmentx1=LookupSegmentX(segmentsx,segment1,1);
934 segmentx2=LookupSegmentX(segmentsx,segment2,2);
935
936 if(!IsOneway(segmentx1) && !IsOneway(segmentx2))
937 ;
938 else if(IsOneway(segmentx1) && IsOneway(segmentx2))
939 {
940 if(IsOnewayTo(segmentx1,nodes[current]) && !IsOnewayFrom(segmentx2,nodes[current])) /* S1 is one-way but S2 doesn't continue */
941 segcount=0;
942
943 if(IsOnewayFrom(segmentx1,nodes[current]) && !IsOnewayTo(segmentx2,nodes[current])) /* S1 is one-way but S2 doesn't continue */
944 segcount=0;
945 }
946 else
947 segcount=0;
948 }
949
950 /* Check if allowed due to highway properties and node restrictions */
951
952 if(segcount==2)
953 {
954 WayX *wayx1,*wayx2;
955
956 wayx1=LookupWayX(waysx,way1,1);
957 wayx2=LookupWayX(waysx,way2,2);
958
959 if(WaysCompare(&wayx1->way,&wayx2->way))
960 segcount=0;
961
962 if(wayx1->way.name!=wayx2->way.name)
963 segcount=0;
964
965 if((nodex->allow&wayx1->way.allow)!=wayx1->way.allow)
966 segcount=0;
967
968 if((nodex->allow&wayx2->way.allow)!=wayx2->way.allow)
969 segcount=0;
970 }
971
972 /* Update the lists */
973
974 if(segcount==2)
975 {
976 if(upper==(nalloc-1))
977 {
978 nodes =(index_t*)realloc(nodes ,(nalloc+=1024)*sizeof(index_t));
979 segments=(index_t*)realloc(segments, nalloc *sizeof(index_t));
980
981 lats=(double*)realloc(lats,nalloc*sizeof(double));
982 lons=(double*)realloc(lons,nalloc*sizeof(double));
983 }
984
985 if(lower==0) /* move everything up by one */
986 {
987 memmove(nodes+1 ,nodes ,(1+upper-lower)*sizeof(index_t));
988 memmove(segments+1,segments,(1+upper-lower)*sizeof(index_t));
989
990 memmove(lats+1,lats,(1+upper-lower)*sizeof(double));
991 memmove(lons+1,lons,(1+upper-lower)*sizeof(double));
992
993 current++;
994 lower++;
995 upper++;
996 }
997
998 if(lower==upper) /* first */
999 {
1000 lower--;
1001
1002 nodes[lower]=node1;
1003 segments[lower]=segment1;
1004
1005 upper++;
1006
1007 nodes[upper]=node2;
1008 segments[upper-1]=segment2;
1009
1010 current--;
1011 }
1012 else if(current==lower)
1013 {
1014 lower--;
1015
1016 if(nodes[current+1]==node2)
1017 {
1018 nodes[lower]=node1;
1019 segments[lower]=segment1;
1020 }
1021 else /* if(nodes[current+1]==node1) */
1022 {
1023 nodes[lower]=node2;
1024 segments[lower]=segment2;
1025 }
1026
1027 current--;
1028 }
1029 else /* if(current==upper) */
1030 {
1031 upper++;
1032
1033 if(nodes[current-1]==node2)
1034 {
1035 nodes[upper]=node1;
1036 segments[upper-1]=segment1;
1037 }
1038 else /* if(nodes[current-1]==node1) */
1039 {
1040 nodes[upper]=node2;
1041 segments[upper-1]=segment2;
1042 }
1043
1044 current++;
1045 }
1046
1047 if(nodes[upper]==nodes[lower])
1048 {
1049 lowerbounded=1;
1050 upperbounded=1;
1051 }
1052 }
1053 else
1054 {
1055 if(current==upper)
1056 upperbounded=1;
1057
1058 if(current==lower)
1059 {
1060 lowerbounded=1;
1061 current=upper;
1062 }
1063 }
1064 }
1065 while(!(lowerbounded && upperbounded));
1066
1067 /* Mark the nodes */
1068
1069 for(current=lower;current<=upper;current++)
1070 SetBit(checked,nodes[current]);
1071
1072 /* Check for straight highway */
1073
1074 while((upper-lower)>=2)
1075 {
1076 index_t bestc=lower;
1077
1078 for(current=lower+2;current<=upper;current++)
1079 {
1080 double dist1,dist2,dist3,dist3a,dist3b,distp;
1081 index_t c;
1082
1083 dist3=distance(lats[lower],lons[lower],lats[current],lons[current]);
1084
1085 for(c=lower+1;c<current;c++)
1086 {
1087 dist1=distance(lats[lower] ,lons[lower] ,lats[c],lons[c]);
1088 dist2=distance(lats[current],lons[current],lats[c],lons[c]);
1089
1090 /* Use law of cosines (assume flat Earth) */
1091
1092 dist3a=(dist1*dist1-dist2*dist2+dist3*dist3)/(2.0*dist3);
1093 dist3b=dist3-dist3a;
1094
1095 if((dist1+dist2)<dist3)
1096 distp=0;
1097 else if(dist3a>=0 && dist3b>=0)
1098 distp=sqrt(dist1*dist1-dist3a*dist3a);
1099 else if(dist3a>0)
1100 distp=dist2;
1101 else /* if(dist3b>0) */
1102 distp=dist1;
1103
1104 if(distp>maximumf) /* gone too far */
1105 break;
1106 }
1107
1108 if(c>bestc)
1109 bestc=c;
1110
1111 if(bestc>c)
1112 c=bestc;
1113
1114 if(c==current && current!=upper) /* Can replace at least this far (not finished yet) */
1115 continue;
1116
1117 if((c-lower)<2) /* first three points are not straight */
1118 {
1119 lower=c;
1120 break;
1121 }
1122 else /* delete some segments and shift along */
1123 {
1124 SegmentX *segmentx;
1125 distance_t distance=0;
1126
1127 current=c;
1128
1129 for(c=lower+1;c<current;c++)
1130 {
1131 segmentx=LookupSegmentX(segmentsx,segments[c],1);
1132
1133 distance+=DISTANCE(segmentx->distance);
1134
1135 prune_segment(segmentsx,segmentx);
1136
1137 npruned++;
1138 }
1139
1140 segmentx=LookupSegmentX(segmentsx,segments[lower],1);
1141
1142 if(nodes[lower]==nodes[current]) /* loop; all within maximum distance */
1143 {
1144 prune_segment(segmentsx,segmentx);
1145
1146 npruned++;
1147 }
1148 else
1149 {
1150 segmentx->distance+=distance;
1151
1152 if(segmentx->node1==nodes[lower])
1153 modify_segment(segmentsx,segmentx,nodes[lower],nodes[current]);
1154 else /* if(segmentx->node2==nodes[lower]) */
1155 modify_segment(segmentsx,segmentx,nodes[current],nodes[lower]);
1156 }
1157
1158 lower=current;
1159 break;
1160 }
1161 }
1162 }
1163
1164 endloop:
1165
1166 if(!((i+1)%10000))
1167 printf_middle("Pruning Straight Highway Nodes: Nodes=%"Pindex_t" Pruned=%"Pindex_t,i+1,npruned);
1168 }
1169
1170 /* Unmap from memory / close the files */
1171
1172 free(checked);
1173
1174 free(nodes);
1175 free(segments);
1176
1177 free(lats);
1178 free(lons);
1179
1180 #if !SLIM
1181 nodesx->data=UnmapFile(nodesx->data);
1182 segmentsx->data=UnmapFile(segmentsx->data);
1183 waysx->data=UnmapFile(waysx->data);
1184 #else
1185 nodesx->fd=CloseFile(nodesx->fd);
1186 segmentsx->fd=CloseFile(segmentsx->fd);
1187 waysx->fd=CloseFile(waysx->fd);
1188 #endif
1189
1190 /* Print the final message */
1191
1192 printf_last("Pruned Straight Highway Nodes: Nodes=%"Pindex_t" Pruned=%"Pindex_t,nodesx->number,npruned);
1193 }
1194
1195
1196 /*++++++++++++++++++++++++++++++++++++++
1197 Prune a segment; unused nodes and ways will get marked for pruning later.
1198
1199 SegmentsX *segmentsx The set of segments to use.
1200
1201 SegmentX *segmentx The segment to be pruned.
1202 ++++++++++++++++++++++++++++++++++++++*/
1203
1204 static void prune_segment(SegmentsX *segmentsx,SegmentX *segmentx)
1205 {
1206 unlink_segment_node1_refs(segmentsx,segmentx);
1207
1208 unlink_segment_node2_refs(segmentsx,segmentx);
1209
1210 segmentx->node1=NO_NODE;
1211 segmentx->node2=NO_NODE;
1212 segmentx->next2=NO_SEGMENT;
1213
1214 PutBackSegmentX(segmentsx,segmentx);
1215 }
1216
1217
1218 /*++++++++++++++++++++++++++++++++++++++
1219 Modify a segment's nodes; unused nodes will get marked for pruning later.
1220
1221 SegmentsX *segmentsx The set of segments to use.
1222
1223 SegmentX *segmentx The segment to be modified.
1224
1225 index_t newnode1 The new value of node1.
1226
1227 index_t newnode2 The new value of node2.
1228 ++++++++++++++++++++++++++++++++++++++*/
1229
1230 static void modify_segment(SegmentsX *segmentsx,SegmentX *segmentx,index_t newnode1,index_t newnode2)
1231 {
1232 index_t thissegment=IndexSegmentX(segmentsx,segmentx);
1233
1234 if(newnode1>newnode2) /* rotate the segment around */
1235 {
1236 index_t temp;
1237
1238 if(segmentx->distance&(ONEWAY_2TO1|ONEWAY_1TO2))
1239 segmentx->distance^=ONEWAY_2TO1|ONEWAY_1TO2;
1240
1241 temp=newnode1;
1242 newnode1=newnode2;
1243 newnode2=temp;
1244 }
1245
1246 if(newnode1!=segmentx->node1)
1247 unlink_segment_node1_refs(segmentsx,segmentx);
1248
1249 if(newnode2!=segmentx->node2)
1250 unlink_segment_node2_refs(segmentsx,segmentx);
1251
1252 if(newnode1!=segmentx->node1) /* only modify it if the node has changed */
1253 {
1254 segmentx->node1=newnode1;
1255
1256 segmentsx->next1[thissegment]=segmentsx->firstnode[newnode1];
1257 segmentsx->firstnode[newnode1]=thissegment;
1258 }
1259
1260 if(newnode2!=segmentx->node2) /* only modify it if the node has changed */
1261 {
1262 segmentx->node2=newnode2;
1263
1264 segmentx->next2=segmentsx->firstnode[newnode2];
1265 segmentsx->firstnode[newnode2]=thissegment;
1266 }
1267
1268 PutBackSegmentX(segmentsx,segmentx);
1269 }
1270
1271
1272 /*++++++++++++++++++++++++++++++++++++++
1273 Unlink a node1 from a segment by modifying the linked list type arrangement of node references.
1274
1275 SegmentsX *segmentsx The set of segments to use.
1276
1277 SegmentX *segmentx The segment to be modified.
1278 ++++++++++++++++++++++++++++++++++++++*/
1279
1280 static void unlink_segment_node1_refs(SegmentsX *segmentsx,SegmentX *segmentx)
1281 {
1282 index_t segment,thissegment;
1283
1284 thissegment=IndexSegmentX(segmentsx,segmentx);
1285
1286 segment=segmentsx->firstnode[segmentx->node1];
1287
1288 if(segment==thissegment)
1289 segmentsx->firstnode[segmentx->node1]=segmentsx->next1[thissegment];
1290 else
1291 {
1292 do
1293 {
1294 index_t nextsegment;
1295 SegmentX *segx=LookupSegmentX(segmentsx,segment,4);
1296
1297 if(segx->node1==segmentx->node1)
1298 {
1299 nextsegment=segmentsx->next1[segment];
1300
1301 if(nextsegment==thissegment)
1302 segmentsx->next1[segment]=segmentsx->next1[thissegment];
1303 }
1304 else /* if(segx->node2==segmentx->node1) */
1305 {
1306 nextsegment=segx->next2;
1307
1308 if(nextsegment==thissegment)
1309 {
1310 segx->next2=segmentsx->next1[thissegment];
1311
1312 PutBackSegmentX(segmentsx,segx);
1313 }
1314 }
1315
1316 segment=nextsegment;
1317 }
1318 while(segment!=thissegment && segment!=NO_SEGMENT);
1319 }
1320 }
1321
1322
1323 /*++++++++++++++++++++++++++++++++++++++
1324 Unlink a node2 from a segment by modifying the linked list type arrangement of node references.
1325
1326 SegmentsX *segmentsx The set of segments to use.
1327
1328 SegmentX *segmentx The segment to be modified.
1329 ++++++++++++++++++++++++++++++++++++++*/
1330
1331 static void unlink_segment_node2_refs(SegmentsX *segmentsx,SegmentX *segmentx)
1332 {
1333 index_t segment,thissegment;
1334
1335 thissegment=IndexSegmentX(segmentsx,segmentx);
1336
1337 segment=segmentsx->firstnode[segmentx->node2];
1338
1339 if(segment==thissegment)
1340 segmentsx->firstnode[segmentx->node2]=segmentx->next2;
1341 else
1342 {
1343 do
1344 {
1345 index_t nextsegment;
1346 SegmentX *segx=LookupSegmentX(segmentsx,segment,4);
1347
1348 if(segx->node1==segmentx->node2)
1349 {
1350 nextsegment=segmentsx->next1[segment];
1351
1352 if(nextsegment==thissegment)
1353 segmentsx->next1[segment]=segmentx->next2;
1354 }
1355 else /* if(segx->node2==segmentx->node2) */
1356 {
1357 nextsegment=segx->next2;
1358
1359 if(nextsegment==thissegment)
1360 {
1361 segx->next2=segmentx->next2;
1362
1363 PutBackSegmentX(segmentsx,segx);
1364 }
1365 }
1366
1367 segment=nextsegment;
1368 }
1369 while(segment!=thissegment && segment!=NO_SEGMENT);
1370 }
1371 }
1372
1373
1374 /*++++++++++++++++++++++++++++++++++++++
1375 Calculate the distance between two locations.
1376
1377 double distance Returns the distance between the locations.
1378
1379 double lat1 The latitude of the first location.
1380
1381 double lon1 The longitude of the first location.
1382
1383 double lat2 The latitude of the second location.
1384
1385 double lon2 The longitude of the second location.
1386 ++++++++++++++++++++++++++++++++++++++*/
1387
1388 static double distance(double lat1,double lon1,double lat2,double lon2)
1389 {
1390 double dlon = lon1 - lon2;
1391 double dlat = lat1 - lat2;
1392
1393 double a1,a2,a,sa,c,d;
1394
1395 if(dlon==0 && dlat==0)
1396 return 0;
1397
1398 a1 = sin (dlat / 2);
1399 a2 = sin (dlon / 2);
1400 a = (a1 * a1) + cos (lat1) * cos (lat2) * a2 * a2;
1401 sa = sqrt (a);
1402 if (sa <= 1.0)
1403 {c = 2 * asin (sa);}
1404 else
1405 {c = 2 * asin (1.0);}
1406 d = 6378.137 * c;
1407
1408 return(d);
1409 }