brouter/brouter-mapaccess/src/main/java/btools/mapaccess/OsmFile.java
2019-05-30 15:11:12 +02:00

245 lines
6.1 KiB
Java

/**
* cache for a single square
*
* @author ab
*/
package btools.mapaccess;
import java.io.IOException;
import java.io.RandomAccessFile;
import btools.codec.DataBuffers;
import btools.codec.MicroCache;
import btools.codec.MicroCache2;
import btools.codec.TagValueValidator;
import btools.codec.WaypointMatcher;
import btools.util.ByteDataReader;
import btools.util.Crc32;
final class OsmFile
{
private RandomAccessFile is = null;
private long fileOffset;
private int[] posIdx;
private MicroCache[] microCaches;
public int lonDegree;
public int latDegree;
public String filename;
private int divisor;
private int cellsize;
private int ncaches;
private int indexsize;
public OsmFile( PhysicalFile rafile, int lonDegree, int latDegree, DataBuffers dataBuffers ) throws Exception
{
this.lonDegree = lonDegree;
this.latDegree = latDegree;
int lonMod5 = lonDegree % 5;
int latMod5 = latDegree % 5;
int tileIndex = lonMod5 * 5 + latMod5;
if ( rafile != null )
{
divisor = rafile.divisor;
cellsize = 1000000 / divisor;
ncaches = divisor * divisor;
indexsize = ncaches * 4;
byte[] iobuffer = dataBuffers.iobuffer;
filename = rafile.fileName;
long[] index = rafile.fileIndex;
fileOffset = tileIndex > 0 ? index[tileIndex - 1] : 200L;
if ( fileOffset == index[tileIndex] )
return; // empty
is = rafile.ra;
posIdx = new int[ncaches];
microCaches = new MicroCache[ncaches];
is.seek( fileOffset );
is.readFully( iobuffer, 0, indexsize );
if ( rafile.fileHeaderCrcs != null )
{
int headerCrc = Crc32.crc( iobuffer, 0, indexsize );
if ( rafile.fileHeaderCrcs[tileIndex] != headerCrc )
{
throw new IOException( "sub index checksum error" );
}
}
ByteDataReader dis = new ByteDataReader( iobuffer );
for ( int i = 0; i < ncaches; i++ )
{
posIdx[i] = dis.readInt();
}
}
}
public boolean hasData()
{
return microCaches != null;
}
public MicroCache getMicroCache( int ilon, int ilat )
{
int lonIdx = ilon / cellsize;
int latIdx = ilat / cellsize;
int subIdx = ( latIdx - divisor * latDegree ) * divisor + ( lonIdx - divisor * lonDegree );
return microCaches[subIdx];
}
public MicroCache createMicroCache( int ilon, int ilat, DataBuffers dataBuffers, TagValueValidator wayValidator, WaypointMatcher waypointMatcher, OsmNodesMap hollowNodes )
throws Exception
{
int lonIdx = ilon / cellsize;
int latIdx = ilat / cellsize;
MicroCache segment = createMicroCache( lonIdx, latIdx, dataBuffers, wayValidator, waypointMatcher, true, hollowNodes );
int subIdx = ( latIdx - divisor * latDegree ) * divisor + ( lonIdx - divisor * lonDegree );
microCaches[subIdx] = segment;
return segment;
}
private int getPosIdx( int idx )
{
return idx == -1 ? indexsize : posIdx[idx];
}
public int getDataInputForSubIdx( int subIdx, byte[] iobuffer ) throws Exception
{
int startPos = getPosIdx( subIdx - 1 );
int endPos = getPosIdx( subIdx );
int size = endPos - startPos;
if ( size > 0 )
{
is.seek( fileOffset + startPos );
if ( size <= iobuffer.length )
{
is.readFully( iobuffer, 0, size );
}
}
return size;
}
public MicroCache createMicroCache( int lonIdx, int latIdx, DataBuffers dataBuffers, TagValueValidator wayValidator,
WaypointMatcher waypointMatcher, boolean reallyDecode, OsmNodesMap hollowNodes ) throws Exception
{
int subIdx = ( latIdx - divisor * latDegree ) * divisor + ( lonIdx - divisor * lonDegree );
byte[] ab = dataBuffers.iobuffer;
int asize = getDataInputForSubIdx( subIdx, ab );
if ( asize == 0 )
{
return MicroCache.emptyCache();
}
if ( asize > ab.length )
{
ab = new byte[asize];
asize = getDataInputForSubIdx( subIdx, ab );
dataBuffers = new DataBuffers( ab );
}
// hack: the checksum contains the information
// which type of microcache we have
int crcData = Crc32.crc( ab, 0, asize - 4 );
int crcFooter = new ByteDataReader( ab, asize - 4 ).readInt();
if ( crcData == crcFooter )
{
throw new IOException( "old, unsupported data-format" );
}
else if ( ( crcData ^ 2 ) == crcFooter )
{
if ( !reallyDecode )
{
return null;
}
if ( hollowNodes == null )
{
return new MicroCache2( dataBuffers, lonIdx, latIdx, divisor, wayValidator, waypointMatcher );
}
new DirectWeaver( dataBuffers, lonIdx, latIdx, divisor, wayValidator, waypointMatcher, hollowNodes );
MicroCache dummy = MicroCache.emptyCache();
dummy.virgin = false;
return dummy;
}
throw new IOException( "checkum error" );
}
// set this OsmFile to ghost-state:
long setGhostState()
{
long sum = 0;
int nc = microCaches == null ? 0 : microCaches.length;
for ( int i = 0; i < nc; i++ )
{
MicroCache mc = microCaches[i];
if ( mc == null )
continue;
if ( mc.virgin )
{
mc.ghost = true;
sum += mc.getDataSize();
}
else
{
microCaches[i] = null;
}
}
return sum;
}
long collectAll()
{
long deleted = 0;
int nc = microCaches == null ? 0 : microCaches.length;
for ( int i = 0; i < nc; i++ )
{
MicroCache mc = microCaches[i];
if ( mc == null )
continue;
if ( !mc.ghost )
{
deleted += mc.collect( 0 );
}
}
return deleted;
}
long cleanGhosts()
{
long deleted = 0;
int nc = microCaches == null ? 0 : microCaches.length;
for ( int i = 0; i < nc; i++ )
{
MicroCache mc = microCaches[i];
if ( mc == null )
continue;
if ( mc.ghost )
{
microCaches[i] = null;
}
}
return deleted;
}
void clean( boolean all )
{
int nc = microCaches == null ? 0 : microCaches.length;
for ( int i = 0; i < nc; i++ )
{
MicroCache mc = microCaches[i];
if ( mc == null )
continue;
if ( all || !mc.virgin )
{
microCaches[i] = null;
}
}
}
}