reduce points on-the-fly while reading from mapfile

This commit is contained in:
Hannes Janetzek 2013-09-23 01:33:24 +02:00
parent 8a2060ca6e
commit 5c011a2402

View File

@ -18,8 +18,11 @@ package org.oscim.tiling.source.mapfile;
import java.io.IOException; import java.io.IOException;
import java.io.RandomAccessFile; import java.io.RandomAccessFile;
import org.oscim.backend.Log;
import org.oscim.core.GeometryBuffer;
import org.oscim.core.GeometryBuffer.GeometryType; import org.oscim.core.GeometryBuffer.GeometryType;
import org.oscim.core.MapElement; import org.oscim.core.MapElement;
import org.oscim.core.MercatorProjection;
import org.oscim.core.Tag; import org.oscim.core.Tag;
import org.oscim.core.Tile; import org.oscim.core.Tile;
import org.oscim.tiling.MapTile; import org.oscim.tiling.MapTile;
@ -27,50 +30,34 @@ import org.oscim.tiling.source.ITileDataSink;
import org.oscim.tiling.source.ITileDataSource; import org.oscim.tiling.source.ITileDataSource;
import org.oscim.tiling.source.mapfile.header.SubFileParameter; import org.oscim.tiling.source.mapfile.header.SubFileParameter;
import org.oscim.backend.Log;
/** /**
* A class for reading binary map files. * A class for reading binary map files.
* *
* @see <a * @see <a
* href="http://code.google.com/p/mapsforge/wiki/SpecificationBinaryMapFile">Specification</a> * href="http://code.google.com/p/mapsforge/wiki/SpecificationBinaryMapFile">Specification</a>
*/ */
public class MapDatabase implements ITileDataSource { public class MapDatabase implements ITileDataSource {
/** /** Bitmask to extract the block offset from an index entry. */
* Bitmask to extract the block offset from an index entry.
*/
private static final long BITMASK_INDEX_OFFSET = 0x7FFFFFFFFFL; private static final long BITMASK_INDEX_OFFSET = 0x7FFFFFFFFFL;
/** /** Bitmask to extract the water information from an index entry. */
* Bitmask to extract the water information from an index entry.
*/
private static final long BITMASK_INDEX_WATER = 0x8000000000L; private static final long BITMASK_INDEX_WATER = 0x8000000000L;
/** /** Debug message prefix for the block signature. */
* Debug message prefix for the block signature.
*/
private static final String DEBUG_SIGNATURE_BLOCK = "block signature: "; private static final String DEBUG_SIGNATURE_BLOCK = "block signature: ";
/** /** Debug message prefix for the POI signature. */
* Debug message prefix for the POI signature.
*/
// private static final String DEBUG_SIGNATURE_POI = "POI signature: "; // private static final String DEBUG_SIGNATURE_POI = "POI signature: ";
/** /** Debug message prefix for the way signature. */
* Debug message prefix for the way signature.
*/
private static final String DEBUG_SIGNATURE_WAY = "way signature: "; private static final String DEBUG_SIGNATURE_WAY = "way signature: ";
/** /** Error message for an invalid first way offset. */
* Error message for an invalid first way offset.
*/
private static final String INVALID_FIRST_WAY_OFFSET = "invalid first way offset: "; private static final String INVALID_FIRST_WAY_OFFSET = "invalid first way offset: ";
private static final String TAG = MapDatabase.class.getName(); private static final String TAG = MapDatabase.class.getName();
/** /** Maximum way nodes sequence length which is considered as valid. */
* Maximum way nodes sequence length which is considered as valid.
*/
private static final int MAXIMUM_WAY_NODES_SEQUENCE_LENGTH = 8192; private static final int MAXIMUM_WAY_NODES_SEQUENCE_LENGTH = 8192;
/** /**
@ -79,97 +66,60 @@ public class MapDatabase implements ITileDataSource {
*/ */
private static final int MAXIMUM_ZOOM_TABLE_OBJECTS = 65536; private static final int MAXIMUM_ZOOM_TABLE_OBJECTS = 65536;
/** /** Bitmask for the optional POI feature "elevation". */
* Bitmask for the optional POI feature "elevation".
*/
private static final int POI_FEATURE_ELEVATION = 0x20; private static final int POI_FEATURE_ELEVATION = 0x20;
/** /** Bitmask for the optional POI feature "house number". */
* Bitmask for the optional POI feature "house number".
*/
private static final int POI_FEATURE_HOUSE_NUMBER = 0x40; private static final int POI_FEATURE_HOUSE_NUMBER = 0x40;
/** /** Bitmask for the optional POI feature "name". */
* Bitmask for the optional POI feature "name".
*/
private static final int POI_FEATURE_NAME = 0x80; private static final int POI_FEATURE_NAME = 0x80;
/** /** Bitmask for the POI layer. */
* Bitmask for the POI layer.
*/
private static final int POI_LAYER_BITMASK = 0xf0; private static final int POI_LAYER_BITMASK = 0xf0;
/** /** Bit shift for calculating the POI layer. */
* Bit shift for calculating the POI layer.
*/
private static final int POI_LAYER_SHIFT = 4; private static final int POI_LAYER_SHIFT = 4;
/** /** Bitmask for the number of POI tags. */
* Bitmask for the number of POI tags.
*/
private static final int POI_NUMBER_OF_TAGS_BITMASK = 0x0f; private static final int POI_NUMBER_OF_TAGS_BITMASK = 0x0f;
/** /** Length of the debug signature at the beginning of each block. */
* Length of the debug signature at the beginning of each block.
*/
private static final byte SIGNATURE_LENGTH_BLOCK = 32; private static final byte SIGNATURE_LENGTH_BLOCK = 32;
/** /** Length of the debug signature at the beginning of each POI. */
* Length of the debug signature at the beginning of each POI.
*/
private static final byte SIGNATURE_LENGTH_POI = 32; private static final byte SIGNATURE_LENGTH_POI = 32;
/** /** Length of the debug signature at the beginning of each way. */
* Length of the debug signature at the beginning of each way.
*/
private static final byte SIGNATURE_LENGTH_WAY = 32; private static final byte SIGNATURE_LENGTH_WAY = 32;
/** /** Bitmask for the optional way data blocks byte. */
* Bitmask for the optional way data blocks byte.
*/
private static final int WAY_FEATURE_DATA_BLOCKS_BYTE = 0x08; private static final int WAY_FEATURE_DATA_BLOCKS_BYTE = 0x08;
/** /** Bitmask for the optional way double delta encoding. */
* Bitmask for the optional way double delta encoding.
*/
private static final int WAY_FEATURE_DOUBLE_DELTA_ENCODING = 0x04; private static final int WAY_FEATURE_DOUBLE_DELTA_ENCODING = 0x04;
/** /** Bitmask for the optional way feature "house number". */
* Bitmask for the optional way feature "house number".
*/
private static final int WAY_FEATURE_HOUSE_NUMBER = 0x40; private static final int WAY_FEATURE_HOUSE_NUMBER = 0x40;
/** /** Bitmask for the optional way feature "label position". */
* Bitmask for the optional way feature "label position".
*/
private static final int WAY_FEATURE_LABEL_POSITION = 0x10; private static final int WAY_FEATURE_LABEL_POSITION = 0x10;
/** /** Bitmask for the optional way feature "name". */
* Bitmask for the optional way feature "name".
*/
private static final int WAY_FEATURE_NAME = 0x80; private static final int WAY_FEATURE_NAME = 0x80;
/** /** Bitmask for the optional way feature "reference". */
* Bitmask for the optional way feature "reference".
*/
private static final int WAY_FEATURE_REF = 0x20; private static final int WAY_FEATURE_REF = 0x20;
/** /** Bitmask for the way layer. */
* Bitmask for the way layer.
*/
private static final int WAY_LAYER_BITMASK = 0xf0; private static final int WAY_LAYER_BITMASK = 0xf0;
/** /** Bit shift for calculating the way layer. */
* Bit shift for calculating the way layer.
*/
private static final int WAY_LAYER_SHIFT = 4; private static final int WAY_LAYER_SHIFT = 4;
/** /** Bitmask for the number of way tags. */
* Bitmask for the number of way tags.
*/
private static final int WAY_NUMBER_OF_TAGS_BITMASK = 0x0f; private static final int WAY_NUMBER_OF_TAGS_BITMASK = 0x0f;
private long mFileSize; private long mFileSize;
private boolean mDebugFile; private boolean mDebugFile;
private RandomAccessFile mInputFile; private RandomAccessFile mInputFile;
@ -188,6 +138,8 @@ public class MapDatabase implements ITileDataSource {
private final MapFileTileSource mTileSource; private final MapFileTileSource mTileSource;
//private int mReductionCnt;
//private int mSkipPoly;
@Override @Override
public QueryResult executeQuery(MapTile tile, ITileDataSink mapDataSink) { public QueryResult executeQuery(MapTile tile, ITileDataSink mapDataSink) {
@ -201,15 +153,38 @@ public class MapDatabase implements ITileDataSource {
try { try {
mTile = tile; mTile = tile;
// size of tile in map coordinates;
double size = 1.0 / (1 << tile.zoomLevel);
// simplification tolerance
int pixel = (tile.zoomLevel > 11) ? 1 : 2;
int simplify = Tile.SIZE / pixel;
// translate screen pixel for tile to latitude and longitude
// tolerance for point reduction before projection.
minLat = (int) (Math.abs(MercatorProjection.toLatitude(tile.y + size)
- MercatorProjection.toLatitude(tile.y)) * 1e6) / simplify;
minLon = (int) (Math.abs(MercatorProjection.toLongitude(tile.x + size)
- MercatorProjection.toLongitude(tile.x)) * 1e6) / simplify;
//mReductionCnt = 0;
//mSkipPoly = 0;
//Log.d(TAG, "simplify by " + minLat + "/" + minLon);
QueryParameters queryParameters = new QueryParameters(); QueryParameters queryParameters = new QueryParameters();
queryParameters.queryZoomLevel = mTileSource.fileHeader queryParameters.queryZoomLevel =
.getQueryZoomLevel(tile.zoomLevel); mTileSource.fileHeader.getQueryZoomLevel(tile.zoomLevel);
// get and check the sub-file for the query zoom level // get and check the sub-file for the query zoom level
SubFileParameter subFileParameter = mTileSource.fileHeader SubFileParameter subFileParameter =
.getSubFileParameter(queryParameters.queryZoomLevel); mTileSource.fileHeader.getSubFileParameter(queryParameters.queryZoomLevel);
if (subFileParameter == null) { if (subFileParameter == null) {
Log.w(TAG, "no sub-file for zoom level: " Log.w(TAG, "no sub-file for zoom level: "
+ queryParameters.queryZoomLevel); + queryParameters.queryZoomLevel);
return QueryResult.FAILED; return QueryResult.FAILED;
} }
@ -220,24 +195,27 @@ public class MapDatabase implements ITileDataSource {
Log.e(TAG, e.getMessage()); Log.e(TAG, e.getMessage());
return QueryResult.FAILED; return QueryResult.FAILED;
} }
//Log.d(TAG, "reduced points " + mReductionCnt + " / polys " + mSkipPoly);
return QueryResult.SUCCESS; return QueryResult.SUCCESS;
} }
public MapDatabase(MapFileTileSource tileSource) throws IOException { public MapDatabase(MapFileTileSource tileSource) throws IOException {
mTileSource = tileSource; mTileSource = tileSource;
try { try {
// open the file in read only mode // open the file in read only mode
mInputFile = new RandomAccessFile(tileSource.mapFile, "r"); mInputFile = new RandomAccessFile(tileSource.mapFile, "r");
mFileSize = mInputFile.length(); mFileSize = mInputFile.length();
mReadBuffer = new ReadBuffer(mInputFile); mReadBuffer = new ReadBuffer(mInputFile);
} catch (IOException e) { } catch (IOException e) {
Log.e(TAG, e.getMessage()); Log.e(TAG, e.getMessage());
// make sure that the file is closed // make sure that the file is closed
destroy(); destroy();
throw new IOException(); throw new IOException();
}
} }
}
@Override @Override
public void destroy() { public void destroy() {
@ -251,7 +229,6 @@ public class MapDatabase implements ITileDataSource {
Log.e(TAG, e.getMessage()); Log.e(TAG, e.getMessage());
} }
} }
} }
/** /**
@ -267,7 +244,7 @@ public class MapDatabase implements ITileDataSource {
/** /**
* Processes a single block and executes the callback functions on all map * Processes a single block and executes the callback functions on all map
* elements. * elements.
* *
* @param queryParameters * @param queryParameters
* the parameters of the current query. * the parameters of the current query.
* @param subFileParameter * @param subFileParameter
@ -276,8 +253,8 @@ public class MapDatabase implements ITileDataSource {
* the callback which handles the extracted map elements. * the callback which handles the extracted map elements.
*/ */
private void processBlock(QueryParameters queryParameters, private void processBlock(QueryParameters queryParameters,
SubFileParameter subFileParameter, SubFileParameter subFileParameter,
ITileDataSink mapDataSink) { ITileDataSink mapDataSink) {
if (!processBlockSignature()) { if (!processBlockSignature()) {
return; return;
} }
@ -332,8 +309,8 @@ public class MapDatabase implements ITileDataSource {
} }
private void processBlocks(ITileDataSink mapDataSink, private void processBlocks(ITileDataSink mapDataSink,
QueryParameters queryParameters, QueryParameters queryParameters,
SubFileParameter subFileParameter) throws IOException { SubFileParameter subFileParameter) throws IOException {
boolean queryIsWater = true; boolean queryIsWater = true;
// boolean queryReadWaterInfo = false; // boolean queryReadWaterInfo = false;
@ -346,8 +323,8 @@ public class MapDatabase implements ITileDataSource {
long blockNumber = row * subFileParameter.blocksWidth + column; long blockNumber = row * subFileParameter.blocksWidth + column;
// get the current index entry // get the current index entry
long currentBlockIndexEntry = mTileSource.databaseIndexCache.getIndexEntry( long currentBlockIndexEntry =
subFileParameter, blockNumber); mTileSource.databaseIndexCache.getIndexEntry(subFileParameter, blockNumber);
// check if the current query would still return a water tile // check if the current query would still return a water tile
if (queryIsWater) { if (queryIsWater) {
@ -360,7 +337,7 @@ public class MapDatabase implements ITileDataSource {
// get and check the current block pointer // get and check the current block pointer
long currentBlockPointer = currentBlockIndexEntry & BITMASK_INDEX_OFFSET; long currentBlockPointer = currentBlockIndexEntry & BITMASK_INDEX_OFFSET;
if (currentBlockPointer < 1 if (currentBlockPointer < 1
|| currentBlockPointer > subFileParameter.subFileSize) { || currentBlockPointer > subFileParameter.subFileSize) {
Log.w(TAG, "invalid current block pointer: " + currentBlockPointer); Log.w(TAG, "invalid current block pointer: " + currentBlockPointer);
Log.w(TAG, "subFileSize: " + subFileParameter.subFileSize); Log.w(TAG, "subFileSize: " + subFileParameter.subFileSize);
return; return;
@ -373,11 +350,12 @@ public class MapDatabase implements ITileDataSource {
nextBlockPointer = subFileParameter.subFileSize; nextBlockPointer = subFileParameter.subFileSize;
} else { } else {
// get and check the next block pointer // get and check the next block pointer
nextBlockPointer = mTileSource.databaseIndexCache.getIndexEntry( nextBlockPointer =
subFileParameter, blockNumber + 1) mTileSource.databaseIndexCache.getIndexEntry(subFileParameter,
& BITMASK_INDEX_OFFSET; blockNumber + 1)
& BITMASK_INDEX_OFFSET;
if (nextBlockPointer < 1 if (nextBlockPointer < 1
|| nextBlockPointer > subFileParameter.subFileSize) { || nextBlockPointer > subFileParameter.subFileSize) {
Log.w(TAG, "invalid next block pointer: " + nextBlockPointer); Log.w(TAG, "invalid next block pointer: " + nextBlockPointer);
Log.w(TAG, "sub-file size: " + subFileParameter.subFileSize); Log.w(TAG, "sub-file size: " + subFileParameter.subFileSize);
return; return;
@ -388,7 +366,7 @@ public class MapDatabase implements ITileDataSource {
int currentBlockSize = (int) (nextBlockPointer - currentBlockPointer); int currentBlockSize = (int) (nextBlockPointer - currentBlockPointer);
if (currentBlockSize < 0) { if (currentBlockSize < 0) {
Log.w(TAG, "current block size must not be negative: " Log.w(TAG, "current block size must not be negative: "
+ currentBlockSize); + currentBlockSize);
return; return;
} else if (currentBlockSize == 0) { } else if (currentBlockSize == 0) {
// the current block is empty, continue with the next block // the current block is empty, continue with the next block
@ -400,7 +378,7 @@ public class MapDatabase implements ITileDataSource {
continue; continue;
} else if (currentBlockPointer + currentBlockSize > mFileSize) { } else if (currentBlockPointer + currentBlockSize > mFileSize) {
Log.w(TAG, "current block larger than file size: " Log.w(TAG, "current block larger than file size: "
+ currentBlockSize); + currentBlockSize);
return; return;
} }
@ -415,14 +393,15 @@ public class MapDatabase implements ITileDataSource {
} }
// calculate the top-left coordinates of the underlying tile // calculate the top-left coordinates of the underlying tile
double tileLatitudeDeg = Projection.tileYToLatitude( double tileLatitudeDeg =
subFileParameter.boundaryTileTop + row, Projection.tileYToLatitude(subFileParameter.boundaryTileTop + row,
subFileParameter.baseZoomLevel); subFileParameter.baseZoomLevel);
double tileLongitudeDeg = Projection.tileXToLongitude( double tileLongitudeDeg =
subFileParameter.boundaryTileLeft Projection.tileXToLongitude(subFileParameter.boundaryTileLeft + column,
+ column, subFileParameter.baseZoomLevel); subFileParameter.baseZoomLevel);
mTileLatitude = (int) (tileLatitudeDeg * 1000000);
mTileLongitude = (int) (tileLongitudeDeg * 1000000); mTileLatitude = (int) (tileLatitudeDeg * 1E6);
mTileLongitude = (int) (tileLongitudeDeg * 1E6);
processBlock(queryParameters, subFileParameter, mapDataSink); processBlock(queryParameters, subFileParameter, mapDataSink);
} }
@ -438,12 +417,11 @@ public class MapDatabase implements ITileDataSource {
// mWayNodePosition += 8; // mWayNodePosition += 8;
// mapDatabaseCallback.renderWaterBackground(tags, wayDataContainer); // mapDatabaseCallback.renderWaterBackground(tags, wayDataContainer);
// } // }
} }
/** /**
* Processes the block signature, if present. * Processes the block signature, if present.
* *
* @return true if the block signature could be processed successfully, * @return true if the block signature could be processed successfully,
* false otherwise. * false otherwise.
*/ */
@ -461,7 +439,7 @@ public class MapDatabase implements ITileDataSource {
/** /**
* Processes the given number of POIs. * Processes the given number of POIs.
* *
* @param mapDataSink * @param mapDataSink
* the callback which handles the extracted POIs. * the callback which handles the extracted POIs.
* @param numberOfPois * @param numberOfPois
@ -543,15 +521,16 @@ public class MapDatabase implements ITileDataSource {
// Integer.toString(mReadBuffer.readSignedInt()))); // Integer.toString(mReadBuffer.readSignedInt())));
} }
longitude = (int) (longitude / divx - dx); float lon = (float) (longitude / divx - dx);
double sinLat = Math.sin(latitude * PI180); double sinLat = Math.sin(latitude * PI180);
latitude = (int) (Math.log((1.0 + sinLat) / (1.0 - sinLat)) * divy + dy); float lat = Tile.SIZE
- (float) ((Math.log((1.0 + sinLat) / (1.0 - sinLat)) * divy + dy));
mElem.clear(); mElem.clear();
mElem.startPoints();
mElem.addPoint(longitude, latitude);
mElem.type = GeometryType.POINT;
mElem.setLayer(layer); mElem.setLayer(layer);
mElem.startPoints();
mElem.addPoint(lon, lat);
mapDataSink.process(mElem); mapDataSink.process(mElem);
} }
@ -572,7 +551,7 @@ public class MapDatabase implements ITileDataSource {
if (wayLengths.length > numBlocks) if (wayLengths.length > numBlocks)
wayLengths[numBlocks] = -1; wayLengths[numBlocks] = -1;
mElem.pointPos = 0; //mElem.pointPos = 0;
// read the way coordinate blocks // read the way coordinate blocks
for (int coordinateBlock = 0; coordinateBlock < numBlocks; ++coordinateBlock) { for (int coordinateBlock = 0; coordinateBlock < numBlocks; ++coordinateBlock) {
@ -605,44 +584,53 @@ public class MapDatabase implements ITileDataSource {
mReadBuffer.readSignedInt(buffer, length); mReadBuffer.readSignedInt(buffer, length);
float[] outBuffer = mElem.ensurePointSize(mElem.pointPos + length, true); float[] outBuffer = mElem.ensurePointSize(mElem.pointPos + length, true);
int pointPos = mElem.pointPos; int outPos = mElem.pointPos;
int lat, lon;
// get the first way node latitude offset (VBE-S) // get the first way node latitude offset
int wayNodeLatitude = mTileLatitude + buffer[0]; int firstLat = lat = mTileLatitude + buffer[0];
// get the first way node longitude offset (VBE-S) // get the first way node longitude offset
int wayNodeLongitude = mTileLongitude + buffer[1]; int firstLon = lon = mTileLongitude + buffer[1];
// store the first way node outBuffer[outPos++] = lon;
outBuffer[pointPos++] = wayNodeLongitude; outBuffer[outPos++] = lat;
outBuffer[pointPos++] = wayNodeLatitude; int cnt = 2;
int singleDeltaLatitude = 0; int deltaLat = 0;
int singleDeltaLongitude = 0; int deltaLon = 0;
int cnt = 2, nLon, nLat, dLat, dLon;
for (int pos = 2; pos < length; pos += 2) { for (int pos = 2; pos < length; pos += 2) {
deltaLat = buffer[pos] + deltaLat;
lat += deltaLat;
singleDeltaLatitude = buffer[pos] + singleDeltaLatitude; deltaLon = buffer[pos + 1] + deltaLon;
nLat = wayNodeLatitude + singleDeltaLatitude; lon += deltaLon;
dLat = nLat - wayNodeLatitude;
wayNodeLatitude = nLat;
singleDeltaLongitude = buffer[pos + 1] + singleDeltaLongitude; if (pos == length - 2) {
nLon = wayNodeLongitude + singleDeltaLongitude; boolean line = (lon != firstLon && lat != firstLat);
dLon = nLon - wayNodeLongitude; // this also removes closed ways that are not polygon,
wayNodeLongitude = nLon; // but how do we know?
if (line) {
outBuffer[outPos++] = lon;
outBuffer[outPos++] = lat;
cnt += 2;
}
if (dLon > minLon || dLon < -minLon || dLat > minLat || dLat < -minLat if (mElem.type == GeometryType.NONE) {
|| (pos == length - 2)) { mElem.type = line ? GeometryType.LINE : GeometryType.POLY;
outBuffer[pointPos++] = nLon; }
outBuffer[pointPos++] = nLat;
} else if (deltaLon > minLon || deltaLon < -minLon
|| deltaLat > minLat || deltaLat < -minLat) {
outBuffer[outPos++] = lon;
outBuffer[outPos++] = lat;
cnt += 2; cnt += 2;
} }
} }
mElem.pointPos = pointPos; //mReductionCnt += length - cnt;
mElem.pointPos = outPos;
return cnt; return cnt;
} }
@ -652,39 +640,49 @@ public class MapDatabase implements ITileDataSource {
mReadBuffer.readSignedInt(buffer, length); mReadBuffer.readSignedInt(buffer, length);
float[] outBuffer = mElem.ensurePointSize(mElem.pointPos + length, true); float[] outBuffer = mElem.ensurePointSize(mElem.pointPos + length, true);
int pointPos = mElem.pointPos; int outPos = mElem.pointPos;
int lat, lon;
// get the first way node latitude single-delta offset (VBE-S) // get the first way node latitude single-delta offset
int wayNodeLatitude = mTileLatitude + buffer[0]; int firstLat = lat = mTileLatitude + buffer[0];
// get the first way node longitude single-delta offset (VBE-S) // get the first way node longitude single-delta offset
int wayNodeLongitude = mTileLongitude + buffer[1]; int firstLon = lon = mTileLongitude + buffer[1];
// store the first way node outBuffer[outPos++] = lon;
outBuffer[pointPos++] = wayNodeLongitude; outBuffer[outPos++] = lat;
outBuffer[pointPos++] = wayNodeLatitude; int cnt = 2;
int cnt = 2, nLon, nLat, dLat, dLon;
for (int pos = 2; pos < length; pos += 2) { for (int pos = 2; pos < length; pos += 2) {
int deltaLat = buffer[pos];
lat += deltaLat;
nLat = wayNodeLatitude + buffer[pos]; int deltaLon = buffer[pos + 1];
dLat = nLat - wayNodeLatitude; lon += deltaLon;
wayNodeLatitude = nLat;
nLon = wayNodeLongitude + buffer[pos + 1]; if (pos == length - 2) {
dLon = nLon - wayNodeLongitude; boolean line = (lon != firstLon && lat != firstLat);
wayNodeLongitude = nLon;
if (dLon > minLon || dLon < -minLon || dLat > minLat || dLat < -minLat if (line) {
|| (pos == length - 2)) { outBuffer[outPos++] = lon;
outBuffer[pointPos++] = nLon; outBuffer[outPos++] = lat;
outBuffer[pointPos++] = nLat; cnt += 2;
}
if (mElem.type == GeometryType.NONE)
mElem.type = line ? GeometryType.LINE : GeometryType.POLY;
} else if (deltaLon > minLon || deltaLon < -minLon
|| deltaLat > minLat || deltaLat < -minLat) {
outBuffer[outPos++] = lon;
outBuffer[outPos++] = lat;
cnt += 2; cnt += 2;
} }
} }
mElem.pointPos = pointPos; //mReductionCnt += length - cnt;
mElem.pointPos = outPos;
return cnt; return cnt;
} }
@ -692,7 +690,7 @@ public class MapDatabase implements ITileDataSource {
/** /**
* Processes the given number of ways. * Processes the given number of ways.
* *
* @param queryParameters * @param queryParameters
* the parameters of the current query. * the parameters of the current query.
* @param mapDataSink * @param mapDataSink
@ -703,8 +701,8 @@ public class MapDatabase implements ITileDataSource {
* otherwise. * otherwise.
*/ */
private boolean processWays(QueryParameters queryParameters, private boolean processWays(QueryParameters queryParameters,
ITileDataSink mapDataSink, ITileDataSink mapDataSink,
int numberOfWays) { int numberOfWays) {
Tag[] wayTags = mTileSource.fileInfo.wayTags; Tag[] wayTags = mTileSource.fileInfo.wayTags;
int numTags = 0; int numTags = 0;
@ -734,7 +732,7 @@ public class MapDatabase implements ITileDataSource {
if (queryParameters.useTileBitmask) { if (queryParameters.useTileBitmask) {
elementCounter = mReadBuffer.skipWays(queryParameters.queryTileBitmask, elementCounter = mReadBuffer.skipWays(queryParameters.queryTileBitmask,
elementCounter); elementCounter);
if (elementCounter == 0) if (elementCounter == 0)
return true; return true;
@ -746,7 +744,8 @@ public class MapDatabase implements ITileDataSource {
int pos = mReadBuffer.getBufferPosition(); int pos = mReadBuffer.getBufferPosition();
mReadBuffer.setBufferPosition(mReadBuffer.lastTagPosition); mReadBuffer.setBufferPosition(mReadBuffer.lastTagPosition);
byte numberOfTags = (byte) (mReadBuffer.readByte() & WAY_NUMBER_OF_TAGS_BITMASK); byte numberOfTags =
(byte) (mReadBuffer.readByte() & WAY_NUMBER_OF_TAGS_BITMASK);
if (!mReadBuffer.readTags(mElem.tags, wayTags, numberOfTags)) if (!mReadBuffer.readTags(mElem.tags, wayTags, numberOfTags))
return false; return false;
@ -777,7 +776,7 @@ public class MapDatabase implements ITileDataSource {
// bit 5-8 represent the number of tag IDs // bit 5-8 represent the number of tag IDs
byte numberOfTags = (byte) (specialByte & WAY_NUMBER_OF_TAGS_BITMASK); byte numberOfTags = (byte) (specialByte & WAY_NUMBER_OF_TAGS_BITMASK);
if (numberOfTags != 0){ if (numberOfTags != 0) {
if (!mReadBuffer.readTags(mElem.tags, wayTags, numberOfTags)) if (!mReadBuffer.readTags(mElem.tags, wayTags, numberOfTags))
return false; return false;
@ -789,7 +788,8 @@ public class MapDatabase implements ITileDataSource {
byte featureByte = mReadBuffer.readByte(); byte featureByte = mReadBuffer.readByte();
// bit 1-6 enable optional features // bit 1-6 enable optional features
boolean featureWayDoubleDeltaEncoding = (featureByte & WAY_FEATURE_DOUBLE_DELTA_ENCODING) != 0; boolean featureWayDoubleDeltaEncoding =
(featureByte & WAY_FEATURE_DOUBLE_DELTA_ENCODING) != 0;
boolean hasName = (featureByte & WAY_FEATURE_NAME) != 0; boolean hasName = (featureByte & WAY_FEATURE_NAME) != 0;
boolean hasHouseNr = (featureByte & WAY_FEATURE_HOUSE_NUMBER) != 0; boolean hasHouseNr = (featureByte & WAY_FEATURE_HOUSE_NUMBER) != 0;
@ -843,21 +843,20 @@ public class MapDatabase implements ITileDataSource {
wayDataBlocks = 1; wayDataBlocks = 1;
} }
for (int wayDataBlock = 0; wayDataBlock < wayDataBlocks; ++wayDataBlock) { for (int wayDataBlock = 0; wayDataBlock < wayDataBlocks; wayDataBlock++) {
mElem.clear();
if (!processWayDataBlock(featureWayDoubleDeltaEncoding)) if (!processWayDataBlock(featureWayDoubleDeltaEncoding))
return false; return false;
// wayDataContainer.textPos = textPos; if (mElem.isPoly() && mElem.index[0] < 6) {
int l = mElem.index[0]; //mSkipPoly++;
continue;
}
boolean closed = mElem.points[0] == mElem.points[l - 2] projectToTile(mElem);
&& mElem.points[1] == mElem.points[l - 1];
projectToTile(mElem.points, mElem.index);
mElem.type = closed ? GeometryType.POLY : GeometryType.LINE;
mElem.setLayer(layer); mElem.setLayer(layer);
mapDataSink.process(mElem); mapDataSink.process(mElem);
} }
} }
@ -889,17 +888,17 @@ public class MapDatabase implements ITileDataSource {
cumulatedNumberOfWays += mReadBuffer.readUnsignedInt(); cumulatedNumberOfWays += mReadBuffer.readUnsignedInt();
if (cumulatedNumberOfPois < 0 if (cumulatedNumberOfPois < 0
|| cumulatedNumberOfPois > MAXIMUM_ZOOM_TABLE_OBJECTS) { || cumulatedNumberOfPois > MAXIMUM_ZOOM_TABLE_OBJECTS) {
Log.w(TAG, "invalid cumulated number of POIs in row " + row + ' ' Log.w(TAG, "invalid cumulated number of POIs in row " + row + ' '
+ cumulatedNumberOfPois); + cumulatedNumberOfPois);
if (mDebugFile) { if (mDebugFile) {
Log.w(TAG, DEBUG_SIGNATURE_BLOCK + mSignatureBlock); Log.w(TAG, DEBUG_SIGNATURE_BLOCK + mSignatureBlock);
} }
return null; return null;
} else if (cumulatedNumberOfWays < 0 } else if (cumulatedNumberOfWays < 0
|| cumulatedNumberOfWays > MAXIMUM_ZOOM_TABLE_OBJECTS) { || cumulatedNumberOfWays > MAXIMUM_ZOOM_TABLE_OBJECTS) {
Log.w(TAG, "invalid cumulated number of ways in row " + row + ' ' Log.w(TAG, "invalid cumulated number of ways in row " + row + ' '
+ cumulatedNumberOfWays); + cumulatedNumberOfWays);
if (mTileSource.fileInfo.debugFile) { if (mTileSource.fileInfo.debugFile) {
Log.w(TAG, DEBUG_SIGNATURE_BLOCK + mSignatureBlock); Log.w(TAG, DEBUG_SIGNATURE_BLOCK + mSignatureBlock);
} }
@ -916,7 +915,10 @@ public class MapDatabase implements ITileDataSource {
private static final double PI180 = (Math.PI / 180) / 1000000.0; private static final double PI180 = (Math.PI / 180) / 1000000.0;
private static final double PIx4 = Math.PI * 4; private static final double PIx4 = Math.PI * 4;
private boolean projectToTile(float[] coords, short[] indices) { private boolean projectToTile(GeometryBuffer geom) {
float[] coords = geom.points;
short[] indices = geom.index;
long x = mTile.tileX * Tile.SIZE; long x = mTile.tileX * Tile.SIZE;
long y = mTile.tileY * Tile.SIZE + Tile.SIZE; long y = mTile.tileY * Tile.SIZE + Tile.SIZE;
@ -948,15 +950,18 @@ public class MapDatabase implements ITileDataSource {
if (cnt != 0) { if (cnt != 0) {
// drop small distance intermediate nodes // drop small distance intermediate nodes
if (lat == prevLat && lon == prevLon) if (lat == prevLat && lon == prevLon) {
//Log.d(TAG, "drop zero delta ");
continue; continue;
}
} }
coords[outPos++] = prevLon = lon; coords[outPos++] = prevLon = lon;
coords[outPos++] = prevLat = lat; coords[outPos++] = prevLat = lat;
cnt += 2; cnt += 2;
} }
if (coords[first] == coords[outPos - 2] && coords[first + 1] == coords[outPos - 1]) {
if (coords[first] == prevLon && coords[first + 1] == prevLat) {
//Log.d(TAG, "drop closed"); //Log.d(TAG, "drop closed");
indices[i] = (short) (cnt - 2); indices[i] = (short) (cnt - 2);
outPos -= 2; outPos -= 2;