removed memory-route + experimental codec (see experimental branch)

This commit is contained in:
Arndt Brenschede 2018-12-31 17:04:05 +01:00
parent 664925133a
commit dfdfaedb5e
58 changed files with 0 additions and 7303 deletions

View file

@ -1,154 +0,0 @@
package btools.mapdecoder;
public final class BitReadBuffer
{
private byte[] ab;
private int idxMax;
private int idx = -1;
private int bits; // bits left in buffer
private long b;
public BitReadBuffer( byte[] ab )
{
this.ab = ab;
idxMax = ab.length-1;
}
public boolean decodeBit()
{
fillBuffer();
boolean value = ( ( b & 1L ) != 0 );
b >>>= 1;
bits--;
return value;
}
public long decodeBits( int count )
{
if ( count == 0 )
{
return 0;
}
fillBuffer();
long mask = -1L >>> ( 64 - count );
long value = b & mask;
b >>>= count;
bits -= count;
return value;
}
/**
* decode an integer in the range 0..max (inclusive).
*/
public long decodeBounded( long max )
{
long value = 0;
long im = 1; // integer mask
fillBuffer();
while (( value | im ) <= max)
{
if ( ( b & 1 ) != 0 )
value |= im;
b >>>= 1;
bits--;
im <<= 1;
}
return value;
}
/**
* decode a small number with a variable bit length
* (poor mans huffman tree)
* {@code 1 -> 0}
* {@code 01 -> 1} + following 1-bit word ( 1..2 )
* {@code 001 -> 3} + following 2-bit word ( 3..6 )
* {@code 0001 -> 7} + following 3-bit word ( 7..14 ) etc.
*/
public int decodeInt()
{
long range = 1;
int cnt = 1;
fillBuffer();
while ((b & range) == 0)
{
range = (range << 1) | 1;
cnt++;
}
b >>>= cnt;
bits -= cnt;
return (int)((range >>> 1) + ( cnt > 1 ? decodeBits( cnt-1 ) : 0 ));
}
/**
* double-log variant of decodeVarBits better suited for
* distributions with a big-number tail
*/
public long decodeLong()
{
int n = decodeInt();
return (1L << n) + decodeBits( n ) - 1L;
}
public long[] decodeSortedArray()
{
int size = decodeInt();
long[] values = new long[size];
if ( size == 0 )
{
return values;
}
int offset = 0;
long value = 0;
int bits = decodeInt();
int[] sizestack = new int[bits];
int stackpointer = 0;
for(;;)
{
while( size > 1 && bits > 0 )
{
int size2 = (int)decodeBounded( size );
sizestack[stackpointer++] = size2;
size -= size2;
value <<= 1;
bits--;
}
if ( size == 1 )
{
values[offset++] = (value << bits) | decodeBits( bits );
}
else
{
while (size-- > 0)
{
values[offset++] = value;
}
}
if ( stackpointer == 0 )
{
return values;
}
while ( ( value & 1L ) == 1L )
{
value >>= 1;
bits++;
}
value |= 1L;
size = sizestack[--stackpointer];
}
}
private void fillBuffer()
{
while (bits <= 56)
{
if ( idx < idxMax )
{
b |= (ab[++idx] & 0xffL) << bits;
}
bits += 8;
}
}
}

View file

@ -1,44 +0,0 @@
package btools.mapdecoder;
/**
* Decoder for unicode characters, using simple (1st order) huffmann
*/
public final class CharDecoder extends HuffmannTreeDecoder<Character>
{
private long[] alphabet;
private int range;
private char[] buffer = new char[64];
public CharDecoder( BitReadBuffer brb )
{
super( brb );
}
@Override
protected Object decodeTree()
{
alphabet = brb.decodeSortedArray();
range = alphabet.length - 1;
System.out.println( "decoded alphabet of length " + alphabet.length + " idx3 = " + alphabet[3] );
return super.decodeTree();
}
protected Character decodeItem()
{
int idx = (int)brb.decodeBounded( range );
long lc = alphabet[idx];
System.out.println( "decoded item: c=" + ((char)lc) + " idx=" + idx );
return Character.valueOf( (char)lc );
}
public String decodeString()
{
int n = brb.decodeInt();
char[] b = n <= buffer.length ? buffer : new char[n];
for( int i=0; i<n; i++ )
{
b[i] = decode().charValue();
}
return new String( b, 0, n );
}
}

View file

@ -1,59 +0,0 @@
package btools.mapdecoder;
/**
* Decoder for static huffmann coded data
*/
public abstract class HuffmannTreeDecoder<V>
{
private Object tree;
protected BitReadBuffer brb;
protected HuffmannTreeDecoder( BitReadBuffer brb )
{
this.brb = brb;
tree = decodeTree();
}
public V decode()
{
Object node = tree;
while (node instanceof TreeNode)
{
TreeNode tn = (TreeNode) node;
node = brb.decodeBit() ? tn.child2 : tn.child1;
}
if ( node == null )
{
return decodeItem(); // inline item
}
return (V) node;
}
protected Object decodeTree()
{
boolean isNode = brb.decodeBit();
if ( isNode )
{
TreeNode node = new TreeNode();
node.child1 = decodeTree();
node.child2 = decodeTree();
return node;
}
boolean isInlinePrefix = brb.decodeBit();
if ( isInlinePrefix )
{
return null;
}
return decodeItem();
}
private static final class TreeNode
{
public Object child1;
public Object child2;
}
protected abstract V decodeItem();
}

View file

@ -1,70 +0,0 @@
package btools.mapdecoder;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.zip.Inflater;
/**
* Manage the mapping between locale and native node indexes
*/
public class LocaleIndexMapping
{
private int[] refZoomDelta;
private int[] refNativeIndex;
private OsmTile[] tileForZoomDelta;
public LocaleIndexMapping( OsmTile tile, BitReadBuffer brb ) throws Exception
{
// prepare the locale index array
int localeNodeCount = brb.decodeInt();
refZoomDelta = new int[localeNodeCount];
refNativeIndex = new int[localeNodeCount];
tileForZoomDelta = new OsmTile[tile.zoom + 1];
for( OsmTile t = tile; t != null; t = t.parent )
{
tileForZoomDelta[tile.zoom-t.zoom] = t;
}
// decode the down-zoom refs
for( int zoomDelta=tile.zoom; zoomDelta > 0; zoomDelta-- )
{
long[] localeIndexes = brb.decodeSortedArray();
long[] nativeIndexes = brb.decodeSortedArray();
for( int i=0; i<localeIndexes.length; i++ )
{
int idx = (int)localeIndexes[i];
refZoomDelta[idx] = zoomDelta;
refNativeIndex[idx] = (int)nativeIndexes[i];
}
}
// prepare locale->native mapping for zoomDelta=0
int localeIdx = 0;
int nodecount = tile.nodePositions.length;
for( int i=0; i<nodecount; i++)
{
while( refZoomDelta[localeIdx] != 0 )
{
localeIdx++;
}
refNativeIndex[localeIdx++] = i;
}
}
public OsmNode nodeForLocaleIndex( int localeIndex )
{
int zoomDelta = refZoomDelta[localeIndex];
int nativeIndex = refNativeIndex[localeIndex];
return tileForZoomDelta[zoomDelta].nodes.get( nativeIndex );
}
public OsmWay getWay( int zoomDelta, int nativeIndex )
{
return tileForZoomDelta[zoomDelta].ways.get( nativeIndex );
}
}

View file

@ -1,63 +0,0 @@
package btools.mapdecoder;
import java.util.List;
public class NodeTreeElement
{
public int offset;
public int nnodes;
public NodeTreeElement child0;
public NodeTreeElement child1;
public List<OsmNode> nodes;
public static NodeTreeElement createNodeTree( long[] values, int offset, int subsize, long nextbit, long mask )
{
if ( nextbit == 0 )
{
return null;
}
if ( subsize < 1 )
{
return null;
}
long data = mask & values[offset];
mask |= nextbit;
// count 0-bit-fraction
int i = offset;
int end = subsize + offset;
for ( ; i < end; i++ )
{
if ( ( values[i] & mask ) != data )
{
break;
}
}
int size1 = i - offset;
int size2 = subsize - size1;
System.out.println( "createNodeTree: offset=" + offset + " subsize=" + subsize + " size1=" + size1 + " size2=" + size2 );
NodeTreeElement nte = new NodeTreeElement();
nte.offset = offset;
nte.nnodes = subsize;
nte.child0 = createNodeTree( values, offset, size1, nextbit >> 1, mask );
nte.child1 = createNodeTree( values, i, size2, nextbit >> 1, mask );
return nte;
}
public String toString()
{
return " child0=" + (child0 != null ) + " child1=" + (child1 != null );
}
}

View file

@ -1,34 +0,0 @@
package btools.mapdecoder;
public class OsmNode extends OsmObject
{
public int ilon;
public int ilat;
public boolean inBBox( int z, int x, int y )
{
int shift = 28-z;
int x0 = x << shift;
int x1 = (x+1) << shift;
int y0 = y << shift;
int y1 = (y+1) << shift;
boolean outofbox = x1 < ilon || x0 >= ilon || y1 < ilat || y0 >= ilat;
return !outofbox;
}
public static double gudermannian(double y)
{
return Math.atan(Math.sinh(y)) * (180. / Math.PI);
}
public double getLon()
{
return (((double)ilon)/( 1L << 27 ) - 1.)*180.;
}
public double getLat()
{
double y = (1. - ((double)ilat)/( 1L << 27 ))*Math.PI;
return gudermannian(y);
}
}

View file

@ -1,12 +0,0 @@
package btools.mapdecoder;
import java.util.Map;
/**
* Base class of Nodes, Ways and Relations
*/
public class OsmObject
{
public int id;
public Map<String,String> tags;
}

View file

@ -1,48 +0,0 @@
package btools.mapdecoder;
import java.util.List;
public class OsmRelation extends OsmObject
{
public List<OsmRelationMember> members;
// bounding box
int minx;
int miny;
int maxx;
int maxy;
public void calcBBox()
{
for( int i=0; i<members.size(); i++ )
{
OsmWay w = members.get(i).way;
if ( i == 0 )
{
minx = w.minx;
maxx = w.maxx;
miny = w.miny;
maxy = w.maxy;
}
else
{
if ( w.minx < minx ) minx = w.minx;
if ( w.maxx > maxx ) maxx = w.maxx;
if ( w.miny < miny ) miny = w.miny;
if ( w.maxy > maxy ) maxy = w.maxy;
}
}
}
public boolean inBBox( int z, int x, int y )
{
int shift = 28-z;
int x0 = x << shift;
int x1 = (x+1) << shift;
int y0 = y << shift;
int y1 = (y+1) << shift;
boolean outofbox = x1 < minx || x0 >= maxx || y1 < miny || y0 >= maxy;
return !outofbox;
}
}

View file

@ -1,9 +0,0 @@
package btools.mapdecoder;
import java.util.List;
public class OsmRelationMember extends OsmObject
{
public OsmWay way;
public String role;
}

View file

@ -1,35 +0,0 @@
package btools.mapdecoder;
import java.util.Collections;
import java.util.List;
/**
* Container for waydata on the preprocessor level
*
* @author ab
*/
public class OsmTile
{
public OsmTile parent;
public long sourceId;
public int zoom;
public int x;
public int y;
private static List<OsmNode> emptyNodes = Collections.EMPTY_LIST;
private static List<OsmWay> emptyWays = Collections.EMPTY_LIST;
private static List<OsmRelation> emptyRelations = Collections.EMPTY_LIST;
public List<OsmNode> nodes = emptyNodes;
public List<OsmWay> ways = emptyWays;
public List<OsmRelation> relations = emptyRelations;
public long[] nodePositions;
public String toString()
{
return "z=" + zoom+ " x=" + x + " y=" + y + " nodes=" + nodes.size() + " ways=" + ways.size() + " rels=" + relations.size();
}
}

View file

@ -1,45 +0,0 @@
package btools.mapdecoder;
import java.util.List;
public class OsmWay extends OsmObject
{
public List<OsmNode> nodes;
// bounding box
int minx;
int miny;
int maxx;
int maxy;
public void calcBBox()
{
for( int i=0; i<nodes.size(); i++ )
{
OsmNode n = nodes.get(i);
if ( i == 0 )
{
minx = maxx = n.ilon;
miny = maxy = n.ilat;
}
else
{
if ( n.ilon < minx ) minx = n.ilon;
if ( n.ilon > maxx ) maxx = n.ilon;
if ( n.ilat < miny ) miny = n.ilat;
if ( n.ilat > maxy ) maxy = n.ilat;
}
}
}
public boolean inBBox( int z, int x, int y )
{
int shift = 28-z;
int x0 = x << shift;
int x1 = (x+1) << shift;
int y0 = y << shift;
int y1 = (y+1) << shift;
boolean outofbox = x1 < minx || x0 >= maxx || y1 < miny || y0 >= maxy;
return !outofbox;
}
}

View file

@ -1,30 +0,0 @@
package btools.mapdecoder;
/**
* Decoder for a set of tags
*
* Only tagsets detected at least twice
* have their own huffmann-codes, those
* detected only once are coded inline
*/
public final class TagSetDecoder extends HuffmannTreeDecoder<int[]>
{
public TagSetDecoder( BitReadBuffer brb )
{
super( brb );
}
protected int[] decodeItem()
{
int tagcount = brb.decodeInt();
int[] data = new int[tagcount];
int lastIdx = -1;
for( int i=0; i<tagcount; i++ )
{
int idx = lastIdx + 1 + brb.decodeInt();
data[i] = idx;
lastIdx = idx;
}
return data;
}
}

View file

@ -1,88 +0,0 @@
package btools.mapdecoder;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
/**
* Decoder for the list of tags and their value-trees
*/
public class TagValueDecoder
{
private int nextStringStart = 0;
private byte[] textHeader;
private ArrayList<String> stringList;
private ArrayList<Tag> taglist;
private int roleIdx;
private String decodeString( BitReadBuffer brb )
{
boolean newIdx = brb.decodeBit();
if ( newIdx )
{
int slen = brb.decodeInt();
try
{
String s = new String( textHeader, nextStringStart, slen, "UTF8" );
nextStringStart += slen;
stringList.add( s );
return s;
}
catch( UnsupportedEncodingException uee )
{
throw new RuntimeException( uee );
}
}
int idx = (int)brb.decodeBounded( stringList.size()-1 );
return stringList.get( idx );
}
private class Tag extends HuffmannTreeDecoder<String>
{
String name;
Tag( BitReadBuffer brb, String tagName )
{
super( brb );
name = tagName;
}
protected String decodeItem()
{
return decodeString( brb );
}
}
public TagValueDecoder( BitReadBuffer brb, byte[] textHeader )
{
this.textHeader = textHeader;
stringList = new ArrayList<String>();
int ntags = brb.decodeInt();
taglist = new ArrayList<Tag>();
for( int i=0; i<ntags; i++ )
{
String tagName = decodeString( brb );
taglist.add( new Tag( brb, tagName ) );
if ( "role".equals( tagName ) )
{
roleIdx = i;
}
}
}
public String getTagName( int idx )
{
return taglist.get(idx).name;
}
public String decodeValue( int tagIdx )
{
return taglist.get( tagIdx ).decode();
}
public String decodeRole()
{
return taglist.get( roleIdx ).decode();
}
}

View file

@ -1,207 +0,0 @@
package btools.mapdecoder;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.zip.Inflater;
/**
* TileEncoder decodes a compressed osm tile
*/
public class TileDecoder
{
private TagSetDecoder tagSetDecoder;
private TagValueDecoder tagValueDecoder;
public static void main( String[] args ) throws Exception
{
OsmTile t = new TileDecoder().process( new File( args[0] ), null, Integer.parseInt( args[1] ), Integer.parseInt( args[2] ), Integer.parseInt( args[3] ) );
while( t != null )
{
System.out.println( "decoded: " + t );
t = t.parent;
}
}
public OsmTile process( File tileDir, OsmTile template, int zoom, int x, int y ) throws Exception
{
long sourceId = tileDir.getAbsolutePath().hashCode();
// look for a match in the template
for( OsmTile tile = template; tile != null; tile = tile.parent )
{
if ( tile.zoom == zoom && tile.x == x && tile.y == y && tile.sourceId == sourceId )
{
return tile;
}
}
OsmTile td = new OsmTile();
td.sourceId = sourceId;
td.zoom = zoom;
td.x = x;
td.y = y;
if ( zoom > 0 )
{
td.parent = new TileDecoder().process( tileDir, template, zoom-1, x >> 1, y >> 1 );
}
File file = new File( new File( tileDir, "" + zoom ), x + "_" + y + ".osb" );
if ( !file.exists() )
{
return td;
}
DataInputStream dis = new DataInputStream( new FileInputStream( file ) );
int textHeaderLen = dis.readInt();
int textHeaderCompressedLen = dis.readInt();
byte[] textHeaderCompressed = new byte[textHeaderCompressedLen];
dis.readFully( textHeaderCompressed );
byte[] textHeader = new byte[textHeaderLen];
Inflater decompresser = new Inflater();
decompresser.setInput( textHeaderCompressed );
int rawlen = decompresser.inflate( textHeader );
int bufferLen = dis.readInt();
byte[] buffer = new byte[bufferLen];
dis.readFully( buffer );
BitReadBuffer brb = new BitReadBuffer( buffer );
dis.close();
tagSetDecoder = new TagSetDecoder( brb );
tagValueDecoder = new TagValueDecoder( brb, textHeader );
// decode the node positions
td.nodePositions = brb.decodeSortedArray();
int nodecount = td.nodePositions.length;
td.nodes = new ArrayList<OsmNode>(nodecount);
int shift = 56-2*zoom;
long offset = (encodeMorton( x ) << shift) + (encodeMorton( y ) << (shift+1) );
for ( int nidx = 0; nidx < nodecount; nidx++ )
{
OsmNode n = new OsmNode();
long z = offset + td.nodePositions[nidx];
n.id = nidx;
n.ilon = decodeMorton( z );
n.ilat = decodeMorton( z >> 1 );
td.nodes.add( n );
}
LocaleIndexMapping indexMapping = new LocaleIndexMapping( td, brb );
// decode tagged nodes
long[] taggedIndexes = brb.decodeSortedArray();
int ntaggedNodes = taggedIndexes.length;
for( int tnidx=0; tnidx<ntaggedNodes; tnidx++ )
{
int idx = (int)taggedIndexes[tnidx];
td.nodes.get( idx ).tags = decodeTagValues();
}
// decode ways
long[] startIndexes = brb.decodeSortedArray();
int nways = startIndexes.length;
td.ways = new ArrayList<OsmWay>( nways );
for( int widx=0; widx<nways; widx++ )
{
OsmWay w = new OsmWay();
w.tags = decodeTagValues();
int[] nodeIndexes = decodeWayNodes( (int)startIndexes[widx], brb );
w.nodes = new ArrayList<OsmNode>( nodeIndexes.length );
for( int i=0; i<nodeIndexes.length; i++ )
{
w.nodes.add( indexMapping.nodeForLocaleIndex( nodeIndexes[i] ) );
}
w.calcBBox();
td.ways.add( w );
}
// decode relations
int nrels = brb.decodeInt();
td.relations = new ArrayList<OsmRelation>( nrels );
for( int ridx=0; ridx<nrels; ridx++ )
{
OsmRelation r = new OsmRelation();
r.tags = decodeTagValues();
int nmembers = brb.decodeInt();
r.members = new ArrayList<OsmRelationMember>(nmembers);
for( int midx = 0; midx<nmembers; midx++ )
{
OsmRelationMember m = new OsmRelationMember();
int zoomDelta = brb.decodeInt();
int nativeIndex = brb.decodeInt();
m.role = tagValueDecoder.decodeRole();
m.way = indexMapping.getWay( zoomDelta, nativeIndex );
r.members.add( m );
}
r.calcBBox();
td.relations.add( r );
}
return td;
}
private int[] decodeWayNodes( int startIdx, BitReadBuffer brb )
{
boolean closedPoly = brb.decodeBit();
int nnodes = brb.decodeInt() + 2;
int[] ids = new int[ closedPoly ? nnodes+1 : nnodes ];
int lastIdx = startIdx;
ids[0] = startIdx;
for( int i=1; i<nnodes; i++ )
{
boolean negative = brb.decodeBit();
int delta = (int)brb.decodeLong() + 1;
ids[i] = lastIdx = lastIdx + (negative ? -delta : delta );
}
if ( closedPoly )
{
ids[nnodes] = startIdx;
}
return ids;
}
private HashMap<String,String> decodeTagValues()
{
HashMap<String,String> map = new HashMap<String,String>();
int[] tagSet = tagSetDecoder.decode();
for( int i=0; i<tagSet.length; i++ )
{
int tagIdx = tagSet[i];
String key = tagValueDecoder.getTagName( tagIdx );
String value = tagValueDecoder.decodeValue( tagIdx );
map.put( key, value );
}
return map;
}
public static int decodeMorton( long z )
{
long x = z & 0x5555555555555555L;
x = (x | (x >> 1)) & 0x3333333333333333L;
x = (x | (x >> 2)) & 0x0F0F0F0F0F0F0F0FL;
x = (x | (x >> 4)) & 0x00FF00FF00FF00FFL;
x = (x | (x >> 8)) & 0x0000FFFF0000FFFFL;
return (int)(x | (x >> 16));
}
public static long encodeMorton( int x )
{
long z = x & 0xFFFFFFFFL;
z = (z | (z << 16)) & 0x0000FFFF0000FFFFL;
z = (z | (z << 8)) & 0x00FF00FF00FF00FFL;
z = (z | (z << 4)) & 0x0F0F0F0F0F0F0F0FL;
z = (z | (z << 2)) & 0x3333333333333333L;
return (z|(z << 1)) & 0x5555555555555555L;
}
}

View file

