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 1999 - (show annotations) (download) (as text)
Sat Jul 27 10:33:04 2019 UTC (5 years, 8 months ago) by amb
File MIME type: text/x-csrc
File size: 43180 byte(s)
Add more checking of memory allocation success/failure by combining
the allocation and the assert into one function.

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