Routino SVN Repository Browser

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

ViewVC logotype

Contents of /trunk/src/relationsx.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1112 - (show annotations) (download) (as text)
Mon Oct 22 07:53:51 2012 UTC (12 years, 4 months ago) by amb
File MIME type: text/x-csrc
File size: 33623 byte(s)
Fix bug with index parameter in new pre-sort function and change comments to
clarify.

1 /***************************************
2 Extended Relation data type functions.
3
4 Part of the Routino routing software.
5 ******************/ /******************
6 This file Copyright 2010-2012 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 <assert.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include "types.h"
28 #include "segments.h"
29 #include "relations.h"
30
31 #include "nodesx.h"
32 #include "segmentsx.h"
33 #include "waysx.h"
34 #include "relationsx.h"
35
36 #include "files.h"
37 #include "logging.h"
38 #include "sorting.h"
39
40
41 /* Global variables */
42
43 /*+ The command line '--tmpdir' option or its default value. +*/
44 extern char *option_tmpdirname;
45
46 /* Local functions */
47
48 static int sort_by_id(TurnRestrictRelX *a,TurnRestrictRelX *b);
49 static int deduplicate_by_id(TurnRestrictRelX *relationx,index_t index);
50
51 static int geographically_index(TurnRestrictRelX *relationx,index_t index);
52 static int sort_by_via(TurnRestrictRelX *a,TurnRestrictRelX *b);
53
54 /* Local variables */
55
56 /*+ Temporary file-local variables for use by the sort functions. +*/
57 static SegmentsX *sortsegmentsx;
58 static NodesX *sortnodesx;
59
60
61 /*++++++++++++++++++++++++++++++++++++++
62 Allocate a new relation list (create a new file or open an existing one).
63
64 RelationsX *NewRelationList Returns the relation list.
65
66 int append Set to 1 if the file is to be opened for appending (now or later).
67 ++++++++++++++++++++++++++++++++++++++*/
68
69 RelationsX *NewRelationList(int append)
70 {
71 RelationsX *relationsx;
72
73 relationsx=(RelationsX*)calloc(1,sizeof(RelationsX));
74
75 assert(relationsx); /* Check calloc() worked */
76
77
78 /* Route Relations */
79
80 relationsx->rfilename=(char*)malloc(strlen(option_tmpdirname)+32);
81
82 if(append)
83 sprintf(relationsx->rfilename,"%s/relationsx.route.input.tmp",option_tmpdirname);
84 else
85 sprintf(relationsx->rfilename,"%s/relationsx.route.%p.tmp",option_tmpdirname,(void*)relationsx);
86
87 if(append)
88 {
89 off_t size,position=0;
90
91 relationsx->rfd=OpenFileAppend(relationsx->rfilename);
92
93 size=SizeFile(relationsx->rfilename);
94
95 while(position<size)
96 {
97 FILESORT_VARINT relationsize;
98
99 SeekReadFile(relationsx->rfd,&relationsize,FILESORT_VARSIZE,position);
100
101 relationsx->rnumber++;
102 position+=relationsize+FILESORT_VARSIZE;
103 }
104
105 SeekFile(relationsx->rfd,size);
106 }
107 else
108 relationsx->rfd=OpenFileNew(relationsx->rfilename);
109
110
111 /* Turn Restriction Relations */
112
113 relationsx->trfilename=(char*)malloc(strlen(option_tmpdirname)+32);
114
115 if(append)
116 sprintf(relationsx->trfilename,"%s/relationsx.turn.input.tmp",option_tmpdirname);
117 else
118 sprintf(relationsx->trfilename,"%s/relationsx.turn.%p.tmp",option_tmpdirname,(void*)relationsx);
119
120 if(append)
121 {
122 off_t size;
123
124 relationsx->trfd=OpenFileAppend(relationsx->trfilename);
125
126 size=SizeFile(relationsx->trfilename);
127
128 relationsx->trnumber=size/sizeof(TurnRestrictRelX);
129 }
130 else
131 relationsx->trfd=OpenFileNew(relationsx->trfilename);
132
133 return(relationsx);
134 }
135
136
137 /*++++++++++++++++++++++++++++++++++++++
138 Free a relation list.
139
140 RelationsX *relationsx The set of relations to be freed.
141
142 int keep Set to 1 if the file is to be kept (for appending later).
143 ++++++++++++++++++++++++++++++++++++++*/
144
145 void FreeRelationList(RelationsX *relationsx,int keep)
146 {
147 /* Route relations */
148
149 if(!keep)
150 DeleteFile(relationsx->rfilename);
151
152 free(relationsx->rfilename);
153
154
155 /* Turn Restriction relations */
156
157 if(!keep)
158 DeleteFile(relationsx->trfilename);
159
160 free(relationsx->trfilename);
161
162 free(relationsx);
163 }
164
165
166 /*++++++++++++++++++++++++++++++++++++++
167 Append a single relation to an unsorted route relation list.
168
169 RelationsX* relationsx The set of relations to process.
170
171 relation_t id The ID of the relation.
172
173 transports_t routes The types of routes that this relation is for.
174
175 way_t *ways The array of ways that are members of the relation.
176
177 int nways The number of ways that are members of the relation.
178
179 relation_t *relations The array of relations that are members of the relation.
180
181 int nrelations The number of relations that are members of the relation.
182 ++++++++++++++++++++++++++++++++++++++*/
183
184 void AppendRouteRelation(RelationsX* relationsx,relation_t id,
185 transports_t routes,
186 way_t *ways,int nways,
187 relation_t *relations,int nrelations)
188 {
189 RouteRelX relationx;
190 FILESORT_VARINT size;
191 way_t noway=NO_WAY;
192 relation_t norelation=NO_RELATION;
193
194 relationx.id=id;
195 relationx.routes=routes;
196
197 size=sizeof(RouteRelX)+(nways+1)*sizeof(way_t)+(nrelations+1)*sizeof(relation_t);
198
199 WriteFile(relationsx->rfd,&size,FILESORT_VARSIZE);
200 WriteFile(relationsx->rfd,&relationx,sizeof(RouteRelX));
201
202 WriteFile(relationsx->rfd,ways ,nways*sizeof(way_t));
203 WriteFile(relationsx->rfd,&noway, sizeof(way_t));
204
205 WriteFile(relationsx->rfd,relations ,nrelations*sizeof(relation_t));
206 WriteFile(relationsx->rfd,&norelation, sizeof(relation_t));
207
208 relationsx->rnumber++;
209
210 assert(relationsx->rnumber!=0); /* Zero marks the high-water mark for relations. */
211 }
212
213
214 /*++++++++++++++++++++++++++++++++++++++
215 Append a single relation to an unsorted turn restriction relation list.
216
217 RelationsX* relationsx The set of relations to process.
218
219 relation_t id The ID of the relation.
220
221 way_t from The way that the turn restriction starts from.
222
223 way_t to The way that the restriction finished on.
224
225 node_t via The node that the turn restriction passes through.
226
227 TurnRestriction restriction The type of restriction.
228
229 transports_t except The set of transports allowed to bypass the restriction.
230 ++++++++++++++++++++++++++++++++++++++*/
231
232 void AppendTurnRestrictRelation(RelationsX* relationsx,relation_t id,
233 way_t from,way_t to,node_t via,
234 TurnRestriction restriction,transports_t except)
235 {
236 TurnRestrictRelX relationx={0};
237
238 relationx.id=id;
239 relationx.from=from;
240 relationx.to=to;
241 relationx.via=via;
242 relationx.restriction=restriction;
243 relationx.except=except;
244
245 WriteFile(relationsx->trfd,&relationx,sizeof(TurnRestrictRelX));
246
247 relationsx->trnumber++;
248
249 assert(relationsx->trnumber!=0); /* Zero marks the high-water mark for relations. */
250 }
251
252
253 /*++++++++++++++++++++++++++++++++++++++
254 Sort the list of relations.
255
256 RelationsX* relationsx The set of relations to process.
257 ++++++++++++++++++++++++++++++++++++++*/
258
259 void SortRelationList(RelationsX* relationsx)
260 {
261 /* Close the files (finished appending) */
262
263 relationsx->rfd=CloseFile(relationsx->rfd);
264
265 relationsx->trfd=CloseFile(relationsx->trfd);
266
267
268 /* Route Relations */
269
270
271 /* Turn Restriction Relations. */
272
273 if(relationsx->trnumber)
274 {
275 index_t trxnumber;
276 int trfd;
277
278 /* Print the start message */
279
280 printf_first("Sorting Turn Relations");
281
282 /* Re-open the file read-only and a new file writeable */
283
284 relationsx->trfd=ReOpenFile(relationsx->trfilename);
285
286 DeleteFile(relationsx->trfilename);
287
288 trfd=OpenFileNew(relationsx->trfilename);
289
290 /* Sort the relations */
291
292 trxnumber=relationsx->trnumber;
293
294 relationsx->trnumber=filesort_fixed(relationsx->trfd,trfd,sizeof(TurnRestrictRelX),NULL,
295 (int (*)(const void*,const void*))sort_by_id,
296 (int (*)(void*,index_t))deduplicate_by_id);
297
298 /* Close the files */
299
300 relationsx->trfd=CloseFile(relationsx->trfd);
301 CloseFile(trfd);
302
303 /* Print the final message */
304
305 printf_last("Sorted Turn Relations: Relations=%"Pindex_t" Duplicates=%"Pindex_t,trxnumber,trxnumber-relationsx->trnumber);
306 }
307 }
308
309
310 /*++++++++++++++++++++++++++++++++++++++
311 Sort the turn restriction relations into id order.
312
313 int sort_by_id Returns the comparison of the id fields.
314
315 TurnRestrictRelX *a The first extended relation.
316
317 TurnRestrictRelX *b The second extended relation.
318 ++++++++++++++++++++++++++++++++++++++*/
319
320 static int sort_by_id(TurnRestrictRelX *a,TurnRestrictRelX *b)
321 {
322 relation_t a_id=a->id;
323 relation_t b_id=b->id;
324
325 if(a_id<b_id)
326 return(-1);
327 else if(a_id>b_id)
328 return(1);
329 else
330 return(0);
331 }
332
333
334 /*++++++++++++++++++++++++++++++++++++++
335 Deduplicate the extended relations using the id after sorting.
336
337 int deduplicate_by_id Return 1 if the value is to be kept, otherwise 0.
338
339 TurnRestrictRelX *relationx The extended relation.
340
341 index_t index The number of sorted relations that have already been written to the output file.
342 ++++++++++++++++++++++++++++++++++++++*/
343
344 static int deduplicate_by_id(TurnRestrictRelX *relationx,index_t index)
345 {
346 static relation_t previd;
347
348 if(index==0 || relationx->id!=previd)
349 {
350 previd=relationx->id;
351
352 return(1);
353 }
354 else
355 {
356 logerror("Relation %"Prelation_t" is duplicated.\n",relationx->id);
357
358 return(0);
359 }
360 }
361
362
363 /*++++++++++++++++++++++++++++++++++++++
364 Process the route relations and apply the information to the ways.
365
366 RelationsX *relationsx The set of relations to use.
367
368 WaysX *waysx The set of ways to modify.
369 ++++++++++++++++++++++++++++++++++++++*/
370
371 void ProcessRouteRelations(RelationsX *relationsx,WaysX *waysx)
372 {
373 RouteRelX *unmatched=NULL,*lastunmatched=NULL;
374 int nunmatched=0,lastnunmatched=0,iteration=1;
375
376 if(waysx->number==0)
377 return;
378
379 /* Map into memory / open the files */
380
381 #if !SLIM
382 waysx->data=MapFileWriteable(waysx->filename);
383 #else
384 waysx->fd=ReOpenFileWriteable(waysx->filename);
385 #endif
386
387 /* Re-open the file read-only */
388
389 relationsx->rfd=ReOpenFile(relationsx->rfilename);
390
391 /* Read through the file. */
392
393 do
394 {
395 int ways=0,relations=0;
396 index_t i;
397
398 SeekFile(relationsx->rfd,0);
399
400 /* Print the start message */
401
402 printf_first("Processing Route Relations (%d): Relations=0 Modified Ways=0",iteration);
403
404 for(i=0;i<relationsx->rnumber;i++)
405 {
406 FILESORT_VARINT size;
407 RouteRelX relationx;
408 way_t wayid;
409 relation_t relationid;
410 transports_t routes=Transports_None;
411
412 /* Read each route relation */
413
414 ReadFile(relationsx->rfd,&size,FILESORT_VARSIZE);
415 ReadFile(relationsx->rfd,&relationx,sizeof(RouteRelX));
416
417 /* Decide what type of route it is */
418
419 if(iteration==1)
420 {
421 relations++;
422 routes=relationx.routes;
423 }
424 else
425 {
426 int j;
427
428 for(j=0;j<lastnunmatched;j++)
429 if(lastunmatched[j].id==relationx.id)
430 {
431 relations++;
432
433 if((lastunmatched[j].routes|relationx.routes)==relationx.routes)
434 routes=0; /* Nothing new to add */
435 else
436 routes=lastunmatched[j].routes;
437
438 break;
439 }
440 }
441
442 /* Loop through the ways */
443
444 do
445 {
446 ReadFile(relationsx->rfd,&wayid,sizeof(way_t));
447
448 /* Update the ways that are listed for the relation */
449
450 if(wayid==NO_WAY)
451 continue;
452
453 if(routes)
454 {
455 index_t way=IndexWayX(waysx,wayid);
456
457 if(way!=NO_WAY)
458 {
459 WayX *wayx=LookupWayX(waysx,way,1);
460
461 if(routes&Transports_Foot)
462 {
463 if(!(wayx->way.allow&Transports_Foot))
464 {
465 logerror("Route Relation %"Prelation_t" for Foot contains Way %"Pway_t" that does not allow Foot transport; overriding.\n",relationx.id,wayid);
466 wayx->way.allow|=Transports_Foot;
467 }
468 wayx->way.props|=Properties_FootRoute;
469 }
470
471 if(routes&Transports_Bicycle)
472 {
473 if(!(wayx->way.allow&Transports_Bicycle))
474 {
475 logerror("Route Relation %"Prelation_t" for Bicycle contains Way %"Pway_t" that does not allow Bicycle transport; overriding.\n",relationx.id,wayid);
476 wayx->way.allow|=Transports_Bicycle;
477 }
478 wayx->way.props|=Properties_BicycleRoute;
479 }
480
481 PutBackWayX(waysx,wayx);
482
483 ways++;
484 }
485 else
486 logerror("Route Relation %"Prelation_t" contains Way %"Pway_t" but it does not exist in the Routino database.\n",relationx.id,wayid);
487 }
488 }
489 while(wayid!=NO_WAY);
490
491 /* Loop through the relations */
492
493 do
494 {
495 ReadFile(relationsx->rfd,&relationid,sizeof(relation_t));
496
497 /* Add the relations that are listed for this relation to the list for next time */
498
499 if(relationid==NO_RELATION)
500 continue;
501
502 if(relationid==relationx.id)
503 logerror("Relation %"Prelation_t" contains itself.\n",relationx.id);
504 else if(routes)
505 {
506 if(nunmatched%256==0)
507 unmatched=(RouteRelX*)realloc((void*)unmatched,(nunmatched+256)*sizeof(RouteRelX));
508
509 unmatched[nunmatched].id=relationid;
510 unmatched[nunmatched].routes=routes;
511
512 nunmatched++;
513 }
514 }
515 while(relationid!=NO_RELATION);
516
517 if(!((i+1)%1000))
518 printf_middle("Processing Route Relations (%d): Relations=%"Pindex_t" Modified Ways=%"Pindex_t,iteration,relations,ways);
519 }
520
521 if(lastunmatched)
522 free(lastunmatched);
523
524 lastunmatched=unmatched;
525 lastnunmatched=nunmatched;
526
527 unmatched=NULL;
528 nunmatched=0;
529
530 /* Print the final message */
531
532 printf_last("Processed Route Relations (%d): Relations=%"Pindex_t" Modified Ways=%"Pindex_t,iteration,relations,ways);
533 }
534 while(lastnunmatched && iteration++<8);
535
536 if(lastunmatched)
537 free(lastunmatched);
538
539 /* Close the file */
540
541 relationsx->rfd=CloseFile(relationsx->rfd);
542
543 /* Unmap from memory / close the files */
544
545 #if !SLIM
546 waysx->data=UnmapFile(waysx->filename);
547 #else
548 waysx->fd=CloseFile(waysx->fd);
549 #endif
550 }
551
552
553 /*++++++++++++++++++++++++++++++++++++++
554 Process the turn relations (first part) to update them with the node/way information.
555
556 RelationsX *relationsx The set of relations to modify.
557
558 NodesX *nodesx The set of nodes to use.
559
560 WaysX *waysx The set of ways to use.
561 ++++++++++++++++++++++++++++++++++++++*/
562
563 void ProcessTurnRelations1(RelationsX *relationsx,NodesX *nodesx,WaysX *waysx)
564 {
565 int trfd;
566 index_t i,deleted=0;
567
568 /* Print the start message */
569
570 printf_first("Processing Turn Relations (1): Relations=0");
571
572 /* Re-open the file read-only and a new file writeable */
573
574 relationsx->trfd=ReOpenFile(relationsx->trfilename);
575
576 DeleteFile(relationsx->trfilename);
577
578 trfd=OpenFileNew(relationsx->trfilename);
579
580 /* Process all of the relations */
581
582 for(i=0;i<relationsx->trnumber;i++)
583 {
584 TurnRestrictRelX relationx;
585 node_t via;
586 way_t from,to;
587
588 ReadFile(relationsx->trfd,&relationx,sizeof(TurnRestrictRelX));
589
590 via =IndexNodeX(nodesx,relationx.via);
591 from=IndexWayX(waysx,relationx.from);
592 to =IndexWayX(waysx,relationx.to);
593
594 if(via==NO_NODE)
595 logerror("Turn Relation %"Prelation_t" contains Node %"Pnode_t" but it does not exist in the Routino database.\n",relationx.id,relationx.via);
596
597 if(from==NO_WAY)
598 logerror("Turn Relation %"Prelation_t" contains Way %"Pway_t" but it does not exist in the Routino database.\n",relationx.id,relationx.from);
599
600 if(to==NO_WAY)
601 logerror("Turn Relation %"Prelation_t" contains Way %"Pway_t" but it does not exist in the Routino database.\n",relationx.id,relationx.to);
602
603 relationx.via =via;
604 relationx.from=from;
605 relationx.to =to;
606
607 if(relationx.via==NO_NODE || relationx.from==NO_WAY || relationx.to==NO_WAY)
608 deleted++;
609 else
610 WriteFile(trfd,&relationx,sizeof(TurnRestrictRelX));
611
612 if(!((i+1)%1000))
613 printf_middle("Processing Turn Relations (1): Relations=%"Pindex_t" Deleted=%"Pindex_t,i+1,deleted);
614 }
615
616 /* Close the files */
617
618 relationsx->trfd=CloseFile(relationsx->trfd);
619 CloseFile(trfd);
620
621 /* Print the final message */
622
623 printf_last("Processed Turn Relations (1): Relations=%"Pindex_t" Deleted=%"Pindex_t,relationsx->trnumber,deleted);
624
625 relationsx->trnumber-=deleted;
626 }
627
628
629 /*++++++++++++++++++++++++++++++++++++++
630 Process the turn relations (second part) to convert them to nodes.
631
632 RelationsX *relationsx The set of relations to modify.
633
634 NodesX *nodesx The set of nodes to use.
635
636 SegmentsX *segmentsx The set of segments to use.
637
638 WaysX *waysx The set of ways to use.
639 ++++++++++++++++++++++++++++++++++++++*/
640
641 void ProcessTurnRelations2(RelationsX *relationsx,NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx)
642 {
643 TurnRestrictRelX relationx;
644 int trfd;
645 index_t total=0,deleted=0;
646
647 if(nodesx->number==0 || segmentsx->number==0)
648 return;
649
650 /* Print the start message */
651
652 printf_first("Processing Turn Relations (2): Relations=0");
653
654 /* Map into memory / open the files */
655
656 #if !SLIM
657 nodesx->data=MapFileWriteable(nodesx->filename);
658 segmentsx->data=MapFile(segmentsx->filename);
659 waysx->data=MapFile(waysx->filename);
660 #else
661 nodesx->fd=ReOpenFileWriteable(nodesx->filename);
662 segmentsx->fd=ReOpenFile(segmentsx->filename);
663 waysx->fd=ReOpenFile(waysx->filename);
664 #endif
665
666 /* Re-open the file read-only and a new file writeable */
667
668 relationsx->trfd=ReOpenFile(relationsx->trfilename);
669
670 DeleteFile(relationsx->trfilename);
671
672 trfd=OpenFileNew(relationsx->trfilename);
673
674 /* Process all of the relations */
675
676 while(!ReadFile(relationsx->trfd,&relationx,sizeof(TurnRestrictRelX)))
677 {
678 NodeX *nodex;
679 SegmentX *segmentx;
680
681 if(relationx.restriction==TurnRestrict_no_right_turn ||
682 relationx.restriction==TurnRestrict_no_left_turn ||
683 relationx.restriction==TurnRestrict_no_u_turn ||
684 relationx.restriction==TurnRestrict_no_straight_on)
685 {
686 index_t node_from=NO_NODE,node_to=NO_NODE;
687 int oneway_from=0,oneway_to=0,vehicles_from=1,vehicles_to=1;
688
689 /* Find the segments that join the node 'via' */
690
691 segmentx=FirstSegmentX(segmentsx,relationx.via,1);
692
693 while(segmentx)
694 {
695 if(segmentx->way==relationx.from)
696 {
697 WayX *wayx=LookupWayX(waysx,segmentx->way,1);
698
699 if(node_from!=NO_NODE) /* Only one segment can be on the 'from' way */
700 {
701 logerror("Turn Relation %"Prelation_t" is not stored because the 'via' node is not at the end of the 'from' way.\n",relationx.id);
702 deleted++;
703 goto endloop;
704 }
705
706 node_from=OtherNode(segmentx,relationx.via);
707
708 if(IsOnewayFrom(segmentx,relationx.via))
709 oneway_from=1; /* not allowed */
710
711 if(!(wayx->way.allow&(Transports_Bicycle|Transports_Moped|Transports_Motorbike|Transports_Motorcar|Transports_Goods|Transports_HGV|Transports_PSV)))
712 vehicles_from=0; /* not allowed */
713 }
714
715 if(segmentx->way==relationx.to)
716 {
717 WayX *wayx=LookupWayX(waysx,segmentx->way,1);
718
719 if(node_to!=NO_NODE) /* Only one segment can be on the 'to' way */
720 {
721 logerror("Turn Relation %"Prelation_t" is not stored because the 'via' node is not at the end of the 'to' way.\n",relationx.id);
722 deleted++;
723 goto endloop;
724 }
725
726 node_to=OtherNode(segmentx,relationx.via);
727
728 if(IsOnewayTo(segmentx,relationx.via))
729 oneway_to=1; /* not allowed */
730
731 if(!(wayx->way.allow&(Transports_Bicycle|Transports_Moped|Transports_Motorbike|Transports_Motorcar|Transports_Goods|Transports_HGV|Transports_PSV)))
732 vehicles_to=0; /* not allowed */
733 }
734
735 segmentx=NextSegmentX(segmentsx,segmentx,relationx.via);
736 }
737
738 if(node_from==NO_NODE)
739 logerror("Turn Relation %"Prelation_t" is not stored because the 'via' node is not part of the 'from' way.\n",relationx.id);
740
741 if(node_to==NO_NODE)
742 logerror("Turn Relation %"Prelation_t" is not stored because the 'via' node is not part of the 'to' way.\n",relationx.id);
743
744 if(oneway_from)
745 logerror("Turn Relation %"Prelation_t" is not stored because the 'from' way is oneway away from the 'via' node.\n",relationx.id);
746
747 if(oneway_to)
748 logerror("Turn Relation %"Prelation_t" is not needed because the 'to' way is oneway towards the 'via' node.\n",relationx.id);
749
750 if(!vehicles_from)
751 logerror("Turn Relation %"Prelation_t" is not stored because the 'from' way does not allow vehicles.\n",relationx.id);
752
753 if(!vehicles_to)
754 logerror("Turn Relation %"Prelation_t" is not needed because the 'to' way does not allow vehicles.\n",relationx.id);
755
756 if(oneway_from || oneway_to || !vehicles_from || !vehicles_to || node_from==NO_NODE || node_to==NO_NODE)
757 {
758 deleted++;
759 goto endloop;
760 }
761
762 /* Write the results */
763
764 relationx.from=node_from;
765 relationx.to =node_to;
766
767 WriteFile(trfd,&relationx,sizeof(TurnRestrictRelX));
768
769 total++;
770
771 if(!(total%1000))
772 printf_middle("Processing Turn Relations (2): Relations=%"Pindex_t" Deleted=%"Pindex_t" Added=%"Pindex_t,total,deleted,total-relationsx->trnumber+deleted);
773 }
774 else
775 {
776 index_t node_from=NO_NODE,node_to=NO_NODE,node_other[MAX_SEG_PER_NODE];
777 int nnodes_other=0,i;
778 int oneway_from=0,vehicles_from=1;
779
780 /* Find the segments that join the node 'via' */
781
782 segmentx=FirstSegmentX(segmentsx,relationx.via,1);
783
784 while(segmentx)
785 {
786 if(segmentx->way==relationx.from)
787 {
788 WayX *wayx=LookupWayX(waysx,segmentx->way,1);
789
790 if(node_from!=NO_NODE) /* Only one segment can be on the 'from' way */
791 {
792 logerror("Turn Relation %"Prelation_t" is not stored because the 'via' node is not at the end of the 'from' way.\n",relationx.id);
793 deleted++;
794 goto endloop;
795 }
796
797 node_from=OtherNode(segmentx,relationx.via);
798
799 if(IsOnewayFrom(segmentx,relationx.via))
800 oneway_from=1; /* not allowed */
801
802 if(!(wayx->way.allow&(Transports_Bicycle|Transports_Moped|Transports_Motorbike|Transports_Motorcar|Transports_Goods|Transports_HGV|Transports_PSV)))
803 vehicles_from=0; /* not allowed */
804 }
805
806 if(segmentx->way==relationx.to)
807 {
808 if(node_to!=NO_NODE) /* Only one segment can be on the 'to' way */
809 {
810 logerror("Turn Relation %"Prelation_t" is not stored because the 'via' node is not at the end of the 'to' way.\n",relationx.id);
811 deleted++;
812 goto endloop;
813 }
814
815 node_to=OtherNode(segmentx,relationx.via);
816 }
817
818 if(segmentx->way!=relationx.from && segmentx->way!=relationx.to)
819 {
820 WayX *wayx=LookupWayX(waysx,segmentx->way,1);
821
822 if(IsOnewayTo(segmentx,relationx.via))
823 ; /* not allowed */
824 else if(!(wayx->way.allow&(Transports_Bicycle|Transports_Moped|Transports_Motorbike|Transports_Motorcar|Transports_Goods|Transports_HGV|Transports_PSV)))
825 ; /* not allowed */
826 else
827 {
828 assert(nnodes_other<MAX_SEG_PER_NODE); /* Only a limited amount of information stored. */
829
830 node_other[nnodes_other++]=OtherNode(segmentx,relationx.via);
831 }
832 }
833
834 segmentx=NextSegmentX(segmentsx,segmentx,relationx.via);
835 }
836
837 if(node_from==NO_NODE)
838 logerror("Turn Relation %"Prelation_t" is not stored because the 'via' node is not part of the 'from' way.\n",relationx.id);
839
840 if(node_to==NO_NODE)
841 logerror("Turn Relation %"Prelation_t" is not stored because the 'via' node is not part of the 'to' way.\n",relationx.id);
842
843 if(nnodes_other==0)
844 logerror("Turn Relation %"Prelation_t" is not needed because the only allowed exit from the 'via' node is the 'to' way.\n",relationx.id);
845
846 if(oneway_from)
847 logerror("Turn Relation %"Prelation_t" is not needed because the 'from' way is oneway away from the 'via' node.\n",relationx.id);
848
849 if(!vehicles_from)
850 logerror("Turn Relation %"Prelation_t" is not stored because the 'from' way does not allow vehicles.\n",relationx.id);
851
852 if(oneway_from || !vehicles_from || node_from==NO_NODE || node_to==NO_NODE || nnodes_other==0)
853 {
854 deleted++;
855 goto endloop;
856 }
857
858 /* Write the results */
859
860 for(i=0;i<nnodes_other;i++)
861 {
862 relationx.from=node_from;
863 relationx.to =node_other[i];
864
865 WriteFile(trfd,&relationx,sizeof(TurnRestrictRelX));
866
867 total++;
868
869 if(!(total%1000))
870 printf_middle("Processing Turn Relations (2): Relations=%"Pindex_t" Deleted=%"Pindex_t" Added=%"Pindex_t,total,deleted,total-relationsx->trnumber+deleted);
871 }
872 }
873
874 /* Force super nodes on via node and adjacent nodes */
875
876 nodex=LookupNodeX(nodesx,relationx.via,1);
877 nodex->flags|=NODE_TURNRSTRCT;
878 PutBackNodeX(nodesx,nodex);
879
880 segmentx=FirstSegmentX(segmentsx,relationx.via,1);
881
882 while(segmentx)
883 {
884 index_t othernode=OtherNode(segmentx,relationx.via);
885
886 nodex=LookupNodeX(nodesx,othernode,1);
887 nodex->flags|=NODE_TURNRSTRCT2;
888 PutBackNodeX(nodesx,nodex);
889
890 segmentx=NextSegmentX(segmentsx,segmentx,relationx.via);
891 }
892
893 endloop: ;
894 }
895
896 /* Close the files */
897
898 relationsx->trfd=CloseFile(relationsx->trfd);
899 CloseFile(trfd);
900
901 /* Unmap from memory / close the files */
902
903 #if !SLIM
904 nodesx->data=UnmapFile(nodesx->filename);
905 segmentsx->data=UnmapFile(segmentsx->filename);
906 waysx->data=UnmapFile(waysx->filename);
907 #else
908 nodesx->fd=CloseFile(nodesx->fd);
909 segmentsx->fd=CloseFile(segmentsx->fd);
910 waysx->fd=CloseFile(waysx->fd);
911 #endif
912
913 /* Print the final message */
914
915 printf_last("Processed Turn Relations (2): Relations=%"Pindex_t" Deleted=%"Pindex_t" Added=%"Pindex_t,total,deleted,total-relationsx->trnumber+deleted);
916
917 relationsx->trnumber=total;
918 }
919
920
921 /*++++++++++++++++++++++++++++++++++++++
922 Remove pruned turn relations and update the node indexes after pruning nodes.
923
924 RelationsX *relationsx The set of relations to modify.
925
926 NodesX *nodesx The set of nodes to use.
927 ++++++++++++++++++++++++++++++++++++++*/
928
929 void RemovePrunedTurnRelations(RelationsX *relationsx,NodesX *nodesx)
930 {
931 TurnRestrictRelX relationx;
932 index_t total=0,pruned=0,notpruned=0;
933 int trfd;
934
935 /* Print the start message */
936
937 printf_first("Deleting Pruned Turn Relations: Relations=0 Pruned=0");
938
939 /* Re-open the file read-only and a new file writeable */
940
941 relationsx->trfd=ReOpenFile(relationsx->trfilename);
942
943 DeleteFile(relationsx->trfilename);
944
945 trfd=OpenFileNew(relationsx->trfilename);
946
947 /* Process all of the relations */
948
949 while(!ReadFile(relationsx->trfd,&relationx,sizeof(TurnRestrictRelX)))
950 {
951 relationx.from=nodesx->pdata[relationx.from];
952 relationx.via =nodesx->pdata[relationx.via];
953 relationx.to =nodesx->pdata[relationx.to];
954
955 if(relationx.from==NO_NODE || relationx.via==NO_NODE || relationx.to==NO_NODE)
956 pruned++;
957 else
958 {
959 WriteFile(trfd,&relationx,sizeof(TurnRestrictRelX));
960
961 notpruned++;
962 }
963
964 total++;
965
966 if(!(total%1000))
967 printf_middle("Deleting Pruned Turn Relations: Relations=%"Pindex_t" Pruned=%"Pindex_t,total,pruned);
968 }
969
970 relationsx->trnumber=notpruned;
971
972 /* Close the files */
973
974 relationsx->trfd=CloseFile(relationsx->trfd);
975 CloseFile(trfd);
976
977 /* Print the final message */
978
979 printf_last("Deleted Pruned Turn Relations: Relations=%"Pindex_t" Pruned=%"Pindex_t,total,pruned);
980 }
981
982
983 /*++++++++++++++++++++++++++++++++++++++
984 Sort the turn relations geographically after updating the node indexes.
985
986 RelationsX *relationsx The set of relations to modify.
987
988 NodesX *nodesx The set of nodes to use.
989
990 SegmentsX *segmentsx The set of segments to use.
991 ++++++++++++++++++++++++++++++++++++++*/
992
993 void SortTurnRelationListGeographically(RelationsX *relationsx,NodesX *nodesx,SegmentsX *segmentsx)
994 {
995 int trfd;
996
997 /* Print the start message */
998
999 printf_first("Sorting Turn Relations Geographically");
1000
1001 /* Map into memory / open the files */
1002
1003 #if !SLIM
1004 segmentsx->data=MapFile(segmentsx->filename);
1005 #else
1006 segmentsx->fd=ReOpenFile(segmentsx->filename);
1007 #endif
1008
1009 /* Re-open the file read-only and a new file writeable */
1010
1011 relationsx->trfd=ReOpenFile(relationsx->trfilename);
1012
1013 DeleteFile(relationsx->trfilename);
1014
1015 trfd=OpenFileNew(relationsx->trfilename);
1016
1017 /* Update the segments with geographically sorted node indexes and sort them */
1018
1019 sortnodesx=nodesx;
1020 sortsegmentsx=segmentsx;
1021
1022 filesort_fixed(relationsx->trfd,trfd,sizeof(TurnRestrictRelX),(int (*)(void*,index_t))geographically_index,
1023 (int (*)(const void*,const void*))sort_by_via,
1024 NULL);
1025
1026 /* Close the files */
1027
1028 relationsx->trfd=CloseFile(relationsx->trfd);
1029 CloseFile(trfd);
1030
1031 /* Unmap from memory / close the files */
1032
1033 #if !SLIM
1034 segmentsx->data=UnmapFile(segmentsx->filename);
1035 #else
1036 segmentsx->fd=CloseFile(segmentsx->fd);
1037 #endif
1038
1039 /* Print the final message */
1040
1041 printf_last("Sorted Turn Relations Geographically: Turn Relations=%"Pindex_t,relationsx->trnumber);
1042 }
1043
1044
1045 /*++++++++++++++++++++++++++++++++++++++
1046 Update the turn relation indexes.
1047
1048 int geographically_index Return 1 if the value is to be kept, otherwise 0.
1049
1050 TurnRestrictRelX *relationx The extended turn relation.
1051
1052 index_t index The number of unsorted turn relations that have been read from the input file.
1053 ++++++++++++++++++++++++++++++++++++++*/
1054
1055 static int geographically_index(TurnRestrictRelX *relationx,index_t index)
1056 {
1057 SegmentX *segmentx;
1058 index_t from_node,via_node,to_node;
1059
1060 from_node=sortnodesx->gdata[relationx->from];
1061 via_node =sortnodesx->gdata[relationx->via];
1062 to_node =sortnodesx->gdata[relationx->to];
1063
1064 segmentx=FirstSegmentX(sortsegmentsx,via_node,1);
1065
1066 do
1067 {
1068 if(OtherNode(segmentx,via_node)==from_node)
1069 relationx->from=IndexSegmentX(sortsegmentsx,segmentx);
1070
1071 if(OtherNode(segmentx,via_node)==to_node)
1072 relationx->to=IndexSegmentX(sortsegmentsx,segmentx);
1073
1074 segmentx=NextSegmentX(sortsegmentsx,segmentx,via_node);
1075 }
1076 while(segmentx);
1077
1078 relationx->via=via_node;
1079
1080 return(1);
1081 }
1082
1083
1084 /*++++++++++++++++++++++++++++++++++++++
1085 Sort the turn restriction relations into via index order (then by from and to segments).
1086
1087 int sort_by_via Returns the comparison of the via, from and to fields.
1088
1089 TurnRestrictRelX *a The first extended relation.
1090
1091 TurnRestrictRelX *b The second extended relation.
1092 ++++++++++++++++++++++++++++++++++++++*/
1093
1094 static int sort_by_via(TurnRestrictRelX *a,TurnRestrictRelX *b)
1095 {
1096 index_t a_id=a->via;
1097 index_t b_id=b->via;
1098
1099 if(a_id<b_id)
1100 return(-1);
1101 else if(a_id>b_id)
1102 return(1);
1103 else
1104 {
1105 index_t a_id=a->from;
1106 index_t b_id=b->from;
1107
1108 if(a_id<b_id)
1109 return(-1);
1110 else if(a_id>b_id)
1111 return(1);
1112 else
1113 {
1114 index_t a_id=a->to;
1115 index_t b_id=b->to;
1116
1117 if(a_id<b_id)
1118 return(-1);
1119 else if(a_id>b_id)
1120 return(1);
1121 else
1122 return(0);
1123 }
1124 }
1125 }
1126
1127
1128 /*++++++++++++++++++++++++++++++++++++++
1129 Save the relation list to a file.
1130
1131 RelationsX* relationsx The set of relations to save.
1132
1133 const char *filename The name of the file to save.
1134 ++++++++++++++++++++++++++++++++++++++*/
1135
1136 void SaveRelationList(RelationsX* relationsx,const char *filename)
1137 {
1138 index_t i;
1139 int fd;
1140 RelationsFile relationsfile={0};
1141
1142 /* Print the start message */
1143
1144 printf_first("Writing Relations: Turn Relations=0");
1145
1146 /* Re-open the file read-only */
1147
1148 relationsx->trfd=ReOpenFile(relationsx->trfilename);
1149
1150 /* Write out the relations data */
1151
1152 fd=OpenFileNew(filename);
1153
1154 SeekFile(fd,sizeof(RelationsFile));
1155
1156 for(i=0;i<relationsx->trnumber;i++)
1157 {
1158 TurnRestrictRelX relationx;
1159 TurnRelation relation={0};
1160
1161 ReadFile(relationsx->trfd,&relationx,sizeof(TurnRestrictRelX));
1162
1163 relation.from=relationx.from;
1164 relation.via=relationx.via;
1165 relation.to=relationx.to;
1166 relation.except=relationx.except;
1167
1168 WriteFile(fd,&relation,sizeof(TurnRelation));
1169
1170 if(!((i+1)%1000))
1171 printf_middle("Writing Relations: Turn Relations=%"Pindex_t,i+1);
1172 }
1173
1174 /* Write out the header structure */
1175
1176 relationsfile.trnumber=relationsx->trnumber;
1177
1178 SeekFile(fd,0);
1179 WriteFile(fd,&relationsfile,sizeof(RelationsFile));
1180
1181 CloseFile(fd);
1182
1183 /* Close the file */
1184
1185 relationsx->trfd=CloseFile(relationsx->trfd);
1186
1187 /* Print the final message */
1188
1189 printf_last("Wrote Relations: Turn Relations=%"Pindex_t,relationsx->trnumber);
1190 }