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 1614 - (show annotations) (download) (as text)
Sat Oct 25 13:22:29 2014 UTC (10 years, 5 months ago) by amb
File MIME type: text/x-csrc
File size: 43129 byte(s)
Sort the data geographically before pruning so that the data points physically
close together are close together in memory which reduces swapping/paging and
therefore runs much faster when memory is limited.

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