package btools.codec; import java.util.HashMap; import btools.util.ByteDataReader; import btools.util.IByteArrayUnifier; /** * MicroCache2 is the new format that uses statistical encoding and * is able to do access filtering and waypoint matching during encoding */ public final class MicroCache2 extends MicroCache { private int lonBase; private int latBase; private int cellsize; public MicroCache2( int size, byte[] databuffer, int lonIdx, int latIdx, int divisor ) throws Exception { super( databuffer ); // sets ab=databuffer, aboffset=0 faid = new int[size]; fapos = new int[size]; this.size = 0; cellsize = 1000000 / divisor; lonBase = lonIdx*cellsize; latBase = latIdx*cellsize; } public byte[] readUnified( int len, IByteArrayUnifier u ) { byte[] b = u.unify( ab, aboffset, len ); aboffset += len; return b; } public MicroCache2( StatCoderContext bc, DataBuffers dataBuffers, int lonIdx, int latIdx, int divisor, TagValueValidator wayValidator, WaypointMatcher waypointMatcher ) throws Exception { super( null ); cellsize = 1000000 / divisor; lonBase = lonIdx*cellsize; latBase = latIdx*cellsize; TagValueCoder wayTagCoder = new TagValueCoder( bc, dataBuffers, wayValidator ); TagValueCoder nodeTagCoder = new TagValueCoder( bc, dataBuffers, null ); NoisyDiffCoder nodeIdxDiff = new NoisyDiffCoder( bc ); NoisyDiffCoder nodeEleDiff = new NoisyDiffCoder( bc ); NoisyDiffCoder extLonDiff = new NoisyDiffCoder(bc); NoisyDiffCoder extLatDiff = new NoisyDiffCoder(bc); NoisyDiffCoder transEleDiff = new NoisyDiffCoder( bc ); size = bc.decodeNoisyNumber( 5 ); faid = size > dataBuffers.ibuf2.length ? new int[size] : dataBuffers.ibuf2; fapos = size > dataBuffers.ibuf3.length ? new int[size] : dataBuffers.ibuf3; int[] alon = size > dataBuffers.alon.length ? new int[size] : dataBuffers.alon; int[] alat = size > dataBuffers.alat.length ? new int[size] : dataBuffers.alat; if ( debug ) System.out.println( "*** decoding cache of size=" + size + " for lonIdx=" + lonIdx + " latIdx=" + latIdx ); bc.decodeSortedArray( faid, 0, size, 29, 0 ); for( int n = 0; n> 32); alat[n] = (int)(id64 & 0xffffffff); } int netdatasize = bc.decodeNoisyNumber( 10 ); ab = netdatasize > dataBuffers.bbuf1.length ? new byte[netdatasize] : dataBuffers.bbuf1; aboffset = 0; int[] validBits = new int[(size+31)>>5]; int finaldatasize = 0; LinkedListContainer reverseLinks = new LinkedListContainer( size, dataBuffers.ibuf1 ); int selev = 0; for( int n=0; n> 5 ] |= 1 << n; // mark dummy-node valid continue; // empty node escape (delta files only) } while( featureId != 0 ) { int bitsize = bc.decodeNoisyNumber( 5 ); if ( featureId == 2 ) // exceptions to turn-restriction { trExceptions = (short)bc.decodeBounded( 1023 ); } else if ( featureId == 1 ) // turn-restriction { writeBoolean( true ); writeShort( trExceptions ); // exceptions from previous feature trExceptions = 0; writeBoolean( bc.decodeBit() ); // isPositive writeInt( ilon + bc.decodeNoisyDiff( 10 ) ); // fromLon writeInt( ilat + bc.decodeNoisyDiff( 10 ) ); // fromLat writeInt( ilon + bc.decodeNoisyDiff( 10 ) ); // toLon writeInt( ilat + bc.decodeNoisyDiff( 10 ) ); // toLat } else { for( int i=0; i< bitsize; i++ ) bc.decodeBit(); // unknown feature, just skip } featureId = bc.decodeVarBits(); } writeBoolean( false ); selev += nodeEleDiff.decodeSignedValue(); writeShort( (short) selev ); TagValueWrapper nodeTags = nodeTagCoder.decodeTagValueSet(); writeVarBytes( nodeTags == null ? null : nodeTags.data ); int links = bc.decodeNoisyNumber( 1 ); if ( debug ) System.out.println( "*** decoding node " + ilon + "/" + ilat + " with links=" + links ); for( int li=0; li>= 2; } int lon32 = lonBase + dlon; int lat32 = latBase + dlat; return ((long)lon32)<<32 | lat32; } @Override public int shrinkId( long id64 ) { int lon32 = (int)(id64 >> 32); int lat32 = (int)(id64 & 0xffffffff); int dlon = lon32 - lonBase; int dlat = lat32 - latBase; int id32 = 0; for( int bm = 0x4000; bm > 0; bm >>= 1 ) { id32 <<= 2; if ( ( dlon & bm ) != 0 ) id32 |= 1; if ( ( dlat & bm ) != 0 ) id32 |= 2; } return id32; } @Override public boolean isInternal( int ilon, int ilat ) { return ilon >= lonBase && ilon < lonBase + cellsize && ilat >= latBase && ilat < latBase + cellsize; } @Override public int encodeMicroCache( byte[] buffer ) { HashMap idMap = new HashMap(); for( int n=0; n> 32); int ilat = (int)(id64 & 0xffffffff); if ( aboffset == aboffsetEnd ) { bc.encodeVarBits( 13 ); // empty node escape (delta files only) continue; } // write turn restrictions while( readBoolean() ) { short exceptions = readShort(); // except bikes, psv, ... if ( exceptions != 0 ) { bc.encodeVarBits( 2 ); // 2 = tr exceptions bc.encodeNoisyNumber( 10 , 5 ); // bit-count bc.encodeBounded( 1023 , exceptions & 1023 ); } bc.encodeVarBits( 1 ); // 1 = turn restriction bc.encodeNoisyNumber( restrictionBits.getNext(), 5 ); // bit-count using look-ahead fifo long b0 = bc.getWritingBitPosition(); bc.encodeBit( readBoolean() ); // isPositive bc.encodeNoisyDiff( readInt() - ilon, 10 ); // fromLon bc.encodeNoisyDiff( readInt() - ilat, 10 ); // fromLat bc.encodeNoisyDiff( readInt() - ilon, 10 ); // toLon bc.encodeNoisyDiff( readInt() - ilat, 10 ); // toLat restrictionBits.add( (int)( bc.getWritingBitPosition() - b0 ) ); } bc.encodeVarBits( 0 ); // end of extra data if ( dostats ) bc.assignBits( "extradata" ); int selev = readShort(); nodeEleDiff.encodeSignedValue( selev - lastSelev ); if ( dostats ) bc.assignBits( "nodeele" ); lastSelev = selev; nodeTagCoder.encodeTagValueSet( readVarBytes() ); if ( dostats ) bc.assignBits( "nodeTagIdx" ); int nlinks = linkCounts.getNext(); if ( dodebug ) System.out.println( "*** nlinks=" + nlinks ); bc.encodeNoisyNumber( nlinks, 1 ); if ( dostats ) bc.assignBits( "link-counts" ); nlinks = 0; while( hasMoreData() ) // loop over links { // read link data int startPointer = aboffset; int endPointer = getEndPointer(); int ilonlink = ilon + readVarLengthSigned(); int ilatlink = ilat + readVarLengthSigned(); int sizecode = readVarLengthUnsigned(); boolean isReverse = ( sizecode & 1 ) != 0; int descSize = sizecode >> 1; byte[] description = null; if ( descSize > 0 ) { description = new byte[descSize]; readFully( description ); } long link64 = ((long)ilonlink)<<32 | ilatlink; Integer idx = idMap.get( Long.valueOf( link64 ) ); boolean isInternal = idx != null; if ( isReverse && isInternal ) { if ( dodebug ) System.out.println( "*** NOT encoding link reverse=" + isReverse + " internal=" + isInternal ); netdatasize -= aboffset-startPointer; continue; // do not encode internal reverse links } if ( dodebug ) System.out.println( "*** encoding link reverse=" + isReverse + " internal=" + isInternal ); nlinks++; if ( isInternal ) { int nodeIdx = idx.intValue(); if ( dodebug ) System.out.println( "*** target nodeIdx=" + nodeIdx ); if ( nodeIdx == n ) throw new RuntimeException( "ups: self ref?" ); nodeIdxDiff.encodeSignedValue( nodeIdx - n ); if ( dostats ) bc.assignBits( "nodeIdx" ); } else { nodeIdxDiff.encodeSignedValue( 0 ); bc.encodeBit( isReverse ); extLonDiff.encodeSignedValue( ilonlink - ilon ); extLatDiff.encodeSignedValue( ilatlink - ilat ); if ( dostats ) bc.assignBits( "externalNode" ); } wayTagCoder.encodeTagValueSet( description ); if ( dostats ) bc.assignBits( "wayDescIdx" ); if ( !isReverse ) { byte[] geometry = readDataUntil( endPointer ); // write transition nodes int count = transCounts.getNext(); if ( dodebug ) System.out.println( "*** encoding geometry with count=" + count ); bc.encodeVarBits( count++ ); if ( dostats ) bc.assignBits( "transcount" ); int transcount = 0; if ( geometry != null ) { int dlon_remaining = ilonlink - ilon; int dlat_remaining = ilatlink - ilat; ByteDataReader r = new ByteDataReader( geometry ); while ( r.hasMoreData() ) { transcount++; int dlon = r.readVarLengthSigned(); int dlat = r.readVarLengthSigned(); bc.encodePredictedValue( dlon, dlon_remaining/count ); bc.encodePredictedValue( dlat, dlat_remaining/count ); dlon_remaining -= dlon; dlat_remaining -= dlat; if ( count > 1 ) count--; if ( dostats ) bc.assignBits( "transpos" ); transEleDiff.encodeSignedValue( r.readVarLengthSigned() ); if ( dostats ) bc.assignBits( "transele" ); } } transCounts.add( transcount ); } } linkCounts.add( nlinks ); } if ( pass == 3 ) { return bc.closeAndGetEncodedLength(); } } } }