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 1380 - (show annotations) (download) (as text)
Tue Jun 4 19:03:55 2013 UTC (11 years, 9 months ago) by amb
File MIME type: text/x-csrc
File size: 41187 byte(s)
Remember what types of transports we have so that we don't spend time pruning
for transport types we don't have.

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