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