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 nodeMap; private Map wayMap; private List used = new ArrayList(); 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 wayList; private List 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 " ); 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(); nodeMap = new HashMap(); wayMap = new HashMap(); } @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(); 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(); 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(); 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 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 0 ) { ArrayList goodWays = new ArrayList(); 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 tags ) throws Exception { List names; if ( tags == null ) { tags = new HashMap(); } 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( 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" ); } } }