From 179212affccf494c401c9e45a4ae70921366cece Mon Sep 17 00:00:00 2001 From: Hannes Janetzek Date: Sat, 9 Mar 2013 16:32:56 +0100 Subject: [PATCH] mapsforge file reader: - add support for file version 3 back - project POIs - fix sync of shared Header and Index --- .../oscim/database/mapfile/IndexCache.java | 5 +- .../oscim/database/mapfile/MapDatabase.java | 176 ++++++++++-------- .../mapfile/header/RequiredFields.java | 5 +- 3 files changed, 105 insertions(+), 81 deletions(-) diff --git a/src/org/oscim/database/mapfile/IndexCache.java b/src/org/oscim/database/mapfile/IndexCache.java index dba365d5..c6a6b150 100644 --- a/src/org/oscim/database/mapfile/IndexCache.java +++ b/src/org/oscim/database/mapfile/IndexCache.java @@ -16,6 +16,7 @@ package org.oscim.database.mapfile; import java.io.IOException; import java.io.RandomAccessFile; +import java.util.Collections; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; @@ -53,7 +54,7 @@ class IndexCache { */ IndexCache(RandomAccessFile randomAccessFile, int capacity) { this.randomAccessFile = randomAccessFile; - this.map = new LRUCache(capacity); + this.map = Collections.synchronizedMap(new LRUCache(capacity)); } /** @@ -75,7 +76,7 @@ class IndexCache { * the number of the block in the map file. * @return the index entry or -1 if the block number is invalid. */ - long getIndexEntry(SubFileParameter subFileParameter, long blockNumber) { + synchronized long getIndexEntry(SubFileParameter subFileParameter, long blockNumber) { try { // check if the block number is out of bounds if (blockNumber >= subFileParameter.numberOfBlocks) { diff --git a/src/org/oscim/database/mapfile/MapDatabase.java b/src/org/oscim/database/mapfile/MapDatabase.java index 40dd9c2a..bdcd574e 100644 --- a/src/org/oscim/database/mapfile/MapDatabase.java +++ b/src/org/oscim/database/mapfile/MapDatabase.java @@ -203,6 +203,8 @@ public class MapDatabase implements IMapDatabase { private int minLat, minLon; private Tile mTile; + private static boolean sMapExperimental; + /* * (non-Javadoc) * @see org.oscim.map.reader.IMapDatabase#executeQuery(org.oscim.core.Tile, @@ -221,7 +223,7 @@ public class MapDatabase implements IMapDatabase { try { mTile = tile; - // prepareExecution(); + QueryParameters queryParameters = new QueryParameters(); queryParameters.queryZoomLevel = sMapFileHeader .getQueryZoomLevel(tile.zoomLevel); @@ -258,7 +260,7 @@ public class MapDatabase implements IMapDatabase { @Override public String getMapProjection() { - return "WSG84"; // getMapFileInfo().projectionName; + return "WSG84"; } /* @@ -282,7 +284,7 @@ public class MapDatabase implements IMapDatabase { } // make sure to close any previously opened file first - close(); + //close(); File file = new File(options.get("file")); @@ -304,8 +306,8 @@ public class MapDatabase implements IMapDatabase { mFileSize = mInputFile.length(); mReadBuffer = new ReadBuffer(mInputFile); - if (instances > 0) { - instances++; + Log.d(TAG, "open instance " + instances + " " + file.getAbsolutePath()); + if (instances++ > 0) { return OpenResult.SUCCESS; } @@ -317,10 +319,10 @@ public class MapDatabase implements IMapDatabase { return openResult; } - prepareExecution(); - - instances++; + sDatabaseIndexCache = new IndexCache(mInputFile, INDEX_CACHE_SIZE); + sMapExperimental = sMapFileHeader.getMapFileInfo().fileVersion == 4; + Log.d(TAG, "File version: " + sMapFileHeader.getMapFileInfo().fileVersion); return OpenResult.SUCCESS; } catch (IOException e) { Log.e(TAG, e.getMessage()); @@ -336,7 +338,12 @@ public class MapDatabase implements IMapDatabase { */ @Override public void close() { + if (instances == 0) + return; + instances--; + Log.d(TAG, "close instance " + instances); + if (instances > 0) { mReadBuffer = null; return; @@ -371,12 +378,6 @@ public class MapDatabase implements IMapDatabase { } } - private void prepareExecution() { - if (sDatabaseIndexCache == null) { - sDatabaseIndexCache = new IndexCache(mInputFile, INDEX_CACHE_SIZE); - } - } - /** * Processes a single block and executes the callback functions on all map * elements. @@ -538,7 +539,7 @@ public class MapDatabase implements IMapDatabase { mTileLongitude = (int) (tileLongitudeDeg * 1000000); //try { - processBlock(queryParameters, subFileParameter, mapDatabaseCallback); + processBlock(queryParameters, subFileParameter, mapDatabaseCallback); //} catch (ArrayIndexOutOfBoundsException e) { // Log.e(TAG, e.getMessage()); //} @@ -589,6 +590,18 @@ public class MapDatabase implements IMapDatabase { private boolean processPOIs(IMapDatabaseCallback mapDatabaseCallback, int numberOfPois) { Tag[] poiTags = sMapFileHeader.getMapFileInfo().poiTags; Tag[] tags = null; + Tag[] curTags; + + + long x = mTile.pixelX; + long y = mTile.pixelY + Tile.TILE_SIZE; + long z = Tile.TILE_SIZE << mTile.zoomLevel; + + long dx = (x - (z >> 1)); + long dy = (y - (z >> 1)); + + double divx = 180000000.0 / (z >> 1); + double divy = z / PIx4; for (int elementCounter = numberOfPois; elementCounter != 0; --elementCounter) { if (mDebugFile) { @@ -601,8 +614,6 @@ public class MapDatabase implements IMapDatabase { } } - // Log.d("MapDatabase", "read POI"); - // get the POI latitude offset (VBE-S) int latitude = mTileLatitude + mReadBuffer.readSignedInt(); @@ -617,29 +628,26 @@ public class MapDatabase implements IMapDatabase { // bit 5-8 represent the number of tag IDs byte numberOfTags = (byte) (specialByte & POI_NUMBER_OF_TAGS_BITMASK); - // boolean changed = false; - if (numberOfTags != 0) { tags = mReadBuffer.readTags(poiTags, numberOfTags); - // changed = true; } + if (tags == null) return false; + curTags = tags; + // get the feature bitmask (1 byte) byte featureByte = mReadBuffer.readByte(); // bit 1-3 enable optional features - // check if the POI has a name - if ((featureByte & POI_FEATURE_NAME) != 0) { - // int pos = mReadBuffer.getPositionAndSkip(); + if ((featureByte & WAY_FEATURE_NAME) != 0) { String str = mReadBuffer.readUTF8EncodedString(); - Tag[] tmp = tags; - tags = new Tag[tmp.length + 1]; - System.arraycopy(tmp, 0, tags, 0, tmp.length); - tags[tags.length - 1] = new Tag("name", str, false); + curTags = new Tag[tags.length + 1]; + System.arraycopy(tags, 0, curTags, 0, tags.length); + curTags[tags.length] = new Tag(Tag.TAG_KEY_NAME, str, false); } // check if the POI has a house number @@ -657,7 +665,11 @@ public class MapDatabase implements IMapDatabase { // Integer.toString(mReadBuffer.readSignedInt()))); } - mapDatabaseCallback.renderPointOfInterest(layer, tags, latitude, longitude); + longitude = (int) (longitude / divx - dx); + double sinLat = Math.sin(latitude * PI180); + latitude = (int) (Math.log((1.0 + sinLat) / (1.0 - sinLat)) * divy + dy); + + mapDatabaseCallback.renderPointOfInterest(layer, curTags, latitude, longitude); } @@ -809,16 +821,20 @@ public class MapDatabase implements IMapDatabase { int numberOfWays) { Tag[] tags = null; + Tag[] curTags; Tag[] wayTags = sMapFileHeader.getMapFileInfo().wayTags; - int[] textPos = new int[3]; - // float[] labelPosition; - // boolean skippedWays = false; + int wayDataBlocks; // skip string block - int stringsSize = mReadBuffer.readUnsignedInt(); - stringOffset = mReadBuffer.getBufferPosition(); - mReadBuffer.skipBytes(stringsSize); + int stringsSize = 0; + stringOffset = 0; + + if (sMapExperimental) { + stringsSize = mReadBuffer.readUnsignedInt(); + stringOffset = mReadBuffer.getBufferPosition(); + mReadBuffer.skipBytes(stringsSize); + } for (int elementCounter = numberOfWays; elementCounter != 0; --elementCounter) { if (mDebugFile) { @@ -841,7 +857,7 @@ public class MapDatabase implements IMapDatabase { if (elementCounter < 0) return false; - if (mReadBuffer.lastTagPosition > 0) { + if (sMapExperimental && mReadBuffer.lastTagPosition > 0) { int pos = mReadBuffer.getBufferPosition(); mReadBuffer.setBufferPosition(mReadBuffer.lastTagPosition); @@ -851,8 +867,6 @@ public class MapDatabase implements IMapDatabase { if (tags == null) return false; - // skippedWays = true; - mReadBuffer.setBufferPosition(pos); } } else { @@ -862,7 +876,7 @@ public class MapDatabase implements IMapDatabase { if (mDebugFile) { Log.w(TAG, DEBUG_SIGNATURE_BLOCK + mSignatureBlock); } - Log.w(TAG, "EEEEEK way... 2"); + Log.e(TAG, "BUG way 2"); return false; } @@ -878,57 +892,64 @@ public class MapDatabase implements IMapDatabase { // bit 5-8 represent the number of tag IDs byte numberOfTags = (byte) (specialByte & WAY_NUMBER_OF_TAGS_BITMASK); - // boolean changed = skippedWays; - // skippedWays = false; - - if (numberOfTags != 0) { + if (numberOfTags != 0) tags = mReadBuffer.readTags(wayTags, numberOfTags); - // changed = true; - } + if (tags == null) return false; + curTags = tags; + // get the feature bitmask (1 byte) byte featureByte = mReadBuffer.readByte(); // bit 1-6 enable optional features boolean featureWayDoubleDeltaEncoding = (featureByte & WAY_FEATURE_DOUBLE_DELTA_ENCODING) != 0; - // check if the way has a name - if ((featureByte & WAY_FEATURE_NAME) != 0) { - textPos[0] = mReadBuffer.readUnsignedInt(); - // String str = - mReadBuffer.readUTF8EncodedStringAt(stringOffset + textPos[0]); - // if (changed) { - // Tag[] tmp = tags; - // tags = new Tag[tmp.length + 1]; - // System.arraycopy(tmp, 0, tags, 0, tmp.length); - // } - // tags[tags.length - 1] = new Tag(Tag.TAG_KEY_NAME, str, - // false); + if (sMapExperimental) { + // check if the way has a name + if ((featureByte & WAY_FEATURE_NAME) != 0) { + int textPos = mReadBuffer.readUnsignedInt(); + String str = mReadBuffer.readUTF8EncodedStringAt(stringOffset + textPos); + + curTags = new Tag[tags.length + 1]; + System.arraycopy(tags, 0, curTags, 0, tags.length); + curTags[tags.length] = new Tag(Tag.TAG_KEY_NAME, str, false); + } + + // check if the way has a house number + if ((featureByte & WAY_FEATURE_HOUSE_NUMBER) != 0) { + //int textPos = + mReadBuffer.readUnsignedInt(); + } + + // check if the way has a reference + if ((featureByte & WAY_FEATURE_REF) != 0) { + //int textPos = + mReadBuffer.readUnsignedInt(); + } + } else { + if ((featureByte & WAY_FEATURE_NAME) != 0) { + String str = mReadBuffer.readUTF8EncodedString(); + + curTags = new Tag[tags.length + 1]; + System.arraycopy(tags, 0, curTags, 0, tags.length); + curTags[tags.length] = new Tag(Tag.TAG_KEY_NAME, str, false); + } + + // check if the way has a house number + if ((featureByte & WAY_FEATURE_HOUSE_NUMBER) != 0) { + String str = mReadBuffer.readUTF8EncodedString(); + } + + // check if the way has a reference + if ((featureByte & WAY_FEATURE_REF) != 0) { + String str = mReadBuffer.readUTF8EncodedString(); + } } - else - textPos[0] = -1; - - // check if the way has a house number - if ((featureByte & WAY_FEATURE_HOUSE_NUMBER) != 0) { - textPos[1] = mReadBuffer.readUnsignedInt(); - - } - else - textPos[1] = -1; - - // check if the way has a reference - if ((featureByte & WAY_FEATURE_REF) != 0) - textPos[2] = mReadBuffer.readUnsignedInt(); - else - textPos[2] = -1; - if ((featureByte & WAY_FEATURE_LABEL_POSITION) != 0) // labelPosition = readOptionalLabelPosition(); - // else - // labelPosition = null; if ((featureByte & WAY_FEATURE_DATA_BLOCKS_BYTE) != 0) { wayDataBlocks = mReadBuffer.readUnsignedInt(); @@ -954,7 +975,7 @@ public class MapDatabase implements IMapDatabase { && mWayNodes[1] == mWayNodes[l - 1]; projectToTile(mWayNodes, wayLengths); - mapDatabaseCallback.renderWay(layer, tags, mWayNodes, wayLengths, closed, 0); + mapDatabaseCallback.renderWay(layer, curTags, mWayNodes, wayLengths, closed, 0); } } @@ -1068,7 +1089,7 @@ public class MapDatabase implements IMapDatabase { cnt += 2; } - if (coords[first] == coords[outPos-2] && coords[first+1] == coords[outPos-1]){ + if (coords[first] == coords[outPos - 2] && coords[first + 1] == coords[outPos - 1]) { //Log.d(TAG, "drop closed"); indices[i] = (short) (cnt - 2); outPos -= 2; @@ -1079,4 +1100,5 @@ public class MapDatabase implements IMapDatabase { return true; } + } diff --git a/src/org/oscim/database/mapfile/header/RequiredFields.java b/src/org/oscim/database/mapfile/header/RequiredFields.java index ab48887d..446ae55f 100644 --- a/src/org/oscim/database/mapfile/header/RequiredFields.java +++ b/src/org/oscim/database/mapfile/header/RequiredFields.java @@ -50,7 +50,8 @@ final class RequiredFields { /** * Version of the map file format which is supported by this implementation. */ - private static final int SUPPORTED_FILE_VERSION = 4; + private static final int FILE_VERSION_3 = 3; + private static final int FILE_VERSION_4 = 4; /** * The maximum latitude values in microdegrees. @@ -123,7 +124,7 @@ final class RequiredFields { static OpenResult readFileVersion(ReadBuffer readBuffer, MapFileInfoBuilder mapFileInfoBuilder) { // get and check the file version (4 bytes) int fileVersion = readBuffer.readInt(); - if (fileVersion != SUPPORTED_FILE_VERSION) { + if (fileVersion != FILE_VERSION_3 && fileVersion != FILE_VERSION_4) { return new OpenResult("unsupported file version: " + fileVersion); } mapFileInfoBuilder.fileVersion = fileVersion;