1 /***************************************
2 $Header: /home/amb/routino/src/RCS/segmentsx.c,v 1.68 2010/10/09 14:14:42 amb Exp $
4 Extended Segment data type functions.
6 Part of the Routino routing software.
7 ******************/ /******************
8 This file Copyright 2008-2010 Andrew M. Bishop
10 This program is free software: you can redistribute it and/or modify
11 it under the terms of the GNU Affero General Public License as published by
12 the Free Software Foundation, either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU Affero General Public License for more details.
20 You should have received a copy of the GNU Affero General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 ***************************************/
38 #include "segmentsx.h"
44 #include "functions.h"
49 /*+ The command line '--tmpdir' option or its default value. +*/
50 extern char *option_tmpdirname;
54 static int sort_by_id(SegmentX *a,SegmentX *b);
56 static distance_t DistanceX(NodeX *nodex1,NodeX *nodex2);
59 /*++++++++++++++++++++++++++++++++++++++
60 Allocate a new segment list (create a new file or open an existing one).
62 SegmentsX *NewSegmentList Returns the segment list.
64 int append Set to 1 if the file is to be opened for appending (now or later).
65 ++++++++++++++++++++++++++++++++++++++*/
67 SegmentsX *NewSegmentList(int append)
71 segmentsx=(SegmentsX*)calloc(1,sizeof(SegmentsX));
73 assert(segmentsx); /* Check calloc() worked */
75 segmentsx->filename=(char*)malloc(strlen(option_tmpdirname)+32);
78 sprintf(segmentsx->filename,"%s/segmentsx.input.tmp",option_tmpdirname);
80 sprintf(segmentsx->filename,"%s/segmentsx.%p.tmp",option_tmpdirname,segmentsx);
83 segmentsx->sfilename=(char*)malloc(strlen(option_tmpdirname)+32);
85 sprintf(segmentsx->sfilename,"%s/segments.%p.tmp",option_tmpdirname,segmentsx);
92 segmentsx->fd=OpenFileAppend(segmentsx->filename);
94 size=SizeFile(segmentsx->filename);
96 segmentsx->xnumber=size/sizeof(SegmentX);
99 segmentsx->fd=OpenFileNew(segmentsx->filename);
105 /*++++++++++++++++++++++++++++++++++++++
108 SegmentsX *segmentsx The list to be freed.
110 int keep Set to 1 if the file is to be kept.
111 ++++++++++++++++++++++++++++++++++++++*/
113 void FreeSegmentList(SegmentsX *segmentsx,int keep)
116 DeleteFile(segmentsx->filename);
118 free(segmentsx->filename);
121 free(segmentsx->idata);
123 if(segmentsx->firstnode)
124 free(segmentsx->firstnode);
128 free(segmentsx->sdata);
132 DeleteFile(segmentsx->sfilename);
134 free(segmentsx->sfilename);
141 /*++++++++++++++++++++++++++++++++++++++
142 Append a single segment to an unsorted segment list.
144 SegmentsX* segmentsx The set of segments to process.
146 way_t way The way that the segment belongs to.
148 node_t node1 The first node in the segment.
150 node_t node2 The second node in the segment.
152 distance_t distance The distance between the nodes (or just the flags).
153 ++++++++++++++++++++++++++++++++++++++*/
155 void AppendSegment(SegmentsX* segmentsx,way_t way,node_t node1,node_t node2,distance_t distance)
159 segmentx.node1=node1;
160 segmentx.node2=node2;
162 segmentx.distance=distance;
164 WriteFile(segmentsx->fd,&segmentx,sizeof(SegmentX));
166 segmentsx->xnumber++;
168 assert(segmentsx->xnumber<SEGMENT_FAKE); /* SEGMENT_FAKE marks the high-water mark for real segments. */
172 /*++++++++++++++++++++++++++++++++++++++
173 Sort the segment list.
175 SegmentsX* segmentsx The set of segments to process.
176 ++++++++++++++++++++++++++++++++++++++*/
178 void SortSegmentList(SegmentsX* segmentsx)
182 if(segmentsx->xnumber==0)
185 /* Print the start message */
187 printf("Sorting Segments");
190 /* Close the files and re-open them (finished appending) */
192 CloseFile(segmentsx->fd);
193 segmentsx->fd=ReOpenFile(segmentsx->filename);
195 DeleteFile(segmentsx->filename);
197 fd=OpenFileNew(segmentsx->filename);
199 /* Sort by node indexes */
201 filesort_fixed(segmentsx->fd,fd,sizeof(SegmentX),(int (*)(const void*,const void*))sort_by_id,NULL);
203 segmentsx->number=segmentsx->xnumber;
205 /* Close the files and re-open them */
207 CloseFile(segmentsx->fd);
210 segmentsx->fd=ReOpenFile(segmentsx->filename);
212 /* Print the final message */
214 printf("\rSorted Segments: Segments=%d\n",segmentsx->xnumber);
219 /*++++++++++++++++++++++++++++++++++++++
220 Sort the segments into id order (node1 then node2).
222 int sort_by_id Returns the comparison of the node fields.
224 SegmentX *a The first segment.
226 SegmentX *b The second segment.
227 ++++++++++++++++++++++++++++++++++++++*/
229 static int sort_by_id(SegmentX *a,SegmentX *b)
231 node_t a_id1=a->node1;
232 node_t b_id1=b->node1;
238 else /* if(a_id1==b_id1) */
240 node_t a_id2=a->node2;
241 node_t b_id2=b->node2;
249 distance_t a_distance=a->distance;
250 distance_t b_distance=b->distance;
252 if(a_distance<b_distance)
254 else if(a_distance>b_distance)
263 /*++++++++++++++++++++++++++++++++++++++
264 Find the first segment index with a particular starting node.
266 index_t IndexFirstSegmentX Returns a pointer to the index of the first extended segment with the specified id.
268 SegmentsX* segmentsx The set of segments to process.
270 node_t node The node to look for.
271 ++++++++++++++++++++++++++++++++++++++*/
273 index_t IndexFirstSegmentX(SegmentsX* segmentsx,node_t node)
276 int end=segmentsx->number-1;
280 /* Check if the first node index exists */
282 if(segmentsx->firstnode)
284 index_t index=segmentsx->firstnode[node];
286 if(segmentsx->firstnode[node+1]==index)
292 /* Binary search - search key exact match only is required.
294 * # <- start | Check mid and move start or end if it doesn't match
296 * # | Since an exact match is wanted we can set end=mid-1
297 * # <- mid | or start=mid+1 because we know that mid doesn't match.
299 * # | Eventually either end=start or end=start+1 and one of
300 * # <- end | start or end is the wanted one.
303 if(end<start) /* There are no nodes */
305 else if(node<segmentsx->idata[start]) /* Check key is not before start */
307 else if(node>segmentsx->idata[end]) /* Check key is not after end */
313 mid=(start+end)/2; /* Choose mid point */
315 if(segmentsx->idata[mid]<node) /* Mid point is too low */
317 else if(segmentsx->idata[mid]>node) /* Mid point is too high */
319 else /* Mid point is correct */
320 {found=mid; goto found;}
322 while((end-start)>1);
324 if(segmentsx->idata[start]==node) /* Start is correct */
325 {found=start; goto found;}
327 if(segmentsx->idata[end]==node) /* End is correct */
328 {found=end; goto found;}
335 while(found>0 && segmentsx->idata[found-1]==node)
342 /*++++++++++++++++++++++++++++++++++++++
343 Find the next segment index with a particular starting node.
345 index_t IndexNextSegmentX Returns the index of the next segment with the same id.
347 SegmentsX* segmentsx The set of segments to process.
349 index_t segindex The current segment index.
351 index_t nodeindex The node index.
352 ++++++++++++++++++++++++++++++++++++++*/
354 index_t IndexNextSegmentX(SegmentsX* segmentsx,index_t segindex,index_t nodeindex)
356 if(++segindex==segmentsx->firstnode[nodeindex+1])
363 /*++++++++++++++++++++++++++++++++++++++
364 Remove bad segments (duplicated, zero length or missing nodes).
366 NodesX *nodesx The nodes to check.
368 SegmentsX *segmentsx The segments to modify.
369 ++++++++++++++++++++++++++++++++++++++*/
371 void RemoveBadSegments(NodesX *nodesx,SegmentsX *segmentsx)
373 int duplicate=0,loop=0,missing=0,good=0,total=0;
376 node_t prevnode1=NO_NODE,prevnode2=NO_NODE;
378 /* Print the start message */
380 printf("Checking: Segments=0 Duplicate=0 Loop=0 Missing-Node=0");
383 /* Allocate the array of indexes */
385 segmentsx->idata=(node_t*)malloc(segmentsx->xnumber*sizeof(node_t));
387 assert(segmentsx->idata); /* Check malloc() worked */
389 /* Modify the on-disk image */
391 DeleteFile(segmentsx->filename);
393 fd=OpenFileNew(segmentsx->filename);
394 SeekFile(segmentsx->fd,0);
396 while(!ReadFile(segmentsx->fd,&segmentx,sizeof(SegmentX)))
398 if(prevnode1==segmentx.node1 && prevnode2==segmentx.node2)
400 else if(segmentx.node1==segmentx.node2)
402 else if(IndexNodeX(nodesx,segmentx.node1)==NO_NODE ||
403 IndexNodeX(nodesx,segmentx.node2)==NO_NODE)
407 WriteFile(fd,&segmentx,sizeof(SegmentX));
409 segmentsx->idata[good]=segmentx.node1;
412 prevnode1=segmentx.node1;
413 prevnode2=segmentx.node2;
420 printf("\rChecking: Segments=%d Duplicate=%d Loop=%d Missing-Node=%d",total,duplicate,loop,missing);
425 /* Close the files and re-open them */
427 CloseFile(segmentsx->fd);
430 segmentsx->fd=ReOpenFile(segmentsx->filename);
432 segmentsx->number=good;
434 /* Print the final message */
436 printf("\rChecked: Segments=%d Duplicate=%d Loop=%d Missing-Node=%d \n",total,duplicate,loop,missing);
441 /*++++++++++++++++++++++++++++++++++++++
442 Measure the segments and replace node/way ids with indexes.
444 SegmentsX* segmentsx The set of segments to process.
446 NodesX *nodesx The list of nodes to use.
448 WaysX *waysx The list of ways to use.
449 ++++++++++++++++++++++++++++++++++++++*/
451 void UpdateSegments(SegmentsX* segmentsx,NodesX *nodesx,WaysX *waysx)
457 /* Print the start message */
459 printf("Measuring Segments: Segments=0");
462 /* Map into memory */
465 nodesx->xdata=MapFile(nodesx->filename);
468 /* Free the now-unneeded index */
470 free(segmentsx->idata);
471 segmentsx->idata=NULL;
473 /* Allocate the array of indexes */
475 segmentsx->firstnode=(index_t*)malloc((nodesx->number+1)*sizeof(index_t));
477 assert(segmentsx->firstnode); /* Check malloc() worked */
479 for(i=0;i<nodesx->number;i++)
480 segmentsx->firstnode[i]=NO_SEGMENT;
482 segmentsx->firstnode[nodesx->number]=segmentsx->number;
484 /* Modify the on-disk image */
486 DeleteFile(segmentsx->filename);
488 fd=OpenFileNew(segmentsx->filename);
489 SeekFile(segmentsx->fd,0);
491 while(!ReadFile(segmentsx->fd,&segmentx,sizeof(SegmentX)))
493 index_t node1=IndexNodeX(nodesx,segmentx.node1);
494 index_t node2=IndexNodeX(nodesx,segmentx.node2);
495 index_t way =IndexWayX (waysx ,segmentx.way);
497 NodeX *nodex1=LookupNodeX(nodesx,node1,1);
498 NodeX *nodex2=LookupNodeX(nodesx,node2,2);
500 /* Replace the node and way ids with their indexes */
502 segmentx.node1=node1;
503 segmentx.node2=node2;
506 /* Set the distance but preserve the ONEWAY_* flags */
508 segmentx.distance|=DISTANCE(DistanceX(nodex1,nodex2));
510 /* Set the first segment index in the nodes */
512 if(index<segmentsx->firstnode[node1])
513 segmentsx->firstnode[node1]=index;
515 /* Write the modified segment */
517 WriteFile(fd,&segmentx,sizeof(SegmentX));
523 printf("\rMeasuring Segments: Segments=%d",index);
528 /* Close the files and re-open them */
530 CloseFile(segmentsx->fd);
533 segmentsx->fd=ReOpenFile(segmentsx->filename);
535 /* Free the other now-unneeded indexes */
543 /* Unmap from memory */
546 nodesx->xdata=UnmapFile(nodesx->filename);
549 /* Print the final message */
551 printf("\rMeasured Segments: Segments=%d \n",segmentsx->number);
556 /*++++++++++++++++++++++++++++++++++++++
557 Make the segments all point the same way (node1<node2).
559 SegmentsX* segmentsx The set of segments to process.
560 ++++++++++++++++++++++++++++++++++++++*/
562 void RotateSegments(SegmentsX* segmentsx)
564 int index=0,rotated=0;
568 /* Print the start message */
570 printf("Rotating Segments: Segments=0 Rotated=0");
573 /* Close the files and re-open them (finished appending) */
575 CloseFile(segmentsx->fd);
576 segmentsx->fd=ReOpenFile(segmentsx->filename);
578 DeleteFile(segmentsx->filename);
580 fd=OpenFileNew(segmentsx->filename);
582 /* Modify the file contents */
584 while(!ReadFile(segmentsx->fd,&segmentx,sizeof(SegmentX)))
586 if(segmentx.node1>segmentx.node2)
591 segmentx.node1=segmentx.node2;
594 if(segmentx.distance&(ONEWAY_2TO1|ONEWAY_1TO2))
595 segmentx.distance^=ONEWAY_2TO1|ONEWAY_1TO2;
600 WriteFile(fd,&segmentx,sizeof(SegmentX));
606 printf("\rRotating Segments: Segments=%d Rotated=%d",index,rotated);
611 /* Close the files and re-open them */
613 CloseFile(segmentsx->fd);
616 segmentsx->fd=ReOpenFile(segmentsx->filename);
618 /* Print the final message */
620 printf("\rRotated Segments: Segments=%d Rotated=%d \n",index,rotated);
625 /*++++++++++++++++++++++++++++++++++++++
626 Remove the duplicate segments.
628 SegmentsX* segmentsx The set of segments to process.
630 NodesX *nodesx The list of nodes to use.
632 WaysX *waysx The list of ways to use.
633 ++++++++++++++++++++++++++++++++++++++*/
635 void DeduplicateSegments(SegmentsX* segmentsx,NodesX *nodesx,WaysX *waysx)
637 int duplicate=0,good=0;
638 index_t firstindex=0,index=0;
640 SegmentX prevsegmentx[16],segmentx;
642 /* Print the start message */
644 printf("Deduplicating Segments: Segments=0 Duplicate=0");
647 /* Map into memory */
650 waysx->xdata=MapFile(waysx->filename);
653 /* Allocate the array of indexes */
655 segmentsx->firstnode=(index_t*)malloc((nodesx->number+1)*sizeof(index_t));
657 assert(segmentsx->firstnode); /* Check malloc() worked */
659 for(i=0;i<nodesx->number;i++)
660 segmentsx->firstnode[i]=NO_SEGMENT;
662 segmentsx->firstnode[nodesx->number]=segmentsx->number;
664 /* Modify the on-disk image */
666 DeleteFile(segmentsx->filename);
668 fd=OpenFileNew(segmentsx->filename);
669 SeekFile(segmentsx->fd,0);
671 while(!ReadFile(segmentsx->fd,&segmentx,sizeof(SegmentX)))
675 if(index && segmentx.node1==prevsegmentx[0].node1 &&
676 segmentx.node2==prevsegmentx[0].node2)
678 index_t previndex=firstindex;
680 while(previndex<index)
682 int offset=previndex-firstindex;
684 if(DISTFLAG(segmentx.distance)==DISTFLAG(prevsegmentx[offset].distance))
686 WayX *wayx1=LookupWayX(waysx,prevsegmentx[offset].way,1);
687 WayX *wayx2=LookupWayX(waysx, segmentx .way,2);
689 if(!WaysCompare(&wayx1->way,&wayx2->way))
700 assert((index-firstindex)<(sizeof(prevsegmentx)/sizeof(prevsegmentx[0])));
702 prevsegmentx[index-firstindex]=segmentx;
707 prevsegmentx[0]=segmentx;
712 WriteFile(fd,&segmentx,sizeof(SegmentX));
714 if(good<segmentsx->firstnode[segmentx.node1])
715 segmentsx->firstnode[segmentx.node1]=good;
724 printf("\rDeduplicating Segments: Segments=%d Duplicate=%d",index,duplicate);
729 /* Close the files and re-open them */
731 CloseFile(segmentsx->fd);
734 segmentsx->fd=ReOpenFile(segmentsx->filename);
736 segmentsx->number=good;
738 /* Fix-up the firstnode index for the missing nodes */
740 for(i=nodesx->number-1;i>=0;i--)
741 if(segmentsx->firstnode[i]==NO_SEGMENT)
742 segmentsx->firstnode[i]=segmentsx->firstnode[i+1];
744 /* Unmap from memory */
747 waysx->xdata=UnmapFile(waysx->filename);
750 /* Print the final message */
752 printf("\rDeduplicated Segments: Segments=%d Duplicate=%d Unique=%d\n",index,duplicate,index-duplicate);
757 /*++++++++++++++++++++++++++++++++++++++
758 Create the real segments data.
760 SegmentsX* segmentsx The set of segments to use.
762 WaysX* waysx The set of ways to use.
763 ++++++++++++++++++++++++++++++++++++++*/
765 void CreateRealSegments(SegmentsX *segmentsx,WaysX *waysx)
769 if(segmentsx->number==0 || waysx->number==0)
772 /* Print the start message */
774 printf("Creating Real Segments: Segments=0");
777 /* Map into memory */
780 segmentsx->xdata=MapFile(segmentsx->filename);
781 waysx->xdata=MapFile(waysx->filename);
784 /* Free the unneeded memory */
786 free(segmentsx->firstnode);
787 segmentsx->firstnode=NULL;
789 /* Allocate the memory (or open the file) */
792 segmentsx->sdata=(Segment*)malloc(segmentsx->number*sizeof(Segment));
794 assert(segmentsx->sdata); /* Check malloc() worked */
796 segmentsx->sfd=OpenFileNew(segmentsx->sfilename);
799 /* Loop through and fill */
801 for(i=0;i<segmentsx->number;i++)
803 SegmentX *segmentx=LookupSegmentX(segmentsx,i,1);
804 Segment *segment =LookupSegmentXSegment(segmentsx,i,1);
805 WayX *wayx=LookupWayX(waysx,segmentx->way,1);
809 segment->next2=NO_NODE;
810 segment->way=wayx->prop;
811 segment->distance=segmentx->distance;
814 PutBackSegmentXSegment(segmentsx,i,1);
819 printf("\rCreating Real Segments: Segments=%d",i+1);
824 /* Unmap from memory */
827 segmentsx->xdata=UnmapFile(segmentsx->filename);
828 waysx->xdata=UnmapFile(waysx->filename);
831 /* Print the final message */
833 printf("\rCreating Real Segments: Segments=%d \n",segmentsx->number);
838 /*++++++++++++++++++++++++++++++++++++++
839 Assign the nodes indexes to the segments.
841 SegmentsX* segmentsx The set of segments to process.
843 NodesX *nodesx The list of nodes to use.
844 ++++++++++++++++++++++++++++++++++++++*/
846 void IndexSegments(SegmentsX* segmentsx,NodesX *nodesx)
850 if(nodesx->number==0 || segmentsx->number==0)
853 /* Print the start message */
855 printf("Indexing Nodes: Nodes=0");
858 /* Map into memory */
861 nodesx->xdata=MapFile(nodesx->filename);
862 segmentsx->xdata=MapFile(segmentsx->filename);
865 /* Index the segments */
867 for(i=0;i<nodesx->number;i++)
869 NodeX *nodex=LookupNodeX(nodesx,i,1);
870 Node *node =LookupNodeXNode(nodesx,nodex->id,1);
871 index_t index=node->firstseg;
875 SegmentX *segmentx=LookupSegmentX(segmentsx,index,1);
876 Segment *segment =LookupSegmentXSegment(segmentsx,index,1);
878 if(segmentx->node1==nodex->id)
883 PutBackSegmentXSegment(segmentsx,index,1);
888 if(index>=segmentsx->number)
891 segmentx=LookupSegmentX(segmentsx,index,1);
893 if(segmentx->node1!=nodex->id)
901 PutBackSegmentXSegment(segmentsx,index,1);
904 if(segment->next2==NO_NODE)
907 index=segment->next2;
914 printf("\rIndexing Nodes: Nodes=%d",i+1);
919 /* Unmap from memory */
922 nodesx->xdata=UnmapFile(nodesx->filename);
923 segmentsx->xdata=UnmapFile(segmentsx->filename);
926 /* Print the final message */
928 printf("\rIndexed Nodes: Nodes=%d \n",nodesx->number);
933 /*++++++++++++++++++++++++++++++++++++++
934 Save the segment list to a file.
936 SegmentsX* segmentsx The set of segments to save.
938 const char *filename The name of the file to save.
939 ++++++++++++++++++++++++++++++++++++++*/
941 void SaveSegmentList(SegmentsX* segmentsx,const char *filename)
945 SegmentsFile segmentsfile={0};
946 int super_number=0,normal_number=0;
948 /* Print the start message */
950 printf("Writing Segments: Segments=0");
953 /* Write out the segments data */
955 fd=OpenFileNew(filename);
957 SeekFile(fd,sizeof(SegmentsFile));
959 for(i=0;i<segmentsx->number;i++)
961 Segment *segment=LookupSegmentXSegment(segmentsx,i,1);
963 if(IsSuperSegment(segment))
965 if(IsNormalSegment(segment))
968 WriteFile(fd,segment,sizeof(Segment));
972 printf("\rWriting Segments: Segments=%d",i+1);
977 /* Write out the header structure */
979 segmentsfile.number=segmentsx->number;
980 segmentsfile.snumber=super_number;
981 segmentsfile.nnumber=normal_number;
984 WriteFile(fd,&segmentsfile,sizeof(SegmentsFile));
988 /* Print the final message */
990 printf("\rWrote Segments: Segments=%d \n",segmentsx->number);
995 /*++++++++++++++++++++++++++++++++++++++
996 Calculate the distance between two nodes.
998 distance_t DistanceX Returns the distance between the extended nodes.
1000 NodeX *nodex1 The starting node.
1002 NodeX *nodex2 The end node.
1003 ++++++++++++++++++++++++++++++++++++++*/
1005 static distance_t DistanceX(NodeX *nodex1,NodeX *nodex2)
1007 double dlon = latlong_to_radians(nodex1->longitude) - latlong_to_radians(nodex2->longitude);
1008 double dlat = latlong_to_radians(nodex1->latitude) - latlong_to_radians(nodex2->latitude);
1009 double lat1 = latlong_to_radians(nodex1->latitude);
1010 double lat2 = latlong_to_radians(nodex2->latitude);
1012 double a1,a2,a,sa,c,d;
1014 if(dlon==0 && dlat==0)
1017 a1 = sin (dlat / 2);
1018 a2 = sin (dlon / 2);
1019 a = (a1 * a1) + cos (lat1) * cos (lat2) * a2 * a2;
1022 {c = 2 * asin (sa);}
1024 {c = 2 * asin (1.0);}
1027 return km_to_distance(d);