@ -1,232 +0,0 @@
package btools.mapsplitter;
import java.util.TreeMap;
public final class BitWriteBuffer
{
private static TreeMap<String, long[]> statsPerName;
private long lastbitpos = 0;
private byte[] ab;
private int idxMax;
private int idx = -1;
private int bm = 0x100; // byte mask (write mode)
private int b;
public BitWriteBuffer( byte[] ab )
{
this.ab = ab;
idxMax = ab.length-1;
}
/**
* encode a distance with a variable bit length
* (poor mans huffman tree)
* {@code 1 -> 0}
* {@code 01 -> 1} + following 1-bit word ( 1..2 )
* {@code 001 -> 3} + following 2-bit word ( 3..6 )
* {@code 0001 -> 7} + following 3-bit word ( 7..14 ) etc.
*
* @see btools.util.BitCoderContext#decodeVarBits
*
*/
public void encodeInt( int value )
{
int range = 0;
while (value > range)
{
encodeBit( false );
value -= range + 1;
range = 2 * range + 1;
}
encodeBit( true );
encodeBounded( range, value );
}
public void encodeLong( long n )
{
int maxbit = 0;
long nn = n + 1L;
while( nn > 1L )
{
maxbit++;
nn >>= 1;
}
encodeInt( maxbit );
long range = 1 << maxbit;
encodeBounded( range-1L, n + 1L -range );
}
public void encodeBit( boolean value )
{
if ( bm == 0x100 )
{
bm = 1;
ab[++idx] = 0;
}
if ( value )
ab[idx] |= bm;
bm <<= 1;
}
/**
* encode an integer in the range 0..max (inclusive).
* For max = 2^n-1, this just encodes n bits, but in general
* this is variable length encoding, with the shorter codes
* for the central value range
*/
public void encodeBounded( long max, long value )
{
long im = 1L; // integer mask
while (im <= max)
{
if ( bm == 0x100 )
{
bm = 1;
ab[++idx] = 0;
}
if ( ( value & im ) != 0 )
{
ab[idx] |= bm;
max -= im;
}
bm <<= 1;
im <<= 1;
}
}
/**
* @return the encoded length in bytes
*/
public int getEncodedLength()
{
return idx + 1;
}
/**
* @return the encoded length in bits
*/
public long getWritingBitPosition()
{
long bitpos = idx << 3;
int m = bm;
while (m > 1)
{
bitpos++;
m >>= 1;
}
return bitpos;
}
public void encodeSortedArray( long[] values )
{
int size = values.length;
encodeInt( size );
if ( size == 0 )
{
return;
}
long maxValue = values[size-1];
int nbits = 0;
while ( maxValue > 0 )
{
nbits++;
maxValue >>= 1;
}
if ( nbits > 57 ) throw new IllegalArgumentException( "encodeSortedArray accepts 57-bit numbers at max" );
encodeInt( nbits );
encodeSortedArray( values, 0, size, ( 1L << nbits ) >> 1, 0L );
}
private void encodeSortedArray( long[] values, int offset, int subsize, long nextbit, long mask )
{
if ( subsize == 1 ) // last-choice shortcut
{
long bit = 1L;
while ( bit <= nextbit )
{
encodeBit( ( values[offset] & bit ) != 0 );
bit <<= 1;
}
return;
}
if ( nextbit == 0 )
{
return;
}
long data = mask & values[offset];
mask |= nextbit;
// count 0-bit-fraction
int i = offset;
int end = subsize + offset;
for ( ; i < end; i++ )
{
if ( ( values[i] & mask ) != data )
{
break;
}
}
int size1 = i - offset;
int size2 = subsize - size1;
encodeBounded( subsize, size2 );
if ( size1 > 0 )
{
encodeSortedArray( values, offset, size1, nextbit >> 1, mask );
}
if ( size2 > 0 )
{
encodeSortedArray( values, i, size2, nextbit >> 1, mask );
}
}
/**
* assign the de-/encoded bits since the last call assignBits to the given
* name. Used for encoding statistics
*
* @see #getBitReport
*/
public void assignBits( String name )
{
long bitpos = getWritingBitPosition();
if ( statsPerName == null )
{
statsPerName = new TreeMap<String, long[]>();
}
long[] stats = statsPerName.get( name );
if ( stats == null )
{
stats = new long[2];
statsPerName.put( name, stats );
}
stats[0] += bitpos - lastbitpos;
stats[1] += 1;
lastbitpos = bitpos;
}
/**
* Get a textual report on the bit-statistics
*
* @see #assignBits
*/
public static String getBitReport()
{
if ( statsPerName == null )
{
return "<empty bit report>";
}
StringBuilder sb = new StringBuilder();
for ( String name : statsPerName.keySet() )
{
long[] stats = statsPerName.get( name );
sb.append( name + " count=" + stats[1] + " bits=" + stats[0] + "\n" );
}
statsPerName = null;
return sb.toString();
}
}

View file

@ -1,71 +0,0 @@
package btools.mapsplitter;
import java.util.TreeMap;
/**
* Encoder for characters, using simple (1st order) huffmann
*/
public final class CharEncoder extends HuffmanTreeEncoder<Character>
{
private long[] alphabet;
private int range;
private TreeMap<Character,Integer> chars = new TreeMap<Character,Integer>();
public void encode( Character c )
{
if ( pass == 1 )
{
chars.put( c, null );
}
super.encode( c );
}
public void encodeDictionary( BitWriteBuffer bwb )
{
if ( pass == 1 ) // means 2...
{
int idx = 0;
alphabet = new long[chars.size()];
range = chars.size()-1;
for ( Character c : chars.keySet() )
{
System.out.println( "assigning index " + idx + " to char=" + c );
alphabet[idx] = c;
chars.put( c, Integer.valueOf( idx++ ) );
}
}
if ( alphabet != null )
{
bwb.encodeSortedArray( alphabet );
}
super.encodeDictionary( bwb );
}
protected void encodeItem( Character c )
{
int idx = chars.get( c ).intValue();
System.out.println( "encoding item: c=" + c + " idx=" + idx );
bwb.encodeBounded( range, idx );
}
@Override
public boolean itemEquals( Character c1, Character c2 )
{
if ( c1 == null )
{
return c2 == null;
}
if ( c2 == null )
{
return false;
}
return c1.charValue() == c2.charValue();
}
@Override
public int itemHashCode( Character c)
{
return c == 0 ? 0 : c.charValue();
}
}

View file

@ -1,140 +0,0 @@
package btools.mapsplitter;
import java.util.Comparator;
import java.util.HashMap;
import java.util.PriorityQueue;
/**
* Encoder for a set of tags
*
* It detects identical sets and sorts them
* into a huffman-tree according to their frequencies
*
* Adapted for 3-pass encoding (counters -&gt; statistics -&gt; encoding )
* but doesn't do anything at pass1
*/
public abstract class HuffmanTreeEncoder<V>
{
private HashMap<TreeNode, TreeNode> identityMap;
protected BitWriteBuffer bwb;
protected int pass;
private TreeNode freq1;
public void encode( V data )
{
if ( pass == 1 )
{
return;
}
TreeNode probe = new TreeNode();
probe.data = data;
TreeNode tn = identityMap.get( probe );
if ( pass == 3 )
{
if ( tn.frequency == 1 )
{
bwb.encodeBounded( freq1.range - 1, freq1.code );
encodeItem( data );
}
else
{
bwb.encodeBounded( tn.range - 1, tn.code );
}
}
else if ( pass == 2 )
{
if ( tn == null )
{
tn = probe;
identityMap.put( tn, tn );
}
tn.frequency++;
}
}
public void encodeDictionary( BitWriteBuffer bwb )
{
this.bwb = bwb;
if ( ++pass == 3 )
{
freq1 = new TreeNode();
PriorityQueue<TreeNode> queue = new PriorityQueue<TreeNode>(2*identityMap.size(), new Comparator<TreeNode>()
{
@Override
public int compare(TreeNode tn1, TreeNode tn2)
{
if ( tn1.frequency < tn2.frequency )
return -1;
if ( tn1.frequency > tn2.frequency )
return 1;
return 0;
}
} );
queue.add( freq1 );
while (queue.size() > 1)
{
TreeNode node = new TreeNode();
node.child1 = queue.poll();
node.child2 = queue.poll();
node.frequency = node.child1.frequency + node.child2.frequency;
queue.add( node );
}
TreeNode root = queue.poll();
root.encode( 1, 0 );
}
}
public HuffmanTreeEncoder()
{
identityMap = new HashMap<TreeNode, TreeNode>();
}
protected abstract void encodeItem( V data );
protected abstract boolean itemEquals( V i1, V i2 );
protected abstract int itemHashCode( V i);
public final class TreeNode
{
public V data;
public int frequency;
public int code;
public int range;
public TreeNode child1;
public TreeNode child2;
public void encode( int range, int code )
{
this.range = range;
this.code = code;
boolean isNode = child1 != null;
bwb.encodeBit( isNode );
if ( isNode )
{
child1.encode( range << 1, code );
child2.encode( range << 1, code + range );
}
else
{
bwb.encodeBit( data == null );
if ( data != null )
{
encodeItem( data );
}
}
}
@Override
public boolean equals( Object o )
{
return itemEquals( ((TreeNode)o).data, data );
}
@Override
public int hashCode()
{
return itemHashCode( data );
}
}
}

View file

@ -1,173 +0,0 @@
/**
* common base class for the map-filters
*
* @author ab
*/
package btools.mapsplitter;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import btools.util.DiffCoderDataOutputStream;
public abstract class MapCreatorBase implements WayListener, NodeListener, RelationListener
{
private DiffCoderDataOutputStream[] tileOutStreams;
protected File outTileDir;
protected HashMap<String,String> tags;
public void putTag( String key, String value )
{
if ( tags == null ) tags = new HashMap<String,String>();
tags.put( key, value );
}
public String getTag( String key )
{
return tags == null ? null : tags.get( key );
}
public HashMap<String,String> getTagsOrNull()
{
return tags;
}
public void setTags( HashMap<String,String> tags )
{
this.tags = tags;
}
protected static long readId( DataInputStream is) throws IOException
{
int offset = is.readByte();
if ( offset == 32 ) return -1;
long i = is.readInt();
i = i << 5;
return i | offset;
}
protected static void writeId( DataOutputStream o, long id ) throws IOException
{
if ( id == -1 )
{
o.writeByte( 32 );
return;
}
int offset = (int)( id & 0x1f );
int i = (int)( id >> 5 );
o.writeByte( offset );
o.writeInt( i );
}
protected static File[] sortBySizeAsc( File[] files )
{
int n = files.length;
long[] sizes = new long[n];
File[] sorted = new File[n];
for( int i=0; i<n; i++ ) sizes[i] = files[i].length();
for(int nf=0; nf<n; nf++)
{
int idx = -1;
long min = -1;
for( int i=0; i<n; i++ )
{
if ( sizes[i] != -1 && ( idx == -1 || sizes[i] < min ) )
{
min = sizes[i];
idx = i;
}
}
sizes[idx] = -1;
sorted[nf] = files[idx];
}
return sorted;
}
protected File fileFromTemplate( File template, File dir, String suffix )
{
String filename = template.getName();
filename = filename.substring( 0, filename.length() - 3 ) + suffix;
return new File( dir, filename );
}
protected DataInputStream createInStream( File inFile ) throws IOException
{
return new DataInputStream( new BufferedInputStream ( new FileInputStream( inFile ) ) );
}
protected DiffCoderDataOutputStream createOutStream( File outFile ) throws IOException
{
return new DiffCoderDataOutputStream( new BufferedOutputStream( new FileOutputStream( outFile ) ) );
}
protected DiffCoderDataOutputStream getOutStreamForTile( int tileIndex ) throws Exception
{
if ( tileOutStreams == null )
{
tileOutStreams = new DiffCoderDataOutputStream[64];
}
if ( tileOutStreams[tileIndex] == null )
{
tileOutStreams[tileIndex] = createOutStream( new File( outTileDir, getNameForTile( tileIndex ) ) );
}
return tileOutStreams[tileIndex];
}
protected String getNameForTile( int tileIndex )
{
throw new IllegalArgumentException( "getNameForTile not implemented" );
}
protected void closeTileOutStreams() throws Exception
{
if ( tileOutStreams == null )
{
return;
}
for( int tileIndex=0; tileIndex<tileOutStreams.length; tileIndex++ )
{
if ( tileOutStreams[tileIndex] != null ) tileOutStreams[tileIndex].close();
tileOutStreams[tileIndex] = null;
}
}
// interface dummys
@Override
public void nodeFileStart( File nodefile ) throws Exception {}
@Override
public void nextNode( NodeData n ) throws Exception {}
@Override
public void nodeFileEnd( File nodefile ) throws Exception {}
@Override
public void wayFileStart( File wayfile ) throws Exception {}
@Override
public void nextWay( WayData data ) throws Exception {}
@Override
public void wayFileEnd( File wayfile ) throws Exception {}
@Override
public void relationFileStart( File relfile ) throws Exception {}
@Override
public void nextRelation( RelationData data ) throws Exception {}
@Override
public void relationFileEnd( File relfile ) throws Exception {}
}

View file

@ -1,181 +0,0 @@
package btools.mapsplitter;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import btools.util.DiffCoderDataInputStream;
import btools.util.DiffCoderDataOutputStream;
/**
* Container for node data on the preprocessor level
*
* @author ab
*/
public class NodeData extends MapCreatorBase
{
public long nid;
public int ilon;
public int ilat;
public byte[] description;
public short selev = Short.MIN_VALUE;
public long gid; // geo-id
public int zoom = -1; // the zoom level this node is on
public int nativeIndex; // the index along all NATIVE nodes of it's tile
public transient int localeIndex; // the index along all USED nodes of it's tile
public transient boolean used; // whether this node is used by a way
public NodeData( long id, double lon, double lat )
{
nid = id;
double y = gudermannianInv( lat );
ilat = (int)( (1.-y/Math.PI )*( 1L << 27 )+ 0.5);
ilon = (int)( ( lon/180. + 1. )*( 1L << 27 ) + 0.5 );
}
public NodeData( long id, int ilon, int ilat )
{
this.nid = id;
this.ilat = ilat;
this.ilon = ilon;
}
public boolean inBBox( int z, int x, int y )
{
int shift = 28-z;
int x0 = x << shift;
int x1 = (x+1) << shift;
int y0 = y << shift;
int y1 = (y+1) << shift;
boolean outofbox = x1 < ilon || x0 >= ilon || y1 < ilat || y0 >= ilat;
return !outofbox;
}
public static double gudermannianInv(double latitude)
{
double sign = latitude < 0. ? -1. : 1.;
double sin = Math.sin( latitude * (Math.PI / 180.) * sign);
return sign * (Math.log((1.0 + sin) / (1.0 - sin)) / 2.0);
}
public static double gudermannian(double y)
{
return Math.atan(Math.sinh(y)) * (180. / Math.PI);
}
public double getLon()
{
return (((double)ilon)/( 1L << 27 ) - 1.)*180.;
}
public double getLat()
{
double y = (1. - ((double)ilat)/( 1L << 27 ))*Math.PI;
return gudermannian(y);
}
public void calcGeoId()
{
if ( zoom < 0 ) throw new IllegalArgumentException( "no zoom level yet" );
gid = 0L;
for( long bm = 1L << (27-zoom); bm > 0; bm >>= 1 )
{
gid <<= 2;
if ( ( ilon & bm ) != 0 ) gid |= 1;
if ( ( ilat & bm ) != 0 ) gid |= 2;
}
}
public static void sortByGeoId( List<NodeData> nodes )
{
Collections.sort( nodes, new Comparator<NodeData>()
{
@Override
public int compare(NodeData n1, NodeData n2)
{
long d = n1.gid - n2.gid;
// for equal positions sort by nid
if ( d == 0L )
{
d = n1.nid - n2.nid;
}
return d == 0 ? 0 : ( d < 0 ? -1 : 1 );
}
} );
}
public NodeData( DiffCoderDataInputStream dis ) throws Exception
{
zoom = dis.readInt();
nativeIndex = dis.readInt();
nid = dis.readDiffed( 0 );
ilon = (int)dis.readDiffed( 1 );
ilat = (int)dis.readDiffed( 2 );
for (;;)
{
String key = dis.readUTF();
if ( key.length() == 0 ) break;
String value = dis.readUTF();
putTag( key, value );
}
}
public void writeTo( DiffCoderDataOutputStream dos ) throws Exception
{
dos.writeInt( zoom );
dos.writeInt( nativeIndex );
dos.writeDiffed( nid, 0 );
dos.writeDiffed( ilon, 1 );
dos.writeDiffed( ilat, 2 );
if ( getTagsOrNull() != null )
{
for( Map.Entry<String,String> me : getTagsOrNull().entrySet() )
{
if ( me.getKey().length() > 0 )
{
dos.writeUTF( me.getKey() );
dos.writeUTF( me.getValue() );
}
}
}
dos.writeUTF( "" );
}
private int mercatorLon( long x, long z )
{
return (int) ( ( 360000000L * x ) >> z );
}
private int mercatorLat( long y, long z )
{
double n = Math.PI - ( 2.0 * Math.PI * y ) / ( 1L << z );
double d = Math.toDegrees( Math.atan( Math.sinh( n ) ) );
return (int) ( ( d + 90. ) * 1000000. + 0.5 );
}
@Override
public boolean equals( Object o )
{
if ( o instanceof NodeData )
{
NodeData n = (NodeData) o;
return n.nid == nid;
}
return false;
}
@Override
public int hashCode()
{
return (int)((nid >> 32) ^ nid);
}
}

View file

@ -1,65 +0,0 @@
package btools.mapsplitter;
import java.io.BufferedInputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import btools.util.DiffCoderDataInputStream;
/**
* Iterate over a singe nodefile or a directory
* of nodetiles and feed the nodes to the callback listener
*
* @author ab
*/
public class NodeIterator extends MapCreatorBase
{
private NodeListener listener;
public NodeIterator( NodeListener nodeListener )
{
listener = nodeListener;
}
public void processDir( File indir, String inSuffix ) throws Exception
{
if ( !indir.isDirectory() )
{
throw new IllegalArgumentException( "not a directory: " + indir );
}
File[] af = sortBySizeAsc( indir.listFiles() );
for( int i=0; i<af.length; i++ )
{
File nodefile = af[i];
if ( nodefile.getName().endsWith( inSuffix ) )
{
processFile( nodefile );
}
}
}
public void processFile(File nodefile) throws Exception
{
System.out.println( "*** NodeIterator reading: " + nodefile );
listener.nodeFileStart( nodefile );
DiffCoderDataInputStream di = new DiffCoderDataInputStream( new BufferedInputStream ( new FileInputStream( nodefile ) ) );
try
{
for(;;)
{
NodeData n = new NodeData( di );
listener.nextNode( n );
}
}
catch( EOFException eof )
{
di.close();
}
listener.nodeFileEnd( nodefile );
}
}

View file

@ -1,17 +0,0 @@
package btools.mapsplitter;
import java.io.File;
/**
* Callbacklistener for NodeIterator
*
* @author ab
*/
public interface NodeListener
{
void nodeFileStart( File nodefile ) throws Exception;
void nextNode( NodeData data ) throws Exception;
void nodeFileEnd( File nodefile ) throws Exception;
}

View file

@ -1,248 +0,0 @@
package btools.mapsplitter;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.GZIPInputStream;
import btools.util.LongList;
/**
* Parser for OSM data
*
* @author ab
*/
public class OsmParser2 extends MapCreatorBase
{
private BufferedReader _br;
private NodeListener nListener;
private WayListener wListener;
private RelationListener rListener;
public void readMap( File mapFile,
NodeListener nListener,
WayListener wListener,
RelationListener rListener ) throws Exception
{
this.nListener = nListener;
this.wListener = wListener;
this.rListener = rListener;
if ( mapFile == null )
{
_br = new BufferedReader(new InputStreamReader(System.in, "UTF8" ));
}
else
{
if ( mapFile.getName().endsWith( ".gz" ) )
{
_br = new BufferedReader(new InputStreamReader( new GZIPInputStream( new FileInputStream( mapFile ) ),"UTF8" ) );
}
else
{
_br = new BufferedReader(new InputStreamReader( new FileInputStream( mapFile ) , "UTF8" ) );
}
}
for(;;)
{
String line = _br.readLine();
if ( line == null ) break;
if ( checkNode( line ) ) continue;
if ( checkWay( line ) ) continue;
if ( checkRelation( line ) ) continue;
if ( checkChangeset( line ) ) continue;
}
if ( mapFile != null )
{
_br.close();
}
}
private boolean checkNode( String line ) throws Exception
{
int idx0 = line.indexOf( "<node id=\"" );
if ( idx0 < 0 ) return false;
idx0 += 10;
int idx1 = line.indexOf( '"', idx0 );
long nodeId = Long.parseLong( line.substring( idx0, idx1 ) );
int idx2 = line.indexOf( " lat=\"" );
if ( idx2 < 0 ) return false;
idx2 += 6;
int idx3 = line.indexOf( '"', idx2 );
double lat = Double.parseDouble( line.substring( idx2, idx3 ) );
int idx4 = line.indexOf( " lon=\"" );
if ( idx4 < 0 ) return false;
idx4 += 6;
int idx5 = line.indexOf( '"', idx4 );
double lon = Double.parseDouble( line.substring( idx4, idx5 ) );
NodeData n = new NodeData( nodeId, lon, lat );
if ( !line.endsWith( "/>" ) )
{
// read additional tags
for(;;)
{
String l2 = _br.readLine();
if ( l2 == null ) return false;
int i2;
if ( (i2 = l2.indexOf( "<tag k=\"" )) >= 0 )
{ // property-tag
i2 += 8;
int ri2 = l2.indexOf( '"', i2 );
String key = l2.substring( i2, ri2 );
i2 = l2.indexOf( " v=\"", ri2 );
if ( i2 >= 0 )
{
i2 += 4;
int ri3 = l2.indexOf( '"', i2 );
String value = l2.substring( i2, ri3 );
n.putTag( key, value );
}
}
else if ( l2.indexOf( "</node>" ) >= 0 )
{ // end-tag
break;
}
}
}
nListener.nextNode( n );
return true;
}
private boolean checkWay( String line ) throws Exception
{
int idx0 = line.indexOf( "<way id=\"" );
if ( idx0 < 0 ) return false;
idx0 += 9;
int idx1 = line.indexOf( '"', idx0 );
long id = Long.parseLong( line.substring( idx0, idx1 ) );
WayData w = new WayData( id );
// read the nodes
for(;;)
{
String l2 = _br.readLine();
if ( l2 == null ) return false;
int i2;
if ( (i2 = l2.indexOf( "<nd ref=\"" )) >= 0 )
{ // node reference
i2 += 9;
int ri2 = l2.indexOf( '"', i2 );
long nid = Long.parseLong( l2.substring( i2, ri2 ) );
w.nodes.add( nid );
}
else if ( (i2 = l2.indexOf( "<tag k=\"" )) >= 0 )
{ // property-tag
i2 += 8;
int ri2 = l2.indexOf( '"', i2 );
String key = l2.substring( i2, ri2 );
i2 = l2.indexOf( " v=\"", ri2 );
if ( i2 >= 0 )
{
i2 += 4;
int ri3 = l2.indexOf( '"', i2 );
String value = l2.substring( i2, ri3 );
w.putTag( key, value );
}
}
else if ( l2.indexOf( "</way>" ) >= 0 )
{ // end-tag
break;
}
}
wListener.nextWay( w );
return true;
}
private boolean checkChangeset( String line ) throws Exception
{
int idx0 = line.indexOf( "<changeset id=\"" );
if ( idx0 < 0 ) return false;
if ( !line.endsWith( "/>" ) )
{
int loopcheck = 0;
for(;;)
{
String l2 = _br.readLine();
if ( l2.indexOf("</changeset>") >= 0 || ++loopcheck > 10000 ) break;
}
}
return true;
}
private boolean checkRelation( String line ) throws Exception
{
int idx0 = line.indexOf( "<relation id=\"" );
if ( idx0 < 0 ) return false;
idx0 += 14;
int idx1 = line.indexOf( '"', idx0 );
long rid = Long.parseLong( line.substring( idx0, idx1 ) );
LongList wayIds = new LongList( 16 );
List<String> roles = new ArrayList<String>(16);
RelationData r = new RelationData( rid, wayIds, roles );
// read the nodes
for(;;)
{
String l2 = _br.readLine();
if ( l2 == null ) return false;
int i2;
if ( (i2 = l2.indexOf( "<member type=\"way\" ref=\"" )) >= 0 ) // <member type="relation" ref="452156" role="backward"/>
{ // node reference
i2 += 24;
int ri2 = l2.indexOf( '"', i2 );
long wid = Long.parseLong( l2.substring( i2, ri2 ) );
int role1 = ri2 + 8;
int role2 = l2.indexOf( '"', role1 );
String role = l2.substring( role1, role2 );
r.ways.add( wid );
r.roles.add( role );
}
else if ( (i2 = l2.indexOf( "<tag k=\"" )) >= 0 )
{ // property-tag
i2 += 8;
int ri2 = l2.indexOf( '"', i2 );
String key = l2.substring( i2, ri2 );
i2 = l2.indexOf( " v=\"", ri2 );
if ( i2 >= 0 )
{
i2 += 4;
int ri3 = l2.indexOf( '"', i2 );
String value = l2.substring( i2, ri3 );
r.putTag( key, value );
}
}
else if ( l2.indexOf( "</relation>" ) >= 0 )
{ // end-tag
break;
}
}
rListener.nextRelation( r );
return true;
}
}

