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