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 951 - (show annotations) (download) (as text)
Sat Jan 14 14:55:05 2012 UTC (13 years, 2 months ago) by amb
File MIME type: text/x-csrc
File size: 31517 byte(s)
Zero the structure before filling it in so that no junk is written to disk.

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