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 1163 - (show annotations) (download) (as text)
Tue Nov 20 14:30:56 2012 UTC (12 years, 3 months ago) by amb
File MIME type: text/x-csrc
File size: 37682 byte(s)
Tidy up all of the recent code changes - Rename TurnRestrictRelX structure to
TurnRelX.

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