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 1139 - (show annotations) (download) (as text)
Thu Nov 15 19:16:47 2012 UTC (12 years, 4 months ago) by amb
File MIME type: text/x-csrc
File size: 37681 byte(s)
Fixed the --preserve option.

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