Routino SVN Repository Browser

Check out the latest version of Routino: svn co http://routino.org/svn/trunk routino

ViewVC logotype

Contents of /branches/MS-Windows/src/relationsx.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1697 - (show annotations) (download) (as text)
Sun May 31 16:31:27 2015 UTC (9 years, 9 months ago) by amb
File MIME type: text/x-csrc
File size: 42797 byte(s)
Microsoft Windows does not allow deleting an open file and continuing
to use it like UNIX does.  For MS Windows rename the file instead of
deleting and replacing it and do not delete open files immediately but
wait until they are closed.

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