static void output_junctions(index_t node,double latitude,double longitude)
{
 Node *nodep=LookupNode(OSMNodes,node,1);
 Segment *segment;
 Way *firstway;
 int count=0,difference=0;

 segment=FirstSegment(OSMSegments,nodep,1);
 firstway=LookupWay(OSMWays,segment->way,1);

 do
   {
    Way *way=LookupWay(OSMWays,segment->way,2);

    if(IsNormalSegment(segment))
       count++;

    if(WaysCompare(firstway,way))
       difference=1;

    segment=NextSegment(OSMSegments,segment,node);
   }
 while(segment);

 if(count!=2 || difference)
    printf("%.6f %.6f %d\n",radians_to_degrees(latitude),radians_to_degrees(longitude),count);
}
Example #2
0
static int sort_by_name_and_prop_and_id(WayX *a,WayX *b)
{
 int compare;
 index_t a_name=a->way.name;
 index_t b_name=b->way.name;

 if(a_name<b_name)
    return(-1);
 else if(a_name>b_name)
    return(1);

 compare=WaysCompare(&a->way,&b->way);

 if(compare)
    return(compare);

 return(sort_by_id(a,b));
}
Example #3
0
static int deduplicate_and_index_by_compact_id(WayX *wayx,index_t index)
{
 static Way lastway;

 if(index==0 || wayx->way.name!=lastway.name || WaysCompare(&lastway,&wayx->way))
   {
    lastway=wayx->way;

    sortwaysx->cdata[wayx->id]=index;

    wayx->id=index;

    return(1);
   }
 else
   {
    sortwaysx->cdata[wayx->id]=index-1;

    return(0);
   }
}
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);
}
void PruneShortSegments(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx,distance_t minimum)
{
 index_t i;
 index_t nshort=0,npruned=0;

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

 /* Print the start message */

 printf_first("Pruning Short Segments: Segments=0 Short=0 Pruned=0");

 /* Map into memory / open the files */

#if !SLIM
 nodesx->data=MapFileWriteable(nodesx->filename_tmp);
 segmentsx->data=MapFileWriteable(segmentsx->filename_tmp);
 waysx->data=MapFile(waysx->filename_tmp);
#else
 nodesx->fd=SlimMapFileWriteable(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

 /* Loop through the segments and find the short ones for possible modification */

 for(i=0;i<segmentsx->number;i++)
   {
    SegmentX *segmentx2=LookupSegmentX(segmentsx,i,2);

    if(IsPrunedSegmentX(segmentx2))
       goto endloop;

    /*
                       :
      Initial state: ..N3 -------- N2
                       :     S2

                       :
      Final state:   ..N3
                       :

      = OR =

                       :                               :
      Initial state: ..N1 -------- N2 ---- N3 -------- N4..
                       :     S1        S2        S3    :

                       :                               :
      Final state:   ..N1 ------------ N3 ------------ N4..
                       :       S1               S3     :

      Not if N1 is the same as N4.
      Must not delete N2 (or N3) if S2 (or S3) has different one-way properties from S1.
      Must not delete N2 (or N3) if S2 (or S3) has different highway properties from S1.
      Must combine N2, S2 and N3 disallowed transports into new N3.
      Must not delete N2 (or N3) if it is a mini-roundabout.
      Must not delete N2 (or N3) if it is involved in a turn restriction.

      = OR =

                       :                   :
      Initial state: ..N1 -------- N2 ---- N3..
                       :     S1        S2  :

                       :               :
      Final state:   ..N1 ------------ N3..
                       :       S1      :

      Not if N1 is the same as N3.
      Not if S1 has different one-way properties from S2.
      Not if S1 has different highway properties from S2.
      Not if N2 disallows transports allowed on S1 and S2.
      Not if N2 is a mini-roundabout.
      Not if N2 is involved in a turn restriction.
     */

    if(DISTANCE(segmentx2->distance)<=minimum)
      {
       index_t node1=NO_NODE,node2,node3,node4=NO_NODE;
       index_t segment1=NO_SEGMENT,segment2=i,segment3=NO_SEGMENT;
       SegmentX *segmentx;
       int segcount2=0,segcount3=0;

       nshort++;

       node2=segmentx2->node1;
       node3=segmentx2->node2;

       /* Count the segments connected to N2 */

       segmentx=FirstSegmentX(segmentsx,node2,4);

       while(segmentx)
         {
          segcount2++;

          if(segment1==NO_SEGMENT)
            {
             index_t segment=IndexSegmentX(segmentsx,segmentx);

             if(segment!=segment2)
               {
                segment1=segment;
                node1=OtherNode(segmentx,node2);
               }
            }
          else if(segcount2>2)
             break;

          segmentx=NextSegmentX(segmentsx,segmentx,node2);
         }

       /* Count the segments connected to N3 */

       segmentx=FirstSegmentX(segmentsx,node3,4);

       while(segmentx)
         {
          segcount3++;

          if(segment3==NO_SEGMENT)
            {
             index_t segment=IndexSegmentX(segmentsx,segmentx);

             if(segment!=segment2)
               {
                segment3=segment;
                node4=OtherNode(segmentx,node3);
               }
            }
          else if(segcount3>2)
             break;

          segmentx=NextSegmentX(segmentsx,segmentx,node3);
         }

       /* Check which case we are handling (and canonicalise) */

       if(segcount2>2 && segcount3>2) /* none of the cases in diagram - too complicated */
         {
          goto endloop;
         }
       else if(segcount2==1 || segcount3==1) /* first case in diagram - prune segment */
         {
          prune_segment(segmentsx,segmentx2);
         }
       else if(segcount2==2 && segcount3==2) /* second case in diagram - modify one segment and prune segment */
         {
          SegmentX *segmentx1,*segmentx3;
          WayX *wayx1,*wayx2,*wayx3;
          NodeX *nodex2,*nodex3,*newnodex;
          index_t newnode;
          int join12=1,join23=1;

          /* Check if pruning would collapse a loop */

          if(node1==node4)
             goto endloop;

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

          segmentx1=LookupSegmentX(segmentsx,segment1,1);
          segmentx3=LookupSegmentX(segmentsx,segment3,3);

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

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

          if(!IsOneway(segmentx3) && !IsOneway(segmentx2))
             ;
          else if(IsOneway(segmentx3) && IsOneway(segmentx2))
            {
             if(IsOnewayTo(segmentx3,node3) && !IsOnewayFrom(segmentx2,node3)) /* S3 is one-way but S2 doesn't continue */
                join23=0;

             if(IsOnewayFrom(segmentx3,node3) && !IsOnewayTo(segmentx2,node3)) /* S3 is one-way but S2 doesn't continue */
                join23=0;
            }
          else
             join23=0;

          if(!join12 && !join23)
             goto endloop;

          /* Check if allowed due to highway properties */

          wayx1=LookupWayX(waysx,segmentx1->way,1);
          wayx2=LookupWayX(waysx,segmentx2->way,2);
          wayx3=LookupWayX(waysx,segmentx3->way,3);

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

          if(WaysCompare(&wayx3->way,&wayx2->way))
             join23=0;

          if(!join12 && !join23)
             goto endloop;

          /* Check if allowed due to mini-roundabout and turn restriction */

          nodex2=LookupNodeX(nodesx,node2,2);
          nodex3=LookupNodeX(nodesx,node3,3);

          if(nodex2->flags&NODE_MINIRNDBT)
             join12=0;

          if(nodex3->flags&NODE_MINIRNDBT)
             join23=0;

          if(!join12 && !join23)
             goto endloop;

          if(nodex2->flags&NODE_TURNRSTRCT2 || nodex2->flags&NODE_TURNRSTRCT)
             join12=0;

          if(nodex3->flags&NODE_TURNRSTRCT2 || nodex3->flags&NODE_TURNRSTRCT)
             join23=0;

          if(!join12 && !join23)
             goto endloop;

          /* New node properties */

          if(join12)
            {
             newnode=node3;
             newnodex=nodex3;
            }
          else /* if(join23) */
            {
             newnode=node2;
             newnodex=nodex2;
            }

          newnodex->allow=nodex2->allow&nodex3->allow; /* combine the restrictions of the two nodes */
          newnodex->allow&=~((~wayx2->way.allow)&wayx3->way.allow); /* disallow anything blocked by segment2 */
          newnodex->allow&=~((~wayx2->way.allow)&wayx1->way.allow); /* disallow anything blocked by segment2 */

          newnodex->latitude =(nodex2->latitude +nodex3->latitude )/2;
          newnodex->longitude=(nodex2->longitude+nodex3->longitude)/2;

          PutBackNodeX(nodesx,newnodex);

          /* Modify segments */

          segmentx1->distance+=DISTANCE(segmentx2->distance)/2;
          segmentx3->distance+=DISTANCE(segmentx2->distance)-DISTANCE(segmentx2->distance)/2;

          if(segmentx1->node1==node1)
            {
             if(segmentx1->node2!=newnode)
                modify_segment(segmentsx,segmentx1,node1,newnode);
             else
                PutBackSegmentX(segmentsx,segmentx1);
            }
          else /* if(segmentx1->node2==node1) */
            {
             if(segmentx1->node1!=newnode)
                modify_segment(segmentsx,segmentx1,newnode,node1);
             else
                PutBackSegmentX(segmentsx,segmentx1);
            }

          if(segmentx3->node1==node4)
            {
             if(segmentx3->node2!=newnode)
                modify_segment(segmentsx,segmentx3,node4,newnode);
             else
                PutBackSegmentX(segmentsx,segmentx3);
            }
          else /* if(segmentx3->node2==node4) */
            {
             if(segmentx3->node1!=newnode)
                modify_segment(segmentsx,segmentx3,newnode,node4);
             else
                PutBackSegmentX(segmentsx,segmentx3);
            }

          ReLookupSegmentX(segmentsx,segmentx2);

          prune_segment(segmentsx,segmentx2);
         }
       else                     /* third case in diagram - prune one segment */
         {
          SegmentX *segmentx1;
          WayX *wayx1,*wayx2;
          NodeX *nodex2;

          if(segcount3==2) /* not as in diagram, shuffle things round */
            {
             index_t temp;

             temp=segment1; segment1=segment3; segment3=temp;
             temp=node1; node1=node4; node4=temp;
             temp=node2; node2=node3; node3=temp;
            }

          /* Check if pruning would collapse a loop */

          if(node1==node3)
             goto endloop;

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

          segmentx1=LookupSegmentX(segmentsx,segment1,1);

          if(!IsOneway(segmentx1) && !IsOneway(segmentx2))
             ;
          else if(IsOneway(segmentx1) && IsOneway(segmentx2))
            {
             if(IsOnewayTo(segmentx1,node2) && !IsOnewayFrom(segmentx2,node2)) /* S1 is one-way but S2 doesn't continue */
                goto endloop;

             if(IsOnewayFrom(segmentx1,node2) && !IsOnewayTo(segmentx2,node2)) /* S1 is one-way but S2 doesn't continue */
                goto endloop;
            }
          else
             goto endloop;

          /* Check if allowed due to highway properties */

          wayx1=LookupWayX(waysx,segmentx1->way,1);
          wayx2=LookupWayX(waysx,segmentx2->way,2);

          if(WaysCompare(&wayx1->way,&wayx2->way))
             goto endloop;

          /* Check if allowed due to mini-roundabout and turn restriction */

          nodex2=LookupNodeX(nodesx,node2,2);

          if(nodex2->flags&NODE_MINIRNDBT)
             goto endloop;

          if(nodex2->flags&NODE_TURNRSTRCT2 || nodex2->flags&NODE_TURNRSTRCT)
             goto endloop;

          /* Check if allowed due to node restrictions */

          if((nodex2->allow&wayx1->way.allow)!=wayx1->way.allow)
             goto endloop;

          if((nodex2->allow&wayx2->way.allow)!=wayx2->way.allow)
             goto endloop;

          /* Modify segments */

          segmentx1->distance+=DISTANCE(segmentx2->distance);

          if(segmentx1->node1==node1)
             modify_segment(segmentsx,segmentx1,node1,node3);
          else /* if(segmentx1->node2==node1) */
             modify_segment(segmentsx,segmentx1,node3,node1);

          ReLookupSegmentX(segmentsx,segmentx2);

          prune_segment(segmentsx,segmentx2);
         }

       npruned++;
      }

   endloop:

    if(!((i+1)%10000))
       printf_middle("Pruning Short Segments: Segments=%"Pindex_t" Short=%"Pindex_t" Pruned=%"Pindex_t,i+1,nshort,npruned);
   }

 /* Unmap from memory / close the files */

#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 Short Segments: Segments=%"Pindex_t" Short=%"Pindex_t" Pruned=%"Pindex_t,segmentsx->number,nshort,npruned);
}
void ChooseSuperNodes(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx)
{
 index_t i;
 index_t nnodes=0;

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

 /* Print the start message */

 printf_first("Finding Super-Nodes: Nodes=0 Super-Nodes=0");

 /* Allocate and set the super-node markers */

 if(!nodesx->super)
   {
    nodesx->super=AllocBitMask(nodesx->number);

    assert(nodesx->super); /* Check AllocBitMask() worked */

    SetAllBits1(nodesx->super,nodesx->number);
   }

 /* Map into memory / open the files */

#if !SLIM
 nodesx->data=MapFile(nodesx->filename);
 segmentsx->data=MapFile(segmentsx->filename);
 waysx->data=MapFile(waysx->filename);
#else
 nodesx->fd=ReOpenFile(nodesx->filename);
 segmentsx->fd=ReOpenFile(segmentsx->filename);
 waysx->fd=ReOpenFile(waysx->filename);
#endif

 /* Find super-nodes */

 for(i=0;i<nodesx->number;i++)
   {
    if(IsBitSet(nodesx->super,i))
      {
       int issuper=0;
       NodeX *nodex=LookupNodeX(nodesx,i,1);

       if(IsPrunedNodeX(nodex))
          issuper=0;
       else if(nodex->flags&(NODE_TURNRSTRCT|NODE_TURNRSTRCT2))
          issuper=1;
       else
         {
          int count=0,j;
          Way segmentway[MAX_SEG_PER_NODE];
          int segmentweight[MAX_SEG_PER_NODE];
          SegmentX *segmentx=FirstSegmentX(segmentsx,i,1);

          while(segmentx)
            {
             WayX *wayx=LookupWayX(waysx,segmentx->way,1);
             int nsegments;

             /* Segments that are loops count twice */

             assert(count<MAX_SEG_PER_NODE); /* Only a limited amount of information stored. */

             if(segmentx->node1==segmentx->node2)
                segmentweight[count]=2;
             else
                segmentweight[count]=1;

             segmentway[count]=wayx->way;

             /* If the node allows less traffic types than any connecting way then it is super */

             if((wayx->way.allow&nodex->allow)!=wayx->way.allow)
               {
                issuper=1;
                break;
               }

             nsegments=segmentweight[count];

             for(j=0;j<count;j++)
                if(wayx->way.allow & segmentway[j].allow)
                  {
                   /* If two ways are different in any attribute and there is a type of traffic that can use both then it is super */

                   if(WaysCompare(&segmentway[j],&wayx->way))
                     {
                      issuper=1;
                      break;
                     }

                   /* If there are two other segments that can be used by the same types of traffic as this one then it is super */

                   nsegments+=segmentweight[j];
                   if(nsegments>2)
                     {
                      issuper=1;
                      break;
                     }
                  }

             if(issuper)
                break;

             segmentx=NextSegmentX(segmentsx,segmentx,i);

             count++;
            }
         }

       /* Mark the node as super if it is. */

       if(issuper)
          nnodes++;
       else
          ClearBit(nodesx->super,i);
      }

    if(!((i+1)%10000))
       printf_middle("Finding Super-Nodes: Nodes=%"Pindex_t" Super-Nodes=%"Pindex_t,i+1,nnodes);
   }

 /* Unmap from memory / close the files */

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

 /* Print the final message */

 printf_last("Found Super-Nodes: Nodes=%"Pindex_t" Super-Nodes=%"Pindex_t,nodesx->number,nnodes);
}
static Results *FindRoutesWay(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx,node_t start,Way *match)
{
 Results *results;
 Queue *queue;
 Result *result1,*result2;
 WayX *wayx;

 /* Insert the first node into the queue */

 results=NewResultsList(4);

 queue=NewQueueList();

 result1=InsertResult(results,start,NO_SEGMENT);

 InsertInQueue(queue,result1);

 /* Loop across all nodes in the queue */

 while((result1=PopFromQueue(queue)))
   {
    index_t node1;
    SegmentX *segmentx;

    node1=result1->node;

    segmentx=FirstSegmentX(segmentsx,node1,2); /* position 1 is already used */

    while(segmentx)
      {
       index_t node2,seg2;
       distance_t cumulative_distance;

       /* must not be one-way against the direction of travel */
       if(IsOnewayTo(segmentx,node1))
          goto endloop;

       node2=OtherNode(segmentx,node1);

       seg2=IndexSegmentX(segmentsx,segmentx);

       /* must not be a u-turn */
       if(result1->segment==seg2)
          goto endloop;

       wayx=LookupWayX(waysx,segmentx->way,2); /* position 1 is already used */

       /* must be the right type of way */
       if(WaysCompare(&wayx->way,match))
          goto endloop;

       cumulative_distance=(distance_t)result1->score+DISTANCE(segmentx->distance);

       result2=FindResult(results,node2,seg2);

       if(!result2)                         /* New end node */
         {
          result2=InsertResult(results,node2,seg2);
          result2->prev=result1;
          result2->score=cumulative_distance;
          result2->sortby=cumulative_distance;

          /* don't route beyond a super-node. */
          if(!IsBitSet(nodesx->super,node2))
             InsertInQueue(queue,result2);
         }
       else if(cumulative_distance<result2->score)
         {
          result2->prev=result1;
          result2->score=cumulative_distance;
          result2->sortby=cumulative_distance;

          /* don't route beyond a super-node. */
          if(!IsBitSet(nodesx->super,node2))
             InsertInQueue(queue,result2);
         }

      endloop:

       segmentx=NextSegmentX(segmentsx,segmentx,node1);
      }
   }

 FreeQueueList(queue);

 return(results);
}
SegmentsX *CreateSuperSegments(NodesX *nodesx,SegmentsX *segmentsx,WaysX *waysx)
{
 index_t i;
 SegmentsX *supersegmentsx;
 index_t sn=0,ss=0;

 supersegmentsx=NewSegmentList(0);

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

 /* Print the start message */

 printf_first("Creating Super-Segments: Super-Nodes=0 Super-Segments=0");

 /* Map into memory / open the files */

#if !SLIM
 segmentsx->data=MapFile(segmentsx->filename);
 waysx->data=MapFile(waysx->filename);
#else
 segmentsx->fd=ReOpenFile(segmentsx->filename);
 waysx->fd=ReOpenFile(waysx->filename);
#endif

 /* Create super-segments for each super-node. */

 for(i=0;i<nodesx->number;i++)
   {
    if(IsBitSet(nodesx->super,i))
      {
       SegmentX *segmentx;
       int count=0,match;
       Way prevway[MAX_SEG_PER_NODE];

       segmentx=FirstSegmentX(segmentsx,i,1);

       while(segmentx)
         {
          WayX *wayx=LookupWayX(waysx,segmentx->way,1);

          /* Check that this type of way hasn't already been routed */

          match=0;

          if(count>0)
            {
             int j;

             for(j=0;j<count;j++)
                if(!WaysCompare(&prevway[j],&wayx->way))
                  {
                   match=1;
                   break;
                  }
            }

          assert(count<MAX_SEG_PER_NODE); /* Only a limited amount of history stored. */

          prevway[count++]=wayx->way;

          /* Route the way and store the super-segments. */

          if(!match)
            {
             Results *results=FindRoutesWay(nodesx,segmentsx,waysx,i,&wayx->way);
             Result *result=FirstResult(results);

             while(result)
               {
                if(IsBitSet(nodesx->super,result->node) && result->segment!=NO_SEGMENT)
                  {
                   if(wayx->way.type&Way_OneWay && result->node!=i)
                      AppendSegment(supersegmentsx,segmentx->way,i,result->node,DISTANCE((distance_t)result->score)|ONEWAY_1TO2);
                   else
                      AppendSegment(supersegmentsx,segmentx->way,i,result->node,DISTANCE((distance_t)result->score));

                   ss++;
                  }

                result=NextResult(results,result);
               }

             FreeResultsList(results);
            }

          segmentx=NextSegmentX(segmentsx,segmentx,i);
         }

       sn++;

       if(!(sn%10000))
          printf_middle("Creating Super-Segments: Super-Nodes=%"Pindex_t" Super-Segments=%"Pindex_t,sn,ss);
      }
   }

 /* Unmap from memory / close the files */

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

 /* Print the final message */

 printf_last("Created Super-Segments: Super-Nodes=%"Pindex_t" Super-Segments=%"Pindex_t,sn,ss);

 return(supersegmentsx);
}