Routino SVN Repository Browser

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

ViewVC logotype

Contents of /branches/destination-access/src/relationsx.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1957 - (show annotations) (download) (as text)
Fri Sep 21 17:29:51 2018 UTC (6 years, 5 months ago) by amb
File MIME type: text/x-csrc
File size: 43052 byte(s)
Merge from trunk.  Also update tagging for 'destination' access.

1 /***************************************
2 Extended Relation data type functions.
3
4 Part of the Routino routing software.
5 ******************/ /******************
6 This file Copyright 2010-2015, 2018 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(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 offset_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; /* internal variable (reset by first call in each sort; index==0) */
551
552 if(index==0 || 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; /* internal variable (reset by first call in each sort; index==0) */
603
604 if(index==0 || 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.\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.\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.\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.\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 int convert Set to 1 to convert the segments as well as sorting them (the second time it is called).
1226 ++++++++++++++++++++++++++++++++++++++*/
1227
1228 void SortTurnRelationListGeographically(RelationsX *relationsx,NodesX *nodesx,SegmentsX *segmentsx,int convert)
1229 {
1230 int trfd;
1231
1232 if(segmentsx->number==0)
1233 return;
1234
1235 /* Print the start message */
1236
1237 printf_first("Sorting Turn Relations Geographically");
1238
1239 /* Map into memory / open the files */
1240
1241 #if !SLIM
1242 segmentsx->data=MapFile(segmentsx->filename_tmp);
1243 #else
1244 segmentsx->fd=SlimMapFile(segmentsx->filename_tmp);
1245
1246 InvalidateSegmentXCache(segmentsx->cache);
1247 #endif
1248
1249 /* Re-open the file read-only and a new file writeable */
1250
1251 trfd=ReplaceFileBuffered(relationsx->trfilename_tmp,&relationsx->trfd);
1252
1253 /* Update the segments with geographically sorted node indexes and sort them */
1254
1255 sortnodesx=nodesx;
1256 sortsegmentsx=segmentsx;
1257
1258 if(!convert)
1259 filesort_fixed(relationsx->trfd,trfd,sizeof(TurnRelX),(int (*)(void*,index_t))geographically_index,
1260 (int (*)(const void*,const void*))sort_by_via,
1261 NULL);
1262 else
1263 filesort_fixed(relationsx->trfd,trfd,sizeof(TurnRelX),(int (*)(void*,index_t))geographically_index_convert_segments,
1264 (int (*)(const void*,const void*))sort_by_via,
1265 NULL);
1266
1267 /* Close the files */
1268
1269 relationsx->trfd=CloseFileBuffered(relationsx->trfd);
1270 CloseFileBuffered(trfd);
1271
1272 /* Unmap from memory / close the files */
1273
1274 #if !SLIM
1275 segmentsx->data=UnmapFile(segmentsx->data);
1276 #else
1277 segmentsx->fd=SlimUnmapFile(segmentsx->fd);
1278 #endif
1279
1280 /* Free the memory */
1281
1282 if(nodesx->gdata)
1283 {
1284 log_free(nodesx->gdata);
1285 free(nodesx->gdata);
1286 nodesx->gdata=NULL;
1287 }
1288
1289 /* Print the final message */
1290
1291 printf_last("Sorted Turn Relations Geographically: Turn Relations=%"Pindex_t,relationsx->trnumber);
1292 }
1293
1294
1295 /*++++++++++++++++++++++++++++++++++++++
1296 Update the turn relation indexes.
1297
1298 int geographically_index Return 1 if the value is to be kept, otherwise 0.
1299
1300 TurnRelX *relationx The extended turn relation.
1301
1302 index_t index The number of unsorted turn relations that have been read from the input file.
1303 ++++++++++++++++++++++++++++++++++++++*/
1304
1305 static int geographically_index(TurnRelX *relationx,index_t index)
1306 {
1307 relationx->from=sortnodesx->gdata[relationx->from];
1308 relationx->via =sortnodesx->gdata[relationx->via];
1309 relationx->to =sortnodesx->gdata[relationx->to];
1310
1311 return(1);
1312 }
1313
1314
1315 /*++++++++++++++++++++++++++++++++++++++
1316 Update the turn relation indexes and replace them with segments.
1317
1318 int geographically_index_convert_segments Return 1 if the value is to be kept, otherwise 0.
1319
1320 TurnRelX *relationx The extended turn relation.
1321
1322 index_t index The number of unsorted turn relations that have been read from the input file.
1323 ++++++++++++++++++++++++++++++++++++++*/
1324
1325 static int geographically_index_convert_segments(TurnRelX *relationx,index_t index)
1326 {
1327 SegmentX *segmentx;
1328 index_t from_node,via_node,to_node;
1329
1330 from_node=sortnodesx->gdata[relationx->from];
1331 via_node =sortnodesx->gdata[relationx->via];
1332 to_node =sortnodesx->gdata[relationx->to];
1333
1334 segmentx=FirstSegmentX(sortsegmentsx,via_node,1);
1335
1336 do
1337 {
1338 if(OtherNode(segmentx,via_node)==from_node)
1339 relationx->from=IndexSegmentX(sortsegmentsx,segmentx);
1340
1341 if(OtherNode(segmentx,via_node)==to_node)
1342 relationx->to=IndexSegmentX(sortsegmentsx,segmentx);
1343
1344 segmentx=NextSegmentX(sortsegmentsx,segmentx,via_node);
1345 }
1346 while(segmentx);
1347
1348 relationx->via=via_node;
1349
1350 return(1);
1351 }
1352
1353
1354 /*++++++++++++++++++++++++++++++++++++++
1355 Sort the turn restriction relations into via index order (then by from and to segments).
1356
1357 int sort_by_via Returns the comparison of the via, from and to fields.
1358
1359 TurnRelX *a The first extended relation.
1360
1361 TurnRelX *b The second extended relation.
1362 ++++++++++++++++++++++++++++++++++++++*/
1363
1364 static int sort_by_via(TurnRelX *a,TurnRelX *b)
1365 {
1366 index_t a_id=a->via;
1367 index_t b_id=b->via;
1368
1369 if(a_id<b_id)
1370 return(-1);
1371 else if(a_id>b_id)
1372 return(1);
1373 else
1374 {
1375 index_t a_id=a->from;
1376 index_t b_id=b->from;
1377
1378 if(a_id<b_id)
1379 return(-1);
1380 else if(a_id>b_id)
1381 return(1);
1382 else
1383 {
1384 index_t a_id=a->to;
1385 index_t b_id=b->to;
1386
1387 if(a_id<b_id)
1388 return(-1);
1389 else if(a_id>b_id)
1390 return(1);
1391 else
1392 return(FILESORT_PRESERVE_ORDER(a,b));
1393 }
1394 }
1395 }
1396
1397
1398 /*++++++++++++++++++++++++++++++++++++++
1399 Save the relation list to a file.
1400
1401 RelationsX* relationsx The set of relations to save.
1402
1403 const char *filename The name of the file to save.
1404 ++++++++++++++++++++++++++++++++++++++*/
1405
1406 void SaveRelationList(RelationsX* relationsx,const char *filename)
1407 {
1408 index_t i;
1409 int fd;
1410 RelationsFile relationsfile={0};
1411
1412 /* Print the start message */
1413
1414 printf_first("Writing Relations: Turn Relations=0");
1415
1416 /* Re-open the file read-only */
1417
1418 relationsx->trfd=ReOpenFileBuffered(relationsx->trfilename_tmp);
1419
1420 /* Write out the relations data */
1421
1422 fd=OpenFileBufferedNew(filename);
1423
1424 SeekFileBuffered(fd,sizeof(RelationsFile));
1425
1426 for(i=0;i<relationsx->trnumber;i++)
1427 {
1428 TurnRelX relationx;
1429 TurnRelation relation={0};
1430
1431 ReadFileBuffered(relationsx->trfd,&relationx,sizeof(TurnRelX));
1432
1433 relation.from=relationx.from;
1434 relation.via=relationx.via;
1435 relation.to=relationx.to;
1436 relation.except=relationx.except;
1437
1438 WriteFileBuffered(fd,&relation,sizeof(TurnRelation));
1439
1440 if(!((i+1)%1000))
1441 printf_middle("Writing Relations: Turn Relations=%"Pindex_t,i+1);
1442 }
1443
1444 /* Write out the header structure */
1445
1446 relationsfile.trnumber=relationsx->trnumber;
1447
1448 SeekFileBuffered(fd,0);
1449 WriteFileBuffered(fd,&relationsfile,sizeof(RelationsFile));
1450
1451 CloseFileBuffered(fd);
1452
1453 /* Close the file */
1454
1455 relationsx->trfd=CloseFileBuffered(relationsx->trfd);
1456
1457 /* Print the final message */
1458
1459 printf_last("Wrote Relations: Turn Relations=%"Pindex_t,relationsx->trnumber);
1460 }