View file

@ -1,109 +0,0 @@
/**
* This program
* - reads an *.osm from stdin
* - writes zoom 0 tiles
*
* @author ab
*/
package btools.mapsplitter;
import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import btools.util.DiffCoderDataOutputStream;
public class OsmSplitter extends MapCreatorBase
{
private long recordCnt;
private long nodesParsed;
private long waysParsed;
private long relsParsed;
private long changesetsParsed;
private DataOutputStream wayDos;
private DataOutputStream relDos;
private DiffCoderDataOutputStream nodeDos;
public static void main(String[] args) throws Exception
{
System.out.println("*** OsmSplitter : transform an osm map to zoom 0 tiles");
if (args.length != 2)
{
System.out.println("usage : java OsmSplitter <tile-dir> <inputfile> ");
return;
}
new OsmSplitter().process(
new File( args[0] )
, new File( args[1] )
);
}
public void process (File outTileDir, File mapFile ) throws Exception
{
if ( !outTileDir.isDirectory() ) throw new RuntimeException( "out tile directory " + outTileDir + " does not exist" );
File z0 = new File( outTileDir, "0" );
z0.mkdirs();
File ways = new File( z0, "0_0.wtl" );
File nodes = new File( z0, "0_0.ntl" );
File rels = new File( z0, "0_0.rtl" );
wayDos = new DataOutputStream( new BufferedOutputStream( new FileOutputStream( ways ) ) );
relDos = new DataOutputStream( new BufferedOutputStream( new FileOutputStream( rels ) ) );
nodeDos = new DiffCoderDataOutputStream( new BufferedOutputStream( new FileOutputStream( nodes ) ) );
// read the osm map into memory
long t0 = System.currentTimeMillis();
new OsmParser2().readMap( mapFile, this, this, this );
long t1 = System.currentTimeMillis();
System.out.println( "parsing time (ms) =" + (t1-t0) );
// close all files
wayDos.close();
nodeDos.close();
System.out.println( statsLine() );
}
private void checkStats()
{
if ( (++recordCnt % 100000) == 0 ) System.out.println( statsLine() );
}
private String statsLine()
{
return "records read: " + recordCnt + " nodes=" + nodesParsed + " ways=" + waysParsed + " rels=" + relsParsed + " changesets=" + changesetsParsed;
}
@Override
public void nextNode( NodeData n ) throws Exception
{
nodesParsed++;
checkStats();
n.writeTo( nodeDos );
}
@Override
public void nextWay( WayData w ) throws Exception
{
waysParsed++;
checkStats();
w.writeTo( wayDos );
}
@Override
public void nextRelation( RelationData r ) throws Exception
{
relsParsed++;
checkStats();
r.writeTo( relDos );
}
}

View file

@ -1,74 +0,0 @@
package btools.mapsplitter;
import java.io.DataInputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import btools.util.LongList;
/**
* Container for relation data on the preprocessor level
*
* @author ab
*/
public class RelationData extends MapCreatorBase
{
public long rid;
public LongList ways;
public List<String> roles;
public RelationData( long id, LongList ways, List<String> roles )
{
rid = id;
this.ways = ways;
this.roles = roles;
}
public RelationData( DataInputStream di ) throws Exception
{
ways = new LongList( 16 );
roles = new ArrayList<String>();
rid = readId( di) ;
for (;;)
{
String key = di.readUTF();
if ( key.length() == 0 ) break;
String value = di.readUTF();
putTag( key, value );
}
for (;;)
{
long wid = readId( di );
if ( wid == -1 ) break;
ways.add( wid );
roles.add( di.readUTF() );
}
}
public void writeTo( java.io.DataOutputStream dos ) throws Exception
{
writeId( dos, rid );
if ( getTagsOrNull() != null )
{
for( Map.Entry<String,String> me : getTagsOrNull().entrySet() )
{
if ( me.getKey().length() > 0 )
{
dos.writeUTF( me.getKey() );
dos.writeUTF( me.getValue() );
}
}
}
dos.writeUTF( "" );
int size = ways.size();
for( int i=0; i < size; i++ )
{
writeId( dos, ways.get( i ) );
dos.writeUTF( roles.get(i) );
}
writeId( dos, -1 ); // stopbyte
}
}

View file

@ -1,44 +0,0 @@
package btools.mapsplitter;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
/**
* Iterate over a relation file
*
* @author ab
*/
public class RelationIterator extends MapCreatorBase
{
private RelationListener listener;
public RelationIterator( RelationListener relationListener )
{
listener = relationListener;
}
public void processFile(File relationfile) throws Exception
{
System.out.println( "*** RelationIterator reading: " + relationfile );
listener.relationFileStart( relationfile );
DataInputStream di = new DataInputStream( new BufferedInputStream ( new FileInputStream( relationfile ) ) );
try
{
for(;;)
{
RelationData r = new RelationData( di );
listener.nextRelation( r );
}
}
catch( EOFException eof )
{
di.close();
}
listener.relationFileEnd( relationfile );
}
}

View file

@ -1,18 +0,0 @@
package btools.mapsplitter;
import java.io.File;
/**
* Callbacklistener for Relations
*
* @author ab
*/
public interface RelationListener
{
void relationFileStart( File relfile ) throws Exception;
void nextRelation( RelationData data ) throws Exception;
void relationFileEnd( File relfile ) throws Exception;
}

View file

@ -1,194 +0,0 @@
package btools.mapsplitter;
import java.util.Comparator;
import java.util.HashMap;
import java.util.PriorityQueue;
/**
* Encoder for a set of tags
*
* It detects identical sets and sorts them
* into a huffman-tree according to their frequencies
*
* Adapted for 3-pass encoding (counters -&gt; statistics -&gt; encoding )
* but doesn't do anything at pass1
*/
public final class TagSetEncoder
{
private HashMap<TagSet, TagSet> identityMap;
private BitWriteBuffer bwb;
private int pass;
private TagSet freq1;
public void encodeTagSet( int[] data )
{
if ( pass == 1 )
{
return;
}
TagSet tvsProbe = new TagSet();
tvsProbe.data = data;
TagSet tvs = identityMap.get( tvsProbe );
if ( pass == 3 )
{
if ( tvs.frequency == 1 )
{
bwb.encodeBounded( freq1.range - 1, freq1.code );
encodeTagSequence( bwb, data );
}
else
{
bwb.encodeBounded( tvs.range - 1, tvs.code );
}
}
else if ( pass == 2 )
{
if ( tvs == null )
{
tvs = tvsProbe;
identityMap.put( tvs, tvs );
}
tvs.frequency++;
}
}
public void encodeDictionary( BitWriteBuffer bwb )
{
if ( ++pass == 3 )
{
freq1 = new TagSet();
PriorityQueue<TagSet> queue = new PriorityQueue<TagSet>(2*identityMap.size(), new TagSet.FrequencyComparator());
for( TagSet ts : identityMap.values() )
{
if ( ts.frequency > 1 )
{
queue.add( ts );
}
else
{
freq1.frequency++;
}
}
queue.add( freq1 );
while (queue.size() > 1)
{
TagSet node = new TagSet();
node.child1 = queue.poll();
node.child2 = queue.poll();
node.frequency = node.child1.frequency + node.child2.frequency;
queue.add( node );
}
TagSet root = queue.poll();
root.encode( bwb, 1, 0 );
}
this.bwb = bwb;
}
public TagSetEncoder()
{
identityMap = new HashMap<TagSet, TagSet>();
}
private static void encodeTagSequence( BitWriteBuffer bwb, int[] data )
{
int tagcount = data.length;
bwb.encodeInt( tagcount );
int lastIdx = -1;
for( int i=0; i<tagcount; i++ )
{
int idx = data[i];
bwb.encodeInt( idx - lastIdx -1 );
lastIdx = idx;
}
}
public static final class TagSet
{
public int[] data;
public int frequency;
public int code;
public int range;
public TagSet child1;
public TagSet child2;
public void encode( BitWriteBuffer bwb, int range, int code )
{
this.range = range;
this.code = code;
boolean isNode = child1 != null;
bwb.encodeBit( isNode );
if ( isNode )
{
child1.encode( bwb, range << 1, code );
child2.encode( bwb, range << 1, code + range );
}
else
{
bwb.encodeBit( data == null );
if ( data != null )
{
encodeTagSequence( bwb, data );
}
}
}
@Override
public boolean equals( Object o )
{
if ( o instanceof TagSet )
{
TagSet tvs = (TagSet) o;
if ( data == null )
{
return tvs.data == null;
}
if ( tvs.data == null )
{
return data == null;
}
if ( data.length != tvs.data.length )
{
return false;
}
for ( int i = 0; i < data.length; i++ )
{
if ( data[i] != tvs.data[i] )
{
return false;
}
}
return true;
}
return false;
}
@Override
public int hashCode()
{
if ( data == null )
{
return 0;
}
int h = 17;
for ( int i = 0; i < data.length; i++ )
{
h = ( h << 8 ) + data[i];
}
return h;
}
public static class FrequencyComparator implements Comparator<TagSet>
{
@Override
public int compare(TagSet tvs1, TagSet tvs2) {
if ( tvs1.frequency < tvs2.frequency )
return -1;
if ( tvs1.frequency > tvs2.frequency )
return 1;
return 0;
}
}
}
}

View file

@ -1,303 +0,0 @@
package btools.mapsplitter;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.PriorityQueue;
/**
* Encoder for the tag-value statistics
*
* @author ab
*/
public class TagValueEncoder
{
HashMap<String,Tag> tags = new HashMap<String,Tag>();
ArrayList<TagGroup> groups = new ArrayList<TagGroup>();
ByteArrayOutputStream baos ;
DataOutputStream dos;
ArrayList<String> stringList;
HashMap<String,Integer> stringMap;
ArrayList<Tag> taglist;
private int setId = 0;
private int nextIdx = 0;
private int pass;
private static String[][] taggroups = new String[][] {
{ "highway", "name", "maxspeed", "lanes", "service", "tracktype", "surface" }
, { "access", "foot", "bicycle", "motorcar", "motor_vehicle", "motorcycle", "vehicle" }
, { "building", "addr:street", "addr:housenumber", "addr:city", "addr:postcode", "addr:housename" }
};
private void encodeString( BitWriteBuffer bc, String s )
{
Integer ii = stringMap.get( s );
bc.encodeBit( ii == null );
if ( ii == null )
{
try
{
byte[] textBytes = s.getBytes( "UTF8" );
bc.encodeInt( textBytes.length );
dos.write( textBytes );
}
catch( Exception e )
{
throw new RuntimeException( e );
}
ii = Integer.valueOf( stringList.size() );
stringList.add( s );
stringMap.put( s, ii );
return;
}
bc.encodeBounded( stringList.size()-1, ii.intValue() );
}
private class TagGroup implements Comparable<TagGroup>
{
String[] names;
int count;
int lastSetId = 0;
void incCount()
{
if ( setId != lastSetId ) count++;
lastSetId = setId;
}
TagGroup( String[] names )
{
this.names = names;
for( String name : names )
{
tags.put( name, new Tag( name, this ) );
}
groups.add( this );
}
void indexTags()
{
for( String name : names )
{
Tag t = tags.get( name );
if ( t.count > 0 ) t.idx = nextIdx++;
}
}
@Override
public int compareTo( TagGroup g )
{
return g.count - count;
}
}
public TagValueEncoder()
{
for( String[] names : taggroups )
{
new TagGroup( names );
}
}
public class Tag implements Comparable<Tag>
{
Tag( String name, TagGroup group )
{
this.name = name;
this.group = group;
}
String name;
int count;
int idx;
private Object tree;
HashMap<String,Value> values = new HashMap<String,Value>();
List<Value> valueList;
TagGroup group;
void addValue( String value )
{
Value v = values.get( value );
if ( v == null )
{
v = new Value( value );
values.put( value, v );
}
v.frequency++;
count++;
}
public void encodeDictionary( BitWriteBuffer bc ) throws IOException
{
encodeString( bc, name );
PriorityQueue<Value> queue = new PriorityQueue<Value>( values.size() );
queue.addAll( values.values() );
while (queue.size() > 1)
{
queue.add( new Value( queue.poll(), queue.poll() ) );
}
queue.poll().encodeTree( bc, 1, 0 );
}
@Override
public int compareTo( Tag t )
{
return idx - t.idx;
}
}
private class Value implements Comparable<Value>
{
Value( String value )
{
this.value = value;
}
Value( Value c1, Value c2 )
{
child1 = c1;
child2 = c2;
frequency = c1.frequency + c2.frequency;
}
String value;
int code;
int range;
Value child1;
Value child2;
int frequency;
void encodeTree( BitWriteBuffer bc, int range, int code ) throws IOException
{
this.range = range;
this.code = code;
boolean isNode = child1 != null;
bc.encodeBit( isNode );
if ( isNode )
{
child1.encodeTree( bc, range << 1, code );
child2.encodeTree( bc, range << 1, code + range );
return;
}
bc.encodeBit( false ); // no inline item here
encodeString( bc, value );
}
void encode( BitWriteBuffer bc )
{
bc.encodeBounded( range - 1, code );
}
@Override
public int compareTo( Value v )
{
return frequency - v.frequency;
}
}
public byte[] encodeDictionary( BitWriteBuffer bc ) throws IOException
{
if ( ++pass == 1 )
{
return null;
}
else if ( pass == 2 )
{
nextIdx = 0;
Collections.sort( groups );
for( TagGroup g : groups )
{
g.indexTags();
}
taglist = new ArrayList<Tag>();
for( Tag t : tags.values() )
{
if ( t.count > 0 )
{
taglist.add( t );
}
}
Collections.sort( taglist );
return null;
}
stringList = new ArrayList<String>();
stringMap = new HashMap<String,Integer>();
baos = new ByteArrayOutputStream();
dos = new DataOutputStream( baos );
bc.encodeInt( taglist.size() );
for( Tag t : taglist )
{
t.encodeDictionary( bc );
}
dos.close();
byte[] textData = baos.toByteArray();
dos = null;
baos = null;
return textData;
}
public int getTagIndex( String name )
{
return tags.get( name ).idx;
}
public List<String> sortTagNames( Collection<String> col )
{
ArrayList<Tag> taglist = new ArrayList<Tag>( col.size() );
for( String name : col )
{
taglist.add( tags.get( name ) );
}
Collections.sort( taglist );
ArrayList<String> res = new ArrayList<String>( taglist.size() );
for( Tag t : taglist )
{
res.add( t.name );
}
return res;
}
public void startTagSet()
{
if ( pass == 1 )
{
setId++;
}
}
public void encodeValue( BitWriteBuffer bc, String name, String value )
{
if ( pass == 1 )
{
Tag t = tags.get( name );
if ( t == null )
{
String[] names = new String[1];
names[0] = name;
new TagGroup( names );
t = tags.get( name );
}
t.addValue( value );
}
else // pass 2+3
{
tags.get( name ).values.get( value ).encode( bc );
}
}
}

View file

@ -1,21 +0,0 @@
package btools.mapsplitter;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import btools.util.DiffCoderDataInputStream;
import btools.util.DiffCoderDataOutputStream;
/**
* Container a tile during encoding
*/
public class TileData extends MapCreatorBase
{
public int zoom;
public int x;
public int y;
public List<NodeData> nodeList;
public TileData parent;
}

View file

