statistical encoding
This commit is contained in:
parent
f8dee5b7d1
commit
ccf6641bad
41 changed files with 4543 additions and 1965 deletions
|
|
@ -17,6 +17,11 @@
|
|||
<artifactId>brouter-util</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.btools</groupId>
|
||||
<artifactId>brouter-codec</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.btools</groupId>
|
||||
<artifactId>brouter-expressions</artifactId>
|
||||
|
|
|
|||
|
|
@ -1,287 +1,428 @@
|
|||
/**
|
||||
* Container for an osm node (pre-pocessor version)
|
||||
*
|
||||
* @author ab
|
||||
*/
|
||||
package btools.mapcreator;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import btools.util.ByteDataWriter;
|
||||
|
||||
public class OsmNodeP extends OsmLinkP implements Comparable<OsmNodeP>
|
||||
{
|
||||
public static final int SIGNLON_BITMASK = 0x80;
|
||||
public static final int SIGNLAT_BITMASK = 0x40;
|
||||
public static final int TRANSFERNODE_BITMASK = 0x20;
|
||||
public static final int WRITEDESC_BITMASK = 0x10;
|
||||
public static final int SKIPDETAILS_BITMASK = 0x08;
|
||||
public static final int NODEDESC_BITMASK = 0x04;
|
||||
|
||||
/**
|
||||
* The latitude
|
||||
*/
|
||||
public int ilat;
|
||||
|
||||
/**
|
||||
* The longitude
|
||||
*/
|
||||
public int ilon;
|
||||
|
||||
|
||||
/**
|
||||
* The elevation
|
||||
*/
|
||||
public short selev;
|
||||
|
||||
public final static int NO_BRIDGE_BIT = 1;
|
||||
public final static int NO_TUNNEL_BIT = 2;
|
||||
public final static int BORDER_BIT = 4;
|
||||
public final static int TRAFFIC_BIT = 8;
|
||||
|
||||
public byte bits = 0;
|
||||
|
||||
// interface OsmPos
|
||||
public int getILat()
|
||||
{
|
||||
return ilat;
|
||||
}
|
||||
|
||||
public int getILon()
|
||||
{
|
||||
return ilon;
|
||||
}
|
||||
|
||||
public short getSElev()
|
||||
{
|
||||
// if all bridge or all tunnel, elevation=no-data
|
||||
return ( bits & NO_BRIDGE_BIT ) == 0 || ( bits & NO_TUNNEL_BIT ) == 0 ? Short.MIN_VALUE : selev;
|
||||
}
|
||||
|
||||
public double getElev()
|
||||
{
|
||||
return selev / 4.;
|
||||
}
|
||||
|
||||
|
||||
// populate and return the inherited link, if available,
|
||||
// else create a new one
|
||||
public OsmLinkP createLink( OsmNodeP source )
|
||||
{
|
||||
if ( sourceNode == null && targetNode == null )
|
||||
{
|
||||
// inherited instance is available, use this
|
||||
sourceNode = source;
|
||||
targetNode = this;
|
||||
source.addLink( this );
|
||||
return this;
|
||||
}
|
||||
OsmLinkP link = new OsmLinkP( source, this );
|
||||
addLink( link );
|
||||
source.addLink( link );
|
||||
return link;
|
||||
}
|
||||
|
||||
|
||||
// memory-squeezing-hack: OsmLinkP's "previous" also used as firstlink..
|
||||
|
||||
public void addLink( OsmLinkP link )
|
||||
{
|
||||
link.setNext( previous, this );
|
||||
previous = link;
|
||||
}
|
||||
|
||||
public OsmLinkP getFirstLink()
|
||||
{
|
||||
return sourceNode == null && targetNode == null ? previous : this;
|
||||
}
|
||||
|
||||
public byte[] getNodeDecsription()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public void writeNodeData( ByteDataWriter os, byte[] abBuf ) throws IOException
|
||||
{
|
||||
int lonIdx = ilon/62500;
|
||||
int latIdx = ilat/62500;
|
||||
|
||||
// buffer the body to first calc size
|
||||
ByteDataWriter os2 = new ByteDataWriter( abBuf );
|
||||
os2.writeShort( getSElev() );
|
||||
|
||||
// hack: write node-desc as link tag (copy cycleway-bits)
|
||||
byte[] nodeDescription = getNodeDecsription();
|
||||
|
||||
for( OsmLinkP link0 = getFirstLink(); link0 != null; link0 = link0.getNext( this ) )
|
||||
{
|
||||
int ilonref = ilon;
|
||||
int ilatref = ilat;
|
||||
|
||||
OsmLinkP link = link0;
|
||||
OsmNodeP origin = this;
|
||||
int skipDetailBit = link0.descriptionBitmap == null ? SKIPDETAILS_BITMASK : 0;
|
||||
|
||||
// first pass just to see if that link is consistent
|
||||
while( link != null )
|
||||
{
|
||||
OsmNodeP target = link.getTarget( origin );
|
||||
if ( !target.isTransferNode() )
|
||||
{
|
||||
break;
|
||||
}
|
||||
// next link is the one (of two), does does'nt point back
|
||||
for( link = target.getFirstLink(); link != null; link = link.getNext( target ) )
|
||||
{
|
||||
if ( link.getTarget( target ) != origin ) break;
|
||||
}
|
||||
origin = target;
|
||||
}
|
||||
if ( link == null ) continue; // dead end
|
||||
|
||||
if ( skipDetailBit == 0)
|
||||
{
|
||||
link = link0;
|
||||
origin = this;
|
||||
}
|
||||
byte[] lastDescription = null;
|
||||
while( link != null )
|
||||
{
|
||||
if ( link.descriptionBitmap == null && skipDetailBit == 0 ) throw new IllegalArgumentException( "missing way description...");
|
||||
|
||||
OsmNodeP target = link.getTarget( origin );
|
||||
int tranferbit = target.isTransferNode() ? TRANSFERNODE_BITMASK : 0;
|
||||
int nodedescbit = nodeDescription != null ? NODEDESC_BITMASK : 0;
|
||||
|
||||
int writedescbit = 0;
|
||||
if ( skipDetailBit == 0 ) // check if description changed
|
||||
{
|
||||
int inverseBitByteIndex = 0;
|
||||
boolean inverseDirection = link.isReverse( origin );
|
||||
byte[] ab = link.descriptionBitmap;
|
||||
int abLen = ab.length;
|
||||
int lastLen = lastDescription == null ? 0 : lastDescription.length;
|
||||
boolean equalsCurrent = abLen == lastLen;
|
||||
if ( equalsCurrent )
|
||||
{
|
||||
for( int i=0; i<abLen; i++ )
|
||||
{
|
||||
byte b = ab[i];
|
||||
if ( i == inverseBitByteIndex && inverseDirection ) b ^= 1;
|
||||
if ( b != lastDescription[i] ) { equalsCurrent = false; break; }
|
||||
}
|
||||
}
|
||||
if ( !equalsCurrent )
|
||||
{
|
||||
writedescbit = WRITEDESC_BITMASK;
|
||||
lastDescription = new byte[abLen];
|
||||
System.arraycopy( ab, 0, lastDescription, 0 , abLen );
|
||||
if ( inverseDirection ) lastDescription[inverseBitByteIndex] ^= 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int bm = tranferbit | writedescbit | nodedescbit | skipDetailBit;
|
||||
int dlon = target.ilon - ilonref;
|
||||
int dlat = target.ilat - ilatref;
|
||||
ilonref = target.ilon;
|
||||
ilatref = target.ilat;
|
||||
if ( dlon < 0 ) { bm |= SIGNLON_BITMASK; dlon = - dlon; }
|
||||
if ( dlat < 0 ) { bm |= SIGNLAT_BITMASK; dlat = - dlat; }
|
||||
os2.writeByte( bm );
|
||||
|
||||
int blon = os2.writeVarLengthUnsigned( dlon );
|
||||
int blat = os2.writeVarLengthUnsigned( dlat );
|
||||
|
||||
if ( writedescbit != 0 )
|
||||
{
|
||||
// write the way description, code direction into the first bit
|
||||
os2.writeByte( lastDescription.length );
|
||||
os2.write( lastDescription );
|
||||
}
|
||||
if ( nodedescbit != 0 )
|
||||
{
|
||||
os2.writeByte( nodeDescription.length );
|
||||
os2.write( nodeDescription );
|
||||
nodeDescription = null;
|
||||
}
|
||||
|
||||
link.descriptionBitmap = null; // mark link as written
|
||||
|
||||
if ( tranferbit == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
os2.writeVarLengthSigned( target.getSElev() -getSElev() );
|
||||
// next link is the one (of two), does does'nt point back
|
||||
for( link = target.getFirstLink(); link != null; link = link.getNext( target ) )
|
||||
{
|
||||
if ( link.getTarget( target ) != origin ) break;
|
||||
}
|
||||
if ( link == null ) throw new RuntimeException( "follow-up link not found for transfer-node!" );
|
||||
origin = target;
|
||||
}
|
||||
}
|
||||
|
||||
// calculate the body size
|
||||
int bodySize = os2.size();
|
||||
|
||||
os.ensureCapacity( bodySize + 8 );
|
||||
|
||||
os.writeShort( (short)(ilon - lonIdx*62500 - 31250) );
|
||||
os.writeShort( (short)(ilat - latIdx*62500 - 31250) );
|
||||
|
||||
os.writeVarLengthUnsigned( bodySize );
|
||||
os.write( abBuf, 0, bodySize );
|
||||
}
|
||||
|
||||
public String toString2()
|
||||
{
|
||||
return (ilon-180000000) + "_" + (ilat-90000000) + "_" + (selev/4);
|
||||
}
|
||||
|
||||
public long getIdFromPos()
|
||||
{
|
||||
return ((long)ilon)<<32 | ilat;
|
||||
}
|
||||
|
||||
public boolean isBorderNode()
|
||||
{
|
||||
return (bits & BORDER_BIT) != 0;
|
||||
}
|
||||
|
||||
public boolean hasTraffic()
|
||||
{
|
||||
return (bits & TRAFFIC_BIT) != 0;
|
||||
}
|
||||
|
||||
public boolean isTransferNode()
|
||||
{
|
||||
return (bits & BORDER_BIT) == 0 && _linkCnt() == 2;
|
||||
}
|
||||
|
||||
private int _linkCnt()
|
||||
{
|
||||
int cnt = 0;
|
||||
|
||||
for( OsmLinkP link = getFirstLink(); link != null; link = link.getNext( this ) )
|
||||
{
|
||||
cnt++;
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two OsmNodes for position ordering.
|
||||
*
|
||||
* @return -1,0,1 depending an comparson result
|
||||
*/
|
||||
public int compareTo( OsmNodeP n )
|
||||
{
|
||||
long id1 = getIdFromPos();
|
||||
long id2 = n.getIdFromPos();
|
||||
if ( id1 < id2 ) return -1;
|
||||
if ( id1 > id2 ) return 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Container for an osm node (pre-pocessor version)
|
||||
*
|
||||
* @author ab
|
||||
*/
|
||||
package btools.mapcreator;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import btools.codec.MicroCache;
|
||||
import btools.codec.MicroCache1;
|
||||
import btools.codec.MicroCache2;
|
||||
|
||||
public class OsmNodeP extends OsmLinkP
|
||||
{
|
||||
public static final int SIGNLON_BITMASK = 0x80;
|
||||
public static final int SIGNLAT_BITMASK = 0x40;
|
||||
public static final int TRANSFERNODE_BITMASK = 0x20;
|
||||
public static final int WRITEDESC_BITMASK = 0x10;
|
||||
public static final int SKIPDETAILS_BITMASK = 0x08;
|
||||
public static final int NODEDESC_BITMASK = 0x04;
|
||||
|
||||
/**
|
||||
* The latitude
|
||||
*/
|
||||
public int ilat;
|
||||
|
||||
/**
|
||||
* The longitude
|
||||
*/
|
||||
public int ilon;
|
||||
|
||||
/**
|
||||
* The elevation
|
||||
*/
|
||||
public short selev;
|
||||
|
||||
public final static int NO_BRIDGE_BIT = 1;
|
||||
public final static int NO_TUNNEL_BIT = 2;
|
||||
public final static int BORDER_BIT = 4;
|
||||
public final static int TRAFFIC_BIT = 8;
|
||||
public final static int ANY_WAY_BIT = 16;
|
||||
public final static int MULTI_WAY_BIT = 32;
|
||||
|
||||
public byte bits = 0;
|
||||
|
||||
// interface OsmPos
|
||||
public int getILat()
|
||||
{
|
||||
return ilat;
|
||||
}
|
||||
|
||||
public int getILon()
|
||||
{
|
||||
return ilon;
|
||||
}
|
||||
|
||||
public short getSElev()
|
||||
{
|
||||
// if all bridge or all tunnel, elevation=no-data
|
||||
return ( bits & NO_BRIDGE_BIT ) == 0 || ( bits & NO_TUNNEL_BIT ) == 0 ? Short.MIN_VALUE : selev;
|
||||
}
|
||||
|
||||
public double getElev()
|
||||
{
|
||||
return selev / 4.;
|
||||
}
|
||||
|
||||
// populate and return the inherited link, if available,
|
||||
// else create a new one
|
||||
public OsmLinkP createLink( OsmNodeP source )
|
||||
{
|
||||
if ( sourceNode == null && targetNode == null )
|
||||
{
|
||||
// inherited instance is available, use this
|
||||
sourceNode = source;
|
||||
targetNode = this;
|
||||
source.addLink( this );
|
||||
return this;
|
||||
}
|
||||
OsmLinkP link = new OsmLinkP( source, this );
|
||||
addLink( link );
|
||||
source.addLink( link );
|
||||
return link;
|
||||
}
|
||||
|
||||
// memory-squeezing-hack: OsmLinkP's "previous" also used as firstlink..
|
||||
|
||||
public void addLink( OsmLinkP link )
|
||||
{
|
||||
link.setNext( previous, this );
|
||||
previous = link;
|
||||
}
|
||||
|
||||
public OsmLinkP getFirstLink()
|
||||
{
|
||||
return sourceNode == null && targetNode == null ? previous : this;
|
||||
}
|
||||
|
||||
public byte[] getNodeDecsription()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public void writeNodeData1( MicroCache1 mc ) throws IOException
|
||||
{
|
||||
mc.writeShort( getSElev() );
|
||||
|
||||
// hack: write node-desc as link tag (copy cycleway-bits)
|
||||
byte[] nodeDescription = getNodeDecsription();
|
||||
|
||||
for ( OsmLinkP link0 = getFirstLink(); link0 != null; link0 = link0.getNext( this ) )
|
||||
{
|
||||
int ilonref = ilon;
|
||||
int ilatref = ilat;
|
||||
|
||||
OsmLinkP link = link0;
|
||||
OsmNodeP origin = this;
|
||||
int skipDetailBit = link0.descriptionBitmap == null ? SKIPDETAILS_BITMASK : 0;
|
||||
|
||||
// first pass just to see if that link is consistent
|
||||
while (link != null)
|
||||
{
|
||||
OsmNodeP target = link.getTarget( origin );
|
||||
if ( !target.isTransferNode() )
|
||||
{
|
||||
break;
|
||||
}
|
||||
// next link is the one (of two), does does'nt point back
|
||||
for ( link = target.getFirstLink(); link != null; link = link.getNext( target ) )
|
||||
{
|
||||
if ( link.getTarget( target ) != origin )
|
||||
break;
|
||||
}
|
||||
origin = target;
|
||||
}
|
||||
if ( link == null )
|
||||
continue; // dead end
|
||||
|
||||
if ( skipDetailBit == 0 )
|
||||
{
|
||||
link = link0;
|
||||
origin = this;
|
||||
}
|
||||
byte[] lastDescription = null;
|
||||
while (link != null)
|
||||
{
|
||||
if ( link.descriptionBitmap == null && skipDetailBit == 0 )
|
||||
throw new IllegalArgumentException( "missing way description..." );
|
||||
|
||||
OsmNodeP target = link.getTarget( origin );
|
||||
int tranferbit = target.isTransferNode() ? TRANSFERNODE_BITMASK : 0;
|
||||
int nodedescbit = nodeDescription != null ? NODEDESC_BITMASK : 0;
|
||||
|
||||
int writedescbit = 0;
|
||||
if ( skipDetailBit == 0 ) // check if description changed
|
||||
{
|
||||
int inverseBitByteIndex = 0;
|
||||
boolean inverseDirection = link.isReverse( origin );
|
||||
byte[] ab = link.descriptionBitmap;
|
||||
int abLen = ab.length;
|
||||
int lastLen = lastDescription == null ? 0 : lastDescription.length;
|
||||
boolean equalsCurrent = abLen == lastLen;
|
||||
if ( equalsCurrent )
|
||||
{
|
||||
for ( int i = 0; i < abLen; i++ )
|
||||
{
|
||||
byte b = ab[i];
|
||||
if ( i == inverseBitByteIndex && inverseDirection )
|
||||
b ^= 1;
|
||||
if ( b != lastDescription[i] )
|
||||
{
|
||||
equalsCurrent = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( !equalsCurrent )
|
||||
{
|
||||
writedescbit = WRITEDESC_BITMASK;
|
||||
lastDescription = new byte[abLen];
|
||||
System.arraycopy( ab, 0, lastDescription, 0, abLen );
|
||||
if ( inverseDirection )
|
||||
lastDescription[inverseBitByteIndex] ^= 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int bm = tranferbit | writedescbit | nodedescbit | skipDetailBit;
|
||||
int dlon = target.ilon - ilonref;
|
||||
int dlat = target.ilat - ilatref;
|
||||
ilonref = target.ilon;
|
||||
ilatref = target.ilat;
|
||||
if ( dlon < 0 )
|
||||
{
|
||||
bm |= SIGNLON_BITMASK;
|
||||
dlon = -dlon;
|
||||
}
|
||||
if ( dlat < 0 )
|
||||
{
|
||||
bm |= SIGNLAT_BITMASK;
|
||||
dlat = -dlat;
|
||||
}
|
||||
mc.writeByte( bm );
|
||||
|
||||
mc.writeVarLengthUnsigned( dlon );
|
||||
mc.writeVarLengthUnsigned( dlat );
|
||||
|
||||
if ( writedescbit != 0 )
|
||||
{
|
||||
// write the way description, code direction into the first bit
|
||||
mc.writeByte( lastDescription.length );
|
||||
mc.write( lastDescription );
|
||||
}
|
||||
if ( nodedescbit != 0 )
|
||||
{
|
||||
mc.writeByte( nodeDescription.length );
|
||||
mc.write( nodeDescription );
|
||||
nodeDescription = null;
|
||||
}
|
||||
|
||||
link.descriptionBitmap = null; // mark link as written
|
||||
|
||||
if ( tranferbit == 0 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
mc.writeVarLengthSigned( target.getSElev() - getSElev() );
|
||||
// next link is the one (of two), does does'nt point back
|
||||
for ( link = target.getFirstLink(); link != null; link = link.getNext( target ) )
|
||||
{
|
||||
if ( link.getTarget( target ) != origin )
|
||||
break;
|
||||
}
|
||||
if ( link == null )
|
||||
throw new RuntimeException( "follow-up link not found for transfer-node!" );
|
||||
origin = target;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void writeNodeData( MicroCache mc ) throws IOException
|
||||
{
|
||||
boolean valid = true;
|
||||
if ( mc instanceof MicroCache1 )
|
||||
{
|
||||
writeNodeData1( (MicroCache1) mc );
|
||||
}
|
||||
else if ( mc instanceof MicroCache2 )
|
||||
{
|
||||
valid = writeNodeData2( (MicroCache2) mc );
|
||||
}
|
||||
else
|
||||
throw new IllegalArgumentException( "unknown cache version: " + mc.getClass() );
|
||||
if ( valid )
|
||||
{
|
||||
mc.finishNode( getIdFromPos() );
|
||||
}
|
||||
else
|
||||
{
|
||||
mc.discardNode();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean writeNodeData2( MicroCache2 mc ) throws IOException
|
||||
{
|
||||
boolean hasLinks = false;
|
||||
mc.writeShort( getSElev() );
|
||||
mc.writeVarBytes( getNodeDecsription() );
|
||||
|
||||
// buffer internal reverse links
|
||||
ArrayList<OsmNodeP> internalReverse = new ArrayList<OsmNodeP>();
|
||||
|
||||
for ( OsmLinkP link0 = getFirstLink(); link0 != null; link0 = link0.getNext( this ) )
|
||||
{
|
||||
OsmLinkP link = link0;
|
||||
OsmNodeP origin = this;
|
||||
OsmNodeP target = null;
|
||||
|
||||
// first pass just to see if that link is consistent
|
||||
while (link != null)
|
||||
{
|
||||
target = link.getTarget( origin );
|
||||
if ( !target.isTransferNode() )
|
||||
{
|
||||
break;
|
||||
}
|
||||
// next link is the one (of two), does does'nt point back
|
||||
for ( link = target.getFirstLink(); link != null; link = link.getNext( target ) )
|
||||
{
|
||||
if ( link.getTarget( target ) != origin )
|
||||
break;
|
||||
}
|
||||
|
||||
if ( link != null && link.descriptionBitmap != link0.descriptionBitmap )
|
||||
{
|
||||
throw new IllegalArgumentException( "assertion failed: description change along transfer nodes" );
|
||||
}
|
||||
|
||||
origin = target;
|
||||
}
|
||||
if ( link == null )
|
||||
continue; // dead end
|
||||
if ( target == this )
|
||||
continue; // self-ref
|
||||
hasLinks = true;
|
||||
|
||||
// internal reverse links later
|
||||
boolean isReverse = link0.isReverse( this );
|
||||
if ( isReverse )
|
||||
{
|
||||
if ( mc.isInternal( target.ilon, target.ilat ) )
|
||||
{
|
||||
internalReverse.add( target );
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// write link data
|
||||
int sizeoffset = mc.writeSizePlaceHolder();
|
||||
mc.writeVarLengthSigned( target.ilon - ilon );
|
||||
mc.writeVarLengthSigned( target.ilat - ilat );
|
||||
mc.writeModeAndDesc( isReverse, link0.descriptionBitmap );
|
||||
if ( !isReverse ) // write geometry for forward links only
|
||||
{
|
||||
link = link0;
|
||||
origin = this;
|
||||
while (link != null)
|
||||
{
|
||||
OsmNodeP tranferNode = link.getTarget( origin );
|
||||
if ( !tranferNode.isTransferNode() )
|
||||
{
|
||||
break;
|
||||
}
|
||||
mc.writeVarLengthSigned( tranferNode.ilon - origin.ilon );
|
||||
mc.writeVarLengthSigned( tranferNode.ilat - origin.ilat );
|
||||
mc.writeVarLengthSigned( tranferNode.getSElev() - origin.getSElev() );
|
||||
|
||||
// next link is the one (of two), does does'nt point back
|
||||
for ( link = tranferNode.getFirstLink(); link != null; link = link.getNext( tranferNode ) )
|
||||
{
|
||||
if ( link.getTarget( tranferNode ) != origin )
|
||||
break;
|
||||
}
|
||||
if ( link == null )
|
||||
throw new RuntimeException( "follow-up link not found for transfer-node!" );
|
||||
origin = tranferNode;
|
||||
}
|
||||
}
|
||||
mc.injectSize( sizeoffset );
|
||||
}
|
||||
|
||||
while (internalReverse.size() > 0)
|
||||
{
|
||||
int nextIdx = 0;
|
||||
if ( internalReverse.size() > 1 )
|
||||
{
|
||||
int max32 = Integer.MIN_VALUE;
|
||||
for ( int i = 0; i < internalReverse.size(); i++ )
|
||||
{
|
||||
int id32 = mc.shrinkId( internalReverse.get( i ).getIdFromPos() );
|
||||
if ( id32 > max32 )
|
||||
{
|
||||
max32 = id32;
|
||||
nextIdx = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
OsmNodeP target = internalReverse.remove( nextIdx );
|
||||
int sizeoffset = mc.writeSizePlaceHolder();
|
||||
mc.writeVarLengthSigned( target.ilon - ilon );
|
||||
mc.writeVarLengthSigned( target.ilat - ilat );
|
||||
mc.writeModeAndDesc( true, null );
|
||||
mc.injectSize( sizeoffset );
|
||||
}
|
||||
return hasLinks;
|
||||
}
|
||||
|
||||
public String toString2()
|
||||
{
|
||||
return ( ilon - 180000000 ) + "_" + ( ilat - 90000000 ) + "_" + ( selev / 4 );
|
||||
}
|
||||
|
||||
public long getIdFromPos()
|
||||
{
|
||||
return ( (long) ilon ) << 32 | ilat;
|
||||
}
|
||||
|
||||
public boolean isBorderNode()
|
||||
{
|
||||
return ( bits & BORDER_BIT ) != 0;
|
||||
}
|
||||
|
||||
public boolean hasTraffic()
|
||||
{
|
||||
return ( bits & TRAFFIC_BIT ) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Not really count the ways, just detect if more than one
|
||||
*/
|
||||
public void incWayCount()
|
||||
{
|
||||
if ( ( bits & ANY_WAY_BIT ) != 0 )
|
||||
{
|
||||
bits |= MULTI_WAY_BIT;
|
||||
}
|
||||
bits |= ANY_WAY_BIT;
|
||||
}
|
||||
|
||||
public boolean isTransferNode()
|
||||
{
|
||||
return ( bits & BORDER_BIT ) == 0 && ( bits & MULTI_WAY_BIT ) == 0 && _linkCnt() == 2;
|
||||
}
|
||||
|
||||
private int _linkCnt()
|
||||
{
|
||||
int cnt = 0;
|
||||
|
||||
for ( OsmLinkP link = getFirstLink(); link != null; link = link.getNext( this ) )
|
||||
{
|
||||
cnt++;
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,374 +1,432 @@
|
|||
package btools.mapcreator;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.EOFException;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import btools.expressions.BExpressionContextNode;
|
||||
import btools.expressions.BExpressionContextWay;
|
||||
import btools.expressions.BExpressionMetaData;
|
||||
import btools.util.ByteArrayUnifier;
|
||||
import btools.util.ByteDataWriter;
|
||||
import btools.util.CompactLongMap;
|
||||
import btools.util.CompactLongSet;
|
||||
import btools.util.Crc32;
|
||||
import btools.util.FrozenLongMap;
|
||||
import btools.util.FrozenLongSet;
|
||||
import btools.util.LazyArrayOfLists;
|
||||
|
||||
/**
|
||||
* WayLinker finally puts the pieces together
|
||||
* to create the rd5 files. For each 5*5 tile,
|
||||
* the corresponding nodefile and wayfile is read,
|
||||
* plus the (global) bordernodes file, and an rd5
|
||||
* is written
|
||||
*
|
||||
* @author ab
|
||||
*/
|
||||
public class WayLinker extends MapCreatorBase
|
||||
{
|
||||
private File nodeTilesIn;
|
||||
private File trafficTilesIn;
|
||||
private File dataTilesOut;
|
||||
private File borderFileIn;
|
||||
|
||||
private String dataTilesSuffix;
|
||||
|
||||
private boolean readingBorder;
|
||||
|
||||
private CompactLongMap<OsmNodeP> nodesMap;
|
||||
private OsmTrafficMap trafficMap;
|
||||
private List<OsmNodeP> nodesList;
|
||||
private CompactLongSet borderSet;
|
||||
private short lookupVersion;
|
||||
private short lookupMinorVersion;
|
||||
|
||||
private long creationTimeStamp;
|
||||
|
||||
private BExpressionContextWay expctxWay;
|
||||
private BExpressionContextNode expctxNode;
|
||||
|
||||
private ByteArrayUnifier abUnifier;
|
||||
|
||||
private int minLon;
|
||||
private int minLat;
|
||||
|
||||
private void reset()
|
||||
{
|
||||
minLon = -1;
|
||||
minLat = -1;
|
||||
nodesMap = new CompactLongMap<OsmNodeP>();
|
||||
borderSet = new CompactLongSet();
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception
|
||||
{
|
||||
System.out.println("*** WayLinker: Format a region of an OSM map for routing");
|
||||
if (args.length != 7)
|
||||
{
|
||||
System.out.println("usage: java WayLinker <node-tiles-in> <way-tiles-in> <bordernodes> <lookup-file> <profile-file> <data-tiles-out> <data-tiles-suffix> ");
|
||||
return;
|
||||
}
|
||||
new WayLinker().process( new File( args[0] ), new File( args[1] ), new File( args[2] ), new File( args[3] ), new File( args[4] ), new File( args[5] ), args[6] );
|
||||
}
|
||||
|
||||
public void process( File nodeTilesIn, File wayTilesIn, File borderFileIn, File lookupFile, File profileFile, File dataTilesOut, String dataTilesSuffix ) throws Exception
|
||||
{
|
||||
this.nodeTilesIn = nodeTilesIn;
|
||||
this.trafficTilesIn = new File( "traffic" );
|
||||
this.dataTilesOut = dataTilesOut;
|
||||
this.borderFileIn = borderFileIn;
|
||||
this.dataTilesSuffix = dataTilesSuffix;
|
||||
|
||||
BExpressionMetaData meta = new BExpressionMetaData();
|
||||
|
||||
// read lookup + profile for lookup-version + access-filter
|
||||
expctxWay = new BExpressionContextWay( meta);
|
||||
expctxNode = new BExpressionContextNode( meta);
|
||||
meta.readMetaData( lookupFile );
|
||||
|
||||
lookupVersion = meta.lookupVersion;
|
||||
lookupMinorVersion = meta.lookupMinorVersion;
|
||||
|
||||
expctxWay.parseFile( profileFile, "global" );
|
||||
expctxNode.parseFile( profileFile, "global" );
|
||||
|
||||
creationTimeStamp = System.currentTimeMillis();
|
||||
|
||||
abUnifier = new ByteArrayUnifier( 16384, false );
|
||||
|
||||
// then process all segments
|
||||
new WayIterator( this, true ).processDir( wayTilesIn, ".wt5" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void wayFileStart( File wayfile ) throws Exception
|
||||
{
|
||||
// process corresponding node-file, if any
|
||||
File nodeFile = fileFromTemplate( wayfile, nodeTilesIn, "u5d" );
|
||||
if ( nodeFile.exists() )
|
||||
{
|
||||
reset();
|
||||
|
||||
// read the border file
|
||||
readingBorder = true;
|
||||
new NodeIterator( this, false ).processFile( borderFileIn );
|
||||
borderSet = new FrozenLongSet( borderSet );
|
||||
|
||||
// read this tile's nodes
|
||||
readingBorder = false;
|
||||
new NodeIterator( this, true ).processFile( nodeFile );
|
||||
|
||||
// freeze the nodes-map
|
||||
FrozenLongMap<OsmNodeP> nodesMapFrozen = new FrozenLongMap<OsmNodeP>( nodesMap );
|
||||
nodesMap = nodesMapFrozen;
|
||||
nodesList = nodesMapFrozen.getValueList();
|
||||
}
|
||||
|
||||
// read a traffic-file, if any
|
||||
File trafficFile = fileFromTemplate( wayfile, trafficTilesIn, "trf" );
|
||||
if ( trafficFile.exists() )
|
||||
{
|
||||
trafficMap = new OsmTrafficMap();
|
||||
trafficMap.load( trafficFile, minLon, minLat, minLon + 5000000, minLat + 5000000, false );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nextNode( NodeData data ) throws Exception
|
||||
{
|
||||
OsmNodeP n = data.description == null ? new OsmNodeP() : new OsmNodePT(data.description);
|
||||
n.ilon = data.ilon;
|
||||
n.ilat = data.ilat;
|
||||
n.selev = data.selev;
|
||||
|
||||
if ( readingBorder || (!borderSet.contains( data.nid )) )
|
||||
{
|
||||
nodesMap.fastPut( data.nid, n );
|
||||
}
|
||||
|
||||
if ( readingBorder )
|
||||
{
|
||||
n.bits |= OsmNodeP.BORDER_BIT;
|
||||
borderSet.fastAdd( data.nid );
|
||||
return;
|
||||
}
|
||||
|
||||
// remember the segment coords
|
||||
int min_lon = (n.ilon / 5000000 ) * 5000000;
|
||||
int min_lat = (n.ilat / 5000000 ) * 5000000;
|
||||
if ( minLon == -1 ) minLon = min_lon;
|
||||
if ( minLat == -1 ) minLat = min_lat;
|
||||
if ( minLat != min_lat || minLon != min_lon )
|
||||
throw new IllegalArgumentException( "inconsistent node: " + n.ilon + " " + n.ilat );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nextWay( WayData way ) throws Exception
|
||||
{
|
||||
byte[] description = abUnifier.unify( way.description );
|
||||
int lastTraffic = 0;
|
||||
|
||||
// filter according to profile
|
||||
expctxWay.evaluate( false, description, null );
|
||||
boolean ok = expctxWay.getCostfactor() < 10000.;
|
||||
expctxWay.evaluate( true, description, null );
|
||||
ok |= expctxWay.getCostfactor() < 10000.;
|
||||
if ( !ok ) return;
|
||||
|
||||
byte wayBits = 0;
|
||||
expctxWay.decode( description );
|
||||
if ( !expctxWay.getBooleanLookupValue( "bridge" ) ) wayBits |= OsmNodeP.NO_BRIDGE_BIT;
|
||||
if ( !expctxWay.getBooleanLookupValue( "tunnel" ) ) wayBits |= OsmNodeP.NO_TUNNEL_BIT;
|
||||
|
||||
OsmNodeP n1 = null;
|
||||
OsmNodeP n2 = null;
|
||||
for (int i=0; i<way.nodes.size(); i++)
|
||||
{
|
||||
long nid = way.nodes.get(i);
|
||||
n1 = n2;
|
||||
n2 = nodesMap.get( nid );
|
||||
if ( n1 != null && n2 != null && n1 != n2 )
|
||||
{
|
||||
OsmLinkP link = n2.createLink( n1 );
|
||||
|
||||
int traffic = trafficMap == null ? 0 : trafficMap.getTrafficClass( n1.getIdFromPos(), n2.getIdFromPos() );
|
||||
if ( traffic != lastTraffic )
|
||||
{
|
||||
expctxWay.decode( description );
|
||||
expctxWay.addLookupValue( "estimated_traffic_class", traffic == 0 ? 0 : traffic + 1 );
|
||||
description = abUnifier.unify( expctxWay.encode() );
|
||||
lastTraffic = traffic;
|
||||
}
|
||||
link.descriptionBitmap = description;
|
||||
}
|
||||
if ( n2 != null )
|
||||
{
|
||||
n2.bits |= wayBits;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void wayFileEnd( File wayfile ) throws Exception
|
||||
{
|
||||
nodesMap = null;
|
||||
borderSet = null;
|
||||
trafficMap = null;
|
||||
|
||||
byte[] abBuf = new byte[1024*1024];
|
||||
byte[] abBuf2 = new byte[10*1024*1024];
|
||||
|
||||
int maxLon = minLon + 5000000;
|
||||
int maxLat = minLat + 5000000;
|
||||
|
||||
// write segment data to individual files
|
||||
{
|
||||
int nLonSegs = (maxLon - minLon)/1000000;
|
||||
int nLatSegs = (maxLat - minLat)/1000000;
|
||||
|
||||
// sort the nodes into segments
|
||||
LazyArrayOfLists<OsmNodeP> seglists = new LazyArrayOfLists<OsmNodeP>(nLonSegs*nLatSegs);
|
||||
for( OsmNodeP n : nodesList )
|
||||
{
|
||||
if ( n == null || n.getFirstLink() == null || n.isTransferNode() ) continue;
|
||||
if ( n.ilon < minLon || n.ilon >= maxLon
|
||||
|| n.ilat < minLat || n.ilat >= maxLat ) continue;
|
||||
int lonIdx = (n.ilon-minLon)/1000000;
|
||||
int latIdx = (n.ilat-minLat)/1000000;
|
||||
|
||||
int tileIndex = lonIdx * nLatSegs + latIdx;
|
||||
seglists.getList(tileIndex).add( n );
|
||||
}
|
||||
nodesList = null;
|
||||
seglists.trimAll();
|
||||
|
||||
// open the output file
|
||||
File outfile = fileFromTemplate( wayfile, dataTilesOut, dataTilesSuffix );
|
||||
DataOutputStream os = createOutStream( outfile );
|
||||
|
||||
long[] fileIndex = new long[25];
|
||||
int[] fileHeaderCrcs = new int[25];
|
||||
|
||||
// write 5*5 index dummy
|
||||
for( int i55=0; i55<25; i55++)
|
||||
{
|
||||
os.writeLong( 0 );
|
||||
}
|
||||
long filepos = 200L;
|
||||
|
||||
// sort further in 1/80-degree squares
|
||||
for( int lonIdx = 0; lonIdx < nLonSegs; lonIdx++ )
|
||||
{
|
||||
for( int latIdx = 0; latIdx < nLatSegs; latIdx++ )
|
||||
{
|
||||
int tileIndex = lonIdx * nLatSegs + latIdx;
|
||||
if ( seglists.getSize(tileIndex) > 0 )
|
||||
{
|
||||
List<OsmNodeP> nlist = seglists.getList(tileIndex);
|
||||
|
||||
LazyArrayOfLists<OsmNodeP> subs = new LazyArrayOfLists<OsmNodeP>(6400);
|
||||
byte[][] subByteArrays = new byte[6400][];
|
||||
for( int ni=0; ni<nlist.size(); ni++ )
|
||||
{
|
||||
OsmNodeP n = nlist.get(ni);
|
||||
int subLonIdx = (n.ilon - minLon) / 12500 - 80*lonIdx;
|
||||
int subLatIdx = (n.ilat - minLat) / 12500 - 80*latIdx;
|
||||
int si = subLatIdx*80 + subLonIdx;
|
||||
subs.getList(si).add( n );
|
||||
}
|
||||
subs.trimAll();
|
||||
int[] posIdx = new int[6400];
|
||||
int pos = 25600;
|
||||
for( int si=0; si<6400; si++)
|
||||
{
|
||||
List<OsmNodeP> subList = subs.getList(si);
|
||||
if ( subList.size() > 0 )
|
||||
{
|
||||
Collections.sort( subList );
|
||||
|
||||
ByteDataWriter dos = new ByteDataWriter( abBuf2 );
|
||||
|
||||
dos.writeInt( subList.size() );
|
||||
for( int ni=0; ni<subList.size(); ni++ )
|
||||
{
|
||||
OsmNodeP n = subList.get(ni);
|
||||
n.writeNodeData( dos, abBuf );
|
||||
}
|
||||
byte[] subBytes = dos.toByteArray();
|
||||
pos += subBytes.length + 4; // reserve 4 bytes for crc
|
||||
subByteArrays[si] = subBytes;
|
||||
}
|
||||
posIdx[si] = pos;
|
||||
}
|
||||
|
||||
byte[] abSubIndex = compileSubFileIndex( posIdx );
|
||||
fileHeaderCrcs[tileIndex] = Crc32.crc( abSubIndex, 0, abSubIndex.length );
|
||||
os.write( abSubIndex, 0, abSubIndex.length );
|
||||
for( int si=0; si<6400; si++)
|
||||
{
|
||||
byte[] ab = subByteArrays[si];
|
||||
if ( ab != null )
|
||||
{
|
||||
os.write( ab );
|
||||
os.writeInt( Crc32.crc( ab, 0 , ab.length ) );
|
||||
}
|
||||
}
|
||||
filepos += pos;
|
||||
}
|
||||
fileIndex[ tileIndex ] = filepos;
|
||||
}
|
||||
}
|
||||
|
||||
byte[] abFileIndex = compileFileIndex( fileIndex, lookupVersion, lookupMinorVersion );
|
||||
|
||||
// write extra data: timestamp + index-checksums
|
||||
os.writeLong( creationTimeStamp );
|
||||
os.writeInt( Crc32.crc( abFileIndex, 0, abFileIndex.length ) );
|
||||
for( int i55=0; i55<25; i55++)
|
||||
{
|
||||
os.writeInt( fileHeaderCrcs[i55] );
|
||||
}
|
||||
|
||||
os.close();
|
||||
|
||||
// re-open random-access to write file-index
|
||||
RandomAccessFile ra = new RandomAccessFile( outfile, "rw" );
|
||||
ra.write( abFileIndex, 0, abFileIndex.length );
|
||||
ra.close();
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] compileFileIndex( long[] fileIndex, short lookupVersion, short lookupMinorVersion ) throws Exception
|
||||
{
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream( );
|
||||
DataOutputStream dos = new DataOutputStream( bos );
|
||||
for( int i55=0; i55<25; i55++)
|
||||
{
|
||||
long versionPrefix = i55 == 1 ? lookupMinorVersion : lookupVersion;
|
||||
versionPrefix <<= 48;
|
||||
dos.writeLong( fileIndex[i55] | versionPrefix );
|
||||
}
|
||||
dos.close();
|
||||
return bos.toByteArray();
|
||||
}
|
||||
|
||||
private byte[] compileSubFileIndex( int[] posIdx ) throws Exception
|
||||
{
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream( );
|
||||
DataOutputStream dos = new DataOutputStream( bos );
|
||||
for( int si=0; si<6400; si++)
|
||||
{
|
||||
dos.writeInt( posIdx[si] );
|
||||
}
|
||||
dos.close();
|
||||
return bos.toByteArray();
|
||||
}
|
||||
}
|
||||
package btools.mapcreator;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.util.List;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import btools.codec.DataBuffers;
|
||||
import btools.codec.MicroCache;
|
||||
import btools.codec.MicroCache1;
|
||||
import btools.codec.MicroCache2;
|
||||
import btools.codec.StatCoderContext;
|
||||
import btools.expressions.BExpressionContextWay;
|
||||
import btools.expressions.BExpressionMetaData;
|
||||
import btools.util.ByteArrayUnifier;
|
||||
import btools.util.CompactLongMap;
|
||||
import btools.util.CompactLongSet;
|
||||
import btools.util.Crc32;
|
||||
import btools.util.FrozenLongMap;
|
||||
import btools.util.FrozenLongSet;
|
||||
import btools.util.LazyArrayOfLists;
|
||||
|
||||
/**
|
||||
* WayLinker finally puts the pieces together to create the rd5 files. For each
|
||||
* 5*5 tile, the corresponding nodefile and wayfile is read, plus the (global)
|
||||
* bordernodes file, and an rd5 is written
|
||||
*
|
||||
* @author ab
|
||||
*/
|
||||
public class WayLinker extends MapCreatorBase
|
||||
{
|
||||
private File nodeTilesIn;
|
||||
private File trafficTilesIn;
|
||||
private File dataTilesOut;
|
||||
private File borderFileIn;
|
||||
|
||||
private String dataTilesSuffix;
|
||||
|
||||
private boolean readingBorder;
|
||||
|
||||
private CompactLongMap<OsmNodeP> nodesMap;
|
||||
private OsmTrafficMap trafficMap;
|
||||
private List<OsmNodeP> nodesList;
|
||||
private CompactLongSet borderSet;
|
||||
private short lookupVersion;
|
||||
private short lookupMinorVersion;
|
||||
|
||||
private long creationTimeStamp;
|
||||
|
||||
private BExpressionContextWay expctxWay;
|
||||
|
||||
private ByteArrayUnifier abUnifier;
|
||||
|
||||
private int minLon;
|
||||
private int minLat;
|
||||
|
||||
private int microCacheEncoding = 2;
|
||||
private int divisor = microCacheEncoding == 2 ? 32 : 80;
|
||||
private int cellsize = 1000000 / divisor;
|
||||
|
||||
private void reset()
|
||||
{
|
||||
minLon = -1;
|
||||
minLat = -1;
|
||||
nodesMap = new CompactLongMap<OsmNodeP>();
|
||||
borderSet = new CompactLongSet();
|
||||
}
|
||||
|
||||
public static void main( String[] args ) throws Exception
|
||||
{
|
||||
System.out.println( "*** WayLinker: Format a region of an OSM map for routing" );
|
||||
if ( args.length != 7 )
|
||||
{
|
||||
System.out
|
||||
.println( "usage: java WayLinker <node-tiles-in> <way-tiles-in> <bordernodes> <lookup-file> <profile-file> <data-tiles-out> <data-tiles-suffix> " );
|
||||
return;
|
||||
}
|
||||
new WayLinker().process( new File( args[0] ), new File( args[1] ), new File( args[2] ), new File( args[3] ), new File( args[4] ), new File(
|
||||
args[5] ), args[6] );
|
||||
}
|
||||
|
||||
public void process( File nodeTilesIn, File wayTilesIn, File borderFileIn, File lookupFile, File profileFile, File dataTilesOut,
|
||||
String dataTilesSuffix ) throws Exception
|
||||
{
|
||||
this.nodeTilesIn = nodeTilesIn;
|
||||
this.trafficTilesIn = new File( "traffic" );
|
||||
this.dataTilesOut = dataTilesOut;
|
||||
this.borderFileIn = borderFileIn;
|
||||
this.dataTilesSuffix = dataTilesSuffix;
|
||||
|
||||
BExpressionMetaData meta = new BExpressionMetaData();
|
||||
|
||||
// read lookup + profile for lookup-version + access-filter
|
||||
expctxWay = new BExpressionContextWay( meta );
|
||||
meta.readMetaData( lookupFile );
|
||||
|
||||
lookupVersion = meta.lookupVersion;
|
||||
lookupMinorVersion = meta.lookupMinorVersion;
|
||||
|
||||
expctxWay.parseFile( profileFile, "global" );
|
||||
|
||||
creationTimeStamp = System.currentTimeMillis();
|
||||
|
||||
abUnifier = new ByteArrayUnifier( 16384, false );
|
||||
|
||||
// then process all segments
|
||||
new WayIterator( this, true ).processDir( wayTilesIn, ".wt5" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void wayFileStart( File wayfile ) throws Exception
|
||||
{
|
||||
// process corresponding node-file, if any
|
||||
File nodeFile = fileFromTemplate( wayfile, nodeTilesIn, "u5d" );
|
||||
if ( nodeFile.exists() )
|
||||
{
|
||||
reset();
|
||||
|
||||
// read the border file
|
||||
readingBorder = true;
|
||||
new NodeIterator( this, false ).processFile( borderFileIn );
|
||||
borderSet = new FrozenLongSet( borderSet );
|
||||
|
||||
// read this tile's nodes
|
||||
readingBorder = false;
|
||||
new NodeIterator( this, true ).processFile( nodeFile );
|
||||
|
||||
// freeze the nodes-map
|
||||
FrozenLongMap<OsmNodeP> nodesMapFrozen = new FrozenLongMap<OsmNodeP>( nodesMap );
|
||||
nodesMap = nodesMapFrozen;
|
||||
nodesList = nodesMapFrozen.getValueList();
|
||||
}
|
||||
|
||||
// read a traffic-file, if any
|
||||
File trafficFile = fileFromTemplate( wayfile, trafficTilesIn, "trf" );
|
||||
if ( trafficFile.exists() )
|
||||
{
|
||||
trafficMap = new OsmTrafficMap();
|
||||
trafficMap.load( trafficFile, minLon, minLat, minLon + 5000000, minLat + 5000000, false );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nextNode( NodeData data ) throws Exception
|
||||
{
|
||||
OsmNodeP n = data.description == null ? new OsmNodeP() : new OsmNodePT( data.description );
|
||||
n.ilon = data.ilon;
|
||||
n.ilat = data.ilat;
|
||||
n.selev = data.selev;
|
||||
|
||||
if ( readingBorder || ( !borderSet.contains( data.nid ) ) )
|
||||
{
|
||||
nodesMap.fastPut( data.nid, n );
|
||||
}
|
||||
|
||||
if ( readingBorder )
|
||||
{
|
||||
n.bits |= OsmNodeP.BORDER_BIT;
|
||||
borderSet.fastAdd( data.nid );
|
||||
return;
|
||||
}
|
||||
|
||||
// remember the segment coords
|
||||
int min_lon = ( n.ilon / 5000000 ) * 5000000;
|
||||
int min_lat = ( n.ilat / 5000000 ) * 5000000;
|
||||
if ( minLon == -1 )
|
||||
minLon = min_lon;
|
||||
if ( minLat == -1 )
|
||||
minLat = min_lat;
|
||||
if ( minLat != min_lat || minLon != min_lon )
|
||||
throw new IllegalArgumentException( "inconsistent node: " + n.ilon + " " + n.ilat );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nextWay( WayData way ) throws Exception
|
||||
{
|
||||
byte[] description = abUnifier.unify( way.description );
|
||||
int lastTraffic = 0;
|
||||
|
||||
// filter according to profile
|
||||
expctxWay.evaluate( false, description, null );
|
||||
boolean ok = expctxWay.getCostfactor() < 10000.;
|
||||
expctxWay.evaluate( true, description, null );
|
||||
ok |= expctxWay.getCostfactor() < 10000.;
|
||||
if ( !ok )
|
||||
return;
|
||||
|
||||
byte wayBits = 0;
|
||||
expctxWay.decode( description );
|
||||
if ( !expctxWay.getBooleanLookupValue( "bridge" ) )
|
||||
wayBits |= OsmNodeP.NO_BRIDGE_BIT;
|
||||
if ( !expctxWay.getBooleanLookupValue( "tunnel" ) )
|
||||
wayBits |= OsmNodeP.NO_TUNNEL_BIT;
|
||||
|
||||
OsmNodeP n1 = null;
|
||||
OsmNodeP n2 = null;
|
||||
for ( int i = 0; i < way.nodes.size(); i++ )
|
||||
{
|
||||
long nid = way.nodes.get( i );
|
||||
n1 = n2;
|
||||
n2 = nodesMap.get( nid );
|
||||
|
||||
if ( n1 != null && n2 != null && n1 != n2 )
|
||||
{
|
||||
OsmLinkP link = n2.createLink( n1 );
|
||||
|
||||
int traffic = trafficMap == null ? 0 : trafficMap.getTrafficClass( n1.getIdFromPos(), n2.getIdFromPos() );
|
||||
if ( traffic != lastTraffic )
|
||||
{
|
||||
expctxWay.decode( description );
|
||||
expctxWay.addLookupValue( "estimated_traffic_class", traffic == 0 ? 0 : traffic + 1 );
|
||||
description = abUnifier.unify( expctxWay.encode() );
|
||||
lastTraffic = traffic;
|
||||
}
|
||||
link.descriptionBitmap = description;
|
||||
|
||||
if ( n1.ilon / cellsize != n2.ilon / cellsize || n1.ilat / cellsize != n2.ilat / cellsize )
|
||||
{
|
||||
n2.incWayCount(); // force first node after cell-change to be a
|
||||
// network node
|
||||
}
|
||||
}
|
||||
if ( n2 != null )
|
||||
{
|
||||
n2.bits |= wayBits;
|
||||
n2.incWayCount();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void wayFileEnd( File wayfile ) throws Exception
|
||||
{
|
||||
int ncaches = divisor * divisor;
|
||||
int indexsize = ncaches * 4;
|
||||
|
||||
nodesMap = null;
|
||||
borderSet = null;
|
||||
trafficMap = null;
|
||||
|
||||
byte[] abBuf1 = new byte[10 * 1024 * 1024];
|
||||
byte[] abBuf2 = new byte[10 * 1024 * 1024];
|
||||
|
||||
int maxLon = minLon + 5000000;
|
||||
int maxLat = minLat + 5000000;
|
||||
|
||||
// write segment data to individual files
|
||||
{
|
||||
int nLonSegs = ( maxLon - minLon ) / 1000000;
|
||||
int nLatSegs = ( maxLat - minLat ) / 1000000;
|
||||
|
||||
// sort the nodes into segments
|
||||
LazyArrayOfLists<OsmNodeP> seglists = new LazyArrayOfLists<OsmNodeP>( nLonSegs * nLatSegs );
|
||||
for ( OsmNodeP n : nodesList )
|
||||
{
|
||||
if ( n == null || n.getFirstLink() == null || n.isTransferNode() )
|
||||
continue;
|
||||
if ( n.ilon < minLon || n.ilon >= maxLon || n.ilat < minLat || n.ilat >= maxLat )
|
||||
continue;
|
||||
int lonIdx = ( n.ilon - minLon ) / 1000000;
|
||||
int latIdx = ( n.ilat - minLat ) / 1000000;
|
||||
|
||||
int tileIndex = lonIdx * nLatSegs + latIdx;
|
||||
seglists.getList( tileIndex ).add( n );
|
||||
}
|
||||
nodesList = null;
|
||||
seglists.trimAll();
|
||||
|
||||
// open the output file
|
||||
File outfile = fileFromTemplate( wayfile, dataTilesOut, dataTilesSuffix );
|
||||
DataOutputStream os = createOutStream( outfile );
|
||||
|
||||
long[] fileIndex = new long[25];
|
||||
int[] fileHeaderCrcs = new int[25];
|
||||
|
||||
// write 5*5 index dummy
|
||||
for ( int i55 = 0; i55 < 25; i55++ )
|
||||
{
|
||||
os.writeLong( 0 );
|
||||
}
|
||||
long filepos = 200L;
|
||||
|
||||
// sort further in 1/divisor-degree squares
|
||||
for ( int lonIdx = 0; lonIdx < nLonSegs; lonIdx++ )
|
||||
{
|
||||
for ( int latIdx = 0; latIdx < nLatSegs; latIdx++ )
|
||||
{
|
||||
int tileIndex = lonIdx * nLatSegs + latIdx;
|
||||
if ( seglists.getSize( tileIndex ) > 0 )
|
||||
{
|
||||
List<OsmNodeP> nlist = seglists.getList( tileIndex );
|
||||
|
||||
LazyArrayOfLists<OsmNodeP> subs = new LazyArrayOfLists<OsmNodeP>( ncaches );
|
||||
byte[][] subByteArrays = new byte[ncaches][];
|
||||
for ( int ni = 0; ni < nlist.size(); ni++ )
|
||||
{
|
||||
OsmNodeP n = nlist.get( ni );
|
||||
int subLonIdx = ( n.ilon - minLon ) / cellsize - divisor * lonIdx;
|
||||
int subLatIdx = ( n.ilat - minLat ) / cellsize - divisor * latIdx;
|
||||
int si = subLatIdx * divisor + subLonIdx;
|
||||
subs.getList( si ).add( n );
|
||||
}
|
||||
subs.trimAll();
|
||||
int[] posIdx = new int[ncaches];
|
||||
int pos = indexsize;
|
||||
|
||||
for ( int si = 0; si < ncaches; si++ )
|
||||
{
|
||||
List<OsmNodeP> subList = subs.getList( si );
|
||||
int size = subList.size();
|
||||
if ( size > 0 )
|
||||
{
|
||||
OsmNodeP n0 = subList.get( 0 );
|
||||
int lonIdxDiv = n0.ilon / cellsize;
|
||||
int latIdxDiv = n0.ilat / cellsize;
|
||||
MicroCache mc = microCacheEncoding == 0 ? new MicroCache1( size, abBuf2, lonIdxDiv, latIdxDiv ) : new MicroCache2( size, abBuf2,
|
||||
lonIdxDiv, latIdxDiv, divisor );
|
||||
|
||||
// sort via treemap
|
||||
TreeMap<Integer, OsmNodeP> sortedList = new TreeMap<Integer, OsmNodeP>();
|
||||
for ( OsmNodeP n : subList )
|
||||
{
|
||||
long longId = n.getIdFromPos();
|
||||
int shrinkid = mc.shrinkId( longId );
|
||||
if ( mc.expandId( shrinkid ) != longId )
|
||||
{
|
||||
throw new IllegalArgumentException( "inconstistent shrinking: " + longId );
|
||||
}
|
||||
sortedList.put( Integer.valueOf( shrinkid ), n );
|
||||
}
|
||||
|
||||
for ( OsmNodeP n : sortedList.values() )
|
||||
{
|
||||
n.writeNodeData( mc );
|
||||
}
|
||||
if ( mc.getSize() > 0 )
|
||||
{
|
||||
byte[] subBytes;
|
||||
for ( ;; )
|
||||
{
|
||||
int len = mc.encodeMicroCache( abBuf1 );
|
||||
subBytes = new byte[len];
|
||||
System.arraycopy( abBuf1, 0, subBytes, 0, len );
|
||||
|
||||
// cross-check the encoding: re-instantiate the cache
|
||||
MicroCache mc2 = microCacheEncoding == 0 ? new MicroCache1( subBytes, lonIdxDiv, latIdxDiv ) : new MicroCache2( new DataBuffers(
|
||||
subBytes ), lonIdxDiv, latIdxDiv, divisor, null, null );
|
||||
// ..and check if still the same
|
||||
String diffMessage = mc.compareWith( mc2 );
|
||||
if ( diffMessage != null )
|
||||
{
|
||||
if ( MicroCache.debug )
|
||||
throw new RuntimeException( "encoding crosscheck failed: " + diffMessage );
|
||||
else
|
||||
MicroCache.debug = true;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
pos += subBytes.length + 4; // reserve 4 bytes for crc
|
||||
subByteArrays[si] = subBytes;
|
||||
}
|
||||
}
|
||||
posIdx[si] = pos;
|
||||
}
|
||||
|
||||
byte[] abSubIndex = compileSubFileIndex( posIdx );
|
||||
fileHeaderCrcs[tileIndex] = Crc32.crc( abSubIndex, 0, abSubIndex.length );
|
||||
os.write( abSubIndex, 0, abSubIndex.length );
|
||||
for ( int si = 0; si < ncaches; si++ )
|
||||
{
|
||||
byte[] ab = subByteArrays[si];
|
||||
if ( ab != null )
|
||||
{
|
||||
os.write( ab );
|
||||
os.writeInt( Crc32.crc( ab, 0, ab.length ) ^ microCacheEncoding );
|
||||
}
|
||||
}
|
||||
filepos += pos;
|
||||
}
|
||||
fileIndex[tileIndex] = filepos;
|
||||
}
|
||||
}
|
||||
|
||||
byte[] abFileIndex = compileFileIndex( fileIndex, lookupVersion, lookupMinorVersion );
|
||||
|
||||
// write extra data: timestamp + index-checksums
|
||||
os.writeLong( creationTimeStamp );
|
||||
os.writeInt( Crc32.crc( abFileIndex, 0, abFileIndex.length ) ^ microCacheEncoding );
|
||||
for ( int i55 = 0; i55 < 25; i55++ )
|
||||
{
|
||||
os.writeInt( fileHeaderCrcs[i55] );
|
||||
}
|
||||
|
||||
os.close();
|
||||
|
||||
// re-open random-access to write file-index
|
||||
RandomAccessFile ra = new RandomAccessFile( outfile, "rw" );
|
||||
ra.write( abFileIndex, 0, abFileIndex.length );
|
||||
ra.close();
|
||||
}
|
||||
System.out.println( "**** codec stats: *******\n" + StatCoderContext.getBitReport() );
|
||||
}
|
||||
|
||||
private byte[] compileFileIndex( long[] fileIndex, short lookupVersion, short lookupMinorVersion ) throws Exception
|
||||
{
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
DataOutputStream dos = new DataOutputStream( bos );
|
||||
for ( int i55 = 0; i55 < 25; i55++ )
|
||||
{
|
||||
long versionPrefix = i55 == 1 ? lookupMinorVersion : lookupVersion;
|
||||
versionPrefix <<= 48;
|
||||
dos.writeLong( fileIndex[i55] | versionPrefix );
|
||||
}
|
||||
dos.close();
|
||||
return bos.toByteArray();
|
||||
}
|
||||
|
||||
private byte[] compileSubFileIndex( int[] posIdx ) throws Exception
|
||||
{
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
DataOutputStream dos = new DataOutputStream( bos );
|
||||
for ( int si = 0; si < posIdx.length; si++ )
|
||||
{
|
||||
dos.writeInt( posIdx[si] );
|
||||
}
|
||||
dos.close();
|
||||
return bos.toByteArray();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue