1 /***************************************
2 $Header: /home/amb/routino/src/RCS/nodesx.c,v 1.75 2010/10/09 14:14:42 amb Exp $
4 Extented Node 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 ***************************************/
36 #include "segmentsx.h"
42 #include "functions.h"
47 /*+ The command line '--tmpdir' option or its default value. +*/
48 extern char *option_tmpdirname;
50 /*+ A temporary file-local variable for use by the sort functions. +*/
51 static NodesX *sortnodesx;
55 static int sort_by_id(NodeX *a,NodeX *b);
56 static int index_by_id(NodeX *nodex,index_t index);
58 static int sort_by_lat_long(NodeX *a,NodeX *b);
59 static int index_by_lat_long(NodeX *nodex,index_t index);
62 /*++++++++++++++++++++++++++++++++++++++
63 Allocate a new node list (create a new file or open an existing one).
65 NodesX *NewNodeList Returns the node list.
67 int append Set to 1 if the file is to be opened for appending (now or later).
68 ++++++++++++++++++++++++++++++++++++++*/
70 NodesX *NewNodeList(int append)
74 nodesx=(NodesX*)calloc(1,sizeof(NodesX));
76 assert(nodesx); /* Check calloc() worked */
78 nodesx->filename=(char*)malloc(strlen(option_tmpdirname)+32);
81 sprintf(nodesx->filename,"%s/nodesx.input.tmp",option_tmpdirname);
83 sprintf(nodesx->filename,"%s/nodesx.%p.tmp",option_tmpdirname,nodesx);
86 nodesx->nfilename=(char*)malloc(strlen(option_tmpdirname)+32);
88 sprintf(nodesx->nfilename,"%s/nodes.%p.tmp",option_tmpdirname,nodesx);
95 nodesx->fd=OpenFileAppend(nodesx->filename);
97 size=SizeFile(nodesx->filename);
99 nodesx->xnumber=size/sizeof(NodeX);
102 nodesx->fd=OpenFileNew(nodesx->filename);
108 /*++++++++++++++++++++++++++++++++++++++
111 NodesX *nodesx The list to be freed.
113 int keep Set to 1 if the file is to be kept.
114 ++++++++++++++++++++++++++++++++++++++*/
116 void FreeNodeList(NodesX *nodesx,int keep)
119 DeleteFile(nodesx->filename);
121 free(nodesx->filename);
132 DeleteFile(nodesx->nfilename);
134 free(nodesx->nfilename);
141 free(nodesx->offsets);
147 /*++++++++++++++++++++++++++++++++++++++
148 Append a single node to an unsorted node list.
150 NodesX* nodesx The set of nodes to process.
152 node_t id The node identification.
154 double latitude The latitude of the node.
156 double longitude The longitude of the node.
158 allow_t allow The allowed traffic types through the node.
159 ++++++++++++++++++++++++++++++++++++++*/
161 void AppendNode(NodesX* nodesx,node_t id,double latitude,double longitude,allow_t allow)
166 nodex.latitude =radians_to_latlong(latitude);
167 nodex.longitude=radians_to_latlong(longitude);
170 WriteFile(nodesx->fd,&nodex,sizeof(NodeX));
174 assert(nodesx->xnumber<NODE_FAKE); /* NODE_FAKE marks the high-water mark for real nodes. */
178 /*++++++++++++++++++++++++++++++++++++++
179 Sort the node list (i.e. create the sortable indexes).
181 NodesX* nodesx The set of nodes to process.
182 ++++++++++++++++++++++++++++++++++++++*/
184 void SortNodeList(NodesX* nodesx)
188 /* Print the start message */
190 printf("Sorting Nodes");
193 /* Close the files and re-open them (finished appending) */
195 CloseFile(nodesx->fd);
196 nodesx->fd=ReOpenFile(nodesx->filename);
198 DeleteFile(nodesx->filename);
200 fd=OpenFileNew(nodesx->filename);
202 /* Allocate the array of indexes */
204 nodesx->idata=(node_t*)malloc(nodesx->xnumber*sizeof(node_t));
206 assert(nodesx->idata); /* Check malloc() worked */
208 /* Sort by node indexes */
212 filesort_fixed(nodesx->fd,fd,sizeof(NodeX),(int (*)(const void*,const void*))sort_by_id,(int (*)(void*,index_t))index_by_id);
214 /* Close the files and re-open them */
216 CloseFile(nodesx->fd);
219 nodesx->fd=ReOpenFile(nodesx->filename);
221 /* Print the final message */
223 printf("\rSorted Nodes: Nodes=%d Duplicates=%d\n",nodesx->xnumber,nodesx->xnumber-nodesx->number);
228 /*++++++++++++++++++++++++++++++++++++++
229 Sort the nodes into id order.
231 int sort_by_id Returns the comparison of the id fields.
233 NodeX *a The first extended node.
235 NodeX *b The second extended node.
236 ++++++++++++++++++++++++++++++++++++++*/
238 static int sort_by_id(NodeX *a,NodeX *b)
252 /*++++++++++++++++++++++++++++++++++++++
253 Index the nodes after sorting.
255 int index_by_id Return 1 if the value is to be kept, otherwise zero.
257 NodeX *nodex The extended node.
259 index_t index The index of this node in the total.
260 ++++++++++++++++++++++++++++++++++++++*/
262 static int index_by_id(NodeX *nodex,index_t index)
264 if(index==0 || sortnodesx->idata[index-1]!=nodex->id)
266 sortnodesx->idata[index]=nodex->id;
268 sortnodesx->number++;
277 /*++++++++++++++++++++++++++++++++++++++
278 Sort the node list geographically.
280 NodesX* nodesx The set of nodes to process.
281 ++++++++++++++++++++++++++++++++++++++*/
283 void SortNodeListGeographically(NodesX* nodesx)
287 /* Print the start message */
289 printf("Sorting Nodes Geographically");
292 /* Allocate the memory for the geographical offsets array */
294 nodesx->offsets=(index_t*)malloc((nodesx->latbins*nodesx->lonbins+1)*sizeof(index_t));
298 /* Close the files and re-open them */
300 CloseFile(nodesx->fd);
301 nodesx->fd=ReOpenFile(nodesx->filename);
303 DeleteFile(nodesx->filename);
305 fd=OpenFileNew(nodesx->filename);
307 /* Sort geographically */
311 filesort_fixed(nodesx->fd,fd,sizeof(NodeX),(int (*)(const void*,const void*))sort_by_lat_long,(int (*)(void*,index_t))index_by_lat_long);
313 /* Close the files and re-open them */
315 CloseFile(nodesx->fd);
318 nodesx->fd=ReOpenFile(nodesx->filename);
320 /* Finish off the indexing */
322 for(;nodesx->latlonbin<=(nodesx->latbins*nodesx->lonbins);nodesx->latlonbin++)
323 nodesx->offsets[nodesx->latlonbin]=nodesx->number;
325 /* Print the final message */
327 printf("\rSorted Nodes Geographically \n");
332 /*++++++++++++++++++++++++++++++++++++++
333 Sort the nodes into latitude and longitude order.
335 int sort_by_lat_long Returns the comparison of the latitude and longitude fields.
337 NodeX *a The first extended node.
339 NodeX *b The second extended node.
340 ++++++++++++++++++++++++++++++++++++++*/
342 static int sort_by_lat_long(NodeX *a,NodeX *b)
344 ll_bin_t a_lon=latlong_to_bin(a->longitude);
345 ll_bin_t b_lon=latlong_to_bin(b->longitude);
353 ll_bin_t a_lat=latlong_to_bin(a->latitude);
354 ll_bin_t b_lat=latlong_to_bin(b->latitude);
362 #ifdef REGRESSION_TESTING
363 // Need this for regression testing because filesort_heapsort() is not order
364 // preserving like qsort() is (or was when tested).
381 /*++++++++++++++++++++++++++++++++++++++
382 Index the nodes after sorting.
384 int index_by_lat_long Return 1 if the value is to be kept, otherwise zero.
386 NodeX *nodex The extended node.
388 index_t index The index of this node in the total.
389 ++++++++++++++++++++++++++++++++++++++*/
391 static int index_by_lat_long(NodeX *nodex,index_t index)
393 /* Work out the offsets */
395 ll_bin_t latbin=latlong_to_bin(nodex->latitude )-sortnodesx->latzero;
396 ll_bin_t lonbin=latlong_to_bin(nodex->longitude)-sortnodesx->lonzero;
397 int llbin=lonbin*sortnodesx->latbins+latbin;
399 for(;sortnodesx->latlonbin<=llbin;sortnodesx->latlonbin++)
400 sortnodesx->offsets[sortnodesx->latlonbin]=index;
406 /*++++++++++++++++++++++++++++++++++++++
407 Find a particular node index.
409 index_t IndexNodeX Returns the index of the extended node with the specified id.
411 NodesX* nodesx The set of nodes to process.
413 node_t id The node id to look for.
414 ++++++++++++++++++++++++++++++++++++++*/
416 index_t IndexNodeX(NodesX* nodesx,node_t id)
419 int end=nodesx->number-1;
422 /* Binary search - search key exact match only is required.
424 * # <- start | Check mid and move start or end if it doesn't match
426 * # | Since an exact match is wanted we can set end=mid-1
427 * # <- mid | or start=mid+1 because we know that mid doesn't match.
429 * # | Eventually either end=start or end=start+1 and one of
430 * # <- end | start or end is the wanted one.
433 if(end<start) /* There are no nodes */
435 else if(id<nodesx->idata[start]) /* Check key is not before start */
437 else if(id>nodesx->idata[end]) /* Check key is not after end */
443 mid=(start+end)/2; /* Choose mid point */
445 if(nodesx->idata[mid]<id) /* Mid point is too low */
447 else if(nodesx->idata[mid]>id) /* Mid point is too high */
449 else /* Mid point is correct */
452 while((end-start)>1);
454 if(nodesx->idata[start]==id) /* Start is correct */
457 if(nodesx->idata[end]==id) /* End is correct */
465 /*++++++++++++++++++++++++++++++++++++++
466 Remove any nodes that are not part of a highway.
468 NodesX *nodesx The complete node list.
470 SegmentsX *segmentsx The list of segments.
471 ++++++++++++++++++++++++++++++++++++++*/
473 void RemoveNonHighwayNodes(NodesX *nodesx,SegmentsX *segmentsx)
476 int total=0,highway=0,nothighway=0;
477 ll_bin_t lat_min_bin,lat_max_bin,lon_min_bin,lon_max_bin;
478 latlong_t lat_min,lat_max,lon_min,lon_max;
481 /* Print the start message */
483 printf("Checking: Nodes=0");
486 /* While we are here we can work out the range of data */
488 lat_min=radians_to_latlong( 2);
489 lat_max=radians_to_latlong(-2);
490 lon_min=radians_to_latlong( 4);
491 lon_max=radians_to_latlong(-4);
493 /* Modify the on-disk image */
495 DeleteFile(nodesx->filename);
497 fd=OpenFileNew(nodesx->filename);
498 SeekFile(nodesx->fd,0);
500 while(!ReadFile(nodesx->fd,&nodex,sizeof(NodeX)))
502 if(IndexFirstSegmentX(segmentsx,nodex.id)==NO_SEGMENT)
508 WriteFile(fd,&nodex,sizeof(NodeX));
510 nodesx->idata[highway]=nodesx->idata[total];
513 if(nodex.latitude<lat_min)
514 lat_min=nodex.latitude;
515 if(nodex.latitude>lat_max)
516 lat_max=nodex.latitude;
517 if(nodex.longitude<lon_min)
518 lon_min=nodex.longitude;
519 if(nodex.longitude>lon_max)
520 lon_max=nodex.longitude;
527 printf("\rChecking: Nodes=%d Highway=%d not-Highway=%d",total,highway,nothighway);
532 /* Close the files and re-open them */
534 CloseFile(nodesx->fd);
537 nodesx->fd=ReOpenFile(nodesx->filename);
539 nodesx->number=highway;
541 /* Work out the number of bins */
543 lat_min_bin=latlong_to_bin(lat_min);
544 lon_min_bin=latlong_to_bin(lon_min);
545 lat_max_bin=latlong_to_bin(lat_max);
546 lon_max_bin=latlong_to_bin(lon_max);
548 nodesx->latzero=lat_min_bin;
549 nodesx->lonzero=lon_min_bin;
551 nodesx->latbins=(lat_max_bin-lat_min_bin)+1;
552 nodesx->lonbins=(lon_max_bin-lon_min_bin)+1;
554 /* Allocate and clear the super-node markers */
556 nodesx->super=(uint8_t*)calloc(nodesx->number,sizeof(uint8_t));
558 assert(nodesx->super); /* Check calloc() worked */
560 /* Print the final message */
562 printf("\rChecked: Nodes=%d Highway=%d not-Highway=%d \n",total,highway,nothighway);
567 /*++++++++++++++++++++++++++++++++++++++
568 Create the real node data.
570 NodesX *nodesx The set of nodes to use.
572 int iteration The final super-node iteration.
573 ++++++++++++++++++++++++++++++++++++++*/
575 void CreateRealNodes(NodesX *nodesx,int iteration)
579 /* Print the start message */
581 printf("Creating Real Nodes: Nodes=0");
584 /* Map into memory */
587 nodesx->xdata=MapFile(nodesx->filename);
590 /* Allocate the memory (or open the file) */
593 nodesx->ndata=(Node*)malloc(nodesx->number*sizeof(Node));
595 assert(nodesx->ndata); /* Check malloc() worked */
597 nodesx->nfd=OpenFileNew(nodesx->nfilename);
600 /* Loop through and allocate. */
602 for(i=0;i<nodesx->number;i++)
604 NodeX *nodex=LookupNodeX(nodesx,i,1);
605 Node *node =LookupNodeXNode(nodesx,nodex->id,1);
607 node->latoffset=latlong_to_off(nodex->latitude);
608 node->lonoffset=latlong_to_off(nodex->longitude);
609 node->firstseg=NO_SEGMENT;
610 node->allow=nodex->allow;
613 if(nodesx->super[nodex->id]==iteration)
614 node->flags|=NODE_SUPER;
617 PutBackNodeXNode(nodesx,nodex->id,1);
622 printf("\rCreating Real Nodes: Nodes=%d",i+1);
627 /* Free the unneeded memory */
632 /* Unmap from memory */
635 nodesx->xdata=UnmapFile(nodesx->filename);
638 /* Print the final message */
640 printf("\rCreating Real Nodes: Nodes=%d \n",nodesx->number);
645 /*++++++++++++++++++++++++++++++++++++++
646 Assign the segment indexes to the nodes.
648 NodesX *nodesx The list of nodes to process.
650 SegmentsX* segmentsx The set of segments to use.
651 ++++++++++++++++++++++++++++++++++++++*/
653 void IndexNodes(NodesX *nodesx,SegmentsX *segmentsx)
657 if(nodesx->number==0 || segmentsx->number==0)
660 /* Print the start message */
662 printf("Indexing Segments: Segments=0");
665 /* Map into memory */
668 nodesx->xdata=MapFile(nodesx->filename);
669 segmentsx->xdata=MapFile(segmentsx->filename);
672 /* Index the nodes */
674 for(i=0;i<segmentsx->number;i++)
676 SegmentX *segmentx=LookupSegmentX(segmentsx,i,1);
677 node_t id1=segmentx->node1;
678 node_t id2=segmentx->node2;
679 Node *node1=LookupNodeXNode(nodesx,id1,1);
680 Node *node2=LookupNodeXNode(nodesx,id2,2);
684 if(node1->firstseg==NO_SEGMENT)
689 PutBackNodeXNode(nodesx,id1,1);
694 index_t index=node1->firstseg;
698 segmentx=LookupSegmentX(segmentsx,index,1);
700 if(segmentx->node1==id1)
704 if(index>=segmentsx->number)
707 segmentx=LookupSegmentX(segmentsx,index,1);
709 if(segmentx->node1!=id1)
714 Segment *segment=LookupSegmentXSegment(segmentsx,index,1);
716 if(segment->next2==NO_NODE)
721 PutBackSegmentXSegment(segmentsx,index,1);
727 index=segment->next2;
735 if(node2->firstseg==NO_SEGMENT)
740 PutBackNodeXNode(nodesx,id2,2);
745 index_t index=node2->firstseg;
749 segmentx=LookupSegmentX(segmentsx,index,1);
751 if(segmentx->node1==id2)
755 if(index>=segmentsx->number)
758 segmentx=LookupSegmentX(segmentsx,index,1);
760 if(segmentx->node1!=id2)
765 Segment *segment=LookupSegmentXSegment(segmentsx,index,1);
767 if(segment->next2==NO_NODE)
772 PutBackSegmentXSegment(segmentsx,index,1);
778 index=segment->next2;
786 printf("\rIndexing Segments: Segments=%d",i+1);
791 /* Unmap from memory */
794 nodesx->xdata=UnmapFile(nodesx->filename);
795 segmentsx->xdata=UnmapFile(segmentsx->filename);
798 /* Print the final message */
800 printf("\rIndexed Segments: Segments=%d \n",segmentsx->number);
805 /*++++++++++++++++++++++++++++++++++++++
806 Save the node list to a file.
808 NodesX* nodesx The set of nodes to save.
810 const char *filename The name of the file to save.
811 ++++++++++++++++++++++++++++++++++++++*/
813 void SaveNodeList(NodesX* nodesx,const char *filename)
817 NodesFile nodesfile={0};
820 /* Print the start message */
822 printf("Writing Nodes: Nodes=0");
825 /* Map into memory */
828 nodesx->xdata=MapFile(nodesx->filename);
831 /* Write out the nodes data */
833 fd=OpenFileNew(filename);
835 SeekFile(fd,sizeof(NodesFile));
836 WriteFile(fd,nodesx->offsets,(nodesx->latbins*nodesx->lonbins+1)*sizeof(index_t));
838 for(i=0;i<nodesx->number;i++)
840 NodeX *nodex=LookupNodeX(nodesx,i,1);
841 Node *node=LookupNodeXNode(nodesx,nodex->id,1);
843 if(node->flags&NODE_SUPER)
846 WriteFile(fd,node,sizeof(Node));
850 printf("\rWriting Nodes: Nodes=%d",i+1);
855 /* Write out the header structure */
857 nodesfile.number=nodesx->number;
858 nodesfile.snumber=super_number;
860 nodesfile.latbins=nodesx->latbins;
861 nodesfile.lonbins=nodesx->lonbins;
863 nodesfile.latzero=nodesx->latzero;
864 nodesfile.lonzero=nodesx->lonzero;
867 WriteFile(fd,&nodesfile,sizeof(NodesFile));
871 /* Unmap from memory */
874 nodesx->xdata=UnmapFile(nodesx->filename);
877 /* Print the final message */
879 printf("\rWrote Nodes: Nodes=%d \n",nodesx->number);