@ -1,555 +0,0 @@
package btools.mapsplitter;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.Deflater;
/**
* TileEncoder encodes a given node/way file pair
*
* @author ab
*/
public class TileEncoder extends MapCreatorBase
{
private Map<NodeData,NodeData> nodeMap;
private Map<WayData,WayData> wayMap;
private List<NodeData> used = new ArrayList<NodeData>();
private NodeData templateNode = new NodeData( 0, 0, 0 );
private WayData templateWay = new WayData( 0, null );
private TileData tile;
private BitWriteBuffer bwb;
private byte[] buffer;
private List<WayData> wayList;
private List<RelationData> relationList;
// statistics only
private int nTagSets;
private int nTaggedNodes;
private long totalNodes;
private long totalTaggedNodes;
private long totalWays;
private long totalTextBytes;
private long totalTiles;
private int pass;
private boolean dostats;
private TagValueEncoder tagValueEncoder;
private TagSetEncoder tagSetEnoder;
public static void main( String[] args ) throws Exception
{
System.out.println( "*** TileEncoder: encodes a given node/way file pair" );
if ( args.length != 1 )
{
System.out.println( "usage: java TileEncoder <node-file>" );
return;
}
new TileEncoder().process( new File( args[0] ) );
}
public void process( File nodeFile) throws Exception
{
TileData t0 = new TileData(); // zoom 0 dummy
process( nodeFile, t0 );
System.out.println( "**** total statistics ****" );
System.out.println( "tiles=" + totalTiles + " nodes=" + totalNodes + " taggedNodes=" + totalTaggedNodes + " ways=" + totalWays + " textBytes= " + totalTextBytes );
System.out.println( bwb.getBitReport() );
}
public void process( File nodeFile, TileData tile ) throws Exception
{
this.tile = tile;
if ( !nodeFile.exists() )
{
return;
}
System.out.println( "******* processing: " + nodeFile );
new NodeIterator( this ).processFile( nodeFile );
// process childs
int zoomStep = 2;
int xyStep = 1 << zoomStep;
int nextZoom = tile.zoom + zoomStep;
int x0 = tile.x << zoomStep;
int y0 = tile.y << zoomStep;
File childDir = new File( nodeFile.getParentFile().getParentFile(), "" + nextZoom );
for( int dx = 0; dx < xyStep; dx++ )
{
for( int dy = 0; dy < xyStep; dy++ )
{
TileData nextTile = new TileData();
nextTile.zoom = nextZoom;
nextTile.x = x0 + dx;
nextTile.y = y0 + dy;
nextTile.parent = tile;
File nextFile = new File( childDir, nextTile.x + "_" + nextTile.y + ".ntl" );
process( nextFile, nextTile );
}
}
}
@Override
public void nodeFileStart( File nodeFile ) throws Exception
{
tile.nodeList = new ArrayList<NodeData>();
nodeMap = new HashMap<NodeData,NodeData>();
wayMap = new HashMap<WayData,WayData>();
}
@Override
public void nextNode( NodeData n ) throws Exception
{
// if no level yet, it's ours
if ( n.zoom == -1 || n.zoom == tile.zoom )
{
n.zoom = tile.zoom;
n.used = true;
tile.nodeList.add( n );
}
n.localeIndex = nodeMap.size();
nodeMap.put( n,n );
n.calcGeoId();
}
@Override
public void nodeFileEnd( File nodeFile ) throws Exception
{
NodeData.sortByGeoId( tile.nodeList );
int idx = 0;
for( NodeData n : tile.nodeList )
{
n.nativeIndex = idx++;
}
// read corresponding way-file into wayList
wayList = new ArrayList<WayData>();
String name = nodeFile.getName();
String wayfilename = name.substring( 0, name.length()-3 ) + "wtl";
File wayfile = new File( nodeFile.getParent(), wayfilename );
if ( wayfile.exists() )
{
new WayIterator( this ).processFile( wayfile );
}
// read corresponding relation-file
relationList = new ArrayList<RelationData>();
String relfilename = name.substring( 0, name.length()-3 ) + "rtl";
File relfile = new File( nodeFile.getParent(), relfilename );
if ( relfile.exists() )
{
new RelationIterator( this ).processFile( relfile );
}
int nnodes = tile.nodeList.size();
tagValueEncoder = new TagValueEncoder();
tagSetEnoder = new TagSetEncoder();
long[] nodePositions = new long[nnodes];
for( int i=0; i<nnodes; i++ )
{
nodePositions[i] = tile.nodeList.get(i).gid;
}
for( pass=1;pass<=3; pass++) // 3 passes: counters, stat-collection, encoding
{
nTagSets = 0;
dostats = pass == 3;
buffer = new byte[10000000];
bwb = new BitWriteBuffer( buffer );
tagSetEnoder.encodeDictionary( bwb );
if ( dostats ) bwb.assignBits( "tagset-dictionary" );
// encode the dictionary
byte[] textData = tagValueEncoder.encodeDictionary( bwb );
if ( dostats ) bwb.assignBits( "value-dictionary" );
// encode the node positions
bwb.encodeSortedArray( nodePositions );
if ( dostats ) bwb.assignBits( "node-positions" );
if ( pass == 3 )
{
writeDownzoomRefs( bwb );
}
// encode the tagged nodes
writeTaggedNodes();
writeWays( bwb );
writeRelations( bwb );
if ( pass == 1 && nTagSets == 0 ) // stop it if nothing tagged
{
break;
}
if ( pass == 1 )
{
assignLocalIndexes();
}
if ( pass == 3 )
{
// Compress the text-bytes
Deflater compresser = new Deflater();
compresser.setInput(textData);
compresser.finish();
byte[] textHeader = new byte[textData.length + 1024];
int textHeaderLen = compresser.deflate(textHeader);
totalTiles++;
totalNodes += tile.nodeList.size();
totalTaggedNodes += nTaggedNodes;
totalTextBytes += textHeaderLen;
System.out.println( "nodes=" + tile.nodeList.size() + " taggedNodes=" + nTaggedNodes + " ways=" + wayList.size() + " textBytes= " + textHeaderLen );
// write result to file
String datafilename = name.substring( 0, name.length()-3 ) + "osb";
File datafile = new File( nodeFile.getParent(), datafilename );
DataOutputStream dos = new DataOutputStream( new FileOutputStream( datafile ) );
dos.writeInt( textData.length );
dos.writeInt( textHeaderLen );
dos.write( textHeader, 0, textHeaderLen );
int size = bwb.getEncodedLength();
dos.writeInt( size );
dos.write( buffer, 0, size );
dos.close();
}
}
if ( relfile.exists() )
{
relfile.delete();
}
if ( wayfile.exists() )
{
wayfile.delete();
}
if ( nodeFile.exists() )
{
nodeFile.delete();
}
}
@Override
public void nextWay( WayData way ) throws Exception
{
// if no level yet, it's ours
if ( way.zoom == -1 || way.zoom == tile.zoom )
{
way.zoom = tile.zoom;
way.startNodeIdx = -1;
wayList.add( way );
}
wayMap.put( way,way );
}
@Override
public void nextRelation( RelationData r ) throws Exception
{
relationList.add( r );
}
private void assignLocalIndexes()
{
used = new ArrayList<NodeData>();
for( NodeData n : nodeMap.values() )
{
if ( n.used )
{
used.add( n );
}
}
NodeData.sortByGeoId( used );
int idx = 0;
for( NodeData n : used )
{
n.localeIndex = idx++;
}
}
private void writeDownzoomRefs( BitWriteBuffer bwb )
{
// total locale nodes
bwb.encodeInt( used.size() );
for( int zoom=0; zoom<tile.zoom; zoom++ )
{
// count
int cnt = 0;
for( NodeData n : used )
{
if ( n.zoom == zoom )
{
cnt++;
}
}
long[] localeIndexes = new long[cnt];
long[] nativeIndexes = new long[cnt];
int idx = 0;
for( NodeData n : used )
{
if ( n.zoom == zoom )
{
// System.out.println( " ---> locale=" + n.localeIndex + " native=" + n.nativeIndex );
localeIndexes[idx] = n.localeIndex;
nativeIndexes[idx] = n.nativeIndex;
idx++;
}
}
bwb.encodeSortedArray( localeIndexes );
if ( dostats ) bwb.assignBits( "localindexes" );
bwb.encodeSortedArray( nativeIndexes );
if ( dostats ) bwb.assignBits( "nativeindexes" );
}
}
private int getLocaleIndexForNid( long nid )
{
templateNode.nid = nid;
NodeData n = nodeMap.get( templateNode );
if ( n == null ) throw new IllegalArgumentException( "nid=" + nid + " not found" );
n.used = true;
return n.localeIndex;
}
private void encodeWay( BitWriteBuffer bwb, WayData way ) throws Exception
{
int nnodes = way.nodes.size();
boolean closedPoly = way.nodes.get(0) == way.nodes.get(nnodes-1);
if ( closedPoly )
{
nnodes--;
}
if ( nnodes < 2 )
{
return;
}
writeTags( way.getTagsOrNull() );
bwb.encodeBit( closedPoly );
bwb.encodeInt( nnodes-2 );
if ( dostats ) bwb.assignBits( "way-node-count" );
// determine the tile-index for each node
int lastIdx = 0;
for (int i=0; i<nnodes; i++ )
{
long nid = way.nodes.get(i);
int idx = getLocaleIndexForNid( nid );
if ( i == 0 )
{
way.startNodeIdx = idx;
}
else
{
int delta = idx-lastIdx;
if ( delta == 0 )
{
System.out.println( "double node in way, ignoring" );
way.startNodeIdx = -1;
return;
}
boolean negative = delta < 0;
bwb.encodeBit( negative );
bwb.encodeLong( (negative ? -delta : delta) -1 );
if ( dostats ) bwb.assignBits( "way-node-idx-delta" );
}
lastIdx = idx;
}
}
private void writeWays( BitWriteBuffer bwb ) throws Exception
{
// in pass 3, sort ways according startNodeIdx and encode start-indexes
if ( pass == 3 )
{
if ( wayList.size() > 0 )
{
ArrayList<WayData> goodWays = new ArrayList<WayData>();
for( WayData w : wayList )
{
if ( w.startNodeIdx >= 0 )
{
goodWays.add( w );
}
}
WayData.sortByStartNode( goodWays );
wayList = goodWays;
}
// encode start-node-indexes
int waycount = wayList.size();
long[] startIndexes = new long[waycount];
int i = 0;
for( WayData w : wayList )
{
w.nativeIndex = i;
startIndexes[i++] = w.startNodeIdx;
}
bwb.encodeSortedArray( startIndexes );
if ( dostats ) bwb.assignBits( "way-start-idx" );
}
for( WayData way : wayList )
{
encodeWay( bwb, way );
}
}
private void writeRelations( BitWriteBuffer bwb ) throws Exception
{
bwb.encodeInt( relationList.size() );
if ( dostats ) bwb.assignBits( "relation-count" );
for( RelationData rel : relationList )
{
encodeRelation( bwb, rel );
}
}
private void encodeRelation( BitWriteBuffer bwb, RelationData rel ) throws Exception
{
writeTags( rel.getTagsOrNull() );
int size = rel.ways.size();
if ( dostats ) bwb.assignBits( "way-node-count" );
// count valid members
int validMembers = 0;
for( int i=0; i < size; i++ )
{
long wid = rel.ways.get( i );
String role = rel.roles.get(i);
templateWay.wid = wid;
WayData w = wayMap.get( templateWay );
if ( w == null ) continue;
validMembers++;
}
bwb.encodeInt( validMembers );
for( int i=0; i < size; i++ )
{
long wid = rel.ways.get( i );
String role = rel.roles.get(i);
templateWay.wid = wid;
WayData w = wayMap.get( templateWay );
if ( w == null ) continue;
int zoomDelta = tile.zoom - w.zoom;
bwb.encodeInt( zoomDelta );
bwb.encodeInt( w.nativeIndex );
tagValueEncoder.encodeValue( bwb, "role", role );
}
}
private void writeTaggedNodes() throws Exception
{
// count tagged nodes
int cnt = 0;
for( int idx=0; idx<tile.nodeList.size(); idx++ )
{
NodeData n = tile.nodeList.get( idx );
if ( n.zoom == tile.zoom && n.getTagsOrNull() != null )
{
cnt++;
}
}
// build index array
long[] taggedIndexes = new long[cnt];
int i = 0;
for( int idx=0; idx<tile.nodeList.size(); idx++ )
{
if ( tile.nodeList.get( idx ).getTagsOrNull() != null )
{
taggedIndexes[i++] = idx;
}
}
nTaggedNodes = cnt;
bwb.encodeSortedArray( taggedIndexes );
if ( dostats ) bwb.assignBits( "tagged-node-idx" );
for( int idx=0; idx<tile.nodeList.size(); idx++ )
{
NodeData n = tile.nodeList.get( idx );
if ( n.getTagsOrNull() != null )
{
writeTags( n.getTagsOrNull() );
}
}
}
private void writeTags( HashMap<String, String> tags ) throws Exception
{
List<String> names;
if ( tags == null )
{
tags = new HashMap<String, String>();
}
if ( pass > 1 )
{
// create tagset as sorted int-array
names = tagValueEncoder.sortTagNames( tags.keySet() );
int ntags = names.size();
int[] tagset = new int[ ntags ];
for( int i=0; i<ntags; i++ )
{
tagset[i] = tagValueEncoder.getTagIndex( names.get(i) );
}
// ... and encode it
tagSetEnoder.encodeTagSet( tagset );
if ( dostats ) bwb.assignBits( "tag-set" );
}
else
{
nTagSets++;
names = new ArrayList<String>( tags.keySet() ); // unsorted is o.k. in pass 1
}
// then encode the values
tagValueEncoder.startTagSet();
for( String name : names )
{
String value = tags.get( name );
tagValueEncoder.encodeValue( bwb, name, value );
if ( dostats ) bwb.assignBits( "value-index" );
}
}
}

View file

@ -1,492 +0,0 @@
package btools.mapsplitter;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import btools.util.DenseLongMap;
import btools.util.TinyDenseLongMap;
/**
* TileSplitter splits a tile into pieces
*/
public class TileSplitter extends MapCreatorBase
{
private NodeData templateNode = new NodeData( 0, 0, 0 );
private DenseLongMap nodeIndexMap;
private DenseLongMap bigWayMemberMap;
private DenseLongMap wayIndexMap;
private DenseLongMap bigRelMemberMap;
private DenseLongMap relIndexMap;
private Map<NodeData,NodeData> nodeMap;
private List<NodeData> thisLevelNodes;
private Map<Long,Integer> thisLevelNodesIndexes;
private List<WayData> thisLevelWays;
private Map<Long,Integer> thisLevelWaysIndexes;
private int level;
private int baseLon;
private int baseLat;
private int nodeCount = 0;
private String typeSuffix;
private boolean inPassLoop;
private int pass; // 1 == build tileIndexMap, 2 == collect this-level-nodes, 3 == output nodes
private File inTileDir;
public static void main(String[] args) throws Exception
{
System.out.println("*** TileSplitter: cut tiles into 16 pieces");
if (args.length != 1)
{
System.out.println("usage: java TileSplitter <tile-dir>" );
return;
}
new TileSplitter().process( new File( args[0] ) );
}
public void process( File tileDir) throws Exception
{
for( int level = 0; level < 12; level += 2 )
{
process( tileDir, level );
}
}
public void process( File tileDir, int level ) throws Exception
{
System.out.println("processing level: " + level );
inTileDir = new File( tileDir, "" + (level) );
outTileDir = new File( tileDir, "" + (level+2) );
outTileDir.mkdirs();
this.level = level;
// *** initialize 3-pass processing of nodes, ways and relations
inPassLoop = false;
new NodeIterator( this ).processDir( inTileDir, ".ntl" );
}
@Override
public void nodeFileStart( File nodeFile ) throws Exception
{
if ( !inPassLoop )
{
inPassLoop = true;
pass = 1;
new NodeIterator( this ).processFile( nodeFile );
pass = 2;
new NodeIterator( this ).processFile( nodeFile );
pass = 3;
new NodeIterator( this ).processFile( nodeFile );
pass = 4;
inPassLoop = false;
}
System.out.println( "nodeFileStart pass=" + pass );
if ( pass == 1 )
{
getBaseTileFromName( nodeFile.getName() );
nodeIndexMap = Boolean.getBoolean( "useDenseMaps" ) ? new DenseLongMap() : new TinyDenseLongMap();
}
else if ( pass == 2 )
{
}
else if ( pass == 3 )
{
nodeMap = new HashMap<NodeData,NodeData>();
thisLevelNodes = new ArrayList<NodeData>();
}
else // nodePass = 4
{
NodeData.sortByGeoId( thisLevelNodes );
thisLevelNodesIndexes = new HashMap<Long,Integer>();
int idx = 0;
for( NodeData n : thisLevelNodes )
{
thisLevelNodesIndexes.put( Long.valueOf( n.nid ), Integer.valueOf( idx++ ) );
}
thisLevelNodes = null;
}
typeSuffix = "ntl";
}
private void getBaseTileFromName( String name )
{
System.out.println( "getBaseTileFromName: " + name );
int idx1 = name.indexOf( '_' );
int idx2 = name.indexOf( '.' );
baseLon = Integer.parseInt( name.substring( 0, idx1 ) );
baseLat = Integer.parseInt( name.substring( idx1+1, idx2 ) );
}
@Override
public void nextNode( NodeData n ) throws Exception
{
int tidx = getTileIndex( n );
if ( pass == 1 )
{
nodeCount++;
nodeIndexMap.put( n.nid, tidx );
}
else if ( pass == 2 )
{
}
else
{
boolean usedHere = bigWayMemberMap.getInt( n.nid ) == 0;
if ( usedHere ) // if used on this level...
{
// if no level yet, this is it
if ( n.zoom == -1 )
{
n.zoom = level;
}
}
if ( pass == 3 )
{
if ( n.zoom != -1 )
{
n.calcGeoId();
nodeMap.put( n,n );
if ( n.zoom == level )
{
thisLevelNodes.add( n );
}
}
}
else // pass == 4
{
// add the index
if ( n.zoom == level )
{
n.nativeIndex = thisLevelNodesIndexes.get( Long.valueOf( n.nid ) );
}
if ( usedHere )
{
n.writeTo( getOutStreamForTile( 16 ) );
}
n.writeTo( getOutStreamForTile( tidx ) ); // write to subtile
}
}
}
@Override
public void nodeFileEnd( File nodeFile ) throws Exception
{
System.out.println( "nodeFileEnd pass=" + pass );
closeTileOutStreams();
File parentNodes = new File( outTileDir, getNameForTile( 16 ) );
// read corresponding way-file
if ( pass == 2 )
{
bigWayMemberMap = Boolean.getBoolean( "useDenseMaps" ) ? new DenseLongMap() : new TinyDenseLongMap();
}
String name = nodeFile.getName();
String wayfilename = name.substring( 0, name.length()-3 ) + "wtl";
File wayfile = new File( inTileDir, wayfilename );
if ( wayfile.exists() )
{
new WayIterator( this ).processFile( wayfile );
}
// read corresponding relation-file
if ( pass == 1 )
{
bigRelMemberMap = Boolean.getBoolean( "useDenseMaps" ) ? new DenseLongMap() : new TinyDenseLongMap();
}
String relfilename = name.substring( 0, name.length()-3 ) + "rtl";
File relfile = new File( inTileDir, relfilename );
if ( relfile.exists() )
{
new RelationIterator( this ).processFile( relfile );
}
if ( pass == 4 )
{
nodeFile.delete();
if ( parentNodes.exists() )
{
parentNodes.renameTo( nodeFile );
}
else if ( nodeCount > 0 )
{
nodeFile.createNewFile(); // create even empty to signal existence of childs
}
}
}
@Override
public void wayFileStart( File wayFile ) throws Exception
{
System.out.println( "wayFileStart pass=" + pass );
if ( pass == 1 )
{
wayIndexMap = Boolean.getBoolean( "useDenseMaps" ) ? new DenseLongMap() : new TinyDenseLongMap();
}
else if ( pass == 3 )
{
thisLevelWays = new ArrayList<WayData>();
}
else if ( pass == 4 )
{
WayData.sortByStartNode( thisLevelWays );
thisLevelWaysIndexes = new HashMap<Long,Integer>();
int idx = 0;
for( WayData w : thisLevelWays )
{
thisLevelWaysIndexes.put( Long.valueOf( w.wid ), Integer.valueOf( idx++ ) );
}
thisLevelWays = null;
}
typeSuffix = "wtl";
}
@Override
public void nextWay( WayData w ) throws Exception
{
int widx = getTileIndex( w );
if ( widx == -1 )
{
System.out.println( "************ invalid way: " + w.wid );
return;
}
if ( pass == 1 )
{
wayIndexMap.put( w.wid, widx );
}
else // pass >= 2
{
boolean usedHere = bigRelMemberMap.getInt( w.wid ) == 0;
if ( usedHere || widx == 16 )
{
// if no level yet, this is it
if ( w.zoom == -1 )
{
w.zoom = level;
}
if ( pass == 2 )
{
int nnodes = w.nodes.size();
for (int i=0; i<nnodes; i++ )
{
bigWayMemberMap.put( w.nodes.get(i), 0 );
}
}
}
if ( pass == 3 )
{
if ( w.zoom == level )
{
w.startNodeIdx = getLocaleIndexForNid( w.nodes.get(0) );
thisLevelWays.add( w );
}
}
if ( pass == 4 )
{
if ( w.zoom == level )
{
w.nativeIndex = thisLevelWaysIndexes.get( Long.valueOf( w.wid ) );
}
if ( usedHere && widx != 16 )
{
w.writeTo( getOutStreamForTile( 16 ) );
}
w.writeTo( getOutStreamForTile( widx ) );
}
}
}
@Override
public void wayFileEnd( File wayFile ) throws Exception
{
System.out.println( "wayFileEnd pass=" + pass );
closeTileOutStreams();
if ( pass == 4 )
{
wayFile.delete();
File parentWays = new File( outTileDir, getNameForTile( 16 ) );
if ( parentWays.exists() )
{
parentWays.renameTo( wayFile );
}
}
}
@Override
public void relationFileStart( File relFile ) throws Exception
{
System.out.println( "relFileStart pass=" + pass );
if ( pass == 1 )
{
relIndexMap = Boolean.getBoolean( "useDenseMaps" ) ? new DenseLongMap() : new TinyDenseLongMap();
}
else if ( pass == 2 )
{
}
else // nodePass = 3
{
}
typeSuffix = "rtl";
}
@Override
public void nextRelation( RelationData r ) throws Exception
{
int ridx = getTileIndex( r );
if ( ridx == -1 )
{
System.out.println( "************ invalid relation: " + r.rid );
return;
}
if ( pass == 1 )
{
relIndexMap.put( r.rid, ridx );
}
if ( pass == 1 && ridx == 16 )
{
int nways = r.ways.size();
for (int i=0; i<nways; i++ )
{
bigRelMemberMap.put( r.ways.get(i), 0 );
}
}
if ( pass == 4 )
{
r.writeTo( getOutStreamForTile( ridx ) );
}
}
@Override
public void relationFileEnd( File relFile ) throws Exception
{
System.out.println( "relFileEnd pass=" + pass );
closeTileOutStreams();
if ( pass == 4 )
{
relFile.delete();
File parentRels = new File( outTileDir, getNameForTile( 16 ) );
if ( parentRels.exists() )
{
parentRels.renameTo( relFile );
}
}
}
private int getLocaleIndexForNid( long nid )
{
templateNode.nid = nid;
NodeData n = nodeMap.get( templateNode );
if ( n == null ) throw new IllegalArgumentException( "nid=" + nid + " not found" );
n.used = true;
return n.localeIndex;
}
private int getTileIndex( NodeData n )
{
int idxLon = ( n.ilon >> ( 26 - level ) ) & 3;
int idxLat = ( n.ilat >> ( 26 - level ) ) & 3;
return 4 * idxLon + idxLat;
}
private int getTileIndex( WayData w )
{
int nnodes = w.nodes.size();
int wayTileIndex = 16;
// determine the tile-index for each node
for (int i=0; i<nnodes; i++ )
{
int tileIndex = nodeIndexMap.getInt( w.nodes.get(i) );
if ( tileIndex == -1 )
{
return -1;
}
if ( wayTileIndex == 16 )
{
wayTileIndex = tileIndex;
}
else if ( tileIndex != wayTileIndex )
{
return 16;
}
}
return wayTileIndex;
}
private int getTileIndex( RelationData r )
{
int nways = r.ways.size();
int relTileIndex = 16;
boolean hasAny = false;
// determine the tile-index for each way
for (int i=0; i<nways; i++ )
{
int tileIndex = wayIndexMap.getInt( r.ways.get(i) );
if ( tileIndex == -1 )
{
continue;
}
hasAny = true;
if ( relTileIndex == 16 )
{
relTileIndex = tileIndex;
}
else if ( tileIndex != relTileIndex )
{
return 16;
}
}
return hasAny ? relTileIndex : -1;
}
protected String getNameForTile( int tileIndex )
{
if ( tileIndex == 16 )
{
return "parent." + typeSuffix;
}
int idxLon = baseLon * 4 + (tileIndex >> 2);
int idxLat = baseLat * 4 + (tileIndex & 3);
return idxLon + "_" + idxLat + "." + typeSuffix;
}
}

View file

@ -1,159 +0,0 @@
package btools.mapsplitter;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import btools.util.LongList;
/**
* Container for waydata on the preprocessor level
*
* @author ab
*/
public class WayData extends MapCreatorBase
{
public long wid;
public LongList nodes;
public int startNodeIdx;
private int minx;
private int miny;
private int maxx;
private int maxy;
public int zoom = -1; // the zoom level this node is on
public int nativeIndex; // the index along all NATIVE ways of it's tile
public void calcBBox( List<NodeData> nodeList )
{
int nn = nodes.size();
for( int i=0; i<nn; i++ )
{
NodeData n = nodeList.get((int)nodes.get(i));
if ( i == 0 )
{
minx = maxx = n.ilon;
miny = maxy = n.ilat;
}
else
{
if ( n.ilon < minx ) minx = n.ilon;
if ( n.ilon > maxx ) maxx = n.ilon;
if ( n.ilat < miny ) miny = n.ilat;
if ( n.ilat > maxy ) maxy = n.ilat;
}
}
}
public boolean inBBox( int z, int x, int y )
{
int shift = 28-z;
int x0 = x << shift;
int x1 = (x+1) << shift;
int y0 = y << shift;
int y1 = (y+1) << shift;
boolean outofbox = x1 < minx || x0 >= maxx || y1 < miny || y0 >= maxy;
return !outofbox;
}
public WayData( long id )
{
wid = id;
nodes = new LongList( 16 );
}
public WayData( long id, LongList nodes )
{
wid = id;
this.nodes = nodes;
}
public WayData( DataInputStream di ) throws Exception
{
zoom = di.readInt();
nativeIndex = di.readInt();
nodes = new LongList( 16 );
wid = readId( di) ;
for (;;)
{
String key = di.readUTF();
if ( key.length() == 0 ) break;
String value = di.readUTF();
putTag( key, value );
}
for (;;)
{
long nid = readId( di );
if ( nid == -1 ) break;
nodes.add( nid );
}
}
public void writeTo( DataOutputStream dos ) throws Exception
{
dos.writeInt( zoom );
dos.writeInt( nativeIndex );
writeId( dos, wid );
if ( getTagsOrNull() != null )
{
for( Map.Entry<String,String> me : getTagsOrNull().entrySet() )
{
if ( me.getKey().length() > 0 )
{
dos.writeUTF( me.getKey() );
dos.writeUTF( me.getValue() );
}
}
}
dos.writeUTF( "" );
int size = nodes.size();
for( int i=0; i < size; i++ )
{
writeId( dos, nodes.get( i ) );
}
writeId( dos, -1 ); // stopbyte
}
public static void sortByStartNode( List<WayData> ways )
{
Collections.sort( ways, new Comparator<WayData>()
{
@Override
public int compare(WayData w1, WayData w2)
{
long d = w1.startNodeIdx - w2.startNodeIdx;
// for equal start indexes sort by wid
if ( d == 0L )
{
d = w1.wid - w2.wid;
}
return d == 0 ? 0 : ( d < 0 ? -1 : 1 );
}
} );
}
@Override
public boolean equals( Object o )
{
if ( o instanceof WayData )
{
WayData w = (WayData) o;
return w.wid == wid;
}
return false;
}
@Override
public int hashCode()
{
return (int)((wid >> 32) ^ wid);
}
}

