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 1140 - (show annotations) (download) (as text)
Fri Nov 16 18:47:07 2012 UTC (12 years, 4 months ago) by amb
File MIME type: text/x-csrc
File size: 37891 byte(s)
Code to allow adding OSC change files (.osc files) to an existing set of parsed
(and preserved) data.

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)); /* latest version first */
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=NO_RELATION_ID;
418
419 if(relationx->id!=previd)
420 {
421 previd=relationx->id;
422
423 if(relationx->routes==RELATION_DELETED)
424 return(0);
425 else
426 return(1);
427 }
428 else
429 {
430 logerror("Relation %"Prelation_t" is duplicated.\n",relationx->id);
431
432 return(0);
433 }
434 }
435
436
437 /*++++++++++++++++++++++++++++++++++++++
438 Sort the turn restriction relations into id order.
439
440 int sort_turn_by_id Returns the comparison of the id fields.
441
442 TurnRestrictRelX *a The first extended relation.
443
444 TurnRestrictRelX *b The second extended relation.
445 ++++++++++++++++++++++++++++++++++++++*/
446
447 static int sort_turn_by_id(TurnRestrictRelX *a,TurnRestrictRelX *b)
448 {
449 relation_t a_id=a->id;
450 relation_t b_id=b->id;
451
452 if(a_id<b_id)
453 return(-1);
454 else if(a_id>b_id)
455 return(1);
456 else
457 return(-FILESORT_PRESERVE_ORDER(a,b)); /* latest version first */
458 }
459
460
461 /*++++++++++++++++++++++++++++++++++++++
462 Deduplicate the turn restriction relations using the id after sorting.
463
464 int deduplicate_turn_by_id Return 1 if the value is to be kept, otherwise 0.
465
466 TurnRestrictRelX *relationx The extended relation.
467
468 index_t index The number of sorted relations that have already been written to the output file.
469 ++++++++++++++++++++++++++++++++++++++*/
470
471 static int deduplicate_turn_by_id(TurnRestrictRelX *relationx,index_t index)
472 {
473 static relation_t previd=NO_RELATION_ID;
474
475 if(relationx->id!=previd)
476 {
477 previd=relationx->id;
478
479 if(relationx->except==RELATION_DELETED)
480 return(0);
481 else
482 return(1);
483 }
484 else
485 {
486 logerror("Relation %"Prelation_t" is duplicated.\n",relationx->id);
487
488 return(0);
489 }
490 }
491
492
493 /*++++++++++++++++++++++++++++++++++++++
494 Process the route relations and apply the information to the ways.
495
496 RelationsX *relationsx The set of relations to use.
497
498 WaysX *waysx The set of ways to modify.
499
500 int preserve If set to 1 then keep the old data file otherwise delete it.
501 ++++++++++++++++++++++++++++++++++++++*/
502
503 void ProcessRouteRelations(RelationsX *relationsx,WaysX *waysx,int preserve)
504 {
505 RouteRelX *unmatched=NULL,*lastunmatched=NULL;
506 int nunmatched=0,lastnunmatched=0,iteration=1;
507
508 if(waysx->number==0)
509 return;
510
511 /* Map into memory / open the files */
512
513 #if !SLIM
514 waysx->data=MapFileWriteable(waysx->filename_tmp);
515 #else
516 waysx->fd=ReOpenFileWriteable(waysx->filename_tmp);
517 #endif
518
519 /* Re-open the file read-only */
520
521 relationsx->rfd=ReOpenFile(relationsx->rfilename_tmp);
522
523 /* Read through the file. */
524
525 do
526 {
527 int ways=0,relations=0;
528 index_t i;
529
530 SeekFile(relationsx->rfd,0);
531
532 /* Print the start message */
533
534 printf_first("Processing Route Relations (%d): Relations=0 Modified Ways=0",iteration);
535
536 for(i=0;i<relationsx->rnumber;i++)
537 {
538 FILESORT_VARINT size;
539 RouteRelX relationx;
540 way_t wayid;
541 relation_t relationid;
542 transports_t routes=Transports_None;
543
544 /* Read each route relation */
545
546 ReadFile(relationsx->rfd,&size,FILESORT_VARSIZE);
547 ReadFile(relationsx->rfd,&relationx,sizeof(RouteRelX));
548
549 /* Decide what type of route it is */
550
551 if(iteration==1)
552 {
553 relations++;
554 routes=relationx.routes;
555 }
556 else
557 {
558 int j;
559
560 for(j=0;j<lastnunmatched;j++)
561 if(lastunmatched[j].id==relationx.id)
562 {
563 relations++;
564
565 if((lastunmatched[j].routes|relationx.routes)==relationx.routes)
566 routes=0; /* Nothing new to add */
567 else
568 routes=lastunmatched[j].routes;
569
570 break;
571 }
572 }
573
574 /* Loop through the ways */
575
576 do
577 {
578 ReadFile(relationsx->rfd,&wayid,sizeof(way_t));
579
580 /* Update the ways that are listed for the relation */
581
582 if(wayid==NO_WAY_ID)
583 continue;
584
585 if(routes)
586 {
587 index_t way=IndexWayX(waysx,wayid);
588
589 if(way!=NO_WAY)
590 {
591 WayX *wayx=LookupWayX(waysx,way,1);
592
593 if(routes&Transports_Foot)
594 {
595 if(!(wayx->way.allow&Transports_Foot))
596 {
597 logerror("Route Relation %"Prelation_t" for Foot contains Way %"Pway_t" that does not allow Foot transport; overriding.\n",relationx.id,wayid);
598 wayx->way.allow|=Transports_Foot;
599 }
600 wayx->way.props|=Properties_FootRoute;
601 }
602
603 if(routes&Transports_Bicycle)
604 {
605 if(!(wayx->way.allow&Transports_Bicycle))
606 {
607 logerror("Route Relation %"Prelation_t" for Bicycle contains Way %"Pway_t" that does not allow Bicycle transport; overriding.\n",relationx.id,wayid);
608 wayx->way.allow|=Transports_Bicycle;
609 }
610 wayx->way.props|=Properties_BicycleRoute;
611 }
612
613 PutBackWayX(waysx,wayx);
614
615 ways++;
616 }
617 else
618 logerror("Route Relation %"Prelation_t" contains Way %"Pway_t" but it does not exist in the Routino database.\n",relationx.id,wayid);
619 }
620 }
621 while(wayid!=NO_WAY_ID);
622
623 /* Loop through the relations */
624
625 do
626 {
627 ReadFile(relationsx->rfd,&relationid,sizeof(relation_t));
628
629 /* Add the relations that are listed for this relation to the list for next time */
630
631 if(relationid==NO_RELATION_ID)
632 continue;
633
634 if(relationid==relationx.id)
635 logerror("Relation %"Prelation_t" contains itself.\n",relationx.id);
636 else if(routes)
637 {
638 if(nunmatched%256==0)
639 unmatched=(RouteRelX*)realloc((void*)unmatched,(nunmatched+256)*sizeof(RouteRelX));
640
641 unmatched[nunmatched].id=relationid;
642 unmatched[nunmatched].routes=routes;
643
644 nunmatched++;
645 }
646 }
647 while(relationid!=NO_RELATION_ID);
648
649 if(!((i+1)%1000))
650 printf_middle("Processing Route Relations (%d): Relations=%"Pindex_t" Modified Ways=%"Pindex_t,iteration,relations,ways);
651 }
652
653 if(lastunmatched)
654 free(lastunmatched);
655
656 lastunmatched=unmatched;
657 lastnunmatched=nunmatched;
658
659 unmatched=NULL;
660 nunmatched=0;
661
662 /* Print the final message */
663
664 printf_last("Processed Route Relations (%d): Relations=%"Pindex_t" Modified Ways=%"Pindex_t,iteration,relations,ways);
665 }
666 while(lastnunmatched && iteration++<8);
667
668 if(lastunmatched)
669 free(lastunmatched);
670
671 /* Close the file */
672
673 relationsx->rfd=CloseFile(relationsx->rfd);
674
675 if(preserve)
676 RenameFile(relationsx->rfilename_tmp,relationsx->rfilename);
677
678 /* Unmap from memory / close the files */
679
680 #if !SLIM
681 waysx->data=UnmapFile(waysx->data);
682 #else
683 waysx->fd=CloseFile(waysx->fd);
684 #endif
685 }
686
687
688 /*++++++++++++++++++++++++++++++++++++++
689 Process the turn relations (first part) to update them with the node/way information.
690
691 RelationsX *relationsx The set of relations to modify.
692
693 NodesX *nodesx The set of nodes to use.
694
695 WaysX *waysx The set of ways to use.
696
697 int preserve If set to 1 then keep the old data file otherwise delete it.
698 ++++++++++++++++++++++++++++++++++++++*/
699
700 void ProcessTurnRelations1(RelationsX *relationsx,NodesX *nodesx,WaysX *waysx,int preserve)
701 {
702 int trfd;
703 index_t i,deleted=0;
704
705 /* Print the start message */
706
707 printf_first("Processing Turn Relations (1): Relations=0");
708
709 /* Re-open the file read-only and a new file writeable */
710
711 relationsx->trfd=ReOpenFile(relationsx->trfilename_tmp);
712
713 if(preserve)
714 RenameFile(relationsx->trfilename_tmp,relationsx->trfilename);
715 else
716 DeleteFile(relationsx->trfilename_tmp);
717
718 trfd=OpenFileNew(relationsx->trfilename_tmp);
719
720 /* Process all of the relations */
721
722 for(i=0;i<relationsx->trnumber;i++)
723 {
724 TurnRestrictRelX relationx;
725 index_t via,from,to;
726
727 ReadFile(relationsx->trfd,&relationx,sizeof(TurnRestrictRelX));
728
729 via =IndexNodeX(nodesx,relationx.via);
730 from=IndexWayX(waysx,relationx.from);
731 to =IndexWayX(waysx,relationx.to);
732
733 if(via==NO_NODE)
734 logerror("Turn Relation %"Prelation_t" contains Node %"Pnode_t" but it does not exist in the Routino database.\n",relationx.id,relationx.via);
735
736 if(from==NO_WAY)
737 logerror("Turn Relation %"Prelation_t" contains Way %"Pway_t" but it does not exist in the Routino database.\n",relationx.id,relationx.from);
738
739 if(to==NO_WAY)
740 logerror("Turn Relation %"Prelation_t" contains Way %"Pway_t" but it does not exist in the Routino database.\n",relationx.id,relationx.to);
741
742 relationx.via =via;
743 relationx.from=from;
744 relationx.to =to;
745
746 if(relationx.via==NO_NODE || relationx.from==NO_WAY || relationx.to==NO_WAY)
747 deleted++;
748 else
749 WriteFile(trfd,&relationx,sizeof(TurnRestrictRelX));
750
751 if(!((i+1)%1000))
752 printf_middle("Processing Turn Relations (1): Relations=%"Pindex_t" Deleted=%"Pindex_t,i+1,deleted);
753 }
754
755 /* Close the files */
756
757 relationsx->trfd=CloseFile(relationsx->trfd);
758 CloseFile(trfd);
759
760 /* Print the final message */
761
762 printf_last("Processed Turn Relations (1): Relations=%"Pindex_t" Deleted=%"Pindex_t,relationsx->trnumber,deleted);
763
764 relationsx->trnumber-=deleted;
765 }
766
767
768 /*++++++++++++++++++++++++++++++++++++++
769 Process the turn relations (second part) to convert them to nodes.
770
771 RelationsX *relationsx The set of relations to modify.
772
773 NodesX *nodesx The set of nodes to use.
774
775 SegmentsX *segmentsx The set of segments to use.
776
777 WaysX *waysx The set of ways to use.
778 ++++++++++++++++++++++++++++++++++++++*/
779
780 void ProcessTurnRelations2(RelationsX *relationsx,NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx)
781 {
782 TurnRestrictRelX relationx;
783 int trfd;
784 index_t total=0,deleted=0;
785
786 if(nodesx->number==0 || segmentsx->number==0)
787 return;
788
789 /* Print the start message */
790
791 printf_first("Processing Turn Relations (2): Relations=0");
792
793 /* Map into memory / open the files */
794
795 #if !SLIM
796 nodesx->data=MapFileWriteable(nodesx->filename_tmp);
797 segmentsx->data=MapFile(segmentsx->filename_tmp);
798 waysx->data=MapFile(waysx->filename_tmp);
799 #else
800 nodesx->fd=ReOpenFileWriteable(nodesx->filename_tmp);
801 segmentsx->fd=ReOpenFile(segmentsx->filename_tmp);
802 waysx->fd=ReOpenFile(waysx->filename_tmp);
803 #endif
804
805 /* Re-open the file read-only and a new file writeable */
806
807 relationsx->trfd=ReOpenFile(relationsx->trfilename_tmp);
808
809 DeleteFile(relationsx->trfilename_tmp);
810
811 trfd=OpenFileNew(relationsx->trfilename_tmp);
812
813 /* Process all of the relations */
814
815 while(!ReadFile(relationsx->trfd,&relationx,sizeof(TurnRestrictRelX)))
816 {
817 NodeX *nodex;
818 SegmentX *segmentx;
819
820 if(relationx.restriction==TurnRestrict_no_right_turn ||
821 relationx.restriction==TurnRestrict_no_left_turn ||
822 relationx.restriction==TurnRestrict_no_u_turn ||
823 relationx.restriction==TurnRestrict_no_straight_on)
824 {
825 index_t node_from=NO_NODE,node_to=NO_NODE;
826 int oneway_from=0,oneway_to=0,vehicles_from=1,vehicles_to=1;
827
828 /* Find the segments that join the node 'via' */
829
830 segmentx=FirstSegmentX(segmentsx,relationx.via,1);
831
832 while(segmentx)
833 {
834 if(segmentx->way==relationx.from)
835 {
836 WayX *wayx=LookupWayX(waysx,segmentx->way,1);
837
838 if(node_from!=NO_NODE) /* Only one segment can be on the 'from' way */
839 {
840 logerror("Turn Relation %"Prelation_t" is not stored because the 'via' node is not at the end of the 'from' way.\n",relationx.id);
841 deleted++;
842 goto endloop;
843 }
844
845 node_from=OtherNode(segmentx,relationx.via);
846
847 if(IsOnewayFrom(segmentx,relationx.via))
848 oneway_from=1; /* not allowed */
849
850 if(!(wayx->way.allow&(Transports_Bicycle|Transports_Moped|Transports_Motorbike|Transports_Motorcar|Transports_Goods|Transports_HGV|Transports_PSV)))
851 vehicles_from=0; /* not allowed */
852 }
853
854 if(segmentx->way==relationx.to)
855 {
856 WayX *wayx=LookupWayX(waysx,segmentx->way,1);
857
858 if(node_to!=NO_NODE) /* Only one segment can be on the 'to' way */
859 {
860 logerror("Turn Relation %"Prelation_t" is not stored because the 'via' node is not at the end of the 'to' way.\n",relationx.id);
861 deleted++;
862 goto endloop;
863 }
864
865 node_to=OtherNode(segmentx,relationx.via);
866
867 if(IsOnewayTo(segmentx,relationx.via))
868 oneway_to=1; /* not allowed */
869
870 if(!(wayx->way.allow&(Transports_Bicycle|Transports_Moped|Transports_Motorbike|Transports_Motorcar|Transports_Goods|Transports_HGV|Transports_PSV)))
871 vehicles_to=0; /* not allowed */
872 }
873
874 segmentx=NextSegmentX(segmentsx,segmentx,relationx.via);
875 }
876
877 if(node_from==NO_NODE)
878 logerror("Turn Relation %"Prelation_t" is not stored because the 'via' node is not part of the 'from' way.\n",relationx.id);
879
880 if(node_to==NO_NODE)
881 logerror("Turn Relation %"Prelation_t" is not stored because the 'via' node is not part of the 'to' way.\n",relationx.id);
882
883 if(oneway_from)
884 logerror("Turn Relation %"Prelation_t" is not stored because the 'from' way is oneway away from the 'via' node.\n",relationx.id);
885
886 if(oneway_to)
887 logerror("Turn Relation %"Prelation_t" is not needed because the 'to' way is oneway towards the 'via' node.\n",relationx.id);
888
889 if(!vehicles_from)
890 logerror("Turn Relation %"Prelation_t" is not stored because the 'from' way does not allow vehicles.\n",relationx.id);
891
892 if(!vehicles_to)
893 logerror("Turn Relation %"Prelation_t" is not needed because the 'to' way does not allow vehicles.\n",relationx.id);
894
895 if(oneway_from || oneway_to || !vehicles_from || !vehicles_to || node_from==NO_NODE || node_to==NO_NODE)
896 {
897 deleted++;
898 goto endloop;
899 }
900
901 /* Write the results */
902
903 relationx.from=node_from;
904 relationx.to =node_to;
905
906 WriteFile(trfd,&relationx,sizeof(TurnRestrictRelX));
907
908 total++;
909
910 if(!(total%1000))
911 printf_middle("Processing Turn Relations (2): Relations=%"Pindex_t" Deleted=%"Pindex_t" Added=%"Pindex_t,total,deleted,total-relationsx->trnumber+deleted);
912 }
913 else
914 {
915 index_t node_from=NO_NODE,node_to=NO_NODE,node_other[MAX_SEG_PER_NODE];
916 int nnodes_other=0,i;
917 int oneway_from=0,vehicles_from=1;
918
919 /* Find the segments that join the node 'via' */
920
921 segmentx=FirstSegmentX(segmentsx,relationx.via,1);
922
923 while(segmentx)
924 {
925 if(segmentx->way==relationx.from)
926 {
927 WayX *wayx=LookupWayX(waysx,segmentx->way,1);
928
929 if(node_from!=NO_NODE) /* Only one segment can be on the 'from' way */
930 {
931 logerror("Turn Relation %"Prelation_t" is not stored because the 'via' node is not at the end of the 'from' way.\n",relationx.id);
932 deleted++;
933 goto endloop;
934 }
935
936 node_from=OtherNode(segmentx,relationx.via);
937
938 if(IsOnewayFrom(segmentx,relationx.via))
939 oneway_from=1; /* not allowed */
940
941 if(!(wayx->way.allow&(Transports_Bicycle|Transports_Moped|Transports_Motorbike|Transports_Motorcar|Transports_Goods|Transports_HGV|Transports_PSV)))
942 vehicles_from=0; /* not allowed */
943 }
944
945 if(segmentx->way==relationx.to)
946 {
947 if(node_to!=NO_NODE) /* Only one segment can be on the 'to' way */
948 {
949 logerror("Turn Relation %"Prelation_t" is not stored because the 'via' node is not at the end of the 'to' way.\n",relationx.id);
950 deleted++;
951 goto endloop;
952 }
953
954 node_to=OtherNode(segmentx,relationx.via);
955 }
956
957 if(segmentx->way!=relationx.from && segmentx->way!=relationx.to)
958 {
959 WayX *wayx=LookupWayX(waysx,segmentx->way,1);
960
961 if(IsOnewayTo(segmentx,relationx.via))
962 ; /* not allowed */
963 else if(!(wayx->way.allow&(Transports_Bicycle|Transports_Moped|Transports_Motorbike|Transports_Motorcar|Transports_Goods|Transports_HGV|Transports_PSV)))
964 ; /* not allowed */
965 else
966 {
967 assert(nnodes_other<MAX_SEG_PER_NODE); /* Only a limited amount of information stored. */
968
969 node_other[nnodes_other++]=OtherNode(segmentx,relationx.via);
970 }
971 }
972
973 segmentx=NextSegmentX(segmentsx,segmentx,relationx.via);
974 }
975
976 if(node_from==NO_NODE)
977 logerror("Turn Relation %"Prelation_t" is not stored because the 'via' node is not part of the 'from' way.\n",relationx.id);
978
979 if(node_to==NO_NODE)
980 logerror("Turn Relation %"Prelation_t" is not stored because the 'via' node is not part of the 'to' way.\n",relationx.id);
981
982 if(nnodes_other==0)
983 logerror("Turn Relation %"Prelation_t" is not needed because the only allowed exit from the 'via' node is the 'to' way.\n",relationx.id);
984
985 if(oneway_from)
986 logerror("Turn Relation %"Prelation_t" is not needed because the 'from' way is oneway away from the 'via' node.\n",relationx.id);
987
988 if(!vehicles_from)
989 logerror("Turn Relation %"Prelation_t" is not stored because the 'from' way does not allow vehicles.\n",relationx.id);
990
991 if(oneway_from || !vehicles_from || node_from==NO_NODE || node_to==NO_NODE || nnodes_other==0)
992 {
993 deleted++;
994 goto endloop;
995 }
996
997 /* Write the results */
998
999 for(i=0;i<nnodes_other;i++)
1000 {
1001 relationx.from=node_from;
1002 relationx.to =node_other[i];
1003
1004 WriteFile(trfd,&relationx,sizeof(TurnRestrictRelX));
1005
1006 total++;
1007
1008 if(!(total%1000))
1009 printf_middle("Processing Turn Relations (2): Relations=%"Pindex_t" Deleted=%"Pindex_t" Added=%"Pindex_t,total,deleted,total-relationsx->trnumber+deleted);
1010 }
1011 }
1012
1013 /* Force super nodes on via node and adjacent nodes */
1014
1015 nodex=LookupNodeX(nodesx,relationx.via,1);
1016 nodex->flags|=NODE_TURNRSTRCT;
1017 PutBackNodeX(nodesx,nodex);
1018
1019 segmentx=FirstSegmentX(segmentsx,relationx.via,1);
1020
1021 while(segmentx)
1022 {
1023 index_t othernode=OtherNode(segmentx,relationx.via);
1024
1025 nodex=LookupNodeX(nodesx,othernode,1);
1026 nodex->flags|=NODE_TURNRSTRCT2;
1027 PutBackNodeX(nodesx,nodex);
1028
1029 segmentx=NextSegmentX(segmentsx,segmentx,relationx.via);
1030 }
1031
1032 endloop: ;
1033 }
1034
1035 /* Close the files */
1036
1037 relationsx->trfd=CloseFile(relationsx->trfd);
1038 CloseFile(trfd);
1039
1040 /* Unmap from memory / close the files */
1041
1042 #if !SLIM
1043 nodesx->data=UnmapFile(nodesx->data);
1044 segmentsx->data=UnmapFile(segmentsx->data);
1045 waysx->data=UnmapFile(waysx->data);
1046 #else
1047 nodesx->fd=CloseFile(nodesx->fd);
1048 segmentsx->fd=CloseFile(segmentsx->fd);
1049 waysx->fd=CloseFile(waysx->fd);
1050 #endif
1051
1052 /* Print the final message */
1053
1054 printf_last("Processed Turn Relations (2): Relations=%"Pindex_t" Deleted=%"Pindex_t" Added=%"Pindex_t,total,deleted,total-relationsx->trnumber+deleted);
1055
1056 relationsx->trnumber=total;
1057 }
1058
1059
1060 /*++++++++++++++++++++++++++++++++++++++
1061 Remove pruned turn relations and update the node indexes after pruning nodes.
1062
1063 RelationsX *relationsx The set of relations to modify.
1064
1065 NodesX *nodesx The set of nodes to use.
1066 ++++++++++++++++++++++++++++++++++++++*/
1067
1068 void RemovePrunedTurnRelations(RelationsX *relationsx,NodesX *nodesx)
1069 {
1070 TurnRestrictRelX relationx;
1071 index_t total=0,pruned=0,notpruned=0;
1072 int trfd;
1073
1074 /* Print the start message */
1075
1076 printf_first("Deleting Pruned Turn Relations: Relations=0 Pruned=0");
1077
1078 /* Re-open the file read-only and a new file writeable */
1079
1080 relationsx->trfd=ReOpenFile(relationsx->trfilename_tmp);
1081
1082 DeleteFile(relationsx->trfilename_tmp);
1083
1084 trfd=OpenFileNew(relationsx->trfilename_tmp);
1085
1086 /* Process all of the relations */
1087
1088 while(!ReadFile(relationsx->trfd,&relationx,sizeof(TurnRestrictRelX)))
1089 {
1090 relationx.from=nodesx->pdata[relationx.from];
1091 relationx.via =nodesx->pdata[relationx.via];
1092 relationx.to =nodesx->pdata[relationx.to];
1093
1094 if(relationx.from==NO_NODE || relationx.via==NO_NODE || relationx.to==NO_NODE)
1095 pruned++;
1096 else
1097 {
1098 WriteFile(trfd,&relationx,sizeof(TurnRestrictRelX));
1099
1100 notpruned++;
1101 }
1102
1103 total++;
1104
1105 if(!(total%1000))
1106 printf_middle("Deleting Pruned Turn Relations: Relations=%"Pindex_t" Pruned=%"Pindex_t,total,pruned);
1107 }
1108
1109 relationsx->trnumber=notpruned;
1110
1111 /* Close the files */
1112
1113 relationsx->trfd=CloseFile(relationsx->trfd);
1114 CloseFile(trfd);
1115
1116 /* Print the final message */
1117
1118 printf_last("Deleted Pruned Turn Relations: Relations=%"Pindex_t" Pruned=%"Pindex_t,total,pruned);
1119 }
1120
1121
1122 /*++++++++++++++++++++++++++++++++++++++
1123 Sort the turn relations geographically after updating the node indexes.
1124
1125 RelationsX *relationsx The set of relations to modify.
1126
1127 NodesX *nodesx The set of nodes to use.
1128
1129 SegmentsX *segmentsx The set of segments to use.
1130 ++++++++++++++++++++++++++++++++++++++*/
1131
1132 void SortTurnRelationListGeographically(RelationsX *relationsx,NodesX *nodesx,SegmentsX *segmentsx)
1133 {
1134 int trfd;
1135
1136 /* Print the start message */
1137
1138 printf_first("Sorting Turn Relations Geographically");
1139
1140 /* Map into memory / open the files */
1141
1142 #if !SLIM
1143 segmentsx->data=MapFile(segmentsx->filename_tmp);
1144 #else
1145 segmentsx->fd=ReOpenFile(segmentsx->filename_tmp);
1146 #endif
1147
1148 /* Re-open the file read-only and a new file writeable */
1149
1150 relationsx->trfd=ReOpenFile(relationsx->trfilename_tmp);
1151
1152 DeleteFile(relationsx->trfilename_tmp);
1153
1154 trfd=OpenFileNew(relationsx->trfilename_tmp);
1155
1156 /* Update the segments with geographically sorted node indexes and sort them */
1157
1158 sortnodesx=nodesx;
1159 sortsegmentsx=segmentsx;
1160
1161 filesort_fixed(relationsx->trfd,trfd,sizeof(TurnRestrictRelX),(int (*)(void*,index_t))geographically_index,
1162 (int (*)(const void*,const void*))sort_by_via,
1163 NULL);
1164
1165 /* Close the files */
1166
1167 relationsx->trfd=CloseFile(relationsx->trfd);
1168 CloseFile(trfd);
1169
1170 /* Unmap from memory / close the files */
1171
1172 #if !SLIM
1173 segmentsx->data=UnmapFile(segmentsx->data);
1174 #else
1175 segmentsx->fd=CloseFile(segmentsx->fd);
1176 #endif
1177
1178 /* Print the final message */
1179
1180 printf_last("Sorted Turn Relations Geographically: Turn Relations=%"Pindex_t,relationsx->trnumber);
1181 }
1182
1183
1184 /*++++++++++++++++++++++++++++++++++++++
1185 Update the turn relation indexes.
1186
1187 int geographically_index Return 1 if the value is to be kept, otherwise 0.
1188
1189 TurnRestrictRelX *relationx The extended turn relation.
1190
1191 index_t index The number of unsorted turn relations that have been read from the input file.
1192 ++++++++++++++++++++++++++++++++++++++*/
1193
1194 static int geographically_index(TurnRestrictRelX *relationx,index_t index)
1195 {
1196 SegmentX *segmentx;
1197 index_t from_node,via_node,to_node;
1198
1199 from_node=sortnodesx->gdata[relationx->from];
1200 via_node =sortnodesx->gdata[relationx->via];
1201 to_node =sortnodesx->gdata[relationx->to];
1202
1203 segmentx=FirstSegmentX(sortsegmentsx,via_node,1);
1204
1205 do
1206 {
1207 if(OtherNode(segmentx,via_node)==from_node)
1208 relationx->from=IndexSegmentX(sortsegmentsx,segmentx);
1209
1210 if(OtherNode(segmentx,via_node)==to_node)
1211 relationx->to=IndexSegmentX(sortsegmentsx,segmentx);
1212
1213 segmentx=NextSegmentX(sortsegmentsx,segmentx,via_node);
1214 }
1215 while(segmentx);
1216
1217 relationx->via=via_node;
1218
1219 return(1);
1220 }
1221
1222
1223 /*++++++++++++++++++++++++++++++++++++++
1224 Sort the turn restriction relations into via index order (then by from and to segments).
1225
1226 int sort_by_via Returns the comparison of the via, from and to fields.
1227
1228 TurnRestrictRelX *a The first extended relation.
1229
1230 TurnRestrictRelX *b The second extended relation.
1231 ++++++++++++++++++++++++++++++++++++++*/
1232
1233 static int sort_by_via(TurnRestrictRelX *a,TurnRestrictRelX *b)
1234 {
1235 index_t a_id=a->via;
1236 index_t b_id=b->via;
1237
1238 if(a_id<b_id)
1239 return(-1);
1240 else if(a_id>b_id)
1241 return(1);
1242 else
1243 {
1244 index_t a_id=a->from;
1245 index_t b_id=b->from;
1246
1247 if(a_id<b_id)
1248 return(-1);
1249 else if(a_id>b_id)
1250 return(1);
1251 else
1252 {
1253 index_t a_id=a->to;
1254 index_t b_id=b->to;
1255
1256 if(a_id<b_id)
1257 return(-1);
1258 else if(a_id>b_id)
1259 return(1);
1260 else
1261 return(FILESORT_PRESERVE_ORDER(a,b));
1262 }
1263 }
1264 }
1265
1266
1267 /*++++++++++++++++++++++++++++++++++++++
1268 Save the relation list to a file.
1269
1270 RelationsX* relationsx The set of relations to save.
1271
1272 const char *filename The name of the file to save.
1273 ++++++++++++++++++++++++++++++++++++++*/
1274
1275 void SaveRelationList(RelationsX* relationsx,const char *filename)
1276 {
1277 index_t i;
1278 int fd;
1279 RelationsFile relationsfile={0};
1280
1281 /* Print the start message */
1282
1283 printf_first("Writing Relations: Turn Relations=0");
1284
1285 /* Re-open the file read-only */
1286
1287 relationsx->trfd=ReOpenFile(relationsx->trfilename_tmp);
1288
1289 /* Write out the relations data */
1290
1291 fd=OpenFileNew(filename);
1292
1293 SeekFile(fd,sizeof(RelationsFile));
1294
1295 for(i=0;i<relationsx->trnumber;i++)
1296 {
1297 TurnRestrictRelX relationx;
1298 TurnRelation relation={0};
1299
1300 ReadFile(relationsx->trfd,&relationx,sizeof(TurnRestrictRelX));
1301
1302 relation.from=relationx.from;
1303 relation.via=relationx.via;
1304 relation.to=relationx.to;
1305 relation.except=relationx.except;
1306
1307 WriteFile(fd,&relation,sizeof(TurnRelation));
1308
1309 if(!((i+1)%1000))
1310 printf_middle("Writing Relations: Turn Relations=%"Pindex_t,i+1);
1311 }
1312
1313 /* Write out the header structure */
1314
1315 relationsfile.trnumber=relationsx->trnumber;
1316
1317 SeekFile(fd,0);
1318 WriteFile(fd,&relationsfile,sizeof(RelationsFile));
1319
1320 CloseFile(fd);
1321
1322 /* Close the file */
1323
1324 relationsx->trfd=CloseFile(relationsx->trfd);
1325
1326 /* Print the final message */
1327
1328 printf_last("Wrote Relations: Turn Relations=%"Pindex_t,relationsx->trnumber);
1329 }