static void find_all_nodes(Nodes *nodes,callback_t callback)
{
 ll_bin_t latminbin=latlong_to_bin(radians_to_latlong(LatMin))-nodes->file.latzero;
 ll_bin_t latmaxbin=latlong_to_bin(radians_to_latlong(LatMax))-nodes->file.latzero;
 ll_bin_t lonminbin=latlong_to_bin(radians_to_latlong(LonMin))-nodes->file.lonzero;
 ll_bin_t lonmaxbin=latlong_to_bin(radians_to_latlong(LonMax))-nodes->file.lonzero;
 ll_bin_t latb,lonb;
 index_t i,index1,index2;

 /* Loop through all of the nodes. */

 for(latb=latminbin;latb<=latmaxbin;latb++)
    for(lonb=lonminbin;lonb<=lonmaxbin;lonb++)
      {
       ll_bin2_t llbin=lonb*nodes->file.latbins+latb;

       if(llbin<0 || llbin>(nodes->file.latbins*nodes->file.lonbins))
          continue;

       index1=LookupNodeOffset(nodes,llbin);
       index2=LookupNodeOffset(nodes,llbin+1);

       for(i=index1;i<index2;i++)
         {
          Node *node=LookupNode(nodes,i,1);

          double lat=latlong_to_radians(bin_to_latlong(nodes->file.latzero+latb)+off_to_latlong(node->latoffset));
          double lon=latlong_to_radians(bin_to_latlong(nodes->file.lonzero+lonb)+off_to_latlong(node->lonoffset));

          if(lat>LatMin && lat<LatMax && lon>LonMin && lon<LonMax)
             (*callback)(i,lat,lon);
         }
      }
}
void PruneStraightHighwayNodes(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx,distance_t maximum)
{
 index_t i;
 index_t npruned=0;
 index_t nalloc;
 BitMask *checked;
 index_t *nodes,*segments;
 double *lats,*lons;
 double maximumf;

 if(nodesx->number==0 || segmentsx->number==0 || waysx->number==0)
    return;

 /* Print the start message */

 printf_first("Pruning Straight Highway Nodes: Nodes=0 Pruned=0");

 /* Map into memory / open the files */

#if !SLIM
 nodesx->data=MapFile(nodesx->filename_tmp);
 segmentsx->data=MapFileWriteable(segmentsx->filename_tmp);
 waysx->data=MapFile(waysx->filename_tmp);
#else
 nodesx->fd=SlimMapFile(nodesx->filename_tmp);
 segmentsx->fd=SlimMapFileWriteable(segmentsx->filename_tmp);
 waysx->fd=SlimMapFile(waysx->filename_tmp);

 InvalidateNodeXCache(nodesx->cache);
 InvalidateSegmentXCache(segmentsx->cache);
 InvalidateWayXCache(waysx->cache);
#endif

 checked=AllocBitMask(nodesx->number);

 logassert(checked,"Failed to allocate memory (try using slim mode?)"); /* Check AllocBitMask() worked */

 nodes   =(index_t*)malloc((nalloc=1024)*sizeof(index_t));
 segments=(index_t*)malloc( nalloc      *sizeof(index_t));

 logassert(nodes,"Failed to allocate memory (try using slim mode?)");    /* Check malloc() worked */
 logassert(segments,"Failed to allocate memory (try using slim mode?)"); /* Check malloc() worked */

 lats=(double*)malloc(nalloc*sizeof(double));
 lons=(double*)malloc(nalloc*sizeof(double));

 logassert(lats,"Failed to allocate memory (try using slim mode?)");    /* Check malloc() worked */
 logassert(lons,"Failed to allocate memory (try using slim mode?)");    /* Check malloc() worked */

 /* Loop through the nodes and find stretches of simple highway for possible modification */

 maximumf=distance_to_km(maximum);

 for(i=0;i<nodesx->number;i++)
   {
    int lowerbounded=0,upperbounded=0;
    index_t lower=nalloc/2,current=nalloc/2,upper=nalloc/2;

    if(IsBitSet(checked,i))
       goto endloop;

    if(segmentsx->firstnode[i]==NO_SEGMENT)
       goto endloop;

    /* Find all connected nodes */

    nodes[current]=i;

    do
      {
       index_t node1=NO_NODE,node2=NO_NODE;
       index_t segment1=NO_SEGMENT,segment2=NO_SEGMENT;
       index_t way1=NO_WAY,way2=NO_WAY;
       int segcount=0;
       NodeX *nodex;

       /* Get the node data */

       nodex=LookupNodeX(nodesx,nodes[current],1);

       lats[current]=latlong_to_radians(nodex->latitude);
       lons[current]=latlong_to_radians(nodex->longitude);

       /* Count the segments at the node if not forced to be an end node */

       if(IsBitSet(checked,nodes[current]))
          ;
       else if(nodex->flags&NODE_MINIRNDBT)
          ;
       else if(nodex->flags&NODE_TURNRSTRCT2 || nodex->flags&NODE_TURNRSTRCT)
          ;
       else
         {
          SegmentX *segmentx;

          /* Count the segments connected to the node */

          segmentx=FirstSegmentX(segmentsx,nodes[current],3);

          while(segmentx)
            {
             segcount++;

             if(node1==NO_NODE)
               {
                segment1=IndexSegmentX(segmentsx,segmentx);
                node1=OtherNode(segmentx,nodes[current]);
                way1=segmentx->way;
               }
             else if(node2==NO_NODE)
               {
                segment2=IndexSegmentX(segmentsx,segmentx);
                node2=OtherNode(segmentx,nodes[current]);
                way2=segmentx->way;
               }
             else
                break;

             segmentx=NextSegmentX(segmentsx,segmentx,nodes[current]);
            }
         }

       /* Check if allowed due to one-way properties */

       if(segcount==2)
         {
          SegmentX *segmentx1,*segmentx2;

          segmentx1=LookupSegmentX(segmentsx,segment1,1);
          segmentx2=LookupSegmentX(segmentsx,segment2,2);

          if(!IsOneway(segmentx1) && !IsOneway(segmentx2))
             ;
          else if(IsOneway(segmentx1) && IsOneway(segmentx2))
            {
             if(IsOnewayTo(segmentx1,nodes[current]) && !IsOnewayFrom(segmentx2,nodes[current])) /* S1 is one-way but S2 doesn't continue */
                segcount=0;

             if(IsOnewayFrom(segmentx1,nodes[current]) && !IsOnewayTo(segmentx2,nodes[current])) /* S1 is one-way but S2 doesn't continue */
                segcount=0;
            }
          else
             segcount=0;
         }

       /* Check if allowed due to highway properties and node restrictions */

       if(segcount==2)
         {
          WayX *wayx1,*wayx2;

          wayx1=LookupWayX(waysx,way1,1);
          wayx2=LookupWayX(waysx,way2,2);

          if(WaysCompare(&wayx1->way,&wayx2->way))
             segcount=0;

          if(wayx1->way.name!=wayx2->way.name)
             segcount=0;

          if((nodex->allow&wayx1->way.allow)!=wayx1->way.allow)
             segcount=0;

          if((nodex->allow&wayx2->way.allow)!=wayx2->way.allow)
             segcount=0;
         }

       /* Update the lists */

       if(segcount==2)
         {
          /* Make space in the lists */

          if(upper==(nalloc-1))
            {
             nodes   =(index_t*)realloc(nodes   ,(nalloc+=1024)*sizeof(index_t));
             segments=(index_t*)realloc(segments, nalloc       *sizeof(index_t));

             lats=(double*)realloc(lats,nalloc*sizeof(double));
             lons=(double*)realloc(lons,nalloc*sizeof(double));
            }

          if(lower==0)     /* move everything up by one */
            {
             memmove(nodes+1   ,nodes   ,(1+upper-lower)*sizeof(index_t));
             memmove(segments+1,segments,(1+upper-lower)*sizeof(index_t));

             memmove(lats+1,lats,(1+upper-lower)*sizeof(double));
             memmove(lons+1,lons,(1+upper-lower)*sizeof(double));

             current++;
             lower++;
             upper++;
            }

          if(lower==upper) /* first */
            {
             lower--;

             nodes[lower]=node1;
             segments[lower]=segment1;

             upper++;

             nodes[upper]=node2;
             segments[upper-1]=segment2;
             segments[upper]=NO_SEGMENT;

             current--;
            }
          else if(current==lower)
            {
             lower--;

             if(nodes[current+1]==node2)
               {
                nodes[lower]=node1;
                segments[lower]=segment1;
               }
             else /* if(nodes[current+1]==node1) */
               {
                nodes[lower]=node2;
                segments[lower]=segment2;
               }

             current--;
            }
          else /* if(current==upper) */
            {
             upper++;

             if(nodes[current-1]==node2)
               {
                nodes[upper]=node1;
                segments[upper-1]=segment1;
               }
             else /* if(nodes[current-1]==node1) */
               {
                nodes[upper]=node2;
                segments[upper-1]=segment2;
               }

             segments[upper]=NO_SEGMENT;

             current++;
            }

          if(nodes[upper]==nodes[lower])
            {
             if(!lowerbounded && !upperbounded)
               {
                nodex=LookupNodeX(nodesx,nodes[lower],1);

                lats[lower]=latlong_to_radians(nodex->latitude);
                lons[lower]=latlong_to_radians(nodex->longitude);
               }

             lats[upper]=lats[lower];
             lons[upper]=lons[lower];

             lowerbounded=1;
             upperbounded=1;
            }
         }
       else /* if(segment!=2) */
         {
          if(current==upper)
             upperbounded=1;

          if(current==lower)
            {
             lowerbounded=1;
             current=upper;
            }
         }
      }
    while(!(lowerbounded && upperbounded));

    /* Mark the nodes */

    for(current=lower;current<=upper;current++)
       SetBit(checked,nodes[current]);

    /* Check for straight highway */

    for(;lower<(upper-1);lower++)
      {
       for(current=upper;current>(lower+1);current--)
         {
          SegmentX *segmentx;
          distance_t dist=0;
          double dist1,dist2,dist3,distp;
          index_t c;

          dist3=distance(lats[lower],lons[lower],lats[current],lons[current]);

          for(c=lower+1;c<current;c++)
            {
             dist1=distance(lats[lower]  ,lons[lower]  ,lats[c],lons[c]);
             dist2=distance(lats[current],lons[current],lats[c],lons[c]);

             /* Use law of cosines (assume flat Earth) */

             if(dist3==0)
                distp=dist1; /* == dist2 */
             else if((dist1+dist2)<dist3)
                distp=0;
             else
               {
                double dist3a=(dist1*dist1-dist2*dist2+dist3*dist3)/(2.0*dist3);
                double dist3b=dist3-dist3a;

                if(dist3a>=0 && dist3b>=0)
                   distp=sqrt(dist1*dist1-dist3a*dist3a);
                else if(dist3a>0)
                   distp=dist2;
                else /* if(dist3b>0) */
                   distp=dist1;
               }

             if(distp>maximumf) /* gone too far */
                break;
            }

          if(c<current) /* not finished */
             continue;

          /* Delete some segments and shift along */

          for(c=lower+1;c<current;c++)
            {
             segmentx=LookupSegmentX(segmentsx,segments[c],1);

             dist+=DISTANCE(segmentx->distance);

             prune_segment(segmentsx,segmentx);

             npruned++;
            }

          segmentx=LookupSegmentX(segmentsx,segments[lower],1);

          if(nodes[lower]==nodes[current]) /* loop; all within maximum distance */
            {
             prune_segment(segmentsx,segmentx);

             npruned++;
            }
          else
            {
             segmentx->distance+=dist;

             if(segmentx->node1==nodes[lower])
                modify_segment(segmentsx,segmentx,nodes[lower],nodes[current]);
             else /* if(segmentx->node2==nodes[lower]) */
                modify_segment(segmentsx,segmentx,nodes[current],nodes[lower]);
            }

          lower=current-1;
          break;
         }
      }

   endloop:

    if(!((i+1)%10000))
       printf_middle("Pruning Straight Highway Nodes: Nodes=%"Pindex_t" Pruned=%"Pindex_t,i+1,npruned);
   }

 /* Unmap from memory / close the files */

 free(checked);

 free(nodes);
 free(segments);

 free(lats);
 free(lons);

#if !SLIM
 nodesx->data=UnmapFile(nodesx->data);
 segmentsx->data=UnmapFile(segmentsx->data);
 waysx->data=UnmapFile(waysx->data);
#else
 nodesx->fd=SlimUnmapFile(nodesx->fd);
 segmentsx->fd=SlimUnmapFile(segmentsx->fd);
 waysx->fd=SlimUnmapFile(waysx->fd);
#endif

 /* Print the final message */

 printf_last("Pruned Straight Highway Nodes: Nodes=%"Pindex_t" Pruned=%"Pindex_t,nodesx->number,npruned);
}