mapsforge: estimate whether a closed way is line or polygon
- refactor projection - cleanups
This commit is contained in:
parent
ef34ba9766
commit
68fe1f8b8a
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011, 2012 mapsforge.org
|
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||||
* Copyright 2013 Hannes Janetzek
|
* Copyright 2013, 2014 Hannes Janetzek
|
||||||
*
|
*
|
||||||
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
|
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
|
||||||
*
|
*
|
||||||
@ -23,7 +23,6 @@ import static org.oscim.tiling.ITileDataSink.QueryResult.SUCCESS;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.RandomAccessFile;
|
import java.io.RandomAccessFile;
|
||||||
|
|
||||||
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.MercatorProjection;
|
||||||
@ -140,11 +139,33 @@ public class MapDatabase implements ITileDataSource {
|
|||||||
|
|
||||||
private final MapElement mElem = new MapElement();
|
private final MapElement mElem = new MapElement();
|
||||||
|
|
||||||
private int minLat, minLon;
|
private int minDeltaLat, minDeltaLon;
|
||||||
private Tile mTile;
|
|
||||||
|
private final TileProjection mTileProjection;
|
||||||
|
private final TileClipper mTileClipper;
|
||||||
|
|
||||||
private final MapFileTileSource mTileSource;
|
private final MapFileTileSource mTileSource;
|
||||||
|
|
||||||
|
public MapDatabase(MapFileTileSource tileSource) throws IOException {
|
||||||
|
mTileSource = tileSource;
|
||||||
|
try {
|
||||||
|
/* open the file in read only mode */
|
||||||
|
mInputFile = new RandomAccessFile(tileSource.mapFile, "r");
|
||||||
|
mFileSize = mInputFile.length();
|
||||||
|
mReadBuffer = new ReadBuffer(mInputFile);
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error(e.getMessage());
|
||||||
|
/* make sure that the file is closed */
|
||||||
|
dispose();
|
||||||
|
throw new IOException();
|
||||||
|
}
|
||||||
|
|
||||||
|
mTileProjection = new TileProjection();
|
||||||
|
|
||||||
|
mTileClipper = new TileClipper(-2, -2, Tile.SIZE + 2, Tile.SIZE + 2);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void query(MapTile tile, ITileDataSink sink) {
|
public void query(MapTile tile, ITileDataSink sink) {
|
||||||
|
|
||||||
@ -157,28 +178,29 @@ public class MapDatabase implements ITileDataSource {
|
|||||||
mIntBuffer = new int[MAXIMUM_WAY_NODES_SEQUENCE_LENGTH * 2];
|
mIntBuffer = new int[MAXIMUM_WAY_NODES_SEQUENCE_LENGTH * 2];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mTile = tile;
|
mTileProjection.setTile(tile);
|
||||||
|
//mTile = tile;
|
||||||
|
|
||||||
// size of tile in map coordinates;
|
/* size of tile in map coordinates; */
|
||||||
double size = 1.0 / (1 << tile.zoomLevel);
|
double size = 1.0 / (1 << tile.zoomLevel);
|
||||||
|
|
||||||
// simplification tolerance
|
/* simplification tolerance */
|
||||||
int pixel = (tile.zoomLevel > 11) ? 1 : 2;
|
int pixel = (tile.zoomLevel > 11) ? 1 : 2;
|
||||||
|
|
||||||
int simplify = Tile.SIZE / pixel;
|
int simplify = Tile.SIZE / pixel;
|
||||||
|
|
||||||
// translate screen pixel for tile to latitude and longitude
|
/* translate screen pixel for tile to latitude and longitude
|
||||||
// tolerance for point reduction before projection.
|
* tolerance for point reduction before projection. */
|
||||||
minLat = (int) (Math.abs(MercatorProjection.toLatitude(tile.y + size)
|
minDeltaLat = (int) (Math.abs(MercatorProjection.toLatitude(tile.y + size)
|
||||||
- MercatorProjection.toLatitude(tile.y)) * 1e6) / simplify;
|
- MercatorProjection.toLatitude(tile.y)) * 1e6) / simplify;
|
||||||
minLon = (int) (Math.abs(MercatorProjection.toLongitude(tile.x + size)
|
minDeltaLon = (int) (Math.abs(MercatorProjection.toLongitude(tile.x + size)
|
||||||
- MercatorProjection.toLongitude(tile.x)) * 1e6) / simplify;
|
- MercatorProjection.toLongitude(tile.x)) * 1e6) / simplify;
|
||||||
|
|
||||||
QueryParameters queryParameters = new QueryParameters();
|
QueryParameters queryParameters = new QueryParameters();
|
||||||
queryParameters.queryZoomLevel =
|
queryParameters.queryZoomLevel =
|
||||||
mTileSource.fileHeader.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 =
|
SubFileParameter subFileParameter =
|
||||||
mTileSource.fileHeader.getSubFileParameter(queryParameters.queryZoomLevel);
|
mTileSource.fileHeader.getSubFileParameter(queryParameters.queryZoomLevel);
|
||||||
|
|
||||||
@ -202,22 +224,6 @@ public class MapDatabase implements ITileDataSource {
|
|||||||
sink.completed(SUCCESS);
|
sink.completed(SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MapDatabase(MapFileTileSource tileSource) throws IOException {
|
|
||||||
mTileSource = tileSource;
|
|
||||||
try {
|
|
||||||
// open the file in read only mode
|
|
||||||
mInputFile = new RandomAccessFile(tileSource.mapFile, "r");
|
|
||||||
mFileSize = mInputFile.length();
|
|
||||||
mReadBuffer = new ReadBuffer(mInputFile);
|
|
||||||
|
|
||||||
} catch (IOException e) {
|
|
||||||
log.error(e.getMessage());
|
|
||||||
// make sure that the file is closed
|
|
||||||
dispose();
|
|
||||||
throw new IOException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dispose() {
|
public void dispose() {
|
||||||
mReadBuffer = null;
|
mReadBuffer = null;
|
||||||
@ -272,7 +278,7 @@ public class MapDatabase implements ITileDataSource {
|
|||||||
int poisOnQueryZoomLevel = zoomTable[zoomTableRow][0];
|
int poisOnQueryZoomLevel = zoomTable[zoomTableRow][0];
|
||||||
int waysOnQueryZoomLevel = zoomTable[zoomTableRow][1];
|
int waysOnQueryZoomLevel = zoomTable[zoomTableRow][1];
|
||||||
|
|
||||||
// get the relative offset to the first stored way in the block
|
/* get the relative offset to the first stored way in the block */
|
||||||
int firstWayOffset = mReadBuffer.readUnsignedInt();
|
int firstWayOffset = mReadBuffer.readUnsignedInt();
|
||||||
if (firstWayOffset < 0) {
|
if (firstWayOffset < 0) {
|
||||||
log.warn(INVALID_FIRST_WAY_OFFSET + firstWayOffset);
|
log.warn(INVALID_FIRST_WAY_OFFSET + firstWayOffset);
|
||||||
@ -282,7 +288,7 @@ public class MapDatabase implements ITileDataSource {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// add the current buffer position to the relative first way offset
|
/* add the current buffer position to the relative first way offset */
|
||||||
firstWayOffset += mReadBuffer.getBufferPosition();
|
firstWayOffset += mReadBuffer.getBufferPosition();
|
||||||
if (firstWayOffset > mReadBuffer.getBufferSize()) {
|
if (firstWayOffset > mReadBuffer.getBufferSize()) {
|
||||||
log.warn(INVALID_FIRST_WAY_OFFSET + firstWayOffset);
|
log.warn(INVALID_FIRST_WAY_OFFSET + firstWayOffset);
|
||||||
@ -296,7 +302,7 @@ public class MapDatabase implements ITileDataSource {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// finished reading POIs, check if the current buffer position is valid
|
/* finished reading POIs, check if the current buffer position is valid */
|
||||||
if (mReadBuffer.getBufferPosition() > firstWayOffset) {
|
if (mReadBuffer.getBufferPosition() > firstWayOffset) {
|
||||||
log.warn("invalid buffer position: " + mReadBuffer.getBufferPosition());
|
log.warn("invalid buffer position: " + mReadBuffer.getBufferPosition());
|
||||||
if (mDebugFile) {
|
if (mDebugFile) {
|
||||||
@ -305,7 +311,7 @@ public class MapDatabase implements ITileDataSource {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// move the pointer to the first way
|
/* move the pointer to the first way */
|
||||||
mReadBuffer.setBufferPosition(firstWayOffset);
|
mReadBuffer.setBufferPosition(firstWayOffset);
|
||||||
|
|
||||||
if (!processWays(queryParameters, mapDataSink, waysOnQueryZoomLevel)) {
|
if (!processWays(queryParameters, mapDataSink, waysOnQueryZoomLevel)) {
|
||||||
@ -323,21 +329,21 @@ public class MapDatabase implements ITileDataSource {
|
|||||||
boolean queryIsWater = true;
|
boolean queryIsWater = true;
|
||||||
// boolean queryReadWaterInfo = false;
|
// boolean queryReadWaterInfo = false;
|
||||||
|
|
||||||
// read and process all blocks from top to bottom and from left to right
|
/* read and process all blocks from top to bottom and from left to right */
|
||||||
for (long row = queryParameters.fromBlockY; row <= queryParameters.toBlockY; row++) {
|
for (long row = queryParameters.fromBlockY; row <= queryParameters.toBlockY; row++) {
|
||||||
for (long column = queryParameters.fromBlockX; column <= queryParameters.toBlockX; column++) {
|
for (long column = queryParameters.fromBlockX; column <= queryParameters.toBlockX; column++) {
|
||||||
mCurrentCol = column - queryParameters.fromBlockX;
|
mCurrentCol = column - queryParameters.fromBlockX;
|
||||||
mCurrentRow = row - queryParameters.fromBlockY;
|
mCurrentRow = row - queryParameters.fromBlockY;
|
||||||
|
|
||||||
// calculate the actual block number of the needed block in the
|
/* calculate the actual block number of the needed block in the
|
||||||
// file
|
* file */
|
||||||
long blockNumber = row * subFileParameter.blocksWidth + column;
|
long blockNumber = row * subFileParameter.blocksWidth + column;
|
||||||
|
|
||||||
// get the current index entry
|
/* get the current index entry */
|
||||||
long currentBlockIndexEntry =
|
long currentBlockIndexEntry =
|
||||||
mTileSource.databaseIndexCache.getIndexEntry(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) {
|
||||||
// check the water flag of the current block in its index
|
// check the water flag of the current block in its index
|
||||||
// entry
|
// entry
|
||||||
@ -345,7 +351,7 @@ public class MapDatabase implements ITileDataSource {
|
|||||||
// queryReadWaterInfo = true;
|
// queryReadWaterInfo = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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) {
|
||||||
@ -355,12 +361,12 @@ public class MapDatabase implements ITileDataSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
long nextBlockPointer;
|
long nextBlockPointer;
|
||||||
// check if the current block is the last block in the file
|
/* check if the current block is the last block in the file */
|
||||||
if (blockNumber + 1 == subFileParameter.numberOfBlocks) {
|
if (blockNumber + 1 == subFileParameter.numberOfBlocks) {
|
||||||
// set the next block pointer to the end of the file
|
/* set the next block pointer to the end of the file */
|
||||||
nextBlockPointer = subFileParameter.subFileSize;
|
nextBlockPointer = subFileParameter.subFileSize;
|
||||||
} else {
|
} else {
|
||||||
// get and check the next block pointer
|
/* get and check the next block pointer */
|
||||||
nextBlockPointer =
|
nextBlockPointer =
|
||||||
mTileSource.databaseIndexCache.getIndexEntry(subFileParameter,
|
mTileSource.databaseIndexCache.getIndexEntry(subFileParameter,
|
||||||
blockNumber + 1)
|
blockNumber + 1)
|
||||||
@ -373,18 +379,18 @@ public class MapDatabase implements ITileDataSource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculate the size of the current block
|
/* calculate the size of the current block */
|
||||||
int currentBlockSize = (int) (nextBlockPointer - currentBlockPointer);
|
int currentBlockSize = (int) (nextBlockPointer - currentBlockPointer);
|
||||||
if (currentBlockSize < 0) {
|
if (currentBlockSize < 0) {
|
||||||
log.warn("current block size must not be negative: "
|
log.warn("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 */
|
||||||
continue;
|
continue;
|
||||||
} else if (currentBlockSize > ReadBuffer.MAXIMUM_BUFFER_SIZE) {
|
} else if (currentBlockSize > ReadBuffer.MAXIMUM_BUFFER_SIZE) {
|
||||||
// the current block is too large, continue with the next
|
/* the current block is too large, continue with the next
|
||||||
// block
|
* block */
|
||||||
log.warn("current block size too large: " + currentBlockSize);
|
log.warn("current block size too large: " + currentBlockSize);
|
||||||
continue;
|
continue;
|
||||||
} else if (currentBlockPointer + currentBlockSize > mFileSize) {
|
} else if (currentBlockPointer + currentBlockSize > mFileSize) {
|
||||||
@ -393,17 +399,17 @@ public class MapDatabase implements ITileDataSource {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// seek to the current block in the map file
|
/* seek to the current block in the map file */
|
||||||
mInputFile.seek(subFileParameter.startAddress + currentBlockPointer);
|
mInputFile.seek(subFileParameter.startAddress + currentBlockPointer);
|
||||||
|
|
||||||
// read the current block into the buffer
|
/* read the current block into the buffer */
|
||||||
if (!mReadBuffer.readFromFile(currentBlockSize)) {
|
if (!mReadBuffer.readFromFile(currentBlockSize)) {
|
||||||
// skip the current block
|
/* skip the current block */
|
||||||
log.warn("reading current block has failed: " + currentBlockSize);
|
log.warn("reading current block has failed: " + currentBlockSize);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculate the top-left coordinates of the underlying tile
|
/* calculate the top-left coordinates of the underlying tile */
|
||||||
double tileLatitudeDeg =
|
double tileLatitudeDeg =
|
||||||
Projection.tileYToLatitude(subFileParameter.boundaryTileTop + row,
|
Projection.tileYToLatitude(subFileParameter.boundaryTileTop + row,
|
||||||
subFileParameter.baseZoomLevel);
|
subFileParameter.baseZoomLevel);
|
||||||
@ -438,7 +444,7 @@ public class MapDatabase implements ITileDataSource {
|
|||||||
*/
|
*/
|
||||||
private boolean processBlockSignature() {
|
private boolean processBlockSignature() {
|
||||||
if (mDebugFile) {
|
if (mDebugFile) {
|
||||||
// get and check the block signature
|
/* get and check the block signature */
|
||||||
mSignatureBlock = mReadBuffer.readUTF8EncodedString(SIGNATURE_LENGTH_BLOCK);
|
mSignatureBlock = mReadBuffer.readUTF8EncodedString(SIGNATURE_LENGTH_BLOCK);
|
||||||
if (!mSignatureBlock.startsWith("###TileStart")) {
|
if (!mSignatureBlock.startsWith("###TileStart")) {
|
||||||
log.warn("invalid block signature: " + mSignatureBlock);
|
log.warn("invalid block signature: " + mSignatureBlock);
|
||||||
@ -460,21 +466,13 @@ public class MapDatabase implements ITileDataSource {
|
|||||||
*/
|
*/
|
||||||
private boolean processPOIs(ITileDataSink mapDataSink, int numberOfPois) {
|
private boolean processPOIs(ITileDataSink mapDataSink, int numberOfPois) {
|
||||||
Tag[] poiTags = mTileSource.fileInfo.poiTags;
|
Tag[] poiTags = mTileSource.fileInfo.poiTags;
|
||||||
|
MapElement e = mElem;
|
||||||
|
|
||||||
int numTags = 0;
|
int numTags = 0;
|
||||||
|
|
||||||
long x = mTile.tileX * Tile.SIZE;
|
|
||||||
long y = mTile.tileY * Tile.SIZE + Tile.SIZE;
|
|
||||||
long z = 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) {
|
for (int elementCounter = numberOfPois; elementCounter != 0; --elementCounter) {
|
||||||
if (mDebugFile) {
|
if (mDebugFile) {
|
||||||
// get and check the POI signature
|
/* get and check the POI signature */
|
||||||
mSignaturePoi = mReadBuffer.readUTF8EncodedString(SIGNATURE_LENGTH_POI);
|
mSignaturePoi = mReadBuffer.readUTF8EncodedString(SIGNATURE_LENGTH_POI);
|
||||||
if (!mSignaturePoi.startsWith("***POIStart")) {
|
if (!mSignaturePoi.startsWith("***POIStart")) {
|
||||||
log.warn("invalid POI signature: " + mSignaturePoi);
|
log.warn("invalid POI signature: " + mSignaturePoi);
|
||||||
@ -483,88 +481,77 @@ public class MapDatabase implements ITileDataSource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the POI latitude offset (VBE-S)
|
/* get the POI latitude offset (VBE-S) */
|
||||||
int latitude = mTileLatitude + mReadBuffer.readSignedInt();
|
int latitude = mTileLatitude + mReadBuffer.readSignedInt();
|
||||||
|
/* get the POI longitude offset (VBE-S) */
|
||||||
// get the POI longitude offset (VBE-S)
|
|
||||||
int longitude = mTileLongitude + mReadBuffer.readSignedInt();
|
int longitude = mTileLongitude + mReadBuffer.readSignedInt();
|
||||||
|
|
||||||
// get the special byte which encodes multiple flags
|
/* get the special byte which encodes multiple flags */
|
||||||
byte specialByte = mReadBuffer.readByte();
|
byte specialByte = mReadBuffer.readByte();
|
||||||
|
|
||||||
// bit 1-4 represent the layer
|
/* bit 1-4 represent the layer */
|
||||||
byte layer = (byte) ((specialByte & POI_LAYER_BITMASK) >>> POI_LAYER_SHIFT);
|
byte layer = (byte) ((specialByte & POI_LAYER_BITMASK) >>> POI_LAYER_SHIFT);
|
||||||
// bit 5-8 represent the number of tag IDs
|
|
||||||
|
/* bit 5-8 represent the number of tag IDs */
|
||||||
byte numberOfTags = (byte) (specialByte & POI_NUMBER_OF_TAGS_BITMASK);
|
byte numberOfTags = (byte) (specialByte & POI_NUMBER_OF_TAGS_BITMASK);
|
||||||
|
|
||||||
if (numberOfTags != 0) {
|
if (numberOfTags != 0) {
|
||||||
if (!mReadBuffer.readTags(mElem.tags, poiTags, numberOfTags))
|
if (!mReadBuffer.readTags(e.tags, poiTags, numberOfTags))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
numTags = numberOfTags;
|
numTags = numberOfTags;
|
||||||
}
|
}
|
||||||
|
|
||||||
// reset to common tag position
|
/* reset to common tag position */
|
||||||
mElem.tags.numTags = numTags;
|
e.tags.numTags = numTags;
|
||||||
|
|
||||||
// get the feature bitmask (1 byte)
|
/* get the feature bitmask (1 byte) */
|
||||||
byte featureByte = mReadBuffer.readByte();
|
byte featureByte = mReadBuffer.readByte();
|
||||||
|
|
||||||
// bit 1-3 enable optional features
|
/* bit 1-3 enable optional features
|
||||||
// check if the POI has a name
|
* check if the POI has a name */
|
||||||
if ((featureByte & POI_FEATURE_NAME) != 0) {
|
if ((featureByte & POI_FEATURE_NAME) != 0) {
|
||||||
String str = mReadBuffer.readUTF8EncodedString();
|
String str = mReadBuffer.readUTF8EncodedString();
|
||||||
mElem.tags.add(new Tag(Tag.KEY_NAME, str, false));
|
e.tags.add(new Tag(Tag.KEY_NAME, str, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if the POI has a house number
|
/* check if the POI has a house number */
|
||||||
if ((featureByte & POI_FEATURE_HOUSE_NUMBER) != 0) {
|
if ((featureByte & POI_FEATURE_HOUSE_NUMBER) != 0) {
|
||||||
// mReadBuffer.getPositionAndSkip();
|
// mReadBuffer.getPositionAndSkip();
|
||||||
// String str =
|
// String str =
|
||||||
mReadBuffer.readUTF8EncodedString();
|
mReadBuffer.readUTF8EncodedString();
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if the POI has an elevation
|
/* check if the POI has an elevation */
|
||||||
if ((featureByte & POI_FEATURE_ELEVATION) != 0) {
|
if ((featureByte & POI_FEATURE_ELEVATION) != 0) {
|
||||||
mReadBuffer.readSignedInt();
|
mReadBuffer.readSignedInt();
|
||||||
// mReadBuffer.getPositionAndSkip();// tags.add(new
|
// mReadBuffer.getPositionAndSkip();// tags.add(new
|
||||||
// Tag(Tag.TAG_KEY_ELE,
|
// Tag(Tag.TAG_KEY_ELE,
|
||||||
// Integer.toString(mReadBuffer.readSignedInt())));
|
// Integer.toString(mReadBuffer.readSignedInt())));
|
||||||
}
|
}
|
||||||
|
mTileProjection.projectPoint(latitude, longitude, e);
|
||||||
|
|
||||||
float lon = (float) (longitude / divx - dx);
|
e.setLayer(layer);
|
||||||
|
|
||||||
double sinLat = Math.sin(latitude * PI180);
|
mapDataSink.process(e);
|
||||||
float lat = Tile.SIZE
|
|
||||||
- (float) ((Math.log((1.0 + sinLat) / (1.0 - sinLat)) * divy + dy));
|
|
||||||
|
|
||||||
mElem.clear();
|
|
||||||
mElem.setLayer(layer);
|
|
||||||
mElem.startPoints();
|
|
||||||
mElem.addPoint(lon, lat);
|
|
||||||
|
|
||||||
mapDataSink.process(mElem);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean processWayDataBlock(boolean doubleDeltaEncoding) {
|
private boolean processWayDataBlock(MapElement e, boolean doubleDeltaEncoding, boolean isLine) {
|
||||||
// get and check the number of way coordinate blocks (VBE-U)
|
/* get and check the number of way coordinate blocks (VBE-U) */
|
||||||
int numBlocks = mReadBuffer.readUnsignedInt();
|
int numBlocks = mReadBuffer.readUnsignedInt();
|
||||||
if (numBlocks < 1 || numBlocks > Short.MAX_VALUE) {
|
if (numBlocks < 1 || numBlocks > Short.MAX_VALUE) {
|
||||||
log.warn("invalid number of way coordinate blocks: " + numBlocks);
|
log.warn("invalid number of way coordinate blocks: " + numBlocks);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//short[] wayLengths = new short[numBlocks];
|
int[] wayLengths = e.ensureIndexSize(numBlocks, false);
|
||||||
int[] wayLengths = mElem.ensureIndexSize(numBlocks, false);
|
|
||||||
if (wayLengths.length > numBlocks)
|
if (wayLengths.length > numBlocks)
|
||||||
wayLengths[numBlocks] = -1;
|
wayLengths[numBlocks] = -1;
|
||||||
|
|
||||||
//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) {
|
||||||
// get and check the number of way nodes (VBE-U)
|
// get and check the number of way nodes (VBE-U)
|
||||||
int numWayNodes = mReadBuffer.readUnsignedInt();
|
int numWayNodes = mReadBuffer.readUnsignedInt();
|
||||||
@ -575,13 +562,13 @@ public class MapDatabase implements ITileDataSource {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// each way node consists of latitude and longitude
|
/* each way node consists of latitude and longitude */
|
||||||
int len = numWayNodes * 2;
|
int len = numWayNodes * 2;
|
||||||
|
|
||||||
if (doubleDeltaEncoding) {
|
if (doubleDeltaEncoding) {
|
||||||
len = decodeWayNodesDoubleDelta(len);
|
len = decodeWayNodesDoubleDelta(e, len, isLine);
|
||||||
} else {
|
} else {
|
||||||
len = decodeWayNodesSingleDelta(len);
|
len = decodeWayNodesSingleDelta(e, len, isLine);
|
||||||
}
|
}
|
||||||
wayLengths[coordinateBlock] = (short) len;
|
wayLengths[coordinateBlock] = (short) len;
|
||||||
}
|
}
|
||||||
@ -589,19 +576,19 @@ public class MapDatabase implements ITileDataSource {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int decodeWayNodesDoubleDelta(int length) {
|
private int decodeWayNodesDoubleDelta(MapElement e, int length, boolean isLine) {
|
||||||
int[] buffer = mIntBuffer;
|
int[] buffer = mIntBuffer;
|
||||||
|
|
||||||
mReadBuffer.readSignedInt(buffer, length);
|
mReadBuffer.readSignedInt(buffer, length);
|
||||||
|
|
||||||
float[] outBuffer = mElem.ensurePointSize(mElem.pointPos + length, true);
|
float[] outBuffer = e.ensurePointSize(e.pointPos + length, true);
|
||||||
int outPos = mElem.pointPos;
|
int outPos = e.pointPos;
|
||||||
int lat, lon;
|
int lat, lon;
|
||||||
|
|
||||||
// get the first way node latitude offset
|
/* get the first way node latitude offset */
|
||||||
int firstLat = lat = mTileLatitude + buffer[0];
|
int firstLat = lat = mTileLatitude + buffer[0];
|
||||||
|
|
||||||
// get the first way node longitude offset
|
/* get the first way node longitude offset */
|
||||||
int firstLon = lon = mTileLongitude + buffer[1];
|
int firstLon = lon = mTileLongitude + buffer[1];
|
||||||
|
|
||||||
outBuffer[outPos++] = lon;
|
outBuffer[outPos++] = lon;
|
||||||
@ -619,45 +606,43 @@ public class MapDatabase implements ITileDataSource {
|
|||||||
lon += deltaLon;
|
lon += deltaLon;
|
||||||
|
|
||||||
if (pos == length - 2) {
|
if (pos == length - 2) {
|
||||||
boolean line = (lon != firstLon && lat != firstLat);
|
boolean line = isLine || (lon != firstLon && lat != firstLat);
|
||||||
// this also removes closed ways that are not polygon,
|
/* this also removes closed ways that are not polygon,
|
||||||
// but how do we know?
|
* but how do we know? */
|
||||||
if (line) {
|
if (line) {
|
||||||
outBuffer[outPos++] = lon;
|
outBuffer[outPos++] = lon;
|
||||||
outBuffer[outPos++] = lat;
|
outBuffer[outPos++] = lat;
|
||||||
cnt += 2;
|
cnt += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mElem.type == GeometryType.NONE) {
|
if (e.type == GeometryType.NONE) {
|
||||||
mElem.type = line ? GeometryType.LINE : GeometryType.POLY;
|
e.type = line ? GeometryType.LINE : GeometryType.POLY;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (deltaLon > minLon || deltaLon < -minLon
|
} else if (deltaLon > minDeltaLon || deltaLon < -minDeltaLon
|
||||||
|| deltaLat > minLat || deltaLat < -minLat) {
|
|| deltaLat > minDeltaLat || deltaLat < -minDeltaLat) {
|
||||||
outBuffer[outPos++] = lon;
|
outBuffer[outPos++] = lon;
|
||||||
outBuffer[outPos++] = lat;
|
outBuffer[outPos++] = lat;
|
||||||
cnt += 2;
|
cnt += 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//mReductionCnt += length - cnt;
|
e.pointPos = outPos;
|
||||||
mElem.pointPos = outPos;
|
|
||||||
|
|
||||||
return cnt;
|
return cnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int decodeWayNodesSingleDelta(int length) {
|
private int decodeWayNodesSingleDelta(MapElement e, int length, boolean isLine) {
|
||||||
int[] buffer = mIntBuffer;
|
int[] buffer = mIntBuffer;
|
||||||
mReadBuffer.readSignedInt(buffer, length);
|
mReadBuffer.readSignedInt(buffer, length);
|
||||||
|
|
||||||
float[] outBuffer = mElem.ensurePointSize(mElem.pointPos + length, true);
|
float[] outBuffer = e.ensurePointSize(e.pointPos + length, true);
|
||||||
int outPos = mElem.pointPos;
|
int outPos = e.pointPos;
|
||||||
int lat, lon;
|
int lat, lon;
|
||||||
|
|
||||||
// get the first way node latitude single-delta offset
|
/* get the first way node latitude single-delta offset */
|
||||||
int firstLat = lat = mTileLatitude + buffer[0];
|
int firstLat = lat = mTileLatitude + buffer[0];
|
||||||
|
|
||||||
// get the first way node longitude single-delta offset
|
/* get the first way node longitude single-delta offset */
|
||||||
int firstLon = lon = mTileLongitude + buffer[1];
|
int firstLon = lon = mTileLongitude + buffer[1];
|
||||||
|
|
||||||
outBuffer[outPos++] = lon;
|
outBuffer[outPos++] = lon;
|
||||||
@ -672,7 +657,7 @@ public class MapDatabase implements ITileDataSource {
|
|||||||
lon += deltaLon;
|
lon += deltaLon;
|
||||||
|
|
||||||
if (pos == length - 2) {
|
if (pos == length - 2) {
|
||||||
boolean line = (lon != firstLon && lat != firstLat);
|
boolean line = isLine || (lon != firstLon && lat != firstLat);
|
||||||
|
|
||||||
if (line) {
|
if (line) {
|
||||||
outBuffer[outPos++] = lon;
|
outBuffer[outPos++] = lon;
|
||||||
@ -680,19 +665,18 @@ public class MapDatabase implements ITileDataSource {
|
|||||||
cnt += 2;
|
cnt += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mElem.type == GeometryType.NONE)
|
if (e.type == GeometryType.NONE)
|
||||||
mElem.type = line ? GeometryType.LINE : GeometryType.POLY;
|
e.type = line ? GeometryType.LINE : GeometryType.POLY;
|
||||||
|
|
||||||
} else if (deltaLon > minLon || deltaLon < -minLon
|
} else if (deltaLon > minDeltaLon || deltaLon < -minDeltaLon
|
||||||
|| deltaLat > minLat || deltaLat < -minLat) {
|
|| deltaLat > minDeltaLat || deltaLat < -minDeltaLat) {
|
||||||
outBuffer[outPos++] = lon;
|
outBuffer[outPos++] = lon;
|
||||||
outBuffer[outPos++] = lat;
|
outBuffer[outPos++] = lat;
|
||||||
cnt += 2;
|
cnt += 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//mReductionCnt += length - cnt;
|
e.pointPos = outPos;
|
||||||
mElem.pointPos = outPos;
|
|
||||||
|
|
||||||
return cnt;
|
return cnt;
|
||||||
}
|
}
|
||||||
@ -715,6 +699,8 @@ public class MapDatabase implements ITileDataSource {
|
|||||||
ITileDataSink mapDataSink, int numberOfWays) {
|
ITileDataSink mapDataSink, int numberOfWays) {
|
||||||
|
|
||||||
Tag[] wayTags = mTileSource.fileInfo.wayTags;
|
Tag[] wayTags = mTileSource.fileInfo.wayTags;
|
||||||
|
MapElement e = mElem;
|
||||||
|
|
||||||
int numTags = 0;
|
int numTags = 0;
|
||||||
|
|
||||||
int wayDataBlocks;
|
int wayDataBlocks;
|
||||||
@ -754,6 +740,7 @@ public class MapDatabase implements ITileDataSource {
|
|||||||
if (mCurrentRow < numRows)
|
if (mCurrentRow < numRows)
|
||||||
ymax = (int) (mCurrentRow * h + h);
|
ymax = (int) (mCurrentRow * h + h);
|
||||||
//log.debug(xmin + " " + ymin + " " + xmax + " " + ymax);
|
//log.debug(xmin + " " + ymin + " " + xmax + " " + ymax);
|
||||||
|
|
||||||
mTileClipper.setRect(xmin, ymin, xmax, ymax);
|
mTileClipper.setRect(xmin, ymin, xmax, ymax);
|
||||||
} else {
|
} else {
|
||||||
mTileClipper.setRect(-2, -2, Tile.SIZE + 2, Tile.SIZE + 2);
|
mTileClipper.setRect(-2, -2, Tile.SIZE + 2, Tile.SIZE + 2);
|
||||||
@ -786,7 +773,7 @@ public class MapDatabase implements ITileDataSource {
|
|||||||
|
|
||||||
byte numberOfTags =
|
byte numberOfTags =
|
||||||
(byte) (mReadBuffer.readByte() & WAY_NUMBER_OF_TAGS_BITMASK);
|
(byte) (mReadBuffer.readByte() & WAY_NUMBER_OF_TAGS_BITMASK);
|
||||||
if (!mReadBuffer.readTags(mElem.tags, wayTags, numberOfTags))
|
if (!mReadBuffer.readTags(e.tags, wayTags, numberOfTags))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
numTags = numberOfTags;
|
numTags = numberOfTags;
|
||||||
@ -804,30 +791,30 @@ public class MapDatabase implements ITileDataSource {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ignore the way tile bitmask (2 bytes)
|
/* ignore the way tile bitmask (2 bytes) */
|
||||||
mReadBuffer.skipBytes(2);
|
mReadBuffer.skipBytes(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the special byte which encodes multiple flags
|
/* get the special byte which encodes multiple flags */
|
||||||
byte specialByte = mReadBuffer.readByte();
|
byte specialByte = mReadBuffer.readByte();
|
||||||
|
|
||||||
// bit 1-4 represent the layer
|
/* bit 1-4 represent the layer */
|
||||||
byte layer = (byte) ((specialByte & WAY_LAYER_BITMASK) >>> WAY_LAYER_SHIFT);
|
byte layer = (byte) ((specialByte & WAY_LAYER_BITMASK) >>> WAY_LAYER_SHIFT);
|
||||||
// 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(e.tags, wayTags, numberOfTags))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
numTags = numberOfTags;
|
numTags = numberOfTags;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the feature bitmask (1 byte)
|
/* get the feature bitmask (1 byte) */
|
||||||
byte featureByte = mReadBuffer.readByte();
|
byte featureByte = mReadBuffer.readByte();
|
||||||
|
|
||||||
// bit 1-6 enable optional features
|
/* bit 1-6 enable optional features */
|
||||||
boolean featureWayDoubleDeltaEncoding =
|
boolean featureWayDoubleDeltaEncoding =
|
||||||
(featureByte & WAY_FEATURE_DOUBLE_DELTA_ENCODING) != 0;
|
(featureByte & WAY_FEATURE_DOUBLE_DELTA_ENCODING) != 0;
|
||||||
|
|
||||||
@ -835,36 +822,36 @@ public class MapDatabase implements ITileDataSource {
|
|||||||
boolean hasHouseNr = (featureByte & WAY_FEATURE_HOUSE_NUMBER) != 0;
|
boolean hasHouseNr = (featureByte & WAY_FEATURE_HOUSE_NUMBER) != 0;
|
||||||
boolean hasRef = (featureByte & WAY_FEATURE_REF) != 0;
|
boolean hasRef = (featureByte & WAY_FEATURE_REF) != 0;
|
||||||
|
|
||||||
mElem.tags.numTags = numTags;
|
e.tags.numTags = numTags;
|
||||||
|
|
||||||
if (mTileSource.experimental) {
|
if (mTileSource.experimental) {
|
||||||
if (hasName) {
|
if (hasName) {
|
||||||
int textPos = mReadBuffer.readUnsignedInt();
|
int textPos = mReadBuffer.readUnsignedInt();
|
||||||
String str = mReadBuffer.readUTF8EncodedStringAt(stringOffset + textPos);
|
String str = mReadBuffer.readUTF8EncodedStringAt(stringOffset + textPos);
|
||||||
mElem.tags.add(new Tag(Tag.KEY_NAME, str, false));
|
e.tags.add(new Tag(Tag.KEY_NAME, str, false));
|
||||||
}
|
}
|
||||||
if (hasHouseNr) {
|
if (hasHouseNr) {
|
||||||
int textPos = mReadBuffer.readUnsignedInt();
|
int textPos = mReadBuffer.readUnsignedInt();
|
||||||
String str = mReadBuffer.readUTF8EncodedStringAt(stringOffset + textPos);
|
String str = mReadBuffer.readUTF8EncodedStringAt(stringOffset + textPos);
|
||||||
mElem.tags.add(new Tag(Tag.KEY_HOUSE_NUMBER, str, false));
|
e.tags.add(new Tag(Tag.KEY_HOUSE_NUMBER, str, false));
|
||||||
}
|
}
|
||||||
if (hasRef) {
|
if (hasRef) {
|
||||||
int textPos = mReadBuffer.readUnsignedInt();
|
int textPos = mReadBuffer.readUnsignedInt();
|
||||||
String str = mReadBuffer.readUTF8EncodedStringAt(stringOffset + textPos);
|
String str = mReadBuffer.readUTF8EncodedStringAt(stringOffset + textPos);
|
||||||
mElem.tags.add(new Tag(Tag.KEY_REF, str, false));
|
e.tags.add(new Tag(Tag.KEY_REF, str, false));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (hasName) {
|
if (hasName) {
|
||||||
String str = mReadBuffer.readUTF8EncodedString();
|
String str = mReadBuffer.readUTF8EncodedString();
|
||||||
mElem.tags.add(new Tag(Tag.KEY_NAME, str, false));
|
e.tags.add(new Tag(Tag.KEY_NAME, str, false));
|
||||||
}
|
}
|
||||||
if (hasHouseNr) {
|
if (hasHouseNr) {
|
||||||
String str = mReadBuffer.readUTF8EncodedString();
|
String str = mReadBuffer.readUTF8EncodedString();
|
||||||
mElem.tags.add(new Tag(Tag.KEY_HOUSE_NUMBER, str, false));
|
e.tags.add(new Tag(Tag.KEY_HOUSE_NUMBER, str, false));
|
||||||
}
|
}
|
||||||
if (hasRef) {
|
if (hasRef) {
|
||||||
String str = mReadBuffer.readUTF8EncodedString();
|
String str = mReadBuffer.readUTF8EncodedString();
|
||||||
mElem.tags.add(new Tag(Tag.KEY_REF, str, false));
|
e.tags.add(new Tag(Tag.KEY_REF, str, false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((featureByte & WAY_FEATURE_LABEL_POSITION) != 0)
|
if ((featureByte & WAY_FEATURE_LABEL_POSITION) != 0)
|
||||||
@ -883,42 +870,49 @@ public class MapDatabase implements ITileDataSource {
|
|||||||
wayDataBlocks = 1;
|
wayDataBlocks = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int wayDataBlock = 0; wayDataBlock < wayDataBlocks; wayDataBlock++) {
|
boolean linearFeature = e.tags.containsKey("highway") ||
|
||||||
mElem.clear();
|
e.tags.containsKey("boundary") ||
|
||||||
|
e.tags.containsKey("railway");
|
||||||
|
if (linearFeature) {
|
||||||
|
Tag areaTag = e.tags.get("area");
|
||||||
|
if (areaTag != null && areaTag.value == Tag.VALUE_YES)
|
||||||
|
linearFeature = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!processWayDataBlock(featureWayDoubleDeltaEncoding))
|
for (int wayDataBlock = 0; wayDataBlock < wayDataBlocks; wayDataBlock++) {
|
||||||
|
e.clear();
|
||||||
|
|
||||||
|
if (!processWayDataBlock(e, featureWayDoubleDeltaEncoding, linearFeature))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (mElem.isPoly() && mElem.index[0] < 6) {
|
/* drop invalid outer ring */
|
||||||
//mSkipPoly++;
|
if (e.isPoly() && e.index[0] < 6) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
projectToTile(mElem);
|
mTileProjection.project(e);
|
||||||
|
|
||||||
if (mElem.isPoly()) {
|
if (e.isPoly()) {
|
||||||
if (!mTileClipper.clip(mElem)) {
|
if (!mTileClipper.clip(e)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mElem.setLayer(layer);
|
e.setLayer(layer);
|
||||||
mapDataSink.process(mElem);
|
mapDataSink.process(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final TileClipper mTileClipper = new TileClipper(-2, -2, Tile.SIZE + 2, Tile.SIZE + 2);
|
|
||||||
|
|
||||||
private float[] readOptionalLabelPosition() {
|
private float[] readOptionalLabelPosition() {
|
||||||
float[] labelPosition = new float[2];
|
float[] labelPosition = new float[2];
|
||||||
|
|
||||||
// get the label position latitude offset (VBE-S)
|
/* get the label position latitude offset (VBE-S) */
|
||||||
labelPosition[1] = mTileLatitude + mReadBuffer.readSignedInt();
|
labelPosition[1] = mTileLatitude + mReadBuffer.readSignedInt();
|
||||||
|
|
||||||
// get the label position longitude offset (VBE-S)
|
/* get the label position longitude offset (VBE-S) */
|
||||||
labelPosition[0] = mTileLongitude + mReadBuffer.readSignedInt();
|
labelPosition[0] = mTileLongitude + mReadBuffer.readSignedInt();
|
||||||
|
|
||||||
return labelPosition;
|
return labelPosition;
|
||||||
@ -960,65 +954,92 @@ public class MapDatabase implements ITileDataSource {
|
|||||||
return zoomTable;
|
return zoomTable;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final double PI180 = (Math.PI / 180) / 1000000.0;
|
static class TileProjection {
|
||||||
private static final double PIx4 = Math.PI * 4;
|
private static final double COORD_SCALE = 1000000.0;
|
||||||
|
|
||||||
private boolean projectToTile(GeometryBuffer geom) {
|
long dx, dy;
|
||||||
|
double divx, divy;
|
||||||
|
|
||||||
float[] coords = geom.points;
|
void setTile(Tile tile) {
|
||||||
int[] indices = geom.index;
|
/* tile position in pixels at tile zoom */
|
||||||
|
long x = tile.tileX * Tile.SIZE;
|
||||||
|
long y = tile.tileY * Tile.SIZE + Tile.SIZE;
|
||||||
|
|
||||||
long x = mTile.tileX * Tile.SIZE;
|
/* size of the map in pixel at tile zoom */
|
||||||
long y = mTile.tileY * Tile.SIZE + Tile.SIZE;
|
long mapExtents = Tile.SIZE << tile.zoomLevel;
|
||||||
long z = Tile.SIZE << mTile.zoomLevel;
|
|
||||||
|
|
||||||
double divx, divy = 0;
|
/* offset relative to lat/lon == 0 */
|
||||||
long dx = (x - (z >> 1));
|
dx = (x - (mapExtents >> 1));
|
||||||
long dy = (y - (z >> 1));
|
dy = (y - (mapExtents >> 1));
|
||||||
|
|
||||||
divx = 180000000.0 / (z >> 1);
|
/* scales longitude(1e6) to map-pixel */
|
||||||
divy = z / PIx4;
|
divx = (180.0 * COORD_SCALE) / (mapExtents >> 1);
|
||||||
|
|
||||||
for (int pos = 0, outPos = 0, i = 0, m = indices.length; i < m; i++) {
|
/* scale latidute to map-pixel */
|
||||||
int len = indices[i];
|
divy = (mapExtents >> 1) / (Math.PI * 2.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void projectPoint(int lat, int lon, MapElement out) {
|
||||||
|
out.clear();
|
||||||
|
out.startPoints();
|
||||||
|
out.addPoint(projectLon(lon), projectLat(lat));
|
||||||
|
}
|
||||||
|
|
||||||
|
public float projectLat(double lat) {
|
||||||
|
double s = Math.sin(lat * ((Math.PI / 180) / COORD_SCALE));
|
||||||
|
double r = Math.log((1.0 + s) / (1.0 - s));
|
||||||
|
|
||||||
|
return Tile.SIZE - (float) (r * divy + dy);
|
||||||
|
}
|
||||||
|
|
||||||
|
public float projectLon(double lon) {
|
||||||
|
return (float) (lon / divx - dx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void project(MapElement e) {
|
||||||
|
|
||||||
|
float[] coords = e.points;
|
||||||
|
int[] indices = e.index;
|
||||||
|
|
||||||
|
int inPos = 0;
|
||||||
|
int outPos = 0;
|
||||||
|
|
||||||
|
for (int idx = 0, m = indices.length; idx < m; idx++) {
|
||||||
|
int len = indices[idx];
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
continue;
|
continue;
|
||||||
if (len < 0)
|
if (len < 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
int cnt = 0;
|
float lat, lon, pLon = 0, pLat = 0;
|
||||||
float lat, lon, prevLon = 0, prevLat = 0;
|
int cnt = 0, first = outPos;
|
||||||
int first = outPos;
|
|
||||||
|
|
||||||
for (int end = pos + len; pos < end; pos += 2) {
|
for (int end = inPos + len; inPos < end; inPos += 2) {
|
||||||
|
lon = projectLon(coords[inPos]);
|
||||||
lon = (float) ((coords[pos]) / divx - dx);
|
lat = projectLat(coords[inPos + 1]);
|
||||||
double sinLat = Math.sin(coords[pos + 1] * PI180);
|
|
||||||
lat = (float) (Tile.SIZE - (Math.log((1.0 + sinLat) / (1.0 - sinLat)) * divy + dy));
|
|
||||||
|
|
||||||
if (cnt != 0) {
|
if (cnt != 0) {
|
||||||
// drop small distance intermediate nodes
|
/* drop small distance intermediate nodes */
|
||||||
if (lat == prevLat && lon == prevLon) {
|
if (lat == pLat && lon == pLon) {
|
||||||
//log.debug("drop zero delta ");
|
//log.debug("drop zero delta ");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
coords[outPos++] = prevLon = lon;
|
coords[outPos++] = pLon = lon;
|
||||||
coords[outPos++] = prevLat = lat;
|
coords[outPos++] = pLat = lat;
|
||||||
|
|
||||||
cnt += 2;
|
cnt += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (coords[first] == prevLon && coords[first + 1] == prevLat) {
|
if (coords[first] == pLon && coords[first + 1] == pLat) {
|
||||||
//log.debug("drop closed");
|
/* remove identical start/end point */
|
||||||
indices[i] = (short) (cnt - 2);
|
log.debug("would drop closing point {}", e);
|
||||||
outPos -= 2;
|
//indices[idx] = (short) (cnt - 2);
|
||||||
|
//outPos -= 2;
|
||||||
|
}
|
||||||
|
//else {
|
||||||
|
indices[idx] = (short) cnt;
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
indices[i] = (short) cnt;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user