2024-04-03 22:42:30 +02:00

217 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.StatCoderContext;
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 indexsize;
protected byte elevationType = 3;
public OsmFile(PhysicalFile rafile, int lonDegree, int latDegree, DataBuffers dataBuffers) throws IOException {
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;
elevationType = rafile.elevationType;
cellsize = 1000000 / divisor;
int 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 IOException {
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 IOException {
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);
}
StatCoderContext bc = new StatCoderContext(ab);
try {
if (!reallyDecode) {
return null;
}
if (hollowNodes == null) {
return new MicroCache2(bc, dataBuffers, lonIdx, latIdx, divisor, wayValidator, waypointMatcher);
}
new DirectWeaver(bc, dataBuffers, lonIdx, latIdx, divisor, wayValidator, waypointMatcher, hollowNodes);
return MicroCache.emptyNonVirgin;
} finally {
// crc check only if the buffer has not been fully read
int readBytes = (bc.getReadingBitPosition() + 7) >> 3;
if (readBytes != asize - 4) {
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) {
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;
}
}
}
}