1 /***************************************
2 $Header: /home/amb/routino/src/RCS/segmentsx.c,v 1.69 2010/11/13 14:22:28 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"
45 #include "functions.h"
50 /*+ The command line '--tmpdir' option or its default value. +*/
51 extern char *option_tmpdirname;
55 static int sort_by_id(SegmentX *a,SegmentX *b);
57 static distance_t DistanceX(NodeX *nodex1,NodeX *nodex2);
60 /*++++++++++++++++++++++++++++++++++++++
61 Allocate a new segment list (create a new file or open an existing one).
63 SegmentsX *NewSegmentList Returns the segment list.
65 int append Set to 1 if the file is to be opened for appending (now or later).
66 ++++++++++++++++++++++++++++++++++++++*/
68 SegmentsX *NewSegmentList(int append)
72 segmentsx=(SegmentsX*)calloc(1,sizeof(SegmentsX));
74 assert(segmentsx); /* Check calloc() worked */
76 segmentsx->filename=(char*)malloc(strlen(option_tmpdirname)+32);
79 sprintf(segmentsx->filename,"%s/segmentsx.input.tmp",option_tmpdirname);
81 sprintf(segmentsx->filename,"%s/segmentsx.%p.tmp",option_tmpdirname,segmentsx);
84 segmentsx->sfilename=(char*)malloc(strlen(option_tmpdirname)+32);
86 sprintf(segmentsx->sfilename,"%s/segments.%p.tmp",option_tmpdirname,segmentsx);
93 segmentsx->fd=OpenFileAppend(segmentsx->filename);
95 size=SizeFile(segmentsx->filename);
97 segmentsx->xnumber=size/sizeof(SegmentX);
100 segmentsx->fd=OpenFileNew(segmentsx->filename);
106 /*++++++++++++++++++++++++++++++++++++++
109 SegmentsX *segmentsx The list to be freed.
111 int keep Set to 1 if the file is to be kept.
112 ++++++++++++++++++++++++++++++++++++++*/
114 void FreeSegmentList(SegmentsX *segmentsx,int keep)
117 DeleteFile(segmentsx->filename);
119 free(segmentsx->filename);
122 free(segmentsx->idata);
124 if(segmentsx->firstnode)
125 free(segmentsx->firstnode);
129 free(segmentsx->sdata);
133 DeleteFile(segmentsx->sfilename);
135 free(segmentsx->sfilename);
142 /*++++++++++++++++++++++++++++++++++++++
143 Append a single segment to an unsorted segment list.
145 SegmentsX* segmentsx The set of segments to process.
147 way_t way The way that the segment belongs to.
149 node_t node1 The first node in the segment.
151 node_t node2 The second node in the segment.
153 distance_t distance The distance between the nodes (or just the flags).
154 ++++++++++++++++++++++++++++++++++++++*/
156 void AppendSegment(SegmentsX* segmentsx,way_t way,node_t node1,node_t node2,distance_t distance)
160 segmentx.node1=node1;
161 segmentx.node2=node2;
163 segmentx.distance=distance;
165 WriteFile(segmentsx->fd,&segmentx,sizeof(SegmentX));
167 segmentsx->xnumber++;
169 assert(segmentsx->xnumber<SEGMENT_FAKE); /* SEGMENT_FAKE marks the high-water mark for real segments. */
173 /*++++++++++++++++++++++++++++++++++++++
174 Sort the segment list.
176 SegmentsX* segmentsx The set of segments to process.
177 ++++++++++++++++++++++++++++++++++++++*/
179 void SortSegmentList(SegmentsX* segmentsx)
183 if(segmentsx->xnumber==0)
186 /* Print the start message */
188 printf_first("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_last("Sorted Segments: Segments=%d",segmentsx->xnumber);
218 /*++++++++++++++++++++++++++++++++++++++
219 Sort the segments into id order (node1 then node2).
221 int sort_by_id Returns the comparison of the node fields.
223 SegmentX *a The first segment.
225 SegmentX *b The second segment.
226 ++++++++++++++++++++++++++++++++++++++*/
228 static int sort_by_id(SegmentX *a,SegmentX *b)
230 node_t a_id1=a->node1;
231 node_t b_id1=b->node1;
237 else /* if(a_id1==b_id1) */
239 node_t a_id2=a->node2;
240 node_t b_id2=b->node2;
248 distance_t a_distance=a->distance;
249 distance_t b_distance=b->distance;
251 if(a_distance<b_distance)
253 else if(a_distance>b_distance)
262 /*++++++++++++++++++++++++++++++++++++++
263 Find the first segment index with a particular starting node.
265 index_t IndexFirstSegmentX Returns a pointer to the index of the first extended segment with the specified id.
267 SegmentsX* segmentsx The set of segments to process.
269 node_t node The node to look for.
270 ++++++++++++++++++++++++++++++++++++++*/
272 index_t IndexFirstSegmentX(SegmentsX* segmentsx,node_t node)
275 int end=segmentsx->number-1;
279 /* Check if the first node index exists */
281 if(segmentsx->firstnode)
283 index_t index=segmentsx->firstnode[node];
285 if(segmentsx->firstnode[node+1]==index)
291 /* Binary search - search key exact match only is required.
293 * # <- start | Check mid and move start or end if it doesn't match
295 * # | Since an exact match is wanted we can set end=mid-1
296 * # <- mid | or start=mid+1 because we know that mid doesn't match.
298 * # | Eventually either end=start or end=start+1 and one of
299 * # <- end | start or end is the wanted one.
302 if(end<start) /* There are no nodes */
304 else if(node<segmentsx->idata[start]) /* Check key is not before start */
306 else if(node>segmentsx->idata[end]) /* Check key is not after end */
312 mid=(start+end)/2; /* Choose mid point */
314 if(segmentsx->idata[mid]<node) /* Mid point is too low */
316 else if(segmentsx->idata[mid]>node) /* Mid point is too high */
318 else /* Mid point is correct */
319 {found=mid; goto found;}
321 while((end-start)>1);
323 if(segmentsx->idata[start]==node) /* Start is correct */
324 {found=start; goto found;}
326 if(segmentsx->idata[end]==node) /* End is correct */
327 {found=end; goto found;}
334 while(found>0 && segmentsx->idata[found-1]==node)
341 /*++++++++++++++++++++++++++++++++++++++
342 Find the next segment index with a particular starting node.
344 index_t IndexNextSegmentX Returns the index of the next segment with the same id.
346 SegmentsX* segmentsx The set of segments to process.
348 index_t segindex The current segment index.
350 index_t nodeindex The node index.
351 ++++++++++++++++++++++++++++++++++++++*/
353 index_t IndexNextSegmentX(SegmentsX* segmentsx,index_t segindex,index_t nodeindex)
355 if(++segindex==segmentsx->firstnode[nodeindex+1])
362 /*++++++++++++++++++++++++++++++++++++++
363 Remove bad segments (duplicated, zero length or missing nodes).
365 NodesX *nodesx The nodes to check.
367 SegmentsX *segmentsx The segments to modify.
368 ++++++++++++++++++++++++++++++++++++++*/
370 void RemoveBadSegments(NodesX *nodesx,SegmentsX *segmentsx)
372 int duplicate=0,loop=0,missing=0,good=0,total=0;
375 node_t prevnode1=NO_NODE,prevnode2=NO_NODE;
377 /* Print the start message */
379 printf_first("Checking: Segments=0 Duplicate=0 Loop=0 Missing-Node=0");
381 /* Allocate the array of indexes */
383 segmentsx->idata=(node_t*)malloc(segmentsx->xnumber*sizeof(node_t));
385 assert(segmentsx->idata); /* Check malloc() worked */
387 /* Modify the on-disk image */
389 DeleteFile(segmentsx->filename);
391 fd=OpenFileNew(segmentsx->filename);
392 SeekFile(segmentsx->fd,0);
394 while(!ReadFile(segmentsx->fd,&segmentx,sizeof(SegmentX)))
396 if(prevnode1==segmentx.node1 && prevnode2==segmentx.node2)
398 else if(segmentx.node1==segmentx.node2)
400 else if(IndexNodeX(nodesx,segmentx.node1)==NO_NODE ||
401 IndexNodeX(nodesx,segmentx.node2)==NO_NODE)
405 WriteFile(fd,&segmentx,sizeof(SegmentX));
407 segmentsx->idata[good]=segmentx.node1;
410 prevnode1=segmentx.node1;
411 prevnode2=segmentx.node2;
417 printf_middle("Checking: Segments=%d Duplicate=%d Loop=%d Missing-Node=%d",total,duplicate,loop,missing);
420 /* Close the files and re-open them */
422 CloseFile(segmentsx->fd);
425 segmentsx->fd=ReOpenFile(segmentsx->filename);
427 segmentsx->number=good;
429 /* Print the final message */
431 printf_last("Checked: Segments=%d Duplicate=%d Loop=%d Missing-Node=%d",total,duplicate,loop,missing);
435 /*++++++++++++++++++++++++++++++++++++++
436 Measure the segments and replace node/way ids with indexes.
438 SegmentsX* segmentsx The set of segments to process.
440 NodesX *nodesx The list of nodes to use.
442 WaysX *waysx The list of ways to use.
443 ++++++++++++++++++++++++++++++++++++++*/
445 void UpdateSegments(SegmentsX* segmentsx,NodesX *nodesx,WaysX *waysx)
451 /* Print the start message */
453 printf_first("Measuring Segments: Segments=0");
455 /* Map into memory */
458 nodesx->xdata=MapFile(nodesx->filename);
461 /* Free the now-unneeded index */
463 free(segmentsx->idata);
464 segmentsx->idata=NULL;
466 /* Allocate the array of indexes */
468 segmentsx->firstnode=(index_t*)malloc((nodesx->number+1)*sizeof(index_t));
470 assert(segmentsx->firstnode); /* Check malloc() worked */
472 for(i=0;i<nodesx->number;i++)
473 segmentsx->firstnode[i]=NO_SEGMENT;
475 segmentsx->firstnode[nodesx->number]=segmentsx->number;
477 /* Modify the on-disk image */
479 DeleteFile(segmentsx->filename);
481 fd=OpenFileNew(segmentsx->filename);
482 SeekFile(segmentsx->fd,0);
484 while(!ReadFile(segmentsx->fd,&segmentx,sizeof(SegmentX)))
486 index_t node1=IndexNodeX(nodesx,segmentx.node1);
487 index_t node2=IndexNodeX(nodesx,segmentx.node2);
488 index_t way =IndexWayX (waysx ,segmentx.way);
490 NodeX *nodex1=LookupNodeX(nodesx,node1,1);
491 NodeX *nodex2=LookupNodeX(nodesx,node2,2);
493 /* Replace the node and way ids with their indexes */
495 segmentx.node1=node1;
496 segmentx.node2=node2;
499 /* Set the distance but preserve the ONEWAY_* flags */
501 segmentx.distance|=DISTANCE(DistanceX(nodex1,nodex2));
503 /* Set the first segment index in the nodes */
505 if(index<segmentsx->firstnode[node1])
506 segmentsx->firstnode[node1]=index;
508 /* Write the modified segment */
510 WriteFile(fd,&segmentx,sizeof(SegmentX));
515 printf_middle("Measuring Segments: Segments=%d",index);
518 /* Close the files and re-open them */
520 CloseFile(segmentsx->fd);
523 segmentsx->fd=ReOpenFile(segmentsx->filename);
525 /* Free the other now-unneeded indexes */
533 /* Unmap from memory */
536 nodesx->xdata=UnmapFile(nodesx->filename);
539 /* Print the final message */
541 printf_last("Measured Segments: Segments=%d",segmentsx->number);
545 /*++++++++++++++++++++++++++++++++++++++
546 Make the segments all point the same way (node1<node2).
548 SegmentsX* segmentsx The set of segments to process.
549 ++++++++++++++++++++++++++++++++++++++*/
551 void RotateSegments(SegmentsX* segmentsx)
553 int index=0,rotated=0;
557 /* Print the start message */
559 printf_first("Rotating Segments: Segments=0 Rotated=0");
561 /* Close the files and re-open them (finished appending) */
563 CloseFile(segmentsx->fd);
564 segmentsx->fd=ReOpenFile(segmentsx->filename);
566 DeleteFile(segmentsx->filename);
568 fd=OpenFileNew(segmentsx->filename);
570 /* Modify the file contents */
572 while(!ReadFile(segmentsx->fd,&segmentx,sizeof(SegmentX)))
574 if(segmentx.node1>segmentx.node2)
579 segmentx.node1=segmentx.node2;
582 if(segmentx.distance&(ONEWAY_2TO1|ONEWAY_1TO2))
583 segmentx.distance^=ONEWAY_2TO1|ONEWAY_1TO2;
588 WriteFile(fd,&segmentx,sizeof(SegmentX));
593 printf_middle("Rotating Segments: Segments=%d Rotated=%d",index,rotated);
596 /* Close the files and re-open them */
598 CloseFile(segmentsx->fd);
601 segmentsx->fd=ReOpenFile(segmentsx->filename);
603 /* Print the final message */
605 printf_last("Rotated Segments: Segments=%d Rotated=%d",index,rotated);
609 /*++++++++++++++++++++++++++++++++++++++
610 Remove the duplicate segments.
612 SegmentsX* segmentsx The set of segments to process.
614 NodesX *nodesx The list of nodes to use.
616 WaysX *waysx The list of ways to use.
617 ++++++++++++++++++++++++++++++++++++++*/
619 void DeduplicateSegments(SegmentsX* segmentsx,NodesX *nodesx,WaysX *waysx)
621 int duplicate=0,good=0;
622 index_t firstindex=0,index=0;
624 SegmentX prevsegmentx[16],segmentx;
626 /* Print the start message */
628 printf_first("Deduplicating Segments: Segments=0 Duplicate=0");
630 /* Map into memory */
633 waysx->xdata=MapFile(waysx->filename);
636 /* Allocate the array of indexes */
638 segmentsx->firstnode=(index_t*)malloc((nodesx->number+1)*sizeof(index_t));
640 assert(segmentsx->firstnode); /* Check malloc() worked */
642 for(i=0;i<nodesx->number;i++)
643 segmentsx->firstnode[i]=NO_SEGMENT;
645 segmentsx->firstnode[nodesx->number]=segmentsx->number;
647 /* Modify the on-disk image */
649 DeleteFile(segmentsx->filename);
651 fd=OpenFileNew(segmentsx->filename);
652 SeekFile(segmentsx->fd,0);
654 while(!ReadFile(segmentsx->fd,&segmentx,sizeof(SegmentX)))
658 if(index && segmentx.node1==prevsegmentx[0].node1 &&
659 segmentx.node2==prevsegmentx[0].node2)
661 index_t previndex=firstindex;
663 while(previndex<index)
665 int offset=previndex-firstindex;
667 if(DISTFLAG(segmentx.distance)==DISTFLAG(prevsegmentx[offset].distance))
669 WayX *wayx1=LookupWayX(waysx,prevsegmentx[offset].way,1);
670 WayX *wayx2=LookupWayX(waysx, segmentx .way,2);
672 if(!WaysCompare(&wayx1->way,&wayx2->way))
683 assert((index-firstindex)<(sizeof(prevsegmentx)/sizeof(prevsegmentx[0])));
685 prevsegmentx[index-firstindex]=segmentx;
690 prevsegmentx[0]=segmentx;
695 WriteFile(fd,&segmentx,sizeof(SegmentX));
697 if(good<segmentsx->firstnode[segmentx.node1])
698 segmentsx->firstnode[segmentx.node1]=good;
706 printf_middle("Deduplicating Segments: Segments=%d Duplicate=%d",index,duplicate);
709 /* Close the files and re-open them */
711 CloseFile(segmentsx->fd);
714 segmentsx->fd=ReOpenFile(segmentsx->filename);
716 segmentsx->number=good;
718 /* Fix-up the firstnode index for the missing nodes */
720 for(i=nodesx->number-1;i>=0;i--)
721 if(segmentsx->firstnode[i]==NO_SEGMENT)
722 segmentsx->firstnode[i]=segmentsx->firstnode[i+1];
724 /* Unmap from memory */
727 waysx->xdata=UnmapFile(waysx->filename);
730 /* Print the final message */
732 printf_last("Deduplicated Segments: Segments=%d Duplicate=%d Unique=%d",index,duplicate,index-duplicate);
736 /*++++++++++++++++++++++++++++++++++++++
737 Create the real segments data.
739 SegmentsX* segmentsx The set of segments to use.
741 WaysX* waysx The set of ways to use.
742 ++++++++++++++++++++++++++++++++++++++*/
744 void CreateRealSegments(SegmentsX *segmentsx,WaysX *waysx)
748 if(segmentsx->number==0 || waysx->number==0)
751 /* Print the start message */
753 printf_first("Creating Real Segments: Segments=0");
755 /* Map into memory */
758 segmentsx->xdata=MapFile(segmentsx->filename);
759 waysx->xdata=MapFile(waysx->filename);
762 /* Free the unneeded memory */
764 free(segmentsx->firstnode);
765 segmentsx->firstnode=NULL;
767 /* Allocate the memory (or open the file) */
770 segmentsx->sdata=(Segment*)malloc(segmentsx->number*sizeof(Segment));
772 assert(segmentsx->sdata); /* Check malloc() worked */
774 segmentsx->sfd=OpenFileNew(segmentsx->sfilename);
777 /* Loop through and fill */
779 for(i=0;i<segmentsx->number;i++)
781 SegmentX *segmentx=LookupSegmentX(segmentsx,i,1);
782 Segment *segment =LookupSegmentXSegment(segmentsx,i,1);
783 WayX *wayx=LookupWayX(waysx,segmentx->way,1);
787 segment->next2=NO_NODE;
788 segment->way=wayx->prop;
789 segment->distance=segmentx->distance;
792 PutBackSegmentXSegment(segmentsx,i,1);
796 printf_middle("Creating Real Segments: Segments=%d",i+1);
799 /* Unmap from memory */
802 segmentsx->xdata=UnmapFile(segmentsx->filename);
803 waysx->xdata=UnmapFile(waysx->filename);
806 /* Print the final message */
808 printf_last("Creating Real Segments: Segments=%d",segmentsx->number);
812 /*++++++++++++++++++++++++++++++++++++++
813 Assign the nodes indexes to the segments.
815 SegmentsX* segmentsx The set of segments to process.
817 NodesX *nodesx The list of nodes to use.
818 ++++++++++++++++++++++++++++++++++++++*/
820 void IndexSegments(SegmentsX* segmentsx,NodesX *nodesx)
824 if(nodesx->number==0 || segmentsx->number==0)
827 /* Print the start message */
829 printf_first("Indexing Nodes: Nodes=0");
831 /* Map into memory */
834 nodesx->xdata=MapFile(nodesx->filename);
835 segmentsx->xdata=MapFile(segmentsx->filename);
838 /* Index the segments */
840 for(i=0;i<nodesx->number;i++)
842 NodeX *nodex=LookupNodeX(nodesx,i,1);
843 Node *node =LookupNodeXNode(nodesx,nodex->id,1);
844 index_t index=node->firstseg;
848 SegmentX *segmentx=LookupSegmentX(segmentsx,index,1);
849 Segment *segment =LookupSegmentXSegment(segmentsx,index,1);
851 if(segmentx->node1==nodex->id)
856 PutBackSegmentXSegment(segmentsx,index,1);
861 if(index>=segmentsx->number)
864 segmentx=LookupSegmentX(segmentsx,index,1);
866 if(segmentx->node1!=nodex->id)
874 PutBackSegmentXSegment(segmentsx,index,1);
877 if(segment->next2==NO_NODE)
880 index=segment->next2;
886 printf_middle("Indexing Nodes: Nodes=%d",i+1);
889 /* Unmap from memory */
892 nodesx->xdata=UnmapFile(nodesx->filename);
893 segmentsx->xdata=UnmapFile(segmentsx->filename);
896 /* Print the final message */
898 printf_last("Indexed Nodes: Nodes=%d",nodesx->number);
902 /*++++++++++++++++++++++++++++++++++++++
903 Save the segment list to a file.
905 SegmentsX* segmentsx The set of segments to save.
907 const char *filename The name of the file to save.
908 ++++++++++++++++++++++++++++++++++++++*/
910 void SaveSegmentList(SegmentsX* segmentsx,const char *filename)
914 SegmentsFile segmentsfile={0};
915 int super_number=0,normal_number=0;
917 /* Print the start message */
919 printf_first("Writing Segments: Segments=0");
921 /* Write out the segments data */
923 fd=OpenFileNew(filename);
925 SeekFile(fd,sizeof(SegmentsFile));
927 for(i=0;i<segmentsx->number;i++)
929 Segment *segment=LookupSegmentXSegment(segmentsx,i,1);
931 if(IsSuperSegment(segment))
933 if(IsNormalSegment(segment))
936 WriteFile(fd,segment,sizeof(Segment));
939 printf_middle("Writing Segments: Segments=%d",i+1);
942 /* Write out the header structure */
944 segmentsfile.number=segmentsx->number;
945 segmentsfile.snumber=super_number;
946 segmentsfile.nnumber=normal_number;
949 WriteFile(fd,&segmentsfile,sizeof(SegmentsFile));
953 /* Print the final message */
955 printf_last("Wrote Segments: Segments=%d",segmentsx->number);
959 /*++++++++++++++++++++++++++++++++++++++
960 Calculate the distance between two nodes.
962 distance_t DistanceX Returns the distance between the extended nodes.
964 NodeX *nodex1 The starting node.
966 NodeX *nodex2 The end node.
967 ++++++++++++++++++++++++++++++++++++++*/
969 static distance_t DistanceX(NodeX *nodex1,NodeX *nodex2)
971 double dlon = latlong_to_radians(nodex1->longitude) - latlong_to_radians(nodex2->longitude);
972 double dlat = latlong_to_radians(nodex1->latitude) - latlong_to_radians(nodex2->latitude);
973 double lat1 = latlong_to_radians(nodex1->latitude);
974 double lat2 = latlong_to_radians(nodex2->latitude);
976 double a1,a2,a,sa,c,d;
978 if(dlon==0 && dlat==0)
983 a = (a1 * a1) + cos (lat1) * cos (lat2) * a2 * a2;
988 {c = 2 * asin (1.0);}
991 return km_to_distance(d);