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