View file

@ -1,45 +0,0 @@
package btools.mapsplitter;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
/**
* Iterate over a singe wayfile or a directory
* of waytiles and feed the ways to the callback listener
*
* @author ab
*/
public class WayIterator extends MapCreatorBase
{
private WayListener listener;
public WayIterator( WayListener wayListener )
{
listener = wayListener;
}
public void processFile(File wayfile) throws Exception
{
System.out.println( "*** WayIterator reading: " + wayfile );
listener.wayFileStart( wayfile );
DataInputStream di = new DataInputStream( new BufferedInputStream ( new FileInputStream( wayfile ) ) );
try
{
for(;;)
{
WayData w = new WayData( di );
listener.nextWay( w );
}
}
catch( EOFException eof )
{
di.close();
}
listener.wayFileEnd( wayfile );
}
}

View file

@ -1,17 +0,0 @@
package btools.mapsplitter;
import java.io.File;
/**
* Callbacklistener for WayIterator
*
* @author ab
*/
public interface WayListener
{
void wayFileStart( File wayfile ) throws Exception;
void nextWay( WayData data ) throws Exception;
void wayFileEnd( File wayfile ) throws Exception;
}

View file

@ -1,141 +0,0 @@
package btools.mapsplitter;
import java.util.Arrays;
import java.util.Random;
import org.junit.Assert;
import org.junit.Test;
import btools.mapdecoder.BitReadBuffer;
import btools.mapdecoder.CharDecoder;
public class BitCodingTest
{
// @Test
public void charEncodeDecodeTest()
{
byte[] ab = new byte[4000];
BitWriteBuffer bwb = new BitWriteBuffer( ab );
CharEncoder ce = new CharEncoder();
for( int pass=1; pass<=3; pass++ )
{
ce.encodeDictionary( bwb );
for ( char c = 'a'; c <= 'z'; c++ )
{
ce.encode( Character.valueOf( c ) );
}
}
BitReadBuffer brb = new BitReadBuffer( ab );
CharDecoder cd = new CharDecoder( brb );
for ( char c = 'a'; c <= 'z'; c++ )
{
Character c1 = cd.decode();
Assert.assertTrue( "char mismatch c=" + c + "c1=" + c1, c == c1.charValue() );
}
}
@Test
public void varBitsEncodeDecodeTest()
{
byte[] ab = new byte[4000];
BitWriteBuffer bwb = new BitWriteBuffer( ab );
for ( int i = 0; i < 1000; i++ )
{
bwb.encodeInt( i );
bwb.encodeLong( i );
}
BitReadBuffer brb = new BitReadBuffer( ab );
for ( int i = 0; i < 1000; i++ )
{
int value = brb.decodeInt();
Assert.assertTrue( "int value mismatch i=" + i + "v=" + value, value == i );
long lvalue = brb.decodeLong();
Assert.assertTrue( "long value mismatch i=" + i + "v=" + lvalue, value == i );
}
}
@Test
public void boundedEncodeDecodeTest()
{
byte[] ab = new byte[581969];
BitWriteBuffer bwb = new BitWriteBuffer( ab );
for ( int max = 1; max < 1000; max++ )
{
for ( int val = 0; val <= max; val++ )
{
bwb.encodeBounded( max, val );
}
}
BitReadBuffer brb = new BitReadBuffer( ab );
for ( int max = 1; max < 1000; max++ )
{
for ( int val = 0; val <= max; val++ )
{
long valDecoded = brb.decodeBounded( max );
if ( valDecoded != val )
{
Assert.fail( "mismatch at max=" + max + " " + valDecoded + "<>" + val );
}
}
}
}
@Test
public void sortedLongArrayEncodeDecodeTest()
{
Random rand = new Random(1234);
int size = 20;
long[] values = new long[size];
for ( int i = 0; i < size; i++ )
{
values[i] = rand.nextInt() & 0x0fffffff;
}
values[5] = 175384; // force collision
values[8] = 175384;
values[15] = 275384; // force neighbours
values[18] = 275385;
encodeDecodeArray( "Test1", values );
values = new long[1];
values[0] = 0x134567890123456L;
encodeDecodeArray( "Test2", values );
values = new long[0];
encodeDecodeArray( "Test3", values );
values = new long[100000];
for ( int i = 0; i < values.length; i++ )
{
values[i] = (((long)rand.nextInt())&0xffffffffL) << rand.nextInt(26); // 32 + 25 bits
}
encodeDecodeArray( "Test4", values );
}
private void encodeDecodeArray( String testName, long[] values )
{
Arrays.sort( values );
byte[] ab = new byte[3000000];
BitWriteBuffer bwb = new BitWriteBuffer( ab );
bwb.encodeSortedArray( values );
long[] decodedValues = new BitReadBuffer( ab ).decodeSortedArray();
for ( int i = 0; i < values.length; i++ )
{
if ( values[i] != decodedValues[i] )
{
Assert.fail( "mismatch at " + testName + " i=" + i + " " + values[i] + "<>" + decodedValues[i] );
}
}
}
}

View file

@ -1,37 +0,0 @@
package btools.mapsplitter;
import java.util.Random;
import java.util.HashMap;
import org.junit.Assert;
import org.junit.Test;
import java.net.URL;
import java.io.File;
import btools.mapdecoder.TileDecoder;
import btools.mapdecoder.OsmTile;
public class MapsplitterTest
{
@Test
public void mapsplitterTest() throws Exception
{
URL mapurl = this.getClass().getResource( "/dreieich.osm.gz" );
Assert.assertTrue( "test-osm-map dreieich.osm not found", mapurl != null );
File mapfile = new File(mapurl.getFile());
File workingDir = mapfile.getParentFile();
File tmpdir = new File( workingDir, "tmp2" );
tmpdir.mkdir();
// run OsmSplitter
File tiles = new File( tmpdir, "tiles" );
tiles.mkdir();
new OsmSplitter().process( tiles, mapfile );
// run TileSplitter to split up to level 12
new TileSplitter().process( tiles );
new TileEncoder().process( new File( tiles, "0/0_0.ntl" ) );
new TileDecoder().process( tiles, null, 12, 2147, 1389 );
}
}

View file

@ -1,45 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.btools</groupId>
<artifactId>brouter</artifactId>
<version>1.4.11</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>brouter-mem-router</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.btools</groupId>
<artifactId>brouter-util</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.btools</groupId>
<artifactId>brouter-expressions</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.btools</groupId>
<artifactId>brouter-mapaccess</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.btools</groupId>
<artifactId>brouter-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.btools</groupId>
<artifactId>brouter-map-creator</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
</dependencies>
</project>

View file

@ -1,317 +0,0 @@
package btools.memrouter;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import btools.expressions.BExpressionContextWay;
import btools.expressions.BExpressionMetaData;
import btools.mapaccess.OsmPos;
import btools.mapcreator.MapCreatorBase;
import btools.mapcreator.NodeData;
import btools.mapcreator.NodeIterator;
import btools.mapcreator.WayData;
import btools.mapcreator.WayIterator;
import btools.util.ByteArrayUnifier;
import btools.util.CompactLongMap;
import btools.util.FrozenLongMap;
import btools.util.LazyArrayOfLists;
/**
* GraphLoader loads the routing graph from
* the nodes+way files (much like mapcreator.WayLinker)
*
* @author ab
*/
public class GraphLoader extends MapCreatorBase
{
private CompactLongMap<OsmNodeP> nodesMap;
private Map<String, StationNode> stationMap;
private BExpressionContextWay expctxWay;
private ByteArrayUnifier abUnifier;
private int currentTile;
private long linksLoaded = 0L;
private long nodesLoaded = 0L;
private static final int MAXTILES = 2592;
private List<LazyArrayOfLists<OsmNodeP>> seglistsArray = new ArrayList<LazyArrayOfLists<OsmNodeP>>(2592);
public static void main(String[] args) throws Exception
{
System.out.println("*** GraphLoader: load a routing graph in memory");
if (args.length != 5)
{
System.out.println("usage: java GraphLoader <node-tiles-in> <way-tiles-in> <lookup-file> <profile-file> <fahtplan-file>");
return;
}
BExpressionMetaData meta = new BExpressionMetaData();
// read lookup + profile for lookup-version + access-filter
BExpressionContextWay expctxWay = new BExpressionContextWay(meta);
File lookupFile = new File( args[2] );
File profileFile = new File( args[3] );
meta.readMetaData( lookupFile );
expctxWay.parseFile( profileFile, "global" );
GraphLoader graph = new GraphLoader();
File[] fahrplanFiles = new File[2];
fahrplanFiles[0] = new File( args[4] );
fahrplanFiles[1] = new File( args[5] );
graph.process( new File( args[0] ), new File( args[1] ), fahrplanFiles, expctxWay );
}
public void process( File nodeTilesIn, File wayTilesIn, File[] fahrplanFiles, BExpressionContextWay expctxWay ) throws Exception
{
this.expctxWay = expctxWay;
seglistsArray = new ArrayList<LazyArrayOfLists<OsmNodeP>>(MAXTILES);
for( int i=0; i < MAXTILES; i++ )
{
seglistsArray.add( null );
}
abUnifier = new ByteArrayUnifier( 16384, false );
nodesMap = new CompactLongMap<OsmNodeP>();
// read all nodes
new NodeIterator( this, false ).processDir( nodeTilesIn, ".u5d" );
// freeze the nodes-map
nodesMap = new FrozenLongMap<OsmNodeP>( nodesMap );
// trim the list array
for( int i=0; i<MAXTILES; i++ )
{
if ( seglistsArray.get(i) != null )
{
seglistsArray.get(i).trimAll();
}
}
// then read the ways
new WayIterator( this, false ).processDir( wayTilesIn, ".wt5" );
nodesMap = null; // don't need that anymore
System.out.println( "nodesLoaded=" + nodesLoaded + " linksLoaded=" + linksLoaded );
// now load the train-schedules
stationMap = ScheduleParser.parseTrainTable( fahrplanFiles, this, expctxWay );
System.gc();
long mem = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
System.out.println( "memory after graph loading: " + mem / 1024 / 1024 + " MB" );
}
public OsmNodeP matchNodeForPosition( OsmPos pos, BExpressionContextWay wayCtx, boolean transitonly )
{
if ( transitonly )
{
return matchStationForPosition( pos );
}
int ilon = pos.getILon();
int ilat = pos.getILat();
List<OsmNodeP> nodes = new ArrayList<OsmNodeP>();
nodes.addAll( subListForPos( ilon-6125, ilat-6125 ) );
nodes.addAll( subListForPos( ilon-6125, ilat+6125 ) );
nodes.addAll( subListForPos( ilon+6125, ilat-6125 ) );
nodes.addAll( subListForPos( ilon+6125, ilat+6125 ) );
int mindist = Integer.MAX_VALUE;
OsmNodeP bestmatch = null;
for( OsmNodeP node : nodes )
{
if ( transitonly )
{
StationNode sn = getStationNode( node );
if ( sn != null )
{
int dist = pos.calcDistance( sn );
if ( dist < mindist )
{
mindist = dist;
bestmatch = sn;
}
}
continue;
}
int dist = pos.calcDistance( node );
if ( dist < mindist )
{
if ( wayCtx == null || hasRoutableLinks(node, wayCtx) )
{
mindist = dist;
bestmatch = node;
}
}
}
return bestmatch;
}
private StationNode getStationNode( OsmNodeP node )
{
for( OsmLinkP link = node.getFirstLink(); link != null; link = link.getNext( node ) )
{
OsmNodeP tn = link.getTarget( node );
if ( tn instanceof StationNode )
{
return (StationNode)tn;
}
}
return null;
}
public OsmNodeP matchStationForPosition( OsmPos pos )
{
int mindist = Integer.MAX_VALUE;
OsmNodeP bestmatch = null;
for( OsmNodeP node : stationMap.values() )
{
int dist = pos.calcDistance( node );
if ( dist < mindist )
{
mindist = dist;
bestmatch = node;
}
}
return bestmatch;
}
private boolean hasRoutableLinks( OsmNodeP node, BExpressionContextWay wayCtx )
{
for( OsmLinkP link = node.getFirstLink(); link != null; link = link.getNext( node ) )
{
if ( link.isWayLink() )
{
wayCtx.evaluate( false, link.descriptionBitmap );
if ( wayCtx.getCostfactor() < 10000.f )
{
return true;
}
}
}
return false;
}
@Override
public void nodeFileStart( File nodefile ) throws Exception
{
currentTile = tileForFilename( nodefile.getName() );
seglistsArray.set(currentTile, new LazyArrayOfLists<OsmNodeP>(160000) );
System.out.println( "nodes currentTile=" + currentTile );
}
@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;
// add to the map
nodesMap.fastPut( data.nid, n );
// add also to the list array
subListForPos( n.ilon, n.ilat ).add( n );
nodesLoaded++;
}
@Override
public boolean wayFileStart( File wayfile ) throws Exception
{
currentTile = tileForFilename( wayfile.getName() );
System.out.println( "ways currentTile=" + currentTile );
return true;
}
@Override
public void nextWay( WayData way ) throws Exception
{
byte[] description = abUnifier.unify( way.description );
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 )
{
if ( tileForPos( n1.ilon, n1.ilat ) == currentTile )
{
OsmLinkP link = n2.createLink(n1);
link.descriptionBitmap = description;
linksLoaded++;
}
}
if ( n2 != null )
{
n2.wayBits |= wayBits;
}
}
}
// from BInstallerView.java
private int tileForFilename( String filename )
{
String basename = filename.substring( 0, filename.length() - 4 );
String uname = basename.toUpperCase();
int idx = uname.indexOf( "_" );
if ( idx < 0 ) return -1;
String slon = uname.substring( 0, idx );
String slat = uname.substring( idx+1 );
int ilon = slon.charAt(0) == 'W' ? -Integer.valueOf( slon.substring(1) ) :
( slon.charAt(0) == 'E' ? Integer.valueOf( slon.substring(1) ) : -1 );
int ilat = slat.charAt(0) == 'S' ? -Integer.valueOf( slat.substring(1) ) :
( slat.charAt(0) == 'N' ? Integer.valueOf( slat.substring(1) ) : -1 );
if ( ilon < -180 || ilon >= 180 || ilon % 5 != 0 ) return -1;
if ( ilat < - 90 || ilat >= 90 || ilat % 5 != 0 ) return -1;
return (ilon+180) / 5 + 72*((ilat+90)/5);
}
private int tileForPos( int ilon, int ilat )
{
return ilon / 5000000 + 72 * ( ilat / 5000000 );
}
private int subIdxForPos( int ilon, int ilat )
{
int lonModulo = ilon % 5000000;
int latModulo = ilat % 5000000;
return ( lonModulo / 12500 ) + 400 * (latModulo / 12500);
}
private List<OsmNodeP> subListForPos( int ilon, int ilat )
{
if ( ilon < 0 || ilon >= 360000000 || ilat < 0 || ilat >= 180000000 )
{
throw new IllegalArgumentException( "illegal position: " + ilon + " " + ilat );
}
int tileNr = tileForPos( ilon, ilat );
if ( seglistsArray.get(tileNr) == null ) return new ArrayList<OsmNodeP>();
return seglistsArray.get(tileNr).getList( subIdxForPos( ilon, ilat ) );
}
}

View file

@ -1,77 +0,0 @@
/**
* Set off departure offsets (immutable)
*
* @author ab
*/
package btools.memrouter;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import btools.router.OsmTrack;
public class Iternity implements Comparable<Iternity>
{
OsmTrack track;
OffsetSet offsets;
List<String> details = new ArrayList<String>();
List<String> lines = new ArrayList<String>();
long departtime;
long arrivaltime;
@Override
public int compareTo( Iternity it )
{
return arrivaltime == it.arrivaltime ? 0 : ( arrivaltime < it.arrivaltime ? -1 : 1 );
}
void appendSummary( List<String> sum )
{
SimpleDateFormat df = new SimpleDateFormat( "dd.MM HH:mm", Locale.GERMAN );
sum.add( "depart: " + df.format( new Date( departtime ) )+ " arrive: " + df.format( new Date( arrivaltime ) ) );
StringBuilder sb = new StringBuilder( "--- " );
for( String line: lines )
{
sb.append( line ).append( ' ' );
}
sb.append( "--- " );
long mins = ( arrivaltime-departtime ) / 60000L;
sb.append( mins ).append( "min" );
sum.add( sb.toString() );
int firstOffset = -1;
boolean hasLaterTrips = false;
sb = new StringBuilder( "(+later trips: " );
for ( int offset = 0; offset < offsets.size(); offset++ )
{
if ( offsets.contains( offset ) )
{
if ( firstOffset < 0 )
{
firstOffset = offset;
}
else
{
sb.append( "+" + (offset-firstOffset) + "min " );
hasLaterTrips = true;
}
}
if ( sb.length() > 47 )
{
sb.setLength( 47 );
sb.append( "..." );
}
}
sb.append( ")" );
if ( hasLaterTrips )
{
sum.add( sb.toString() );
}
}
}

View file

@ -1,189 +0,0 @@
/**
* Set off departure offsets (immutable)
*
* @author ab
*/
package btools.memrouter;
import java.util.BitSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedSet;
public class OffsetSet
{
private Map<BitSet, OffsetSet> existingSets = new HashMap<BitSet, OffsetSet>();
private static final int size = 185;
protected BitSet mask;
public OffsetSet emptySet()
{
return new OffsetSet( new BitSet( size ), existingSets );
}
public static OffsetSet fullSet()
{
BitSet allbits = new BitSet( size );
allbits.set( 0, size );
return new OffsetSet( allbits, new HashMap<BitSet, OffsetSet>() );
}
private OffsetSet( BitSet m, Map<BitSet, OffsetSet> knownSets )
{
existingSets = knownSets;
existingSets.put( m , this );
mask = m;
}
private OffsetSet create( BitSet m )
{
if ( m.isEmpty() )
{
return null;
}
if ( m.equals( mask ) )
{
return this;
}
OffsetSet set = existingSets.get( m );
if ( set == null )
{
set = new OffsetSet( m, existingSets );
// System.out.println( "created set: " + set + " instancecount=" + existingSets.size() );
}
return set;
}
public OffsetSet create( List<Integer> offsets )
{
BitSet m = new BitSet( size );
for ( Integer offset : offsets )
{
int i = offset.intValue();
if ( i >= 0 && i < size )
{
m.set( i );
}
}
return create( m );
}
public OffsetSet filterWithSet( SortedSet<Integer> usedTimes, int minuteArrival )
{
BitSet fmask = (BitSet)mask.clone();
int idx = 0;
int maxtime = usedTimes.isEmpty() ? Integer.MAX_VALUE: usedTimes.first().intValue() + size();
for(;;)
{
idx = fmask.nextSetBit( idx );
if ( idx < 0 ) break;
int i = minuteArrival + idx;
if ( i > maxtime || !usedTimes.add( Integer.valueOf(i) ) )
{
fmask.set( idx, false );
}
idx++;
}
return create( fmask );
}
public int size()
{
return size;
}
public boolean contains( int offset )
{
return mask.get( offset );
}
public OffsetSet add( int offset )
{
if ( mask.get( offset ) )
{
return this;
}
BitSet m = (BitSet)mask.clone();
m.set( offset );
return create( m );
}
public OffsetSet add( OffsetSet offsets )
{
BitSet m = (BitSet)mask.clone();
m.or( offsets.mask );
return create( m );
}
// clear all bits from this set in the argument set
public OffsetSet filter( OffsetSet in )
{
BitSet fmask = (BitSet)in.mask.clone();
fmask.andNot( mask );
return create( fmask );
}
public OffsetSet ensureMaxOffset( int max )
{
if ( max < size )
{
BitSet fmask = (BitSet)mask.clone();
fmask.set( max > 0 ? max : 0, size, false );
return create( fmask );
}
return this;
}
public OffsetSet filterAndClose( OffsetSetHolder gateHolder, boolean closeGate )
{
OffsetSet gate = gateHolder.getOffsetSet();
BitSet gmask = (BitSet)gate.mask.clone();
BitSet fmask = (BitSet)mask.clone();
fmask.andNot( gmask );
gmask.or( fmask );
if ( closeGate )
{
gateHolder.setOffsetSet( create( gmask ) ); // modify the gate
}
return create( fmask );
}
public OffsetSet sweepWith( OffsetSet sweeper, int timeDiff )
{
BitSet sweepmask = sweeper.mask;
BitSet fmask = (BitSet)mask.clone();
if ( timeDiff >= 0 )
{
int idx = 0;
for(;;)
{
idx = sweepmask.nextSetBit( idx ) + 1;
if ( idx < 1 ) break;
int sweepStart = Math.max( 0, idx-timeDiff );
fmask.set( sweepStart, idx, false );
}
int sweepStart = Math.max( 0, size-timeDiff );
fmask.set( sweepStart, size, false );
}
// System.out.println( "sweep: " + mask + " with: " + sweepmask + "=" + fmask );
return create( fmask );
}
@Override
public String toString()
{
return mask.toString();
}
}

View file

@ -1,13 +0,0 @@
/**
* Set off departure offsets (immutable)
*
* @author ab
*/
package btools.memrouter;
public interface OffsetSetHolder
{
OffsetSet getOffsetSet();
void setOffsetSet( OffsetSet offsetSet );
}

