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 1342 - (show annotations) (download) (as text)
Sat May 25 15:10:07 2013 UTC (11 years, 10 months ago) by amb
File MIME type: text/x-csrc
File size: 42220 byte(s)
Rename the route relation structure parameters (r* -> rr*) to match the turn
relation parameter names (tr*).

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