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 1698 - (show annotations) (download) (as text)
Sun May 31 16:34:57 2015 UTC (9 years, 10 months ago) by amb
File MIME type: text/x-csrc
File size: 42869 byte(s)
Merge changes from trunk: remove -Wfloat-conversion option, change
web/Makefile order, ensure allocated strings are long enough.

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)+48); /* allow %p to be up to 20 bytes */
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)+48); /* allow %p to be up to 20 bytes */
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 }