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/relationsx.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1138 - (show annotations) (download) (as text)
Mon Nov 12 19:24:09 2012 UTC (12 years, 4 months ago) by amb
File MIME type: text/x-csrc
File size: 37436 byte(s)
Fix mis-use of NO_WAY/NO_WAY_ID and NO_RELATION/NO_RELATION_ID constants in
route relation handling.

1 /***************************************
2 Extended Relation data type functions.
3
4 Part of the Routino routing software.
5 ******************/ /******************
6 This file Copyright 2010-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 <assert.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include "types.h"
28 #include "segments.h"
29 #include "relations.h"
30
31 #include "nodesx.h"
32 #include "segmentsx.h"
33 #include "waysx.h"
34 #include "relationsx.h"
35
36 #include "files.h"
37 #include "logging.h"
38 #include "sorting.h"
39
40
41 /* Global variables */
42
43 /*+ The command line '--tmpdir' option or its default value. +*/
44 extern char *option_tmpdirname;
45
46 /* Local functions */
47
48 static int sort_route_by_id(RouteRelX *a,RouteRelX *b);
49 static int deduplicate_route_by_id(RouteRelX *relationx,index_t index);
50
51 static int sort_turn_by_id(TurnRestrictRelX *a,TurnRestrictRelX *b);
52 static int deduplicate_turn_by_id(TurnRestrictRelX *relationx,index_t index);
53
54 static int geographically_index(TurnRestrictRelX *relationx,index_t index);
55 static int sort_by_via(TurnRestrictRelX *a,TurnRestrictRelX *b);
56
57 /* Local variables */
58
59 /*+ Temporary file-local variables for use by the sort functions. +*/
60 static SegmentsX *sortsegmentsx;
61 static NodesX *sortnodesx;
62
63
64 /*++++++++++++++++++++++++++++++++++++++
65 Allocate a new relation list (create a new file or open an existing one).
66
67 RelationsX *NewRelationList Returns the relation list.
68
69 int append Set to 1 if the file is to be opened for appending.
70
71 int readonly Set to 1 if the file is not to be opened.
72 ++++++++++++++++++++++++++++++++++++++*/
73
74 RelationsX *NewRelationList(int append,int readonly)
75 {
76 RelationsX *relationsx;
77
78 relationsx=(RelationsX*)calloc(1,sizeof(RelationsX));
79
80 assert(relationsx); /* Check calloc() worked */
81
82
83 /* Route Relations */
84
85 relationsx->rfilename =(char*)malloc(strlen(option_tmpdirname)+32);
86 relationsx->rfilename_tmp=(char*)malloc(strlen(option_tmpdirname)+32);
87
88 sprintf(relationsx->rfilename ,"%s/relationsx.route.parsed.mem",option_tmpdirname);
89 sprintf(relationsx->rfilename_tmp,"%s/relationsx.route.%p.tmp" ,option_tmpdirname,(void*)relationsx);
90
91 if(append || readonly)
92 if(ExistsFile(relationsx->rfilename))
93 {
94 off_t size,position=0;
95 int rfd;
96
97 size=SizeFile(relationsx->rfilename);
98
99 rfd=ReOpenFile(relationsx->rfilename);
100
101 while(position<size)
102 {
103 FILESORT_VARINT relationsize;
104
105 SeekReadFile(rfd,&relationsize,FILESORT_VARSIZE,position);
106
107 relationsx->rnumber++;
108 position+=relationsize+FILESORT_VARSIZE;
109 }
110
111 CloseFile(rfd);
112 }
113
114 if(append)
115 relationsx->rfd=OpenFileAppend(relationsx->rfilename);
116 else if(!readonly)
117 relationsx->rfd=OpenFileNew(relationsx->rfilename);
118 else
119 relationsx->rfd=-1;
120
121
122 /* Turn Restriction Relations */
123
124 relationsx->trfilename =(char*)malloc(strlen(option_tmpdirname)+32);
125 relationsx->trfilename_tmp=(char*)malloc(strlen(option_tmpdirname)+32);
126
127 sprintf(relationsx->trfilename ,"%s/relationsx.turn.parsed.mem",option_tmpdirname);
128 sprintf(relationsx->trfilename_tmp,"%s/relationsx.turn.%p.tmp" ,option_tmpdirname,(void*)relationsx);
129
130 if(append || readonly)
131 if(ExistsFile(relationsx->trfilename))
132 {
133 off_t size;
134
135 size=SizeFile(relationsx->trfilename);
136
137 relationsx->trnumber=size/sizeof(TurnRestrictRelX);
138 }
139
140 if(append)
141 relationsx->trfd=OpenFileAppend(relationsx->trfilename);
142 else if(!readonly)
143 relationsx->trfd=OpenFileNew(relationsx->trfilename);
144 else
145 relationsx->trfd=-1;
146
147 return(relationsx);
148 }
149
150
151 /*++++++++++++++++++++++++++++++++++++++
152 Free a relation list.
153
154 RelationsX *relationsx The set of relations to be freed.
155 ++++++++++++++++++++++++++++++++++++++*/
156
157 void FreeRelationList(RelationsX *relationsx)
158 {
159 /* Route relations */
160
161 DeleteFile(relationsx->rfilename_tmp);
162
163 free(relationsx->rfilename);
164 free(relationsx->rfilename_tmp);
165
166
167 /* Turn Restriction relations */
168
169 DeleteFile(relationsx->trfilename_tmp);
170
171 free(relationsx->trfilename);
172 free(relationsx->trfilename_tmp);
173
174 free(relationsx);
175 }
176
177
178 /*++++++++++++++++++++++++++++++++++++++
179 Append a single relation to an unsorted route relation list.
180
181 RelationsX* relationsx The set of relations to process.
182
183 relation_t id The ID of the relation.
184
185 transports_t routes The types of routes that this relation is for.
186
187 way_t *ways The array of ways that are members of the relation.
188
189 int nways The number of ways that are members of the relation.
190
191 relation_t *relations The array of relations that are members of the relation.
192
193 int nrelations The number of relations that are members of the relation.
194 ++++++++++++++++++++++++++++++++++++++*/
195
196 void AppendRouteRelation(RelationsX* relationsx,relation_t id,
197 transports_t routes,
198 way_t *ways,int nways,
199 relation_t *relations,int nrelations)
200 {
201 RouteRelX relationx;
202 FILESORT_VARINT size;
203 way_t noway=NO_WAY_ID;
204 relation_t norelation=NO_RELATION_ID;
205
206 relationx.id=id;
207 relationx.routes=routes;
208
209 size=sizeof(RouteRelX)+(nways+1)*sizeof(way_t)+(nrelations+1)*sizeof(relation_t);
210
211 WriteFile(relationsx->rfd,&size,FILESORT_VARSIZE);
212 WriteFile(relationsx->rfd,&relationx,sizeof(RouteRelX));
213
214 WriteFile(relationsx->rfd,ways ,nways*sizeof(way_t));
215 WriteFile(relationsx->rfd,&noway, sizeof(way_t));
216
217 WriteFile(relationsx->rfd,relations ,nrelations*sizeof(relation_t));
218 WriteFile(relationsx->rfd,&norelation, sizeof(relation_t));
219
220 relationsx->rnumber++;
221
222 assert(relationsx->rnumber!=0); /* Zero marks the high-water mark for relations. */
223 }
224
225
226 /*++++++++++++++++++++++++++++++++++++++
227 Append a single relation to an unsorted turn restriction relation list.
228
229 RelationsX* relationsx The set of relations to process.
230
231 relation_t id The ID of the relation.
232
233 way_t from The way that the turn restriction starts from.
234
235 way_t to The way that the restriction finished on.
236
237 node_t via The node that the turn restriction passes through.
238
239 TurnRestriction restriction The type of restriction.
240
241 transports_t except The set of transports allowed to bypass the restriction.
242 ++++++++++++++++++++++++++++++++++++++*/
243
244 void AppendTurnRestrictRelation(RelationsX* relationsx,relation_t id,
245 way_t from,way_t to,node_t via,
246 TurnRestriction restriction,transports_t except)
247 {
248 TurnRestrictRelX relationx={0};
249
250 relationx.id=id;
251 relationx.from=from;
252 relationx.to=to;
253 relationx.via=via;
254 relationx.restriction=restriction;
255 relationx.except=except;
256
257 WriteFile(relationsx->trfd,&relationx,sizeof(TurnRestrictRelX));
258
259 relationsx->trnumber++;
260
261 assert(relationsx->trnumber!=0); /* Zero marks the high-water mark for relations. */
262 }
263
264
265 /*++++++++++++++++++++++++++++++++++++++
266 Finish appending relations and change the filename over.
267
268 RelationsX *relationsx The relations that have been appended.
269 ++++++++++++++++++++++++++++++++++++++*/
270
271 void FinishRelationList(RelationsX *relationsx)
272 {
273 /* Close the files (finished appending) */
274
275 if(relationsx->rfd!=-1)
276 relationsx->rfd =CloseFile(relationsx->rfd);
277
278 if(relationsx->trfd!=-1)
279 relationsx->trfd=CloseFile(relationsx->trfd);
280
281 /* Rename the files to the temporary names (used everywhere else) */
282
283 RenameFile(relationsx->rfilename ,relationsx->rfilename_tmp);
284 RenameFile(relationsx->trfilename,relationsx->trfilename_tmp);
285 }
286
287
288 /*++++++++++++++++++++++++++++++++++++++
289 Sort the list of relations.
290
291 RelationsX* relationsx The set of relations to process.
292 ++++++++++++++++++++++++++++++++++++++*/
293
294 void SortRelationList(RelationsX* relationsx)
295 {
296 /* Route Relations */
297
298 if(relationsx->rnumber)
299 {
300 index_t rxnumber;
301 int rfd;
302
303 /* Print the start message */
304
305 printf_first("Sorting Route Relations");
306
307 /* Re-open the file read-only and a new file writeable */
308
309 relationsx->rfd=ReOpenFile(relationsx->rfilename_tmp);
310
311 DeleteFile(relationsx->rfilename_tmp);
312
313 rfd=OpenFileNew(relationsx->rfilename_tmp);
314
315 /* Sort the relations */
316
317 rxnumber=relationsx->rnumber;
318
319 relationsx->rnumber=filesort_vary(relationsx->rfd,rfd,NULL,
320 (int (*)(const void*,const void*))sort_route_by_id,
321 (int (*)(void*,index_t))deduplicate_route_by_id);
322
323 /* Close the files */
324
325 relationsx->rfd=CloseFile(relationsx->rfd);
326 CloseFile(rfd);
327
328 /* Print the final message */
329
330 printf_last("Sorted Route Relations: Relations=%"Pindex_t" Duplicates=%"Pindex_t,rxnumber,rxnumber-relationsx->rnumber);
331 }
332
333 /* Turn Restriction Relations. */
334
335 if(relationsx->trnumber)
336 {
337 index_t trxnumber;
338 int trfd;
339
340 /* Print the start message */
341
342 printf_first("Sorting Turn Relations");
343
344 /* Re-open the file read-only and a new file writeable */
345
346 relationsx->trfd=ReOpenFile(relationsx->trfilename_tmp);
347
348 DeleteFile(relationsx->trfilename_tmp);
349
350 trfd=OpenFileNew(relationsx->trfilename_tmp);
351
352 /* Sort the relations */
353
354 trxnumber=relationsx->trnumber;
355
356 relationsx->trnumber=filesort_fixed(relationsx->trfd,trfd,sizeof(TurnRestrictRelX),NULL,
357 (int (*)(const void*,const void*))sort_turn_by_id,
358 (int (*)(void*,index_t))deduplicate_turn_by_id);
359
360 /* Close the files */
361
362 relationsx->trfd=CloseFile(relationsx->trfd);
363 CloseFile(trfd);
364
365 /* Print the final message */
366
367 printf_last("Sorted Turn Relations: Relations=%"Pindex_t" Duplicates=%"Pindex_t,trxnumber,trxnumber-relationsx->trnumber);
368 }
369 }
370
371
372 /*++++++++++++++++++++++++++++++++++++++
373 Sort the route relations into id order.
374
375 int sort_route_by_id Returns the comparison of the id fields.
376
377 RouteRelX *a The first extended relation.
378
379 RouteRelX *b The second extended relation.
380 ++++++++++++++++++++++++++++++++++++++*/
381
382 static int sort_route_by_id(RouteRelX *a,RouteRelX *b)
383 {
384 relation_t a_id=a->id;
385 relation_t b_id=b->id;
386
387 if(a_id<b_id)
388 return(-1);
389 else if(a_id>b_id)
390 return(1);
391 else
392 return(FILESORT_PRESERVE_ORDER(a,b));
393 }
394
395
396 /*++++++++++++++++++++++++++++++++++++++
397 Deduplicate the route relations using the id after sorting.
398
399 int deduplicate_route_by_id Return 1 if the value is to be kept, otherwise 0.
400
401 RouteRelX *relationx The extended relation.
402
403 index_t index The number of sorted relations that have already been written to the output file.
404 ++++++++++++++++++++++++++++++++++++++*/
405
406 static int deduplicate_route_by_id(RouteRelX *relationx,index_t index)
407 {
408 static relation_t previd;
409
410 if(index==0 || relationx->id!=previd)
411 {
412 previd=relationx->id;
413
414 return(1);
415 }
416 else
417 {
418 logerror("Relation %"Prelation_t" is duplicated.\n",relationx->id);
419
420 return(0);
421 }
422 }
423
424
425 /*++++++++++++++++++++++++++++++++++++++
426 Sort the turn restriction relations into id order.
427
428 int sort_turn_by_id Returns the comparison of the id fields.
429
430 TurnRestrictRelX *a The first extended relation.
431
432 TurnRestrictRelX *b The second extended relation.
433 ++++++++++++++++++++++++++++++++++++++*/
434
435 static int sort_turn_by_id(TurnRestrictRelX *a,TurnRestrictRelX *b)
436 {
437 relation_t a_id=a->id;
438 relation_t b_id=b->id;
439
440 if(a_id<b_id)
441 return(-1);
442 else if(a_id>b_id)
443 return(1);
444 else
445 return(FILESORT_PRESERVE_ORDER(a,b));
446 }
447
448
449 /*++++++++++++++++++++++++++++++++++++++
450 Deduplicate the turn restriction relations using the id after sorting.
451
452 int deduplicate_turn_by_id Return 1 if the value is to be kept, otherwise 0.
453
454 TurnRestrictRelX *relationx The extended relation.
455
456 index_t index The number of sorted relations that have already been written to the output file.
457 ++++++++++++++++++++++++++++++++++++++*/
458
459 static int deduplicate_turn_by_id(TurnRestrictRelX *relationx,index_t index)
460 {
461 static relation_t previd;
462
463 if(index==0 || relationx->id!=previd)
464 {
465 previd=relationx->id;
466
467 return(1);
468 }
469 else
470 {
471 logerror("Relation %"Prelation_t" is duplicated.\n",relationx->id);
472
473 return(0);
474 }
475 }
476
477
478 /*++++++++++++++++++++++++++++++++++++++
479 Process the route relations and apply the information to the ways.
480
481 RelationsX *relationsx The set of relations to use.
482
483 WaysX *waysx The set of ways to modify.
484
485 int preserve If set to 1 then keep the old data file otherwise delete it.
486 ++++++++++++++++++++++++++++++++++++++*/
487
488 void ProcessRouteRelations(RelationsX *relationsx,WaysX *waysx,int preserve)
489 {
490 RouteRelX *unmatched=NULL,*lastunmatched=NULL;
491 int nunmatched=0,lastnunmatched=0,iteration=1;
492
493 if(waysx->number==0)
494 return;
495
496 /* Map into memory / open the files */
497
498 #if !SLIM
499 waysx->data=MapFileWriteable(waysx->filename_tmp);
500 #else
501 waysx->fd=ReOpenFileWriteable(waysx->filename_tmp);
502 #endif
503
504 /* Re-open the file read-only */
505
506 relationsx->rfd=ReOpenFile(relationsx->rfilename_tmp);
507
508 /* Read through the file. */
509
510 do
511 {
512 int ways=0,relations=0;
513 index_t i;
514
515 SeekFile(relationsx->rfd,0);
516
517 /* Print the start message */
518
519 printf_first("Processing Route Relations (%d): Relations=0 Modified Ways=0",iteration);
520
521 for(i=0;i<relationsx->rnumber;i++)
522 {
523 FILESORT_VARINT size;
524 RouteRelX relationx;
525 way_t wayid;
526 relation_t relationid;
527 transports_t routes=Transports_None;
528
529 /* Read each route relation */
530
531 ReadFile(relationsx->rfd,&size,FILESORT_VARSIZE);
532 ReadFile(relationsx->rfd,&relationx,sizeof(RouteRelX));
533
534 /* Decide what type of route it is */
535
536 if(iteration==1)
537 {
538 relations++;
539 routes=relationx.routes;
540 }
541 else
542 {
543 int j;
544
545 for(j=0;j<lastnunmatched;j++)
546 if(lastunmatched[j].id==relationx.id)
547 {
548 relations++;
549
550 if((lastunmatched[j].routes|relationx.routes)==relationx.routes)
551 routes=0; /* Nothing new to add */
552 else
553 routes=lastunmatched[j].routes;
554
555 break;
556 }
557 }
558
559 /* Loop through the ways */
560
561 do
562 {
563 ReadFile(relationsx->rfd,&wayid,sizeof(way_t));
564
565 /* Update the ways that are listed for the relation */
566
567 if(wayid==NO_WAY_ID)
568 continue;
569
570 if(routes)
571 {
572 index_t way=IndexWayX(waysx,wayid);
573
574 if(way!=NO_WAY)
575 {
576 WayX *wayx=LookupWayX(waysx,way,1);
577
578 if(routes&Transports_Foot)
579 {
580 if(!(wayx->way.allow&Transports_Foot))
581 {
582 logerror("Route Relation %"Prelation_t" for Foot contains Way %"Pway_t" that does not allow Foot transport; overriding.\n",relationx.id,wayid);
583 wayx->way.allow|=Transports_Foot;
584 }
585 wayx->way.props|=Properties_FootRoute;
586 }
587
588 if(routes&Transports_Bicycle)
589 {
590 if(!(wayx->way.allow&Transports_Bicycle))
591 {
592 logerror("Route Relation %"Prelation_t" for Bicycle contains Way %"Pway_t" that does not allow Bicycle transport; overriding.\n",relationx.id,wayid);
593 wayx->way.allow|=Transports_Bicycle;
594 }
595 wayx->way.props|=Properties_BicycleRoute;
596 }
597
598 PutBackWayX(waysx,wayx);
599
600 ways++;
601 }
602 else
603 logerror("Route Relation %"Prelation_t" contains Way %"Pway_t" but it does not exist in the Routino database.\n",relationx.id,wayid);
604 }
605 }
606 while(wayid!=NO_WAY_ID);
607
608 /* Loop through the relations */
609
610 do
611 {
612 ReadFile(relationsx->rfd,&relationid,sizeof(relation_t));
613
614 /* Add the relations that are listed for this relation to the list for next time */
615
616 if(relationid==NO_RELATION_ID)
617 continue;
618
619 if(relationid==relationx.id)
620 logerror("Relation %"Prelation_t" contains itself.\n",relationx.id);
621 else if(routes)
622 {
623 if(nunmatched%256==0)
624 unmatched=(RouteRelX*)realloc((void*)unmatched,(nunmatched+256)*sizeof(RouteRelX));
625
626 unmatched[nunmatched].id=relationid;
627 unmatched[nunmatched].routes=routes;
628
629 nunmatched++;
630 }
631 }
632 while(relationid!=NO_RELATION_ID);
633
634 if(!((i+1)%1000))
635 printf_middle("Processing Route Relations (%d): Relations=%"Pindex_t" Modified Ways=%"Pindex_t,iteration,relations,ways);
636 }
637
638 if(lastunmatched)
639 free(lastunmatched);
640
641 lastunmatched=unmatched;
642 lastnunmatched=nunmatched;
643
644 unmatched=NULL;
645 nunmatched=0;
646
647 /* Print the final message */
648
649 printf_last("Processed Route Relations (%d): Relations=%"Pindex_t" Modified Ways=%"Pindex_t,iteration,relations,ways);
650 }
651 while(lastnunmatched && iteration++<8);
652
653 if(lastunmatched)
654 free(lastunmatched);
655
656 /* Close the file */
657
658 relationsx->rfd=CloseFile(relationsx->rfd);
659
660 if(preserve)
661 RenameFile(relationsx->rfilename_tmp,relationsx->rfilename);
662
663 /* Unmap from memory / close the files */
664
665 #if !SLIM
666 waysx->data=UnmapFile(waysx->data);
667 #else
668 waysx->fd=CloseFile(waysx->fd);
669 #endif
670 }
671
672
673 /*++++++++++++++++++++++++++++++++++++++
674 Process the turn relations (first part) to update them with the node/way information.
675
676 RelationsX *relationsx The set of relations to modify.
677
678 NodesX *nodesx The set of nodes to use.
679
680 WaysX *waysx The set of ways to use.
681
682 int preserve If set to 1 then keep the old data file otherwise delete it.
683 ++++++++++++++++++++++++++++++++++++++*/
684
685 void ProcessTurnRelations1(RelationsX *relationsx,NodesX *nodesx,WaysX *waysx,int preserve)
686 {
687 int trfd;
688 index_t i,deleted=0;
689
690 /* Print the start message */
691
692 printf_first("Processing Turn Relations (1): Relations=0");
693
694 /* Re-open the file read-only and a new file writeable */
695
696 relationsx->trfd=ReOpenFile(relationsx->trfilename_tmp);
697
698 if(preserve)
699 RenameFile(relationsx->trfilename_tmp,relationsx->trfilename);
700 else
701 DeleteFile(relationsx->trfilename_tmp);
702
703 trfd=OpenFileNew(relationsx->trfilename_tmp);
704
705 /* Process all of the relations */
706
707 for(i=0;i<relationsx->trnumber;i++)
708 {
709 TurnRestrictRelX relationx;
710 index_t via,from,to;
711
712 ReadFile(relationsx->trfd,&relationx,sizeof(TurnRestrictRelX));
713
714 via =IndexNodeX(nodesx,relationx.via);
715 from=IndexWayX(waysx,relationx.from);
716 to =IndexWayX(waysx,relationx.to);
717
718 if(via==NO_NODE)
719 logerror("Turn Relation %"Prelation_t" contains Node %"Pnode_t" but it does not exist in the Routino database.\n",relationx.id,relationx.via);
720
721 if(from==NO_WAY)
722 logerror("Turn Relation %"Prelation_t" contains Way %"Pway_t" but it does not exist in the Routino database.\n",relationx.id,relationx.from);
723
724 if(to==NO_WAY)
725 logerror("Turn Relation %"Prelation_t" contains Way %"Pway_t" but it does not exist in the Routino database.\n",relationx.id,relationx.to);
726
727 relationx.via =via;
728 relationx.from=from;
729 relationx.to =to;
730
731 if(relationx.via==NO_NODE || relationx.from==NO_WAY || relationx.to==NO_WAY)
732 deleted++;
733 else
734 WriteFile(trfd,&relationx,sizeof(TurnRestrictRelX));
735
736 if(!((i+1)%1000))
737 printf_middle("Processing Turn Relations (1): Relations=%"Pindex_t" Deleted=%"Pindex_t,i+1,deleted);
738 }
739
740 /* Close the files */
741
742 relationsx->trfd=CloseFile(relationsx->trfd);
743 CloseFile(trfd);
744
745 /* Print the final message */
746
747 printf_last("Processed Turn Relations (1): Relations=%"Pindex_t" Deleted=%"Pindex_t,relationsx->trnumber,deleted);
748
749 relationsx->trnumber-=deleted;
750 }
751
752
753 /*++++++++++++++++++++++++++++++++++++++
754 Process the turn relations (second part) to convert them to nodes.
755
756 RelationsX *relationsx The set of relations to modify.
757
758 NodesX *nodesx The set of nodes to use.
759
760 SegmentsX *segmentsx The set of segments to use.
761
762 WaysX *waysx The set of ways to use.
763 ++++++++++++++++++++++++++++++++++++++*/
764
765 void ProcessTurnRelations2(RelationsX *relationsx,NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx)
766 {
767 TurnRestrictRelX relationx;
768 int trfd;
769 index_t total=0,deleted=0;
770
771 if(nodesx->number==0 || segmentsx->number==0)
772 return;
773
774 /* Print the start message */
775
776 printf_first("Processing Turn Relations (2): Relations=0");
777
778 /* Map into memory / open the files */
779
780 #if !SLIM
781 nodesx->data=MapFileWriteable(nodesx->filename_tmp);
782 segmentsx->data=MapFile(segmentsx->filename_tmp);
783 waysx->data=MapFile(waysx->filename_tmp);
784 #else
785 nodesx->fd=ReOpenFileWriteable(nodesx->filename_tmp);
786 segmentsx->fd=ReOpenFile(segmentsx->filename_tmp);
787 waysx->fd=ReOpenFile(waysx->filename_tmp);
788 #endif
789
790 /* Re-open the file read-only and a new file writeable */
791
792 relationsx->trfd=ReOpenFile(relationsx->trfilename_tmp);
793
794 DeleteFile(relationsx->trfilename_tmp);
795
796 trfd=OpenFileNew(relationsx->trfilename_tmp);
797
798 /* Process all of the relations */
799
800 while(!ReadFile(relationsx->trfd,&relationx,sizeof(TurnRestrictRelX)))
801 {
802 NodeX *nodex;
803 SegmentX *segmentx;
804
805 if(relationx.restriction==TurnRestrict_no_right_turn ||
806 relationx.restriction==TurnRestrict_no_left_turn ||
807 relationx.restriction==TurnRestrict_no_u_turn ||
808 relationx.restriction==TurnRestrict_no_straight_on)
809 {
810 index_t node_from=NO_NODE,node_to=NO_NODE;
811 int oneway_from=0,oneway_to=0,vehicles_from=1,vehicles_to=1;
812
813 /* Find the segments that join the node 'via' */
814
815 segmentx=FirstSegmentX(segmentsx,relationx.via,1);
816
817 while(segmentx)
818 {
819 if(segmentx->way==relationx.from)
820 {
821 WayX *wayx=LookupWayX(waysx,segmentx->way,1);
822
823 if(node_from!=NO_NODE) /* Only one segment can be on the 'from' way */
824 {
825 logerror("Turn Relation %"Prelation_t" is not stored because the 'via' node is not at the end of the 'from' way.\n",relationx.id);
826 deleted++;
827 goto endloop;
828 }
829
830 node_from=OtherNode(segmentx,relationx.via);
831
832 if(IsOnewayFrom(segmentx,relationx.via))
833 oneway_from=1; /* not allowed */
834
835 if(!(wayx->way.allow&(Transports_Bicycle|Transports_Moped|Transports_Motorbike|Transports_Motorcar|Transports_Goods|Transports_HGV|Transports_PSV)))
836 vehicles_from=0; /* not allowed */
837 }
838
839 if(segmentx->way==relationx.to)
840 {
841 WayX *wayx=LookupWayX(waysx,segmentx->way,1);
842
843 if(node_to!=NO_NODE) /* Only one segment can be on the 'to' way */
844 {
845 logerror("Turn Relation %"Prelation_t" is not stored because the 'via' node is not at the end of the 'to' way.\n",relationx.id);
846 deleted++;
847 goto endloop;
848 }
849
850 node_to=OtherNode(segmentx,relationx.via);
851
852 if(IsOnewayTo(segmentx,relationx.via))
853 oneway_to=1; /* not allowed */
854
855 if(!(wayx->way.allow&(Transports_Bicycle|Transports_Moped|Transports_Motorbike|Transports_Motorcar|Transports_Goods|Transports_HGV|Transports_PSV)))
856 vehicles_to=0; /* not allowed */
857 }
858
859 segmentx=NextSegmentX(segmentsx,segmentx,relationx.via);
860 }
861
862 if(node_from==NO_NODE)
863 logerror("Turn Relation %"Prelation_t" is not stored because the 'via' node is not part of the 'from' way.\n",relationx.id);
864
865 if(node_to==NO_NODE)
866 logerror("Turn Relation %"Prelation_t" is not stored because the 'via' node is not part of the 'to' way.\n",relationx.id);
867
868 if(oneway_from)
869 logerror("Turn Relation %"Prelation_t" is not stored because the 'from' way is oneway away from the 'via' node.\n",relationx.id);
870
871 if(oneway_to)
872 logerror("Turn Relation %"Prelation_t" is not needed because the 'to' way is oneway towards the 'via' node.\n",relationx.id);
873
874 if(!vehicles_from)
875 logerror("Turn Relation %"Prelation_t" is not stored because the 'from' way does not allow vehicles.\n",relationx.id);
876
877 if(!vehicles_to)
878 logerror("Turn Relation %"Prelation_t" is not needed because the 'to' way does not allow vehicles.\n",relationx.id);
879
880 if(oneway_from || oneway_to || !vehicles_from || !vehicles_to || node_from==NO_NODE || node_to==NO_NODE)
881 {
882 deleted++;
883 goto endloop;
884 }
885
886 /* Write the results */
887
888 relationx.from=node_from;
889 relationx.to =node_to;
890
891 WriteFile(trfd,&relationx,sizeof(TurnRestrictRelX));
892
893 total++;
894
895 if(!(total%1000))
896 printf_middle("Processing Turn Relations (2): Relations=%"Pindex_t" Deleted=%"Pindex_t" Added=%"Pindex_t,total,deleted,total-relationsx->trnumber+deleted);
897 }
898 else
899 {
900 index_t node_from=NO_NODE,node_to=NO_NODE,node_other[MAX_SEG_PER_NODE];
901 int nnodes_other=0,i;
902 int oneway_from=0,vehicles_from=1;
903
904 /* Find the segments that join the node 'via' */
905
906 segmentx=FirstSegmentX(segmentsx,relationx.via,1);
907
908 while(segmentx)
909 {
910 if(segmentx->way==relationx.from)
911 {
912 WayX *wayx=LookupWayX(waysx,segmentx->way,1);
913
914 if(node_from!=NO_NODE) /* Only one segment can be on the 'from' way */
915 {
916 logerror("Turn Relation %"Prelation_t" is not stored because the 'via' node is not at the end of the 'from' way.\n",relationx.id);
917 deleted++;
918 goto endloop;
919 }
920
921 node_from=OtherNode(segmentx,relationx.via);
922
923 if(IsOnewayFrom(segmentx,relationx.via))
924 oneway_from=1; /* not allowed */
925
926 if(!(wayx->way.allow&(Transports_Bicycle|Transports_Moped|Transports_Motorbike|Transports_Motorcar|Transports_Goods|Transports_HGV|Transports_PSV)))
927 vehicles_from=0; /* not allowed */
928 }
929
930 if(segmentx->way==relationx.to)
931 {
932 if(node_to!=NO_NODE) /* Only one segment can be on the 'to' way */
933 {
934 logerror("Turn Relation %"Prelation_t" is not stored because the 'via' node is not at the end of the 'to' way.\n",relationx.id);
935 deleted++;
936 goto endloop;
937 }
938
939 node_to=OtherNode(segmentx,relationx.via);
940 }
941
942 if(segmentx->way!=relationx.from && segmentx->way!=relationx.to)
943 {
944 WayX *wayx=LookupWayX(waysx,segmentx->way,1);
945
946 if(IsOnewayTo(segmentx,relationx.via))
947 ; /* not allowed */
948 else if(!(wayx->way.allow&(Transports_Bicycle|Transports_Moped|Transports_Motorbike|Transports_Motorcar|Transports_Goods|Transports_HGV|Transports_PSV)))
949 ; /* not allowed */
950 else
951 {
952 assert(nnodes_other<MAX_SEG_PER_NODE); /* Only a limited amount of information stored. */
953
954 node_other[nnodes_other++]=OtherNode(segmentx,relationx.via);
955 }
956 }
957
958 segmentx=NextSegmentX(segmentsx,segmentx,relationx.via);
959 }
960
961 if(node_from==NO_NODE)
962 logerror("Turn Relation %"Prelation_t" is not stored because the 'via' node is not part of the 'from' way.\n",relationx.id);
963
964 if(node_to==NO_NODE)
965 logerror("Turn Relation %"Prelation_t" is not stored because the 'via' node is not part of the 'to' way.\n",relationx.id);
966
967 if(nnodes_other==0)
968 logerror("Turn Relation %"Prelation_t" is not needed because the only allowed exit from the 'via' node is the 'to' way.\n",relationx.id);
969
970 if(oneway_from)
971 logerror("Turn Relation %"Prelation_t" is not needed because the 'from' way is oneway away from the 'via' node.\n",relationx.id);
972
973 if(!vehicles_from)
974 logerror("Turn Relation %"Prelation_t" is not stored because the 'from' way does not allow vehicles.\n",relationx.id);
975
976 if(oneway_from || !vehicles_from || node_from==NO_NODE || node_to==NO_NODE || nnodes_other==0)
977 {
978 deleted++;
979 goto endloop;
980 }
981
982 /* Write the results */
983
984 for(i=0;i<nnodes_other;i++)
985 {
986 relationx.from=node_from;
987 relationx.to =node_other[i];
988
989 WriteFile(trfd,&relationx,sizeof(TurnRestrictRelX));
990
991 total++;
992
993 if(!(total%1000))
994 printf_middle("Processing Turn Relations (2): Relations=%"Pindex_t" Deleted=%"Pindex_t" Added=%"Pindex_t,total,deleted,total-relationsx->trnumber+deleted);
995 }
996 }
997
998 /* Force super nodes on via node and adjacent nodes */
999
1000 nodex=LookupNodeX(nodesx,relationx.via,1);
1001 nodex->flags|=NODE_TURNRSTRCT;
1002 PutBackNodeX(nodesx,nodex);
1003
1004 segmentx=FirstSegmentX(segmentsx,relationx.via,1);
1005
1006 while(segmentx)
1007 {
1008 index_t othernode=OtherNode(segmentx,relationx.via);
1009
1010 nodex=LookupNodeX(nodesx,othernode,1);
1011 nodex->flags|=NODE_TURNRSTRCT2;
1012 PutBackNodeX(nodesx,nodex);
1013
1014 segmentx=NextSegmentX(segmentsx,segmentx,relationx.via);
1015 }
1016
1017 endloop: ;
1018 }
1019
1020 /* Close the files */
1021
1022 relationsx->trfd=CloseFile(relationsx->trfd);
1023 CloseFile(trfd);
1024
1025 /* Unmap from memory / close the files */
1026
1027 #if !SLIM
1028 nodesx->data=UnmapFile(nodesx->data);
1029 segmentsx->data=UnmapFile(segmentsx->data);
1030 waysx->data=UnmapFile(waysx->data);
1031 #else
1032 nodesx->fd=CloseFile(nodesx->fd);
1033 segmentsx->fd=CloseFile(segmentsx->fd);
1034 waysx->fd=CloseFile(waysx->fd);
1035 #endif
1036
1037 /* Print the final message */
1038
1039 printf_last("Processed Turn Relations (2): Relations=%"Pindex_t" Deleted=%"Pindex_t" Added=%"Pindex_t,total,deleted,total-relationsx->trnumber+deleted);
1040
1041 relationsx->trnumber=total;
1042 }
1043
1044
1045 /*++++++++++++++++++++++++++++++++++++++
1046 Remove pruned turn relations and update the node indexes after pruning nodes.
1047
1048 RelationsX *relationsx The set of relations to modify.
1049
1050 NodesX *nodesx The set of nodes to use.
1051 ++++++++++++++++++++++++++++++++++++++*/
1052
1053 void RemovePrunedTurnRelations(RelationsX *relationsx,NodesX *nodesx)
1054 {
1055 TurnRestrictRelX relationx;
1056 index_t total=0,pruned=0,notpruned=0;
1057 int trfd;
1058
1059 /* Print the start message */
1060
1061 printf_first("Deleting Pruned Turn Relations: Relations=0 Pruned=0");
1062
1063 /* Re-open the file read-only and a new file writeable */
1064
1065 relationsx->trfd=ReOpenFile(relationsx->trfilename_tmp);
1066
1067 DeleteFile(relationsx->trfilename_tmp);
1068
1069 trfd=OpenFileNew(relationsx->trfilename_tmp);
1070
1071 /* Process all of the relations */
1072
1073 while(!ReadFile(relationsx->trfd,&relationx,sizeof(TurnRestrictRelX)))
1074 {
1075 relationx.from=nodesx->pdata[relationx.from];
1076 relationx.via =nodesx->pdata[relationx.via];
1077 relationx.to =nodesx->pdata[relationx.to];
1078
1079 if(relationx.from==NO_NODE || relationx.via==NO_NODE || relationx.to==NO_NODE)
1080 pruned++;
1081 else
1082 {
1083 WriteFile(trfd,&relationx,sizeof(TurnRestrictRelX));
1084
1085 notpruned++;
1086 }
1087
1088 total++;
1089
1090 if(!(total%1000))
1091 printf_middle("Deleting Pruned Turn Relations: Relations=%"Pindex_t" Pruned=%"Pindex_t,total,pruned);
1092 }
1093
1094 relationsx->trnumber=notpruned;
1095
1096 /* Close the files */
1097
1098 relationsx->trfd=CloseFile(relationsx->trfd);
1099 CloseFile(trfd);
1100
1101 /* Print the final message */
1102
1103 printf_last("Deleted Pruned Turn Relations: Relations=%"Pindex_t" Pruned=%"Pindex_t,total,pruned);
1104 }
1105
1106
1107 /*++++++++++++++++++++++++++++++++++++++
1108 Sort the turn relations geographically after updating the node indexes.
1109
1110 RelationsX *relationsx The set of relations to modify.
1111
1112 NodesX *nodesx The set of nodes to use.
1113
1114 SegmentsX *segmentsx The set of segments to use.
1115 ++++++++++++++++++++++++++++++++++++++*/
1116
1117 void SortTurnRelationListGeographically(RelationsX *relationsx,NodesX *nodesx,SegmentsX *segmentsx)
1118 {
1119 int trfd;
1120
1121 /* Print the start message */
1122
1123 printf_first("Sorting Turn Relations Geographically");
1124
1125 /* Map into memory / open the files */
1126
1127 #if !SLIM
1128 segmentsx->data=MapFile(segmentsx->filename_tmp);
1129 #else
1130 segmentsx->fd=ReOpenFile(segmentsx->filename_tmp);
1131 #endif
1132
1133 /* Re-open the file read-only and a new file writeable */
1134
1135 relationsx->trfd=ReOpenFile(relationsx->trfilename_tmp);
1136
1137 DeleteFile(relationsx->trfilename_tmp);
1138
1139 trfd=OpenFileNew(relationsx->trfilename_tmp);
1140
1141 /* Update the segments with geographically sorted node indexes and sort them */
1142
1143 sortnodesx=nodesx;
1144 sortsegmentsx=segmentsx;
1145
1146 filesort_fixed(relationsx->trfd,trfd,sizeof(TurnRestrictRelX),(int (*)(void*,index_t))geographically_index,
1147 (int (*)(const void*,const void*))sort_by_via,
1148 NULL);
1149
1150 /* Close the files */
1151
1152 relationsx->trfd=CloseFile(relationsx->trfd);
1153 CloseFile(trfd);
1154
1155 /* Unmap from memory / close the files */
1156
1157 #if !SLIM
1158 segmentsx->data=UnmapFile(segmentsx->data);
1159 #else
1160 segmentsx->fd=CloseFile(segmentsx->fd);
1161 #endif
1162
1163 /* Print the final message */
1164
1165 printf_last("Sorted Turn Relations Geographically: Turn Relations=%"Pindex_t,relationsx->trnumber);
1166 }
1167
1168
1169 /*++++++++++++++++++++++++++++++++++++++
1170 Update the turn relation indexes.
1171
1172 int geographically_index Return 1 if the value is to be kept, otherwise 0.
1173
1174 TurnRestrictRelX *relationx The extended turn relation.
1175
1176 index_t index The number of unsorted turn relations that have been read from the input file.
1177 ++++++++++++++++++++++++++++++++++++++*/
1178
1179 static int geographically_index(TurnRestrictRelX *relationx,index_t index)
1180 {
1181 SegmentX *segmentx;
1182 index_t from_node,via_node,to_node;
1183
1184 from_node=sortnodesx->gdata[relationx->from];
1185 via_node =sortnodesx->gdata[relationx->via];
1186 to_node =sortnodesx->gdata[relationx->to];
1187
1188 segmentx=FirstSegmentX(sortsegmentsx,via_node,1);
1189
1190 do
1191 {
1192 if(OtherNode(segmentx,via_node)==from_node)
1193 relationx->from=IndexSegmentX(sortsegmentsx,segmentx);
1194
1195 if(OtherNode(segmentx,via_node)==to_node)
1196 relationx->to=IndexSegmentX(sortsegmentsx,segmentx);
1197
1198 segmentx=NextSegmentX(sortsegmentsx,segmentx,via_node);
1199 }
1200 while(segmentx);
1201
1202 relationx->via=via_node;
1203
1204 return(1);
1205 }
1206
1207
1208 /*++++++++++++++++++++++++++++++++++++++
1209 Sort the turn restriction relations into via index order (then by from and to segments).
1210
1211 int sort_by_via Returns the comparison of the via, from and to fields.
1212
1213 TurnRestrictRelX *a The first extended relation.
1214
1215 TurnRestrictRelX *b The second extended relation.
1216 ++++++++++++++++++++++++++++++++++++++*/
1217
1218 static int sort_by_via(TurnRestrictRelX *a,TurnRestrictRelX *b)
1219 {
1220 index_t a_id=a->via;
1221 index_t b_id=b->via;
1222
1223 if(a_id<b_id)
1224 return(-1);
1225 else if(a_id>b_id)
1226 return(1);
1227 else
1228 {
1229 index_t a_id=a->from;
1230 index_t b_id=b->from;
1231
1232 if(a_id<b_id)
1233 return(-1);
1234 else if(a_id>b_id)
1235 return(1);
1236 else
1237 {
1238 index_t a_id=a->to;
1239 index_t b_id=b->to;
1240
1241 if(a_id<b_id)
1242 return(-1);
1243 else if(a_id>b_id)
1244 return(1);
1245 else
1246 return(FILESORT_PRESERVE_ORDER(a,b));
1247 }
1248 }
1249 }
1250
1251
1252 /*++++++++++++++++++++++++++++++++++++++
1253 Save the relation list to a file.
1254
1255 RelationsX* relationsx The set of relations to save.
1256
1257 const char *filename The name of the file to save.
1258 ++++++++++++++++++++++++++++++++++++++*/
1259
1260 void SaveRelationList(RelationsX* relationsx,const char *filename)
1261 {
1262 index_t i;
1263 int fd;
1264 RelationsFile relationsfile={0};
1265
1266 /* Print the start message */
1267
1268 printf_first("Writing Relations: Turn Relations=0");
1269
1270 /* Re-open the file read-only */
1271
1272 relationsx->trfd=ReOpenFile(relationsx->trfilename_tmp);
1273
1274 /* Write out the relations data */
1275
1276 fd=OpenFileNew(filename);
1277
1278 SeekFile(fd,sizeof(RelationsFile));
1279
1280 for(i=0;i<relationsx->trnumber;i++)
1281 {
1282 TurnRestrictRelX relationx;
1283 TurnRelation relation={0};
1284
1285 ReadFile(relationsx->trfd,&relationx,sizeof(TurnRestrictRelX));
1286
1287 relation.from=relationx.from;
1288 relation.via=relationx.via;
1289 relation.to=relationx.to;
1290 relation.except=relationx.except;
1291
1292 WriteFile(fd,&relation,sizeof(TurnRelation));
1293
1294 if(!((i+1)%1000))
1295 printf_middle("Writing Relations: Turn Relations=%"Pindex_t,i+1);
1296 }
1297
1298 /* Write out the header structure */
1299
1300 relationsfile.trnumber=relationsx->trnumber;
1301
1302 SeekFile(fd,0);
1303 WriteFile(fd,&relationsfile,sizeof(RelationsFile));
1304
1305 CloseFile(fd);
1306
1307 /* Close the file */
1308
1309 relationsx->trfd=CloseFile(relationsx->trfd);
1310
1311 /* Print the final message */
1312
1313 printf_last("Wrote Relations: Turn Relations=%"Pindex_t,relationsx->trnumber);
1314 }