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(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( nways ); for( int widx=0; widx( nodeIndexes.length ); for( int i=0; i( nrels ); for( int ridx=0; ridx(nmembers); for( int midx = 0; midx decodeTagValues() { HashMap map = new HashMap(); int[] tagSet = tagSetDecoder.decode(); for( int i=0; i> 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; } }