View file

@ -1,158 +0,0 @@
/**
* Container for link between two Osm nodes (pre-pocessor version)
*
* @author ab
*/
package btools.memrouter;
public class OsmLinkP implements OffsetSetHolder
{
/**
* The description bitmap is mainly the way description used to calculate the
* costfactor
*/
public byte[] descriptionBitmap;
/**
* The target is either the next link or the target node
*/
protected OsmNodeP sourceNode;
protected OsmNodeP targetNode;
protected OsmLinkP previous;
protected OsmLinkP next;
public static int currentserial = 0; // serial version to invalidate link
// occupation
private int instanceserial = 0;
private OffsetSet offsets;
public boolean isConnection()
{
return descriptionBitmap == null;
}
public boolean isWayLink()
{
return descriptionBitmap != null;
}
public OsmLinkP( OsmNodeP source, OsmNodeP target )
{
sourceNode = source;
targetNode = target;
}
protected OsmLinkP()
{
}
public OffsetSet getOffsetSet()
{
return offsets;
}
public void setOffsetSet( OffsetSet offsets )
{
this.offsets = offsets;
}
public boolean isVirgin()
{
return instanceserial != currentserial;
}
public OffsetSet filterAndClose( OffsetSet in, long arrival )
{
if ( offsets == null || isVirgin() )
{
initLink();
offsets = in;
return in;
}
return in.filterAndClose( this, true );
}
protected void initLink()
{
instanceserial = currentserial;
}
/**
* Set the relevant next-pointer for the given source
*/
public void setNext( OsmLinkP link, OsmNodeP source )
{
if ( sourceNode == source )
{
next = link;
}
else if ( targetNode == source )
{
previous = link;
}
else
{
throw new IllegalArgumentException( "internal error: setNext: unknown source" );
}
}
/**
* Get the relevant next-pointer for the given source
*/
public OsmLinkP getNext( OsmNodeP source )
{
if ( sourceNode == source )
{
return next;
}
else if ( targetNode == source )
{
return previous;
}
else
{
throw new IllegalArgumentException( "internal error: gextNext: unknown source" );
}
}
/**
* Get the relevant target-node for the given source
*/
public OsmNodeP getTarget( OsmNodeP source )
{
if ( sourceNode == source )
{
return targetNode;
}
else if ( targetNode == source )
{
return sourceNode;
}
else
{
throw new IllegalArgumentException( "internal error: getTarget: unknown source" );
}
}
/**
* Check if reverse link for the given source
*/
public boolean isReverse( OsmNodeP source )
{
if ( sourceNode == source )
{
return false;
}
else if ( targetNode == source )
{
return true;
}
else
{
throw new IllegalArgumentException( "internal error: isReverse: unknown source" );
}
}
}

View file

