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 1166 - (show annotations) (download) (as text)
Tue Nov 20 16:12:08 2012 UTC (12 years, 4 months ago) by amb
File MIME type: text/x-csrc
File size: 37898 byte(s)
Replace all assert statements with a custom error message that explains the
cause and suggests a solution.

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 /*+ The option to apply changes (needed to suppress some error log messages) +*/
46 extern int option_changes;
47
48 /* Local variables */
49
50 /*+ Temporary file-local variables for use by the sort functions. +*/
51 static SegmentsX *sortsegmentsx;
52 static NodesX *sortnodesx;
53
54 /* Local functions */
55
56 static int sort_route_by_id(RouteRelX *a,RouteRelX *b);
57 static int deduplicate_route_by_id(RouteRelX *relationx,index_t index);
58
59 static int sort_turn_by_id(TurnRelX *a,TurnRelX *b);
60 static int deduplicate_turn_by_id(TurnRelX *relationx,index_t index);
61
62 static int geographically_index(TurnRelX *relationx,index_t index);
63 static int sort_by_via(TurnRelX *a,TurnRelX *b);
64
65
66 /*++++++++++++++++++++++++++++++++++++++
67 Allocate a new relation list (create a new file or open an existing one).
68
69 RelationsX *NewRelationList Returns the relation list.
70
71 int append Set to 1 if the file is to be opened for appending.
72
73 int readonly Set to 1 if the file is to be opened for reading.
74 ++++++++++++++++++++++++++++++++++++++*/
75
76 RelationsX *NewRelationList(int append,int readonly)
77 {
78 RelationsX *relationsx;
79
80 relationsx=(RelationsX*)calloc(1,sizeof(RelationsX));
81
82 logassert(relationsx,"Failed to allocate memory (try using slim mode?)"); /* Check calloc() worked */
83
84
85 /* Route Relations */
86
87 relationsx->rfilename =(char*)malloc(strlen(option_tmpdirname)+32);
88 relationsx->rfilename_tmp=(char*)malloc(strlen(option_tmpdirname)+32);
89
90 sprintf(relationsx->rfilename ,"%s/relationsx.route.parsed.mem",option_tmpdirname);
91 sprintf(relationsx->rfilename_tmp,"%s/relationsx.route.%p.tmp" ,option_tmpdirname,(void*)relationsx);
92
93 if(append || readonly)
94 if(ExistsFile(relationsx->rfilename))
95 {
96 off_t size,position=0;
97 int rfd;
98
99 size=SizeFile(relationsx->rfilename);
100
101 rfd=ReOpenFile(relationsx->rfilename);
102
103 while(position<size)
104 {
105 FILESORT_VARINT relationsize;
106
107 SeekReadFile(rfd,&relationsize,FILESORT_VARSIZE,position);
108
109 relationsx->rnumber++;
110 position+=relationsize+FILESORT_VARSIZE;
111 }
112
113 CloseFile(rfd);
114
115 RenameFile(relationsx->rfilename ,relationsx->rfilename_tmp);
116 }
117
118 if(append)
119 relationsx->rfd=OpenFileAppend(relationsx->rfilename_tmp);
120 else if(!readonly)
121 relationsx->rfd=OpenFileNew(relationsx->rfilename_tmp);
122 else
123 relationsx->rfd=-1;
124
125
126 /* Turn Restriction Relations */
127
128 relationsx->trfilename =(char*)malloc(strlen(option_tmpdirname)+32);
129 relationsx->trfilename_tmp=(char*)malloc(strlen(option_tmpdirname)+32);
130
131 sprintf(relationsx->trfilename ,"%s/relationsx.turn.parsed.mem",option_tmpdirname);
132 sprintf(relationsx->trfilename_tmp,"%s/relationsx.turn.%p.tmp" ,option_tmpdirname,(void*)relationsx);
133
134 if(append || readonly)
135 if(ExistsFile(relationsx->trfilename))
136 {
137 off_t size;
138
139 size=SizeFile(relationsx->trfilename);
140
141 relationsx->trnumber=size/sizeof(TurnRelX);
142
143 RenameFile(relationsx->trfilename,relationsx->trfilename_tmp);
144 }
145
146 if(append)
147 relationsx->trfd=OpenFileAppend(relationsx->trfilename_tmp);
148 else if(!readonly)
149 relationsx->trfd=OpenFileNew(relationsx->trfilename_tmp);
150 else
151 relationsx->trfd=-1;
152
153 return(relationsx);
154 }
155
156
157 /*++++++++++++++++++++++++++++++++++++++
158 Free a relation list.
159
160 RelationsX *relationsx The set of relations to be freed.
161
162 int preserve If set then the results file is to be preserved.
163 ++++++++++++++++++++++++++++++++++++++*/
164
165 void FreeRelationList(RelationsX *relationsx,int preserve)
166 {
167 /* Route relations */
168
169 if(preserve)
170 RenameFile(relationsx->rfilename_tmp,relationsx->rfilename);
171 else
172 DeleteFile(relationsx->rfilename_tmp);
173
174 free(relationsx->rfilename);
175 free(relationsx->rfilename_tmp);
176
177
178 /* Turn Restriction relations */
179
180 if(preserve)
181 RenameFile(relationsx->trfilename_tmp,relationsx->trfilename);
182 else
183 DeleteFile(relationsx->trfilename_tmp);
184
185 free(relationsx->trfilename);
186 free(relationsx->trfilename_tmp);
187
188 free(relationsx);
189 }
190
191
192 /*++++++++++++++++++++++++++++++++++++++
193 Append a single relation to an unsorted route relation list.
194
195 RelationsX* relationsx The set of relations to process.
196
197 relation_t id The ID of the relation.
198
199 transports_t routes The types of routes that this relation is for.
200
201 way_t *ways The array of ways that are members of the relation.
202
203 int nways The number of ways that are members of the relation.
204
205 relation_t *relations The array of relations that are members of the relation.
206
207 int nrelations The number of relations that are members of the relation.
208 ++++++++++++++++++++++++++++++++++++++*/
209
210 void AppendRouteRelationList(RelationsX* relationsx,relation_t id,
211 transports_t routes,
212 way_t *ways,int nways,
213 relation_t *relations,int nrelations)
214 {
215 RouteRelX relationx={0};
216 FILESORT_VARINT size;
217 way_t noway=NO_WAY_ID;
218 relation_t norelation=NO_RELATION_ID;
219
220 relationx.id=id;
221 relationx.routes=routes;
222
223 size=sizeof(RouteRelX)+(nways+1)*sizeof(way_t)+(nrelations+1)*sizeof(relation_t);
224
225 WriteFile(relationsx->rfd,&size,FILESORT_VARSIZE);
226 WriteFile(relationsx->rfd,&relationx,sizeof(RouteRelX));
227
228 WriteFile(relationsx->rfd,ways ,nways*sizeof(way_t));
229 WriteFile(relationsx->rfd,&noway, sizeof(way_t));
230
231 WriteFile(relationsx->rfd,relations ,nrelations*sizeof(relation_t));
232 WriteFile(relationsx->rfd,&norelation, sizeof(relation_t));
233
234 relationsx->rnumber++;
235
236 logassert(relationsx->rnumber!=0,"Too many route relations (change index_t to 64-bits?)"); /* Zero marks the high-water mark for relations. */
237 }
238
239
240 /*++++++++++++++++++++++++++++++++++++++
241 Append a single relation to an unsorted turn restriction relation list.
242
243 RelationsX* relationsx The set of relations to process.
244
245 relation_t id The ID of the relation.
246
247 way_t from The way that the turn restriction starts from.
248
249 way_t to The way that the restriction finished on.
250
251 node_t via The node that the turn restriction passes through.
252
253 TurnRestriction restriction The type of restriction.
254
255 transports_t except The set of transports allowed to bypass the restriction.
256 ++++++++++++++++++++++++++++++++++++++*/
257
258 void AppendTurnRelationList(RelationsX* relationsx,relation_t id,
259 way_t from,way_t to,node_t via,
260 TurnRestriction restriction,transports_t except)
261 {
262 TurnRelX relationx={0};
263
264 relationx.id=id;
265 relationx.from=from;
266 relationx.to=to;
267 relationx.via=via;
268 relationx.restriction=restriction;
269 relationx.except=except;
270
271 WriteFile(relationsx->trfd,&relationx,sizeof(TurnRelX));
272
273 relationsx->trnumber++;
274
275 logassert(relationsx->trnumber!=0,"Too many turn relations (change index_t to 64-bits?)"); /* Zero marks the high-water mark for relations. */
276 }
277
278
279 /*++++++++++++++++++++++++++++++++++++++
280 Finish appending relations and change the filename over.
281
282 RelationsX *relationsx The relations that have been appended.
283 ++++++++++++++++++++++++++++++++++++++*/
284
285 void FinishRelationList(RelationsX *relationsx)
286 {
287 if(relationsx->rfd!=-1)
288 relationsx->rfd =CloseFile(relationsx->rfd);
289
290 if(relationsx->trfd!=-1)
291 relationsx->trfd=CloseFile(relationsx->trfd);
292 }
293
294
295 /*++++++++++++++++++++++++++++++++++++++
296 Sort the list of relations.
297
298 RelationsX* relationsx The set of relations to process.
299 ++++++++++++++++++++++++++++++++++++++*/
300
301 void SortRelationList(RelationsX* relationsx)
302 {
303 /* Route Relations */
304
305 if(relationsx->rnumber)
306 {
307 index_t rxnumber;
308 int rfd;
309
310 /* Print the start message */
311
312 printf_first("Sorting Route Relations");
313
314 /* Re-open the file read-only and a new file writeable */
315
316 relationsx->rfd=ReOpenFile(relationsx->rfilename_tmp);
317
318 DeleteFile(relationsx->rfilename_tmp);
319
320 rfd=OpenFileNew(relationsx->rfilename_tmp);
321
322 /* Sort the relations */
323
324 rxnumber=relationsx->rnumber;
325
326 relationsx->rnumber=filesort_vary(relationsx->rfd,rfd,NULL,
327 (int (*)(const void*,const void*))sort_route_by_id,
328 (int (*)(void*,index_t))deduplicate_route_by_id);
329
330 /* Close the files */
331
332 relationsx->rfd=CloseFile(relationsx->rfd);
333 CloseFile(rfd);
334
335 /* Print the final message */
336
337 printf_last("Sorted Route Relations: Relations=%"Pindex_t" Duplicates=%"Pindex_t,rxnumber,rxnumber-relationsx->rnumber);
338 }
339
340 /* Turn Restriction Relations. */
341
342 if(relationsx->trnumber)
343 {
344 index_t trxnumber;
345 int trfd;
346
347 /* Print the start message */
348
349 printf_first("Sorting Turn Relations");
350
351 /* Re-open the file read-only and a new file writeable */
352
353 relationsx->trfd=ReOpenFile(relationsx->trfilename_tmp);
354
355 DeleteFile(relationsx->trfilename_tmp);
356
357 trfd=OpenFileNew(relationsx->trfilename_tmp);
358
359 /* Sort the relations */
360
361 trxnumber=relationsx->trnumber;
362
363 relationsx->trnumber=filesort_fixed(relationsx->trfd,trfd,sizeof(TurnRelX),NULL,
364 (int (*)(const void*,const void*))sort_turn_by_id,
365 (int (*)(void*,index_t))deduplicate_turn_by_id);
366
367 /* Close the files */
368
369 relationsx->trfd=CloseFile(relationsx->trfd);
370 CloseFile(trfd);
371
372 /* Print the final message */
373
374 printf_last("Sorted Turn Relations: Relations=%"Pindex_t" Duplicates=%"Pindex_t,trxnumber,trxnumber-relationsx->trnumber);
375 }
376 }
377
378
379 /*++++++++++++++++++++++++++++++++++++++
380 Sort the route relations into id order.
381
382 int sort_route_by_id Returns the comparison of the id fields.
383
384 RouteRelX *a The first extended relation.
385
386 RouteRelX *b The second extended relation.
387 ++++++++++++++++++++++++++++++++++++++*/
388
389 static int sort_route_by_id(RouteRelX *a,RouteRelX *b)
390 {
391 relation_t a_id=a->id;
392 relation_t b_id=b->id;
393
394 if(a_id<b_id)
395 return(-1);
396 else if(a_id>b_id)
397 return(1);
398 else
399 return(-FILESORT_PRESERVE_ORDER(a,b)); /* latest version first */
400 }
401
402
403 /*++++++++++++++++++++++++++++++++++++++
404 Deduplicate the route relations using the id after sorting.
405
406 int deduplicate_route_by_id Return 1 if the value is to be kept, otherwise 0.
407
408 RouteRelX *relationx The extended relation.
409
410 index_t index The number of sorted relations that have already been written to the output file.
411 ++++++++++++++++++++++++++++++++++++++*/
412
413 static int deduplicate_route_by_id(RouteRelX *relationx,index_t index)
414 {
415 static relation_t previd=NO_RELATION_ID;
416
417 if(relationx->id!=previd)
418 {
419 previd=relationx->id;
420
421 if(relationx->routes==RELATION_DELETED)
422 return(0);
423 else
424 return(1);
425 }
426 else
427 {
428 if(!option_changes)
429 logerror("Relation %"Prelation_t" is duplicated.\n",relationx->id);
430
431 return(0);
432 }
433 }
434
435
436 /*++++++++++++++++++++++++++++++++++++++
437 Sort the turn restriction relations into id order.
438
439 int sort_turn_by_id Returns the comparison of the id fields.
440
441 TurnRelX *a The first extended relation.
442
443 TurnRelX *b The second extended relation.
444 ++++++++++++++++++++++++++++++++++++++*/
445
446 static int sort_turn_by_id(TurnRelX *a,TurnRelX *b)
447 {
448 relation_t a_id=a->id;
449 relation_t b_id=b->id;
450
451 if(a_id<b_id)
452 return(-1);
453 else if(a_id>b_id)
454 return(1);
455 else
456 return(-FILESORT_PRESERVE_ORDER(a,b)); /* latest version first */
457 }
458
459
460 /*++++++++++++++++++++++++++++++++++++++
461 Deduplicate the turn restriction relations using the id after sorting.
462
463 int deduplicate_turn_by_id Return 1 if the value is to be kept, otherwise 0.
464
465 TurnRelX *relationx The extended relation.
466
467 index_t index The number of sorted relations that have already been written to the output file.
468 ++++++++++++++++++++++++++++++++++++++*/
469
470 static int deduplicate_turn_by_id(TurnRelX *relationx,index_t index)
471 {
472 static relation_t previd=NO_RELATION_ID;
473
474 if(relationx->id!=previd)
475 {
476 previd=relationx->id;
477
478 if(relationx->except==RELATION_DELETED)
479 return(0);
480 else
481 return(1);
482 }
483 else
484 {
485 if(!option_changes)
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 TurnRelX relationx;
725 index_t via,from,to;
726
727 ReadFile(relationsx->trfd,&relationx,sizeof(TurnRelX));
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(TurnRelX));
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 TurnRelX 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(TurnRelX)))
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(TurnRelX));
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 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. */
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(TurnRelX));
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 TurnRelX 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(TurnRelX)))
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(TurnRelX));
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(TurnRelX),(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 TurnRelX *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(TurnRelX *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 TurnRelX *a The first extended relation.
1229
1230 TurnRelX *b The second extended relation.
1231 ++++++++++++++++++++++++++++++++++++++*/
1232
1233 static int sort_by_via(TurnRelX *a,TurnRelX *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 TurnRelX relationx;
1298 TurnRelation relation={0};
1299
1300 ReadFile(relationsx->trfd,&relationx,sizeof(TurnRelX));
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 }