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 1123 - (show annotations) (download) (as text)
Sat Nov 3 10:44:59 2012 UTC (12 years, 4 months ago) by amb
File MIME type: text/x-csrc
File size: 34871 byte(s)
Don't open the input file for appending if there is no intention to write
anything to it.

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