@ -1,151 +0,0 @@
/**
* Container for an osm node (pre-pocessor version)
*
* @author ab
*/
package btools.memrouter;
import btools.mapaccess.OsmPos;
import btools.util.CheapRulerSingleton;
public class OsmNodeP extends OsmLinkP implements Comparable<OsmNodeP>, OsmPos
{
public OsmNodeP( double dlon, double dlat )
{
ilon = (int)(dlon * 1000000 + 180000000);
ilat = (int)(dlat * 1000000 + 90000000);
}
public OsmNodeP()
{
}
/**
* 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 byte wayBits = 0;
// interface OsmPos
@Override
public int getILat()
{
return ilat;
}
@Override
public int getILon()
{
return ilon;
}
@Override
public short getSElev()
{
// if all bridge or all tunnel, elevation=no-data
return ( wayBits & NO_BRIDGE_BIT ) == 0 || ( wayBits & NO_TUNNEL_BIT ) == 0 ? Short.MIN_VALUE : selev;
}
@Override
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;
}
// interface OsmPos
@Override
public int calcDistance( OsmPos p )
{
return (int)(CheapRulerSingleton.distance(ilon, ilat, p.getILon(), p.getILat()) + 1.0 );
}
@Override
public long getIdFromPos()
{
return ((long)ilon)<<32 | ilat;
}
public byte[] getNodeDecsription()
{
return null;
}
public String toString2()
{
return (ilon-180000000) + "_" + (ilat-90000000) + "_" + (selev/4);
}
/**
* 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;
}
public OffsetSet filterAndCloseNode( OffsetSet in, boolean modifyGate )
{
return in; // do nothing (StationNode overrides)
}
public String getName()
{
return "<waynode>";
}
}

View file

@ -1,27 +0,0 @@
/**
* Container for an osm node with tags (pre-pocessor version)
*
* @author ab
*/
package btools.memrouter;
public class OsmNodePT extends OsmNodeP
{
public byte[] descriptionBits;
public OsmNodePT()
{
}
public OsmNodePT( byte[] descriptionBits )
{
this.descriptionBits = descriptionBits;
}
@Override
public final byte[] getNodeDecsription()
{
return descriptionBits;
}
}

View file

@ -1,175 +0,0 @@
/**
* Parser for a train schedule
*
* @author ab
*/
package btools.memrouter;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
import btools.expressions.BExpressionContextWay;
final class ScheduleParser
{
public static Map<String, StationNode> parseTrainTable( File[] files, GraphLoader graph, BExpressionContextWay expctxWay )
{
ScheduledLine currentLine = null;
StationNode lastStationInLine = null;
boolean readingLocations = false;
Map<String, StationNode> stationMap = new HashMap<String, StationNode>();
for ( File file : files )
{
BufferedReader br = null;
try
{
br = new BufferedReader( new InputStreamReader( new FileInputStream( file ) , "ISO-8859-1" ) );
for ( ;; )
{
String line = br.readLine();
if ( line == null )
break;
line = line.trim();
if ( line.length() == 0 )
continue;
if ( line.startsWith( "#" ) )
continue;
if ( line.startsWith( "-- locations" ) )
{
readingLocations = true;
continue;
}
if ( line.startsWith( "-- trainline" ) )
{
readingLocations = false;
currentLine = new ScheduledLine();
currentLine.name = line.substring( "-- trainline".length() ).trim();
lastStationInLine = null;
continue;
}
if ( readingLocations )
{
StationNode station = new StationNode();
// Eschborn 50.14323,8.56112
StringTokenizer tk = new StringTokenizer( line, " \t" );
station.name = tk.nextToken();
if ( stationMap.containsKey( station.name ) )
{
System.out.println( "skipping station name already known: " + station.name );
continue;
}
int locIdx = 0;
String loc = null;
int elev = 0;
int nconnections = 0;
while (tk.hasMoreTokens() || locIdx == 1)
{
if ( tk.hasMoreTokens() )
{
loc = tk.nextToken();
}
StringTokenizer tloc = new StringTokenizer( loc, "," );
int ilat = (int) ( ( Double.parseDouble( tloc.nextToken() ) + 90. ) * 1000000. + 0.5 );
int ilon = (int) ( ( Double.parseDouble( tloc.nextToken() ) + 180. ) * 1000000. + 0.5 );
if ( locIdx == 0 )
{
station.ilat = ilat;
station.ilon = ilon;
}
else
{
OsmNodeP pos = new OsmNodeP();
pos.ilat = ilat;
pos.ilon = ilon;
OsmNodeP node = graph.matchNodeForPosition( pos, expctxWay, false );
if ( node != null )
{
elev += node.selev;
nconnections++;
// link station to connecting node
OsmLinkP link = new OsmLinkP( station, node );
link.descriptionBitmap = null;
station.addLink( link );
node.addLink( link );
int distance = station.calcDistance( node );
System.out.println( "matched connection for station " + station.name + " at " + distance + " meter" );
}
}
locIdx++;
}
if ( nconnections > 0 )
{
station.selev = (short) ( elev / nconnections );
}
stationMap.put( station.name, station );
}
else if ( currentLine != null )
{
int idx = line.indexOf( ' ' );
String name = line.substring( 0, idx );
StationNode nextStationInLine = stationMap.get( name );
if ( nextStationInLine == null )
{
throw new IllegalArgumentException( "unknown station: " + name );
}
String value = line.substring( idx ).trim();
int offsetMinute = 0;
if ( lastStationInLine == null )
{
currentLine.schedule = new TrainSchedule( value );
}
else
{
if ( value.startsWith( "+" ) )
value = value.substring( 1 );
offsetMinute = Integer.parseInt( value );
ScheduledLink link = new ScheduledLink( lastStationInLine, nextStationInLine );
link.line = currentLine;
link.indexInLine = currentLine.offsetMinutes.size() - 1;
// System.out.println( "adding: " + link );
lastStationInLine.addLink( link );
}
currentLine.offsetMinutes.add( Integer.valueOf( offsetMinute ) );
lastStationInLine = nextStationInLine;
}
}
System.out.println( "read " + stationMap.size() + " stations" );
}
catch (Exception e)
{
throw new RuntimeException( e );
}
finally
{
if ( br != null )
{
try
{
br.close();
}
catch (Exception e) { /* ignore */ }
}
}
}
return stationMap;
}
}

View file

@ -1,22 +0,0 @@
/**
* A specific departure
* (relative to a certain station and line)
*
* @author ab
*/
package btools.memrouter;
final class ScheduledDeparture
{
long waitTime;
long rideTime;
OffsetSet offsets;
@Override
public String toString()
{
return "wait=" + waitTime + " ride=" + rideTime + " offsets=" + offsets;
}
}

View file

@ -1,106 +0,0 @@
/**
* A train line as a common set of stations with many departures
*
* @author ab
*/
package btools.memrouter;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
final class ScheduledLine
{
String name;
List<Integer> offsetMinutes = new ArrayList<Integer>();
TrainSchedule schedule;
/**
* get a list of departures relative to the start-time plus the individual
* offsets according to the offset mask
*
* departures with the same wait-time are aggregated in one result element
* with multiple 1-bits in the offset mask
*
* departures with different wait-times are returned as separate items
*
* @param id
* the value to add to this set.
* @return true if "id" already contained in this set.
*/
public List<ScheduledDeparture> getScheduledDepartures( int idx, long timeFrom, OffsetSet offsets )
{
List<ScheduledDeparture> result = new ArrayList<ScheduledDeparture>();
long minutesFrom = ( timeFrom + 59999L ) / 60000L;
long timeFromCorrection = minutesFrom * 60000L - timeFrom;
if ( idx < 0 || idx >= offsetMinutes.size() - 1 )
return result;
int offsetStart = offsetMinutes.get( idx ).intValue();
int offsetEnd = offsetMinutes.get( idx + 1 ).intValue();
Map<Integer, List<Integer>> waitOffsets = getDepartures( offsetStart, timeFrom + timeFromCorrection, offsets );
for ( Map.Entry<Integer, List<Integer>> e : waitOffsets.entrySet() )
{
ScheduledDeparture depart = new ScheduledDeparture();
depart.waitTime = e.getKey().intValue() * 60000L + timeFromCorrection;
depart.offsets = offsets.create( e.getValue() );
depart.rideTime = ( offsetEnd - offsetStart ) * 60000L;
result.add( depart );
}
return result;
}
private Map<Integer, List<Integer>> getDepartures( int offsetStart, long timeFrom, OffsetSet offsets )
{
Map<Integer, List<Integer>> waitOffsets = new HashMap<Integer, List<Integer>>();
int size = offsets.size();
for ( int offset = 0;; )
{
// skip to next offset bit
while (offset < size && !offsets.contains( offset ))
{
offset++;
}
if ( offset >= size )
return waitOffsets;
int toNext = schedule.getMinutesToNext( timeFrom + 60000L * ( offset - offsetStart ) );
if ( toNext < 0 )
return waitOffsets;
int departOffset = offset + toNext;
// whats the closest offset within the next toNext minutes
int lastOffset = offset;
while (toNext-- >= 0 && offset < size)
{
if ( offsets.contains( offset ) )
{
lastOffset = offset;
}
offset++;
}
// if ( lastOffset == size - 1 )
// return waitOffsets; // todo?
int waitTime = departOffset - lastOffset;
// if we have that wait time in the list, just add the offset bit
List<Integer> offsetList = waitOffsets.get( Integer.valueOf( waitTime ) );
if ( offsetList == null )
{
offsetList = new ArrayList<Integer>();
waitOffsets.put( Integer.valueOf( waitTime ), offsetList );
}
offsetList.add( Integer.valueOf( lastOffset ) );
}
}
}

View file

@ -1,58 +0,0 @@
/**
* Container for link between two Osm nodes (pre-pocessor version)
*
* @author ab
*/
package btools.memrouter;
import java.util.SortedSet;
import java.util.TreeSet;
public class ScheduledLink extends OsmLinkP
{
public ScheduledLink( StationNode source, StationNode target )
{
super( source, target );
}
public ScheduledLine line;
public int indexInLine;
public boolean isConnection()
{
return false;
}
public boolean isWayLink()
{
return false;
}
public String toString()
{
return "ScheduledLink: line=" + line.name + " indexInLine=" + indexInLine;
}
private SortedSet<Integer> usedTimes;
@Override
protected void initLink()
{
super.initLink();
usedTimes = new TreeSet<Integer>();
}
public OffsetSet filterAndClose( OffsetSet in, long arrival )
{
OffsetSet filtered = super.filterAndClose( in, arrival );
if ( filtered != null && arrival >= 0 )
{
int minutesArrival = (int) ( arrival / 60000L );
filtered = filtered.filterWithSet( usedTimes, minutesArrival );
}
return filtered;
}
}

View file

@ -1,597 +0,0 @@
/**
* Simple Train Router
*
* @author ab
*/
package btools.memrouter;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import btools.mapaccess.OsmPos;
import btools.router.OsmPathElement;
import btools.router.OsmTrack;
import btools.router.RoutingContext;
import btools.router.RoutingEngine;
import btools.util.SortedHeap;
final class ScheduledRouter
{
private GraphLoader graph;
public long linksProcessed = 0L;
public long linksReProcessed = 0L;
public long closedSkippedChained = 0L;
public long skippedChained = 0L;
private RoutingContext rc;
private RoutingEngine re;
private long time0;
private OsmNodeP start;
private OsmNodeP end;
SortedHeap<ScheduledTrip> openSet = new SortedHeap<ScheduledTrip>();
ScheduledRouter( GraphLoader graph, RoutingContext rc, RoutingEngine re )
{
this.graph = graph;
this.rc = rc;
this.re = re;
}
private static List<Iternity> trips = new ArrayList<Iternity>();
private static long oldChecksum = 0;
private String startEndText()
{
return (start == null ? "unmatched" : start.getName() ) + "->" + (end == null ? "unmatched" : end.getName() );
}
public OsmTrack findRoute( OsmPos startPos, OsmPos endPos, int alternativeIdx ) throws Exception
{
if ( alternativeIdx == -1 ) // lowest cost result
{
List<Iternity> singleTrip = _findRoute( startPos, endPos, true );
if ( singleTrip.isEmpty() )
{
if ( linksProcessed + linksReProcessed > 5000000 ) throw new RuntimeException( "5 million links limit reached" );
else throw new RuntimeException( "no track found! (" + startEndText() + ")" );
}
Iternity iternity = singleTrip.get( 0 );
OsmTrack t = iternity.track;
t.iternity = iternity.details;
return t;
}
// check for identical params
long[] nogocheck = rc.getNogoChecksums();
long checksum = nogocheck[0] + nogocheck[1] + nogocheck[2];
checksum += startPos.getILat() + startPos.getILon() + endPos.getILat() + endPos.getILon();
checksum += rc.localFunction.hashCode();
if ( checksum != oldChecksum )
{
trips = _findRoute( startPos, endPos, false );
Collections.sort( trips ); // sort by arrival time
oldChecksum = checksum;
}
if ( trips.isEmpty() )
{
if ( linksProcessed + linksReProcessed > 5000000 ) throw new RuntimeException( "5 million links limit reached" );
else throw new RuntimeException( "no track found! (" + startEndText() + ")" );
}
if ( alternativeIdx == 0 ) // = result overview
{
List<String> details = new ArrayList<String>();
for ( int idx = 0; idx < trips.size(); idx++ )
{
if ( idx > 0 ) details.add( "" );
Iternity iternity = trips.get( idx );
iternity.appendSummary( details );
}
Iternity iternity = trips.get( 0 );
OsmTrack t = iternity.track;
t.iternity = details;
return t;
}
int idx = alternativeIdx > trips.size() ? trips.size()-1 : alternativeIdx-1;
Iternity iternity = trips.get( idx );
OsmTrack t = iternity.track;
t.iternity = iternity.details;
return t;
}
private List<Iternity> _findRoute( OsmPos startPos, OsmPos endPos, boolean fastStop ) throws Exception
{
List<Iternity> iternities = new ArrayList<Iternity>();
start = graph.matchNodeForPosition( startPos, rc.expctxWay, rc.transitonly );
if ( start == null )
throw new IllegalArgumentException( "unmatched start: " + startPos );
end = graph.matchNodeForPosition( endPos, rc.expctxWay, rc.transitonly );
if ( end == null )
throw new IllegalArgumentException( "unmatched end: " + endPos );
time0 = System.currentTimeMillis() + (long) ( rc.starttimeoffset * 60000L );
long minutes0 = ( time0 + 59999L ) / 60000L;
time0 = minutes0 * 60000L;
OffsetSet fullSet = OffsetSet.fullSet();
OffsetSet finishedOffsets = fullSet.emptySet();
OsmLinkP startLink = new OsmLinkP( null, start );
ScheduledTrip startTrip = new ScheduledTrip( OffsetSet.fullSet(), startLink, null, null );
openSet.add( 0, startTrip );
for ( ;; )
{
if ( re.isTerminated() )
{
throw new RuntimeException( "operation terminated" );
}
if ( linksProcessed + linksReProcessed > 5000000 )
{
break;
}
// get cheapest trip from heap
ScheduledTrip trip = openSet.popLowestKeyValue();
if ( trip == null )
{
break;
}
OsmLinkP currentLink = trip.link;
OsmNodeP currentNode = trip.getTargetNode();
if ( currentNode == null )
{
System.out.println( "ups: " + trip );
continue;
}
if ( currentLink.isVirgin() )
{
linksProcessed++;
}
else
{
linksReProcessed++;
}
/* int maxOffset = (int)((maxarrival - trip.arrival)/60000L);
OffsetSet offsets = trip.offsets.ensureMaxOffset( maxOffset );
if ( offsets == null )
continue;
*/
OffsetSet offsets = trip.offsets;
// check global closure
offsets = finishedOffsets.filter( offsets );
if ( offsets == null )
continue;
/* offsets = efficientSubset( offsets, trip.adjustedCost );
if ( offsets == null )
continue;
*/
boolean continueOnLineOnly = false;
// check local closure for the target node:
if ( currentNode.filterAndCloseNode( offsets, true ) == null )
{
continueOnLineOnly = true;
}
// check local closure for links:
offsets = currentLink.filterAndClose( offsets, trip.arrival );
if ( offsets == null )
continue;
// check for arrival
if ( currentNode == end )
{
Iternity iternity = null;
OffsetSet toffsets = trip.offsets;
int lastIdx = iternities.size()-1;
// hack: for equal cost tracks, merge offsets (assuming identical iternity)
if ( lastIdx >= 0 && iternities.get( lastIdx ).track.cost == trip.cost )
{
toffsets = toffsets.add( iternities.get( lastIdx ).offsets );
iternities.remove( lastIdx );
}
for ( int offset = 0; offset < trip.offsets.size(); offset++ )
{
if ( trip.offsets.contains( offset ) )
{
iternity = compileTrip( trip, offset );
iternity.offsets = toffsets;
System.out.println( "---- begin route ------ (cost " + iternity.track.cost + ")" );
for ( String s : iternity.details )
System.out.println( s );
System.out.println( "---- end route ------ (arrival " + new Date( iternity.arrivaltime ) + ")" );
break; // + plus more offsets..
}
}
finishedOffsets = finishedOffsets.add( offsets );
if ( iternity != null )
{
// tracks come in cost-ascending order, so the arrival time
// must decrease for the new track to be efficient
// if ( iternities.isEmpty() || iternities.get( iternities.size() - 1 ).arrivaltime > iternity.arrivaltime )
if ( efficientSubset( iternities, iternity.offsets, iternity.track.cost ) != null )
{
iternities.add( iternity );
if ( fastStop )
{
break;
}
System.out.println( "*** added track to result list !**** ");
}
}
System.out.println( "*** finishedOffsets = " + finishedOffsets );
}
for ( OsmLinkP link = currentNode.getFirstLink(); link != null; link = link.getNext( currentNode ) )
{
if ( continueOnLineOnly )
{
if ( ! ( currentLink instanceof ScheduledLink && link instanceof ScheduledLink ) ) continue;
if ( ((ScheduledLink) currentLink).line != ((ScheduledLink) link ).line ) continue;
}
/* // pre-check target closure
if ( link.getTarget( currentNode ).filterAndCloseNode( offsets, false ) == null )
{
continue;
}
*/
if ( !rc.transitonly || link instanceof ScheduledLink )
{
addNextTripsForLink( trip, currentNode, currentLink, link, offsets, 0 );
}
}
}
return iternities;
}
private OffsetSet efficientSubset( List<Iternity> iternities, OffsetSet offsets, int cost )
{
for( Iternity it : iternities )
{
// determine a time-diff from a cost-diff
int dcost = cost - it.track.cost;
int dtime = (int) ( dcost * .06 / rc.cost1speed + 1. ); // 22km/h
offsets = offsets.sweepWith( it.offsets, dtime );
if ( offsets == null )
{
return null;
}
}
return offsets;
}
private void addToOpenSet( ScheduledTrip nextTrip )
{
int distance = nextTrip.getTargetNode().calcDistance( end );
nextTrip.adjustedCost = nextTrip.cost + (int) ( distance * rc.pass1coefficient + 0.5 );
openSet.add( nextTrip.adjustedCost, nextTrip );
}
private void addNextTripsForLink( ScheduledTrip trip, OsmNodeP currentNode, OsmLinkP currentLink, OsmLinkP link, OffsetSet offsets, int level )
{
OsmNodeP node = link.getTarget( currentNode );
if ( node == null )
{
System.out.println( "ups2: " + link );
return;
}
if ( node == trip.originNode )
{
link.filterAndClose( offsets, -1 ); // invalidate reverse link
return;
}
// calc distance and check nogos
rc.nogoCost = 0.;
int distance = rc.calcDistance( currentNode.ilon, currentNode.ilat, node.ilon, node.ilat );
if ( Math.abs(rc.nogoCost) > 0.)
{
return;
}
if ( link instanceof ScheduledLink )
{
// System.out.println( "next trip for link: " + link + " at offset " +
// offsets );
ScheduledLink slink = (ScheduledLink) link;
ScheduledLine line = slink.line;
// line change delay
long delay = 0L;
if ( currentLink instanceof ScheduledLink )
{
delay = ( (ScheduledLink) currentLink ).line == line ? 0L : (long) ( rc.changetime * 1000. ); // 3 minutes
}
long changePenalty = delay > 0 ? 60000L : 0L;
List<ScheduledDeparture> nextDepartures = line.getScheduledDepartures( slink.indexInLine, time0 + trip.arrival + delay, offsets );
for ( ScheduledDeparture nextDeparture : nextDepartures )
{
ScheduledTrip nextTrip = new ScheduledTrip( nextDeparture.offsets, link, currentNode, trip );
long waitTime = nextDeparture.waitTime + delay;
long rideTime = nextDeparture.rideTime;
nextTrip.cost = trip.cost + (int) ( ( rideTime + changePenalty + waitTime * rc.waittimeadjustment ) * rc.cost1speed / 3600. ); // 22km/h
nextTrip.departure = trip.arrival + waitTime;
nextTrip.arrival = nextTrip.departure + rideTime;
addToOpenSet( nextTrip );
// System.out.println( "found: " + nextTrip );
}
}
else if ( link.isWayLink() )
{
// get costfactor
rc.expctxWay.evaluate( link.isReverse( currentNode ), link.descriptionBitmap );
// *** penalty for distance
float costfactor = rc.expctxWay.getCostfactor();
if ( costfactor > 9999. )
{
return;
}
int waycost = (int) ( distance * costfactor + 0.5f );
// *** add initial cost if factor changed
float costdiff = costfactor - trip.lastcostfactor;
if ( costdiff > 0.0005 || costdiff < -0.0005 )
{
waycost += (int) rc.expctxWay.getInitialcost();
}
if ( node.getNodeDecsription() != null )
{
rc.expctxNode.evaluate( rc.expctxWay.getNodeAccessGranted() != 0., node.getNodeDecsription() );
float initialcost = rc.expctxNode.getInitialcost();
if ( initialcost >= 1000000. )
{
return;
}
waycost += (int) initialcost;
}
// *** penalty for turning angles
if ( trip.originNode != null )
{
// penalty proportional to direction change
double angle = rc.calcAngle( trip.originNode.ilon, trip.originNode.ilat, currentNode.ilon, currentNode.ilat, node.ilon, node.ilat );
double cos = 1. - rc.getCosAngle();
int turncost = (int) ( cos * rc.expctxWay.getTurncost() + 0.2 ); // e.g. turncost=90 -> 90 degree = 90m penalty
waycost += turncost;
}
ScheduledTrip nextTrip = new ScheduledTrip( offsets, link, currentNode, trip );
// *** penalty for elevation
short ele2 = node.selev;
short ele1 = trip.selev;
int elefactor = 250000;
if ( ele2 == Short.MIN_VALUE )
ele2 = ele1;
nextTrip.selev = ele2;
if ( ele1 != Short.MIN_VALUE )
{
nextTrip.ehbd = trip.ehbd + ( ele1 - ele2 ) * elefactor - distance * rc.downhillcutoff;
nextTrip.ehbu = trip.ehbu + ( ele2 - ele1 ) * elefactor - distance * rc.uphillcutoff;
}
if ( nextTrip.ehbd > rc.elevationpenaltybuffer )
{
int excess = nextTrip.ehbd - rc.elevationpenaltybuffer;
int reduce = distance * rc.elevationbufferreduce;
if ( reduce > excess )
{
reduce = excess;
}
excess = nextTrip.ehbd - rc.elevationmaxbuffer;
if ( reduce < excess )
{
reduce = excess;
}
nextTrip.ehbd -= reduce;
if ( rc.downhillcostdiv > 0 )
{
int elevationCost = reduce / rc.downhillcostdiv;
waycost += elevationCost;
}
}
else if ( nextTrip.ehbd < 0 )
{
nextTrip.ehbd = 0;
}
if ( nextTrip.ehbu > rc.elevationpenaltybuffer )
{
int excess = nextTrip.ehbu - rc.elevationpenaltybuffer;
int reduce = distance * rc.elevationbufferreduce;
if ( reduce > excess )
{
reduce = excess;
}
excess = nextTrip.ehbu - rc.elevationmaxbuffer;
if ( reduce < excess )
{
reduce = excess;
}
nextTrip.ehbu -= reduce;
if ( rc.uphillcostdiv > 0 )
{
int elevationCost = reduce / rc.uphillcostdiv;
waycost += elevationCost;
}
}
else if ( nextTrip.ehbu < 0 )
{
nextTrip.ehbu = 0;
}
nextTrip.lastcostfactor = costfactor;
nextTrip.cost = trip.cost + (int) ( waycost * rc.additionalcostfactor + 0.5 );
nextTrip.departure = trip.arrival;
nextTrip.arrival = nextTrip.departure + (long) ( waycost * 3600. / rc.cost1speed ); // 22km/h
addToOpenSet( nextTrip );
}
else
// connecting link
{
ScheduledTrip nextTrip = new ScheduledTrip( offsets, link, currentNode, trip );
long delay = (long) ( rc.buffertime * 1000. ); // 2 min
nextTrip.cost = trip.cost + (int) ( delay * rc.waittimeadjustment * rc.cost1speed / 3600. );
nextTrip.departure = trip.arrival;
nextTrip.arrival = nextTrip.departure + delay;
addToOpenSet( nextTrip );
}
}
private Iternity compileTrip( ScheduledTrip trip, int offset )
{
Iternity iternity = new Iternity();
OsmTrack track = new OsmTrack();
ScheduledTrip current = trip;
ScheduledLine lastLine = new ScheduledLine();
ScheduledLine dummyLine = new ScheduledLine();
List<ScheduledTrip> list = new ArrayList<ScheduledTrip>();
int distance = 0;
long departure = 0;
ScheduledTrip itrip = null;
String profile = extractProfile( rc.localFunction );
SimpleDateFormat df = new SimpleDateFormat( "dd.MM HH:mm" );
// time0 = df.parse(startTime).getTime();
OsmNodeP nextNode = null;
while (current != null)
{
departure = current.departure;
// System.out.println( "trip=" + current );
OsmNodeP node = current.getTargetNode();
OsmPathElement pe = OsmPathElement.create( node.ilon, node.ilat, node.selev, null, false );
track.addNode( pe );
if ( nextNode != null )
{
distance += node.calcDistance( nextNode );
}
boolean isScheduled = current.link instanceof ScheduledLink;
boolean isConnection = current.link.descriptionBitmap == null && !isScheduled;
ScheduledLine line = isScheduled ? ( (ScheduledLink) current.link ).line : isConnection ? dummyLine : null;
if ( line != lastLine && !isConnection )
{
itrip = new ScheduledTrip();
itrip.departure = current.departure;
itrip.arrival = current.arrival;
itrip.originNode = current.originNode;
itrip.link = current.link;
if ( isScheduled && list.size() > 0 )
{
list.get( list.size() - 1 ).originNode = current.getTargetNode();
}
list.add( itrip );
}
else if ( itrip != null && !isConnection )
{
itrip.departure = current.departure;
itrip.originNode = current.originNode;
}
lastLine = line;
current = current.origin;
nextNode = node;
}
track.distance = distance;
track.cost = trip.cost;
for ( int i = list.size() - 1; i >= 0; i-- )
{
current = list.get( i );
String lineName = profile;
boolean isScheduled = current.link instanceof ScheduledLink;
if ( isScheduled )
{
lineName = ( (ScheduledLink) current.link ).line.name;
}
String stationName = "*position*";
if ( current.originNode instanceof StationNode )
{
stationName = ( (StationNode) current.originNode ).name;
}
String nextStationName = "*position*";
if ( i > 0 && list.get( i - 1 ).originNode instanceof StationNode )
{
nextStationName = ( (StationNode) list.get( i - 1 ).originNode ).name;
}
if ( i == 0 && current.link.targetNode instanceof StationNode )
{
nextStationName = ( (StationNode)current.link.targetNode ).name;
}
{
Date d0 = new Date( time0 + 60000L * offset + current.departure );
Date d1 = new Date( time0 + 60000L * offset + current.arrival );
if ( iternity.details.size() > 0 )
iternity.details.add( "" );
iternity.details.add( "depart: " + df.format( d0 ) + " " + stationName );
iternity.details.add( " --- " + lineName + " ---" );
iternity.details.add( "arrive: " + df.format( d1 ) + " " + nextStationName );
if ( !iternity.lines.contains( lineName ) )
{
iternity.lines.add( lineName );
}
}
}
iternity.track = track;
iternity.arrivaltime = time0 + 60000L * offset + trip.arrival;
iternity.departtime = time0 + 60000L * offset + departure;
return iternity;
}
private String extractProfile( String s )
{
int idx = s.lastIndexOf( '/' );
if ( idx >= 0 )
s = s.substring( idx + 1 );
idx = s.indexOf( '.' );
if ( idx >= 0 )
s = s.substring( 0, idx );
return s;
}
}

View file

@ -1,64 +0,0 @@
/**
* Simple Train Router
*
* @author ab
*/
package btools.memrouter;
public final class ScheduledTrip
{
public OffsetSet offsets;
ScheduledTrip origin;
OsmLinkP link;
OsmNodeP originNode;
int cost; // in meter!
int adjustedCost; // in meter!
long arrival; // in millis!
long departure; // in millis!
public float lastcostfactor;
public int ehbd; // in micrometer
public int ehbu; // in micrometer
public short selev = Short.MIN_VALUE;
ScheduledTrip()
{
// dummy for OpenSetM
}
ScheduledTrip( OffsetSet offsets, OsmLinkP link, OsmNodeP originNode, ScheduledTrip origin )
{
this.offsets = offsets;
this.link = link;
this.origin = origin;
this.originNode = originNode;
}
public OsmNodeP getTargetNode()
{
return link.getTarget(originNode);
}
@Override
public String toString()
{
String prefix = "PlainLink";
if ( link instanceof ScheduledLink )
{
ScheduledLink l = (ScheduledLink)link;
ScheduledLine line = l.line;
prefix = "ScheduledLink: line=" + line.name;
}
else if ( link.isConnection() )
{
prefix = "ConnectingLink";
}
return prefix + " depart=" + departure + " arrival=" + arrival + " cost=" + cost + " offsets=" + offsets;
}
}

View file

@ -1,56 +0,0 @@
/**
* A train station and it's connections
*
* @author ab
*/
package btools.memrouter;
final class StationNode extends OsmNodeP
{
private int instanceserial = 0;
private static class NodeOffsets implements OffsetSetHolder
{
private OffsetSet offsets;
public OffsetSet getOffsetSet()
{
return offsets;
}
public void setOffsetSet( OffsetSet offsets )
{
this.offsets = offsets;
}
}
private NodeOffsets offsets;
@Override
public OffsetSet filterAndCloseNode( OffsetSet in, boolean closeGate )
{
if ( offsets == null || instanceserial != currentserial )
{
if ( closeGate )
{
instanceserial = currentserial;
offsets = new NodeOffsets();
offsets.setOffsetSet( in );
}
return in;
}
return in.filterAndClose( offsets, closeGate );
}
String name;
public String getName()
{
return name;
}
}

View file

@ -1,282 +0,0 @@
/**
* Information on matched way point
*
* @author ab
*/
package btools.memrouter;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
final class TrainSchedule
{
private static class TrainScheduleCron
{
long minutes;
long hours;
long dows;
TrainScheduleCron( String value )
{
StringTokenizer tk = new StringTokenizer( value, "_" );
minutes = parseElement( tk.nextToken() );
hours = parseElement( tk.nextToken() );
dows = parseElement( tk.nextToken() );
}
private long parseElement( String s )
{
if ( "*".equals( s ) )
{
return Long.MAX_VALUE;
}
StringTokenizer tk = new StringTokenizer( s, "," );
long res = 0;
while (tk.hasMoreTokens())
{
String sub = tk.nextToken();
int start, end;
int idx = sub.indexOf( '-' );
if ( idx < 0 )
{
start = Integer.parseInt( sub );
end = start;
}
else
{
start = Integer.parseInt( sub.substring( 0, idx ) );
end = Integer.parseInt( sub.substring( idx + 1 ) );
}
for ( int i = start; i <= end; i++ )
{
res |= ( 1L << i );
}
}
return res;
}
boolean matches( int minute, int hour, int dow )
{
return ( ( 1L << minute ) & minutes ) != 0 && ( ( 1L << hour ) & hours ) != 0 && ( ( 1L << dow ) & dows ) != 0;
}
}
private List<TrainScheduleCron> cronsPositive;
private List<TrainScheduleCron> cronsNegative;
private Map<String,List<Integer>> timeTable = new HashMap<String,List<Integer>>();
public TrainSchedule( String cronstring )
{
StringTokenizer tk = new StringTokenizer( cronstring, " " );
cronsPositive = new ArrayList<TrainScheduleCron>();
cronsNegative = new ArrayList<TrainScheduleCron>();
while (tk.hasMoreTokens())
{
String prefix = tk.nextToken();
String value = tk.nextToken();
if ( "+".equals( prefix ) )
{
cronsPositive.add( new TrainScheduleCron( value ) );
}
else if ( "-".equals( prefix ) )
{
cronsNegative.add( new TrainScheduleCron( value ) );
}
else
{
// prefix is a calendar id, value a slash-separated time list
List<Integer> times = new ArrayList<Integer>();
StringTokenizer tk3 = new StringTokenizer( value, "/" );
while( tk3.hasMoreTokens() )
{
times.add( Integer.valueOf( time2Minute( tk3.nextToken() ) ) );
}
Collections.sort( times );
timeTable.put( prefix, times );
}
}
}
private static int time2Minute( String s )
{
StringTokenizer tk = new StringTokenizer( s, ":" );
int mins = 60 * Integer.parseInt( tk.nextToken() );
mins += Integer.parseInt( tk.nextToken() );
return mins;
}
public int getMinutesToNext( long timeFrom )
{
if ( timeTable.isEmpty() )
{
return getMinutesToNextCron( timeFrom );
}
Calendar cal = Calendar.getInstance();
cal.setTime( new Date( timeFrom ) );
int minute = cal.get( Calendar.MINUTE );
int hour = cal.get( Calendar.HOUR_OF_DAY );
int year = cal.get( Calendar.YEAR );
int month = cal.get( Calendar.MONTH ) + 1;
int day = cal.get( Calendar.DAY_OF_MONTH );
String sday = "" + ( year*10000 + month * 100 + day );
List<Integer> alltimes = null;
boolean listIsCopy = false;
for( String calId : timeTable.keySet() )
{
if ( calendarHasDate( calId, sday ) )
{
List<Integer> times = timeTable.get( calId );
if ( alltimes == null )
{
alltimes = times;
}
else
{
if ( !listIsCopy )
{
alltimes = new ArrayList<Integer>( alltimes );
listIsCopy = true;
}
alltimes.addAll( times );
}
}
}
if ( alltimes == null ) return -1;
if ( listIsCopy )
{
Collections.sort( alltimes );
}
int mins = 60*hour + minute;
for( Integer t : alltimes )
{
if ( t.intValue() >= mins )
{
return t.intValue() - mins;
}
}
return -1;
}
private int getMinutesToNextCron( long timeFrom )
{
Calendar cal = Calendar.getInstance();
cal.setTime( new Date( timeFrom ) );
int minute = cal.get( Calendar.MINUTE );
int hour = cal.get( Calendar.HOUR_OF_DAY );
int dow = cal.get( Calendar.DAY_OF_WEEK );
dow = dow > 1 ? dow - 1 : dow + 6;
for ( int cnt = 0; cnt < 180; cnt++ )
{
boolean veto = false;
for ( TrainScheduleCron cron : cronsNegative )
{
if ( cron.matches( minute, hour, dow ) )
{
veto = true;
break;
}
}
if ( !veto )
{
for ( TrainScheduleCron cron : cronsPositive )
{
if ( cron.matches( minute, hour, dow ) )
return cnt;
}
}
if ( ++minute == 60 )
{
minute = 0;
if ( ++hour == 24 )
{
hour = 0;
if ( ++dow == 8 )
{
dow = 1;
}
}
}
}
return -1;
}
private static Map<String,Set<String>> calendarMap;
private static boolean calendarHasDate( String calId, String date )
{
if ( calendarMap == null )
{
try
{
readCalendar();
}
catch (Exception e)
{
throw new RuntimeException( "cannot readcalendar: " + e );
}
}
Set<String> idSet = calendarMap.get( calId );
if ( idSet != null )
{
return idSet.contains( date );
}
return true;
}
private static void readCalendar() throws Exception
{
System.out.println( "reading calendar..." );
calendarMap = new HashMap<String,Set<String>>();
Map<String,String> uniqueMap = new HashMap<String,String>();
BufferedReader br = new BufferedReader( new InputStreamReader( new FileInputStream( new File( "../calendar_dates.txt" ) ), "UTF-8" ) );
br.readLine(); // skip header
for ( ;; )
{
String line = br.readLine();
if ( line == null ) break;
StringTokenizer tk = new StringTokenizer( line, "," );
String calId = tk.nextToken();
String calDate = tk.nextToken();
Set<String> idSet = calendarMap.get( calId );
if ( idSet == null )
{
idSet = new HashSet<String>();
calendarMap.put( calId, idSet );
}
String uniqueDate = uniqueMap.get( calDate );
if ( uniqueDate == null )
{
uniqueDate = calDate;
uniqueMap.put( uniqueDate, uniqueDate );
}
idSet.add( uniqueDate );
}
br.close();
System.out.println( "read calendar with " + calendarMap.size() + " ids" );
}
}

View file

@ -1,98 +0,0 @@
package btools.memrouter;
import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import btools.expressions.BExpressionContext;
import btools.router.OsmNodeNamed;
import btools.router.OsmTrack;
import btools.router.RoutingContext;
import btools.router.RoutingEngine;
public class TwinRoutingEngine extends RoutingEngine
{
private static Object graphSync = new Object();
private static GraphLoader graph;
public TwinRoutingEngine( String outfileBase, String logfileBase, String segmentDir,
List<OsmNodeNamed> waypoints, RoutingContext rc )
{
super( outfileBase, logfileBase, segmentDir, waypoints, rc );
}
public void doRun( long maxRunningTime )
{
if ( routingContext.localFunction != null && routingContext.localFunction.startsWith( "../im/") )
{
doMemoryRun( maxRunningTime );
}
else
{
super.doRun( maxRunningTime );
}
}
static private Map<String,BExpressionContext[]> expressionCache = new HashMap<String,BExpressionContext[]>();
private void doMemoryRun( long maxRunningTime )
{
try
{
synchronized( graphSync )
{
if ( graph == null )
{
loadGraph();
}
/* // reuse old expression-caches
BExpressionContext[] exp = expressionCache.get( routingContext.localFunction );
if ( exp == null )
{
exp = new BExpressionContext[2];
exp[0] = routingContext.expctxWay;
exp[1] = routingContext.expctxNode;
expressionCache.put( routingContext.localFunction, exp );
}
else
{
System.out.println( "re-using exp-ctx for : " + routingContext.localFunction );
routingContext.expctxWay = exp[0];
routingContext.expctxNode = exp[1];
}
*/
OsmLinkP.currentserial++;
ScheduledRouter router = new ScheduledRouter( graph, routingContext, this );
foundTrack = router.findRoute( waypoints.get(0), waypoints.get(1), routingContext.getAlternativeIdx(-1,10) );
System.out.println( "linksProcessed=" + router.linksProcessed + " linksReProcessed=" + router.linksReProcessed);
System.out.println( "skippedChained=" + router.skippedChained + " closedSkippedChained=" + router.closedSkippedChained);
System.out.println( "expCtxWay: requests: " + routingContext.expctxWay.cacheStats() );
}
}
catch( Exception e )
{
e.printStackTrace();
errorMessage = e.getMessage();
}
}
private void loadGraph() throws Exception
{
File parentDir = new File( segmentDir ).getParentFile();
File nodeTilesIn = new File( parentDir, "unodes55");
File wayTilesIn = new File( parentDir, "waytiles55");
File[] fahrplanFiles = new File[2];
fahrplanFiles[0] = new File( parentDir, "fahrplan_nahverkehr.txt" );
fahrplanFiles[1] = new File( parentDir, "fahrplan_dbfern.txt" );
graph = new GraphLoader();
graph.process( nodeTilesIn, wayTilesIn, fahrplanFiles, routingContext.expctxWay );
}
}

View file

@ -1,39 +0,0 @@
package btools.memrouter;
import java.io.File;
import java.net.URL;
import org.junit.Assert;
import org.junit.Test;
import btools.expressions.BExpressionContextWay;
import btools.expressions.BExpressionMetaData;
public class MemrouterTest
{
@Test
public void memrouterTest() throws Exception
{
URL dummyurl = this.getClass().getResource( "/dummy.txt" );
Assert.assertTrue( "dummy.txt not found", dummyurl != null );
File workingDir = new File(dummyurl.getFile()).getParentFile();
File profileDir = new File( workingDir, "/../../../misc/profiles2" );
File dataDir = new File( workingDir, "/../../../brouter-map-creator/target/test-classes/tmp" );
File lookupFile = new File( profileDir, "lookups.dat" );
File profileFile = new File( profileDir, "trekking.brf" );
File waytiles55 = new File( dataDir, "waytiles55" );
File unodes55 = new File( dataDir, "unodes55" );
File[] fahrplanFiles = new File[1];
fahrplanFiles[0] = new File( workingDir, "fahrplan.txt" );
// read lookup + profile for lookup-version + access-filter
BExpressionMetaData meta = new BExpressionMetaData();
BExpressionContextWay expctxWay = new BExpressionContextWay(meta);
meta.readMetaData( lookupFile );
expctxWay.parseFile( profileFile, "global" );
// run GraphLoader
new GraphLoader().process( unodes55, waytiles55, fahrplanFiles, expctxWay );
}
}

View file

@ -1,48 +0,0 @@
package btools.memrouter;
import java.util.ArrayList;
import java.util.List;
import org.junit.Assert;
import org.junit.Test;
public class OffsetSetTest
{
@Test
public void offsetSetTest() throws Exception
{
OffsetSet fullset = OffsetSet.fullSet();
OffsetSet s2 = fullset.emptySet().add( 4 );
Assert.assertTrue( "added bit not found", s2.contains( 4 ) );
Assert.assertTrue( "found false bit", !s2.contains( 3 ) );
Assert.assertTrue( "found bit in fullset", fullset.contains( 17 ) );
List<Integer> offsetList = new ArrayList<Integer>();
offsetList.add( Integer.valueOf( 4 ));
offsetList.add( Integer.valueOf( 5 ));
offsetList.add( Integer.valueOf( 23 ));
offsetList.add( Integer.valueOf( 50 ));
OffsetSet s4 = fullset.create( offsetList );
Assert.assertTrue( "added bit 23 not found", s4.contains( 23 ) );
Assert.assertTrue( "found false bit 17", !s4.contains( 17 ) );
OffsetSet s5 = s2.filter( s4 ); // de-select 4 from s4
Assert.assertTrue( "added bit 5 not found", s5.contains( 5 ) );
Assert.assertTrue( "found false bit 4", !s5.contains( 4 ) );
OffsetSet s6 = s4.filter( s2 ); // de-select 4,5,23,50 from s2 -> = null
Assert.assertTrue( "expected empty set", s6 == null );
OsmLinkP holder = new OsmLinkP();
holder.setOffsetSet( fullset.emptySet().add( 24 ) );
OffsetSet s7 = s4.filterAndClose( holder, true );
// Assert.assertTrue( "bit 4 too much", !s7.contains( 4 ) );
// Assert.assertTrue( "bit 5 not found", s7.contains( 5 ) );
// Assert.assertTrue( "bit 23 not found", s7.contains( 23 ) );
// Assert.assertTrue( "bit 50 too much", !s7.contains( 50 ) );
}
}

View file

@ -1,546 +0,0 @@
-- locations
KoblenzHbf 50.35066,7.58997
Frankfurt(M)Hbf 50.10676,8.66323 50.10754,8.66107 50.10596,8.66448 50.10765,8.66566
Frankfurt/Hoechst 50.10271,8.54212 50.10363,8.54240 50.10186,8.54298
Bensheim-Auerbach 49.70216,8.61371
Bensheim 49.68108,8.61724
F-Niederrad 50.08096,8.63768
Walldorf 50.00159,8.58155
Moerfelden 49.97940,8.56534
Gross-G-Dornberg 49.91241,8.49420
Riedstatt-Goddelau 49.83462,8.49087
Stockstadt-Rhein 49.80906,8.47207
Biebesheim 49.78091,8.47350
Gernsheim 49.75359,8.49062
Gross-Rohrheim 49.71415,8.47826
Biblis 49.68821,8.45130
Buerstadt 49.64535,8.45888
Lampertheim 49.59978,8.47715
Mannheim-Waldhof 49.52538,8.48217
MannheimHbf 49.47983,8.47003
WiesbadenHbf 50.07118,8.24377
MainzHbf 50.00159,8.25939
Mainz-Roemisches-Th 49.99350,8.27852
Mainz-Bischofsheim 49.99228,8.35835
Nauheim 49.94192,8.45068
Gross-Gerau 49.92421,8.48589
Klein-Gerau 49.92004,8.51734
Weiterstadt 49.91027,8.57899
DarmstadtHbf 49.87254,8.63142
Darmstadt-Sued 49.85558,8.63703
Wiesbaden-Ost 50.04053,8.25616
Mainz-Nord 50.01062,8.24626
Mainz-Gustavsburg 49.99454,8.31414
Ruesselsheim-Opel 49.98780,8.40201
Ruesselsheim 49.99205,8.41375
Raunheim 50.01000,8.45704
Kelsterbach 50.06329,8.53006
F-Stadion 50.06778,8.63561
Bad-Soden 50.14283,8.50455 50.14339,8.50457 50.14308,8.50359
Sulzbach-Nord 50.13905,8.51788 50.13812,8.51823
Schwalbach-Limes 50.15444,8.52819 50.15485,8.52801
Schwalbach-Nord 50.15976,8.53459 50.15965,8.53487
Niederhoechsstadt 50.15439,8.54707 50.15476,8.54627
Eschborn 50.14371,8.56076 50.14323,8.56112
Eschborn-Sued 50.13352,8.57863 50.13327,8.57807 50.13441,8.57850
Frankfurt-Roedelheim 50.12457,8.60708 50.12431,8.60628 50.12473,8.60800
Frankfurt-West 50.11885,8.63981 50.11876,8.63932
Frankfurt-Messe 50.11190,8.64354 50.11271,8.64371
Frankfurt-Galluswarte 50.10384,8.64487 50.10384,8.64487
F-Taunusanlage 50.11325,8.66906
F-Hauptwache 50.11393,8.67835
F-Konstablerwache 50.11423,8.68621
F-Ostendstrasse 50.11226,8.69710
F-Lokalbahnhof 50.10198,8.69294
Frankfurt-Süd 50.09907,8.68627
F-Stresemannallee 50.09455,8.67173
F-Louisa 50.08320,8.66947
Neu-Isenburg 50.05303,8.66450
Dreieich-Buchschlag 50.02230,8.66256
Langen-Flugsicherung 50.00559,8.65843
Langen 49.99373,8.65786
Egelsbach 49.96785,8.65403
Erzhausen 49.95128,8.65086
D-Wixhausen 49.92889,8.64724
D-Arheiligen 49.91424,8.64625
F-ZusckschwerdStr 50.10290,8.55181
F-Bolognaropalast 50.10140,8.55297
F-TillyStr 50.10173,8.56031
F-NiedKirche 50.09823,8.56726
F-LuthmerStr 50.09907,8.57265
F-BirminghamStr 50.10009,8.57790
F-Jaegerallee 50.10024,8.59112
F-Linnegraben 50.10017,8.59781
F-WaldschulStr 50.10061,8.60305
F-MoenchhofStr 50.10079,8.61903
F-WickererStr 50.10057,8.62240
F-RebstoeckerStr 50.10154,8.62866
F-SchwalbacherStr 50.10235,8.63628
F-SpeyererStr 50.10542,8.65043
F-Gueterplatz 50.10751,8.65557
F-PlatzDerRepublik 50.10929,8.66073
Kronberg 50.17983,8.51726 50.17949,8.51744
Kronberg-Sued 50.17289,8.52965 50.17368,8.52843
Sulzbach(Taunus) 50.12957,8.52836 50.13012,8.52812
Weisskirchen-Steinb 50.17346,8.58782
Stierstadt 50.18486,8.58486
Oberursel 50.19853,8.58769
Bad-Homburg 50.21945,8.62057
Seulberg 50.24286,8.64559
Friedrichsdorf 50.25200,8.64432
Diez-Ost 50.37614,8.03851 50.37512,8.03780
Staffel 50.39929,8.04620 50.39838,8.04605
Elz 50.41450,8.03848 50.41490,8.03826
Niederhadamar 50.43309,8.03737 50.43340,8.03737
Hadamar 50.44710,8.04351 50.44771,8.04416
Niederzeuzheim 50.46802,8.03966 50.46880,8.03954
Frickofen 50.50485,8.03060 50.50485,8.03002
Wilsenroth 50.53191,8.03165 50.53076,8.03371
Wilmenroth 50.53940,7.98573 50.53940,7.98477
Westerburg 50.55747,7.96709 50.55674,7.96668
Langenhahn 50.58733,7.91494 50.58761,7.91676
Elz-Sued 50.40851,8.03211 50.40845,8.03290
Niedererbach 50.42488,7.97713
Dreikirchen 50.44986,7.95879
Steinefrenz 50.44778,7.93970,50.44737,7.94294
Girod 50.45439,7.90259
Goldhausen 50.46131,7.87345 50.46185,7.87268
Montabaur 50.44479,7.82520 50.44415,7.82538 50.44504,7.83017
Dernbach 50.45672,7.78386
Wirges 50.46728,7.78485
Sirshahn 50.48593,7.77162 50.48597,7.77052
Limburg(Lahn) 50.38426,8.06296 50.38495,8.06215
Eschofen 50.39337,8.10427 50.39396,8.10594
Lindenholzhausen 50.37840,8.13335 50.37768,8.13321
Niederbrechen 50.35957,8.15976 50.36031,8.15854
Oberbrechen 50.35454,8.18765 50.35524,8.18722
Niederselters 50.33249,8.22995 50.33283,8.23066
Bad-Camberg 50.29644,8.25516 50.29597,8.25585
Woersdorf 50.24550,8.24926 50.24614,8.24910
Idstein 50.21591,8.25755 50.21665,8.25795
Niedernhausen 50.15972,8.31272 50.16053,8.31281
Hofheim 50.08406,8.44493 50.08502,8.44549
Unterliederbach 50.10796,8.52798 50.10842,8.52797
Liederbach-Sued 50.11538,8.50159 50.11571,8.50118
Liederbach 50.11861,8.48631 50.11823,8.48802
Kelkheim-Muenster 50.12477,8.46183 50.12517,8.46202
Kelkheim 50.13694,8.44781 50.13730,8.44812
Kelkheim-Hornau 50.14692,8.44459 50.14770,8.44509
Schneidhain 50.17261,8.45209 50.17245,8.45160
Koenigstein 50.17758,8.46892 50.17738,8.46989
FfmFlughfFbf 50.05297,8.57086 50.05202,8.57030
Limburg-Sued 50.38241,8.09621 50.38283,8.09445 50.38349,8.09597
Siegburg-Bonn 50.79377,7.20269 50.79446,7.20331
Koeln 50.94299,6.95907 50.94220,6.95798
Kerkerbach 50.40172,8.13610
Runkel 50.40502,8.15961
Villmar 50.39477,8.18734
Arfurt(Lahn) 50.40644,8.21076
Aumenau 50.39990,8.24952
Fürfurt 50.42938,8.25411
Gräveneck 50.45194,8.25117
Weilburg 50.48731,8.26838
Löhnberg 50.50920,8.27367
Stockhausen(Lahn) 50.54039,8.32492
Leun/Braunfels 50.53957,8.36628
Solms 50.54520,8.40752
Albshausen 50.54561,8.43360
Wetzlar 50.56509,8.50360
Dutenhofen(Wetzlar) 50.56379,8.59979
Gießen 50.57804,8.66280
DA-RheinNeckarStrasse 49.87183,8.64463
DA-EscholbrueckerStr 49.86537,8.64717
DA-PrinzEmilGarten 49.86154,8.64708
DA-BessungerStr 49.85836,8.64698
DA-LandskronenStr 49.85335,8.64668
DA-Marienhoehe 49.84355,8.64609
Eberstadt-FriedrichEbert 49.83855,8.64559
Eberstadt-CarlUlrich 49.83321,8.64496
Eberstadt-VonKetteler 49.82911,8.64520
Eberstadt-KatharinenStr 49.82476,8.64482
Eberstadt-Wartehalle 49.82027,8.64411
Eberstadt-Modaubruecke 49.81739,8.64425
Eberstadt-Kirche 49.81429,8.64600
Eberstadt-Friedhof 49.81108,8.64603
Eberstadt-Frankenstein 49.80744,8.64542
Eberstadt-Mittelschneise 49.80234,8.64689
Malchen-Seeheim 49.79020,8.64875
Seeheim-Wingert 49.77274,8.64814
Seeheim-NeuesRathaus 49.76666,8.64623
Seeheim-Tannenberg 49.76287,8.64482
Jugenheim-LudwigStr 49.75676,8.63487
Jugenheim-Bickenbacher 49.75357,8.62937
Alsbach-Beuneweg 49.74641,8.62061
Alsbach-Hikelstein 49.74028,8.61432
-- trainline STR11
Frankfurt(M)Hbf + 4,14,24,34,44,54_6-22_*
F-PlatzDerRepublik +2
F-Gueterplatz +4
F-SpeyererStr +5
Frankfurt-Galluswarte +7
F-SchwalbacherStr +9
F-RebstoeckerStr +11
F-WickererStr +12
F-MoenchhofStr +13
F-WaldschulStr +15
F-Linnegraben +16
F-Jaegerallee +17
F-BirminghamStr +19
F-LuthmerStr +20
F-NiedKirche +22
F-TillyStr +24
F-ZusckschwerdStr +26
-- trainline STR11
F-ZusckschwerdStr + 0,10,20,30,40,50_6-22_*
F-Bolognaropalast +1
F-TillyStr +3
F-NiedKirche +4
F-LuthmerStr +5
F-BirminghamStr +7
F-Jaegerallee +9
F-Linnegraben +10
F-WaldschulStr +11
F-MoenchhofStr +13
F-WickererStr +14
F-RebstoeckerStr +15
F-SchwalbacherStr +17
Frankfurt-Galluswarte +19
F-SpeyererStr +20
F-Gueterplatz +22
F-PlatzDerRepublik +24
Frankfurt(M)Hbf +26
-- trainline S3
Bad-Soden + 20,50_0,5-23_*
Sulzbach-Nord +2
Schwalbach-Limes +5
Schwalbach-Nord +6
Niederhoechsstadt +9
Eschborn +11
Eschborn-Sued +13
Frankfurt-Roedelheim +17
Frankfurt-West +20
Frankfurt-Messe +22
Frankfurt-Galluswarte +24
Frankfurt(M)Hbf +26
F-Taunusanlage +28
F-Hauptwache +30
F-Konstablerwache +31
F-Ostendstrasse +33
F-Lokalbahnhof +35
Frankfurt-Süd +37
F-Stresemannallee +39
F-Louisa +41
Neu-Isenburg +44
Dreieich-Buchschlag +47
Langen-Flugsicherung +49
Langen +51
Egelsbach +54
Erzhausen +56
D-Wixhausen +58
D-Arheiligen +61
DarmstadtHbf +64
-- trainline S4
Kronberg + 8,38_0,5-23_*
Kronberg-Sued +2
Niederhoechsstadt +6
Eschborn +8
Eschborn-Sued +10
Frankfurt-Roedelheim +14
Frankfurt-West +17
Frankfurt-Messe +19
Frankfurt-Galluswarte +21
Frankfurt(M)Hbf +23
F-Taunusanlage +25
F-Hauptwache +27
F-Konstablerwache +28
F-Ostendstrasse +30
F-Lokalbahnhof +32
Frankfurt-Süd +34
F-Stresemannallee +36
F-Louisa +38
Neu-Isenburg +41
Dreieich-Buchschlag +44
Langen-Flugsicherung +46
Langen +48
-- trainline S3
Frankfurt(M)Hbf + 14,44_0,5-23_*
Frankfurt-Galluswarte +3
Frankfurt-Messe +4
Frankfurt-West +6
Frankfurt-Roedelheim +9
Eschborn-Sued +12
Eschborn +15
Bad-Soden +26
-- trainline S4
Frankfurt(M)Hbf + 29,59_0,5-23_*
Frankfurt-Galluswarte +3
Frankfurt-Messe +4
Frankfurt-West +6
Frankfurt-Roedelheim +9
Eschborn-Sued +12
Eschborn +15
Niederhoechsstadt +17
Kronberg-Sued +20
Kronberg +22
-- trainline S5
Frankfurt(M)Hbf + 24,54_0,5-23_*
Frankfurt-Galluswarte +3
Frankfurt-Messe +4
Frankfurt-West +6
Frankfurt-Roedelheim +9
Weisskirchen-Steinb +13
Stierstadt +15
Oberursel +18
Bad-Homburg +21
Seulberg +25
Friedrichsdorf +26
-- trainline S5
Friedrichsdorf + 8,38_0,5-23_*
Seulberg +3
Bad-Homburg +7
Oberursel +11
Stierstadt +13
Weisskirchen-Steinb +15
Frankfurt-Roedelheim +19
Frankfurt-West +22
Frankfurt-Messe +24
Frankfurt-Galluswarte +26
Frankfurt(M)Hbf +29
-- trainline S8
WiesbadenHbf + 19,49_0,5-23_*
Wiesbaden-Ost +4
Mainz-Nord +8
MainzHbf +14
Mainz-Roemisches-Th +17
Mainz-Gustavsburg +20
Mainz-Bischofsheim +23
Ruesselsheim-Opel +26
Ruesselsheim +29
Raunheim +32
Kelsterbach +37
FfmFlughfFbf +43
F-Stadion +47
F-Niederrad +50
Frankfurt(M)Hbf +54
-- trainline HLB
Frankfurt/Hoechst + 28,58_6-23_*
Frankfurt(M)Hbf +11
-- trainline HLB
Frankfurt(M)Hbf + 17,47_6-23_*
Frankfurt/Hoechst +12
Unterliederbach +14
Liederbach-Sued +16
Liederbach +18
Kelkheim-Muenster +21
Kelkheim +25
Kelkheim-Hornau +27
Schneidhain +31
Koenigstein +35
-- trainline HLB
Frankfurt/Hoechst + 0,30_5-20_* - 0_9-15_*
Sulzbach(Taunus) +6
Bad-Soden +9
-- trainline HLB
Bad-Soden + 14,44_5-20_* - 14_9-15_*
Sulzbach(Taunus) +3
Frankfurt/Hoechst +9
-- trainline SE60
Frankfurt(M)Hbf + 6_0,5-23_*
DarmstadtHbf +24
Darmstadt-Sued +27
Bensheim-Auerbach +50
Bensheim +53
-- trainline SE60
Bensheim + 0_0,5-23_*
Bensheim-Auerbach +3
DarmstadtHbf +30
Frankfurt(M)Hbf +48
-- trainline RE60
Frankfurt(M)Hbf + 34_6,8,12,14,16,18,20_1-5
Langen +10
DarmstadtHbf +20
#Bickenbach +29
Bensheim +34
-- trainline RB15707
WiesbadenHbf + 38_6-23_*
MainzHbf +11
Mainz-Roemisches-Th +14
Mainz-Bischofsheim +19
Nauheim +26
Gross-Gerau +29
Klein-Gerau +32
Weiterstadt +36
DarmstadtHbf +43
-- trainline RE50
Frankfurt(M)Hbf + 10_6-23_*
F-Niederrad +6
Walldorf +15
Moerfelden +18
Gross-G-Dornberg +24
Riedstatt-Goddelau +30
Stockstadt-Rhein +33
Biebesheim +37
Gernsheim +41
Gross-Rohrheim +45
Biblis +48
Buerstadt +53
Lampertheim +57
Mannheim-Waldhof +62
MannheimHbf +69
-- trainline Vectus
Frickofen + 49_6,7,9,11,13,15,17,19_* + 19_6_* + 13_9_* + 6_15_*
Niederzeuzheim +6
Hadamar +4
Niederhadamar +13
Elz +16
Staffel +19
Diez-Ost +23
Limburg(Lahn) +26
-- trainline Vectus
Limburg(Lahn) + 8_8,10,12,14,16,18,20_*
Diez-Ost +3
Staffel +8
Elz +11
Niederhadamar +14
Hadamar +16
Niederzeuzheim +20
Frickofen +26
Wilsenroth +31
Wilmenroth +36
Westerburg +42
Langenhahn +49
-- trainline Vectus
Limburg(Lahn) + 54_7,9,10,11,12,13,14,15,16,17,18,19,20_*
Diez-Ost +4
Staffel +7
Elz-Sued +10
Niedererbach +17
Dreikirchen +23
Steinefrenz +26
Girod +30
Goldhausen +38
Montabaur +46
Dernbach +53
Wirges +55
Sirshahn +59
-- trainline Vectus
Sirshahn + 9_7,9,10,11,12,13,14,15,16,17,18,19,20_*
Wirges +4
Dernbach +7
Montabaur +14
Goldhausen +21
Girod +25
Steinefrenz +29
Dreikirchen +32
Niedererbach +38
Elz-Sued +45
Staffel +48
Diez-Ost +52
Limburg(Lahn) +55
-- trainline SE10
Limburg(Lahn) + 18_7-21_*
Eschofen +4
Lindenholzhausen +8
Niederbrechen +12
Oberbrechen +15
Niederselters +19
Bad-Camberg +24
Woersdorf +29
Idstein +33
Niedernhausen +40
Hofheim +52
Frankfurt/Hoechst +59
Frankfurt(M)Hbf +70
-- trainline HLB
Limburg(Lahn) + 23_7-21_*
Eschofen +4
Kerkerbach +7
Runkel +10
Villmar +14
Arfurt(Lahn) +19
Aumenau +23
Fürfurt +27
Gräveneck +31
Weilburg +37
Löhnberg +41
Stockhausen(Lahn) +46
Leun/Braunfels +50
Solms +54
Albshausen +57
Wetzlar +63
Dutenhofen(Wetzlar) +69
Gießen +75
-- trainline SE10
Frankfurt(M)Hbf + 31_7-22_*
Frankfurt/Hoechst +10
Hofheim +18
Niedernhausen +30
Idstein +37
Woersdorf +41
Bad-Camberg +46
Niederselters +50
Oberbrechen +54
Niederbrechen +57
Lindenholzhausen +61
Eschofen +65
Limburg(Lahn) +69
-- trainline RE1530x
Limburg(Lahn) + 55_6,7_*
Eschofen +4
Frankfurt/Hoechst +52
Frankfurt(M)Hbf +63
-- trainline STR8
DA-RheinNeckarStrasse + 16,46_6-23_*
DA-EscholbrueckerStr +2
DA-PrinzEmilGarten +3
DA-BessungerStr +4
DA-LandskronenStr +6
DA-Marienhoehe +8
Eberstadt-FriedrichEbert +9
Eberstadt-CarlUlrich +10
Eberstadt-VonKetteler +12
Eberstadt-KatharinenStr +13
Eberstadt-Wartehalle +14
Eberstadt-Modaubruecke +16
Eberstadt-Kirche +17
Eberstadt-Friedhof +18
Eberstadt-Frankenstein +20
Eberstadt-Mittelschneise +21
Malchen-Seeheim +23
Seeheim-Wingert +26
Seeheim-NeuesRathaus +28
Seeheim-Tannenberg +29
Jugenheim-LudwigStr +31
Jugenheim-Bickenbacher +32
Alsbach-Beuneweg +34
Alsbach-Hikelstein +36

View file

@ -17,7 +17,6 @@
<module>brouter-mapaccess</module> <module>brouter-mapaccess</module>
<module>brouter-core</module> <module>brouter-core</module>
<module>brouter-map-creator</module> <module>brouter-map-creator</module>
<module>brouter-mem-router</module>
<module>brouter-server</module> <module>brouter-server</module>
<module>brouter-routing-app</module> <module>brouter-routing-app</module>
</modules> </modules>