beginnings of oscimap protocol v4 implementation
This commit is contained in:
455
src/org/oscim/database/oscimap4/LwHttp.java
Normal file
455
src/org/oscim/database/oscimap4/LwHttp.java
Normal file
@@ -0,0 +1,455 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 Hannes Janetzek
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under the
|
||||||
|
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||||
|
* Foundation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||||
|
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.oscim.database.oscimap4;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.net.SocketAddress;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
import org.oscim.core.Tile;
|
||||||
|
|
||||||
|
import android.os.SystemClock;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
public class LwHttp {
|
||||||
|
private static final String TAG = LwHttp.class.getName();
|
||||||
|
private final static int BUFFER_SIZE = 1 << 15;
|
||||||
|
byte[] buffer = new byte[BUFFER_SIZE];
|
||||||
|
|
||||||
|
// position in buffer
|
||||||
|
int bufferPos;
|
||||||
|
|
||||||
|
// bytes available in buffer
|
||||||
|
int bufferFill;
|
||||||
|
|
||||||
|
|
||||||
|
// offset of buffer in message
|
||||||
|
private int mBufferOffset;
|
||||||
|
|
||||||
|
// max bytes to read: message = header + content
|
||||||
|
private long mReadEnd;
|
||||||
|
|
||||||
|
// overall bytes of message read
|
||||||
|
private int mReadPos;
|
||||||
|
|
||||||
|
private String mHost;
|
||||||
|
private int mPort;
|
||||||
|
private InputStream mInputStream;
|
||||||
|
|
||||||
|
private int mMaxReq = 0;
|
||||||
|
private Socket mSocket;
|
||||||
|
private OutputStream mCommandStream;
|
||||||
|
private InputStream mResponseStream;
|
||||||
|
long mLastRequest = 0;
|
||||||
|
private SocketAddress mSockAddr;
|
||||||
|
|
||||||
|
private final static byte[] RESPONSE_HTTP_OK = "HTTP/1.1 200 OK".getBytes();
|
||||||
|
private final static int RESPONSE_EXPECTED_LIVES = 100;
|
||||||
|
private final static int RESPONSE_EXPECTED_TIMEOUT = 10000;
|
||||||
|
private final static String TILE_EXT = ".vtm";
|
||||||
|
|
||||||
|
private byte[] REQUEST_GET_START;
|
||||||
|
private byte[] REQUEST_GET_END;
|
||||||
|
|
||||||
|
private byte[] mRequestBuffer;
|
||||||
|
|
||||||
|
boolean setServer(String urlString) {
|
||||||
|
URL url;
|
||||||
|
try {
|
||||||
|
url = new URL(urlString);
|
||||||
|
} catch (MalformedURLException e) {
|
||||||
|
|
||||||
|
e.printStackTrace();
|
||||||
|
return false;
|
||||||
|
//return new OpenResult("invalid url: " + options.get("url"));
|
||||||
|
}
|
||||||
|
|
||||||
|
int port = url.getPort();
|
||||||
|
if (port < 0)
|
||||||
|
port = 80;
|
||||||
|
|
||||||
|
String host = url.getHost();
|
||||||
|
String path = url.getPath();
|
||||||
|
Log.d(TAG, "open oscim database: " + host + " " + port + " " + path);
|
||||||
|
|
||||||
|
REQUEST_GET_START = ("GET " + path).getBytes();
|
||||||
|
REQUEST_GET_END = (TILE_EXT + " HTTP/1.1\n" +
|
||||||
|
"Host: " + host + "\n" +
|
||||||
|
"Connection: Keep-Alive\n\n").getBytes();
|
||||||
|
|
||||||
|
mHost = host;
|
||||||
|
mPort = port;
|
||||||
|
|
||||||
|
mRequestBuffer = new byte[1024];
|
||||||
|
System.arraycopy(REQUEST_GET_START, 0,
|
||||||
|
mRequestBuffer, 0, REQUEST_GET_START.length);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void close() {
|
||||||
|
if (mSocket != null) {
|
||||||
|
try {
|
||||||
|
mSocket.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
mSocket = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int readHeader() throws IOException {
|
||||||
|
InputStream is = mResponseStream;
|
||||||
|
mResponseStream.mark(BUFFER_SIZE);
|
||||||
|
|
||||||
|
byte[] buf = buffer;
|
||||||
|
boolean first = true;
|
||||||
|
int read = 0;
|
||||||
|
int pos = 0;
|
||||||
|
int end = 0;
|
||||||
|
int len = 0;
|
||||||
|
|
||||||
|
// header cannot be larger than BUFFER_SIZE for this to work
|
||||||
|
for (; pos < read || (len = is.read(buf, read, BUFFER_SIZE - read)) >= 0; len = 0) {
|
||||||
|
read += len;
|
||||||
|
while (end < read && (buf[end] != '\n'))
|
||||||
|
end++;
|
||||||
|
|
||||||
|
if (buf[end] == '\n') {
|
||||||
|
if (first) {
|
||||||
|
// check only for OK
|
||||||
|
first = false;
|
||||||
|
if (!compareBytes(buf, pos, end, RESPONSE_HTTP_OK, 15))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
} else if (end - pos == 1) {
|
||||||
|
// check empty line (header end)
|
||||||
|
end += 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// String line = new String(buf, pos, end - pos - 1);
|
||||||
|
// Log.d(TAG, ">" + line + "< " + resp_len);
|
||||||
|
|
||||||
|
pos += (end - pos) + 1;
|
||||||
|
end = pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check 4 bytes available..
|
||||||
|
while ((read - end) < 4 && (len = is.read(buf, read, BUFFER_SIZE - read)) >= 0)
|
||||||
|
read += len;
|
||||||
|
|
||||||
|
if (read - len < 4)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
int contentLength = decodeInt(buf, end);
|
||||||
|
|
||||||
|
// // back to start of content
|
||||||
|
// mResponseStream.reset();
|
||||||
|
// mResponseStream.mark(0);
|
||||||
|
// mResponseStream.skip(end + 4);
|
||||||
|
|
||||||
|
// start of content
|
||||||
|
bufferPos = end + 4;
|
||||||
|
// buffer fill
|
||||||
|
bufferFill = read;
|
||||||
|
mBufferOffset = 0;
|
||||||
|
|
||||||
|
// overall bytes of already read
|
||||||
|
mReadPos = read;
|
||||||
|
mReadEnd = bufferPos + contentLength;
|
||||||
|
|
||||||
|
mInputStream = mResponseStream;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean sendRequest(Tile tile) throws IOException {
|
||||||
|
|
||||||
|
bufferFill = 0;
|
||||||
|
bufferPos = 0;
|
||||||
|
mReadPos = 0;
|
||||||
|
mCacheFile = null;
|
||||||
|
|
||||||
|
if (mSocket != null && ((mMaxReq-- <= 0)
|
||||||
|
|| (SystemClock.elapsedRealtime() - mLastRequest
|
||||||
|
> RESPONSE_EXPECTED_TIMEOUT))) {
|
||||||
|
try {
|
||||||
|
mSocket.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log.d(TAG, "not alive - recreate connection " + mMaxReq);
|
||||||
|
mSocket = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mSocket == null) {
|
||||||
|
lwHttpConnect();
|
||||||
|
// we know our server
|
||||||
|
mMaxReq = RESPONSE_EXPECTED_LIVES;
|
||||||
|
// Log.d(TAG, "create connection");
|
||||||
|
} else {
|
||||||
|
// should not be needed
|
||||||
|
int avail = mResponseStream.available();
|
||||||
|
if (avail > 0) {
|
||||||
|
Log.d(TAG, "Consume left-over bytes: " + avail);
|
||||||
|
mResponseStream.read(buffer, 0, avail);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] request = mRequestBuffer;
|
||||||
|
int pos = REQUEST_GET_START.length;
|
||||||
|
|
||||||
|
pos = writeInt(tile.zoomLevel, pos, request);
|
||||||
|
request[pos++] = '/';
|
||||||
|
pos = writeInt(tile.tileX, pos, request);
|
||||||
|
request[pos++] = '/';
|
||||||
|
pos = writeInt(tile.tileY, pos, request);
|
||||||
|
|
||||||
|
int len = REQUEST_GET_END.length;
|
||||||
|
System.arraycopy(REQUEST_GET_END, 0, request, pos, len);
|
||||||
|
len += pos;
|
||||||
|
|
||||||
|
// this does the same but with a few more allocations:
|
||||||
|
// byte[] request = String.format(REQUEST,
|
||||||
|
// Integer.valueOf(tile.zoomLevel),
|
||||||
|
// Integer.valueOf(tile.tileX), Integer.valueOf(tile.tileY)).getBytes();
|
||||||
|
|
||||||
|
try {
|
||||||
|
mCommandStream.write(request, 0, len);
|
||||||
|
mCommandStream.flush();
|
||||||
|
return true;
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.d(TAG, "recreate connection");
|
||||||
|
}
|
||||||
|
|
||||||
|
lwHttpConnect();
|
||||||
|
|
||||||
|
mCommandStream.write(request, 0, len);
|
||||||
|
mCommandStream.flush();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean lwHttpConnect() throws IOException {
|
||||||
|
if (mSockAddr == null)
|
||||||
|
mSockAddr = new InetSocketAddress(mHost, mPort);
|
||||||
|
|
||||||
|
mSocket = new Socket();
|
||||||
|
mSocket.connect(mSockAddr, 30000);
|
||||||
|
mSocket.setTcpNoDelay(true);
|
||||||
|
|
||||||
|
mCommandStream = mSocket.getOutputStream(); //new BufferedOutputStream();
|
||||||
|
mResponseStream = mSocket.getInputStream();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// write (positive) integer as char sequence to buffer
|
||||||
|
private static int writeInt(int val, int pos, byte[] buf) {
|
||||||
|
if (val == 0) {
|
||||||
|
buf[pos] = '0';
|
||||||
|
return pos + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
for (int n = val; n > 0; n = n / 10, i++)
|
||||||
|
buf[pos + i] = (byte) ('0' + n % 10);
|
||||||
|
|
||||||
|
// reverse bytes
|
||||||
|
for (int j = pos, end = pos + i - 1, mid = pos + i / 2; j < mid; j++, end--) {
|
||||||
|
byte tmp = buf[j];
|
||||||
|
buf[j] = buf[end];
|
||||||
|
buf[end] = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pos + i;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean compareBytes(byte[] buffer, int position, int available,
|
||||||
|
byte[] string, int length) {
|
||||||
|
|
||||||
|
if (available - position < length)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (int i = 0; i < length; i++)
|
||||||
|
if (buffer[position + i] != string[i])
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int decodeInt(byte[] buffer, int offset) {
|
||||||
|
return buffer[offset] << 24 | (buffer[offset + 1] & 0xff) << 16
|
||||||
|
| (buffer[offset + 2] & 0xff) << 8
|
||||||
|
| (buffer[offset + 3] & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasData() {
|
||||||
|
return mBufferOffset + bufferPos < mReadEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int position() {
|
||||||
|
return mBufferOffset + bufferPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void readBuffer(int size) throws IOException {
|
||||||
|
// check if buffer already contains the request bytes
|
||||||
|
if (bufferPos + size < bufferFill)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// check if inputstream is read to the end
|
||||||
|
if (mReadPos == mReadEnd)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int maxSize = buffer.length;
|
||||||
|
|
||||||
|
if (size > maxSize) {
|
||||||
|
Log.d(TAG, "increase read buffer to " + size + " bytes");
|
||||||
|
maxSize = size;
|
||||||
|
byte[] tmp = new byte[maxSize];
|
||||||
|
bufferFill -= bufferPos;
|
||||||
|
System.arraycopy(buffer, bufferPos, tmp, 0, bufferFill);
|
||||||
|
mBufferOffset += bufferPos;
|
||||||
|
bufferPos = 0;
|
||||||
|
buffer = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bufferFill == bufferPos) {
|
||||||
|
mBufferOffset += bufferPos;
|
||||||
|
bufferPos = 0;
|
||||||
|
bufferFill = 0;
|
||||||
|
} else if (bufferPos + size > maxSize) {
|
||||||
|
// copy bytes left to the beginning of buffer
|
||||||
|
bufferFill -= bufferPos;
|
||||||
|
System.arraycopy(buffer, bufferPos, buffer, 0, bufferFill);
|
||||||
|
mBufferOffset += bufferPos;
|
||||||
|
bufferPos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int max = maxSize - bufferFill;
|
||||||
|
|
||||||
|
while ((bufferFill - bufferPos) < size && max > 0) {
|
||||||
|
|
||||||
|
max = maxSize - bufferFill;
|
||||||
|
if (max > mReadEnd - mReadPos)
|
||||||
|
max = (int) (mReadEnd - mReadPos);
|
||||||
|
|
||||||
|
// read until requested size is available in buffer
|
||||||
|
int len = mInputStream.read(buffer, bufferFill, max);
|
||||||
|
|
||||||
|
if (len < 0) {
|
||||||
|
// finished reading, mark end
|
||||||
|
buffer[bufferFill] = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
mReadPos += len;
|
||||||
|
|
||||||
|
// if (mCacheFile != null)
|
||||||
|
// mCacheFile.write(mReadBuffer, mBufferFill, len);
|
||||||
|
|
||||||
|
if (mReadPos == mReadEnd)
|
||||||
|
break;
|
||||||
|
|
||||||
|
bufferFill += len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private FileOutputStream mCacheFile;
|
||||||
|
|
||||||
|
boolean cacheRead(Tile tile, File f) {
|
||||||
|
if (f.exists() && f.length() > 0) {
|
||||||
|
FileInputStream in;
|
||||||
|
|
||||||
|
try {
|
||||||
|
in = new FileInputStream(f);
|
||||||
|
|
||||||
|
mReadEnd = f.length();
|
||||||
|
Log.d(TAG, tile + " - using cache: " + mReadEnd);
|
||||||
|
mInputStream = in;
|
||||||
|
|
||||||
|
//decode();
|
||||||
|
in.close();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (Exception ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
f.delete();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean cacheBegin(Tile tile, File f) {
|
||||||
|
if (MapDatabase.USE_CACHE) {
|
||||||
|
try {
|
||||||
|
Log.d(TAG, tile + " - writing cache");
|
||||||
|
mCacheFile = new FileOutputStream(f);
|
||||||
|
|
||||||
|
if (mReadPos > 0) {
|
||||||
|
try {
|
||||||
|
mCacheFile.write(buffer, bufferPos,
|
||||||
|
bufferFill - bufferPos);
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
mCacheFile = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
mCacheFile = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cacheFinish(Tile tile, File file, boolean success) {
|
||||||
|
if (MapDatabase.USE_CACHE) {
|
||||||
|
if (success) {
|
||||||
|
try {
|
||||||
|
mCacheFile.flush();
|
||||||
|
mCacheFile.close();
|
||||||
|
Log.d(TAG, tile + " - cache written " + file.length());
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
file.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mCacheFile = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
724
src/org/oscim/database/oscimap4/MapDatabase.java
Normal file
724
src/org/oscim/database/oscimap4/MapDatabase.java
Normal file
@@ -0,0 +1,724 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 Hannes Janetzek
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under the
|
||||||
|
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||||
|
* Foundation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||||
|
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.oscim.database.oscimap4;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.SocketException;
|
||||||
|
import java.net.SocketTimeoutException;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import org.oscim.core.BoundingBox;
|
||||||
|
import org.oscim.core.GeoPoint;
|
||||||
|
import org.oscim.core.GeometryBuffer.GeometryType;
|
||||||
|
import org.oscim.core.MapElement;
|
||||||
|
import org.oscim.core.Tag;
|
||||||
|
import org.oscim.core.TagSet;
|
||||||
|
import org.oscim.core.Tile;
|
||||||
|
import org.oscim.database.IMapDatabase;
|
||||||
|
import org.oscim.database.IMapDatabaseCallback;
|
||||||
|
import org.oscim.database.MapInfo;
|
||||||
|
import org.oscim.database.MapOptions;
|
||||||
|
import org.oscim.layers.tile.MapTile;
|
||||||
|
import org.oscim.utils.UTF8Decoder;
|
||||||
|
|
||||||
|
import android.os.Environment;
|
||||||
|
import android.os.SystemClock;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class MapDatabase implements IMapDatabase {
|
||||||
|
private static final String TAG = MapDatabase.class.getName();
|
||||||
|
|
||||||
|
static final boolean USE_CACHE = false;
|
||||||
|
|
||||||
|
private static final MapInfo mMapInfo =
|
||||||
|
new MapInfo(new BoundingBox(-180, -90, 180, 90),
|
||||||
|
new Byte((byte) 4), new GeoPoint(53.11, 8.85),
|
||||||
|
null, 0, 0, 0, "de", "comment", "author", null);
|
||||||
|
|
||||||
|
private static final String CACHE_DIRECTORY = "/Android/data/org.oscim.app/cache/";
|
||||||
|
private static final String CACHE_FILE = "%d-%d-%d.tile";
|
||||||
|
|
||||||
|
private final static float REF_TILE_SIZE = 4096.0f;
|
||||||
|
|
||||||
|
// 'open' state
|
||||||
|
private boolean mOpen = false;
|
||||||
|
private static File cacheDir;
|
||||||
|
|
||||||
|
|
||||||
|
private IMapDatabaseCallback mMapGenerator;
|
||||||
|
private float mScaleFactor;
|
||||||
|
private MapTile mTile;
|
||||||
|
|
||||||
|
//private final boolean debug = false;
|
||||||
|
private LwHttp conn;
|
||||||
|
|
||||||
|
private final UTF8Decoder mStringDecoder;
|
||||||
|
private final MapElement mElem;
|
||||||
|
|
||||||
|
public MapDatabase() {
|
||||||
|
mStringDecoder = new UTF8Decoder();
|
||||||
|
mElem = new MapElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public QueryResult executeQuery(MapTile tile, IMapDatabaseCallback mapDatabaseCallback) {
|
||||||
|
QueryResult result = QueryResult.SUCCESS;
|
||||||
|
|
||||||
|
mTile = tile;
|
||||||
|
|
||||||
|
mMapGenerator = mapDatabaseCallback;
|
||||||
|
|
||||||
|
// scale coordinates to tile size
|
||||||
|
mScaleFactor = REF_TILE_SIZE / Tile.SIZE;
|
||||||
|
|
||||||
|
File f = null;
|
||||||
|
|
||||||
|
if (USE_CACHE) {
|
||||||
|
f = new File(cacheDir, String.format(CACHE_FILE,
|
||||||
|
Integer.valueOf(tile.zoomLevel),
|
||||||
|
Integer.valueOf(tile.tileX),
|
||||||
|
Integer.valueOf(tile.tileY)));
|
||||||
|
|
||||||
|
if (conn.cacheRead(tile, f))
|
||||||
|
return QueryResult.SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
if (conn.sendRequest(tile) && conn.readHeader() >= 0) {
|
||||||
|
conn.cacheBegin(tile, f);
|
||||||
|
decode();
|
||||||
|
} else {
|
||||||
|
Log.d(TAG, tile + " Network Error");
|
||||||
|
result = QueryResult.FAILED;
|
||||||
|
}
|
||||||
|
} catch (SocketException ex) {
|
||||||
|
Log.d(TAG, tile + " Socket exception: " + ex.getMessage());
|
||||||
|
result = QueryResult.FAILED;
|
||||||
|
} catch (SocketTimeoutException ex) {
|
||||||
|
Log.d(TAG, tile + " Socket Timeout exception: " + ex.getMessage());
|
||||||
|
result = QueryResult.FAILED;
|
||||||
|
} catch (UnknownHostException ex) {
|
||||||
|
Log.d(TAG, tile + " no network");
|
||||||
|
result = QueryResult.FAILED;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
result = QueryResult.FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
conn.mLastRequest = SystemClock.elapsedRealtime();
|
||||||
|
|
||||||
|
if (result == QueryResult.SUCCESS) {
|
||||||
|
|
||||||
|
conn.cacheFinish(tile, f, true);
|
||||||
|
} else {
|
||||||
|
conn.cacheFinish(tile, f, false);
|
||||||
|
conn.close();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMapProjection() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MapInfo getMapInfo() {
|
||||||
|
return mMapInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isOpen() {
|
||||||
|
return mOpen;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OpenResult open(MapOptions options) {
|
||||||
|
if (mOpen)
|
||||||
|
return OpenResult.SUCCESS;
|
||||||
|
|
||||||
|
if (options == null || !options.containsKey("url"))
|
||||||
|
return new OpenResult("options missing");
|
||||||
|
|
||||||
|
conn = new LwHttp();
|
||||||
|
|
||||||
|
if (!conn.setServer(options.get("url"))) {
|
||||||
|
return new OpenResult("invalid url: " + options.get("url"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (USE_CACHE) {
|
||||||
|
if (cacheDir == null) {
|
||||||
|
String externalStorageDirectory = Environment
|
||||||
|
.getExternalStorageDirectory()
|
||||||
|
.getAbsolutePath();
|
||||||
|
String cacheDirectoryPath = externalStorageDirectory + CACHE_DIRECTORY;
|
||||||
|
cacheDir = createDirectory(cacheDirectoryPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mOpen = true;
|
||||||
|
initDecorder();
|
||||||
|
|
||||||
|
return OpenResult.SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
mOpen = false;
|
||||||
|
|
||||||
|
conn.close();
|
||||||
|
|
||||||
|
if (USE_CACHE) {
|
||||||
|
cacheDir = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cancel() {
|
||||||
|
}
|
||||||
|
|
||||||
|
private static File createDirectory(String pathName) {
|
||||||
|
File file = new File(pathName);
|
||||||
|
if (!file.exists() && !file.mkdirs()) {
|
||||||
|
throw new IllegalArgumentException("could not create directory: " + file);
|
||||||
|
} else if (!file.isDirectory()) {
|
||||||
|
throw new IllegalArgumentException("not a directory: " + file);
|
||||||
|
} else if (!file.canRead()) {
|
||||||
|
throw new IllegalArgumentException("cannot read directory: " + file);
|
||||||
|
} else if (!file.canWrite()) {
|
||||||
|
throw new IllegalArgumentException("cannot write directory: " + file);
|
||||||
|
}
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
// /////////////// hand sewed tile protocol buffers decoder ///////////////
|
||||||
|
|
||||||
|
private static final int TAG_TILE_VERSION = 1;
|
||||||
|
//private static final int TAG_TILE_TIMESTAMP = 2;
|
||||||
|
//private static final int TAG_TILE_ISWATER = 3;
|
||||||
|
|
||||||
|
|
||||||
|
private static final int TAG_TILE_NUM_TAGS = 11;
|
||||||
|
private static final int TAG_TILE_NUM_KEYS = 12;
|
||||||
|
private static final int TAG_TILE_NUM_VALUES = 13;
|
||||||
|
|
||||||
|
private static final int TAG_TILE_TAG_KEYS = 14;
|
||||||
|
private static final int TAG_TILE_TAG_VALUES = 15;
|
||||||
|
private static final int TAG_TILE_TAGS = 16;
|
||||||
|
|
||||||
|
private static final int TAG_TILE_LINE = 21;
|
||||||
|
private static final int TAG_TILE_POLY = 22;
|
||||||
|
private static final int TAG_TILE_POINT = 23;
|
||||||
|
|
||||||
|
|
||||||
|
private static final int TAG_ELEM_NUM_INDICES = 1;
|
||||||
|
private static final int TAG_ELEM_NUM_TAGS = 2;
|
||||||
|
//private static final int TAG_ELEM_HAS_ELEVATION = 3;
|
||||||
|
private static final int TAG_ELEM_TAGS = 11;
|
||||||
|
private static final int TAG_ELEM_INDEX = 12;
|
||||||
|
private static final int TAG_ELEM_COORDS = 13;
|
||||||
|
private static final int TAG_ELEM_LAYER = 21;
|
||||||
|
//private static final int TAG_ELEM_HEIGHT = 31;
|
||||||
|
//private static final int TAG_ELEM_MIN_HEIGHT = 32;
|
||||||
|
//private static final int TAG_ELEM_PRIORITY = 41;
|
||||||
|
|
||||||
|
private short[] mTmpShortArray = new short[100];
|
||||||
|
private Tag[][] mElementTags;
|
||||||
|
|
||||||
|
private final TagSet curTags = new TagSet(100);
|
||||||
|
//private int mCurTagCnt;
|
||||||
|
|
||||||
|
private void initDecorder() {
|
||||||
|
// reusable tag set
|
||||||
|
Tag[][] tags = new Tag[10][];
|
||||||
|
for (int i = 0; i < 10; i++)
|
||||||
|
tags[i] = new Tag[i + 1];
|
||||||
|
mElementTags = tags;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean decode() throws IOException {
|
||||||
|
|
||||||
|
//mCurTagCnt = 0;
|
||||||
|
curTags.clear(true);
|
||||||
|
int version = -1;
|
||||||
|
|
||||||
|
int val;
|
||||||
|
int numTags = 0;
|
||||||
|
int numKeys= -1;
|
||||||
|
int numValues = -1;
|
||||||
|
|
||||||
|
int curKey = 0;
|
||||||
|
int curValue = 0;
|
||||||
|
|
||||||
|
String [] keys = null;
|
||||||
|
String [] values = null;
|
||||||
|
|
||||||
|
while (conn.hasData() && (val = decodeVarint32()) > 0) {
|
||||||
|
// read tag and wire type
|
||||||
|
int tag = (val >> 3);
|
||||||
|
|
||||||
|
switch (tag) {
|
||||||
|
case TAG_TILE_LINE:
|
||||||
|
case TAG_TILE_POLY:
|
||||||
|
case TAG_TILE_POINT:
|
||||||
|
decodeTileElement(tag);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_TILE_TAG_KEYS:
|
||||||
|
if (keys == null || curKey >= numKeys){
|
||||||
|
Log.d(TAG, mTile + " wrong number of keys " + numKeys);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
keys[curKey++] = decodeString();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_TILE_TAG_VALUES:
|
||||||
|
if (values == null || curValue >= numValues){
|
||||||
|
Log.d(TAG, mTile + " wrong number of values " + numValues);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
values[curValue++] = decodeString();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_TILE_NUM_TAGS:
|
||||||
|
numTags = decodeVarint32();
|
||||||
|
//Log.d(TAG, "num tags " + numTags);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_TILE_NUM_KEYS:
|
||||||
|
numKeys = decodeVarint32();
|
||||||
|
//Log.d(TAG, "num keys " + numKeys);
|
||||||
|
keys = new String[numKeys];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_TILE_NUM_VALUES:
|
||||||
|
numValues = decodeVarint32();
|
||||||
|
//Log.d(TAG, "num values " + numValues);
|
||||||
|
values = new String[numValues];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_TILE_TAGS:
|
||||||
|
mTmpShortArray = decodeShortArray(numTags, mTmpShortArray);
|
||||||
|
if (!decodeTileTags(numTags, mTmpShortArray, keys, values)){
|
||||||
|
Log.d(TAG, mTile + " invalid tags");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_TILE_VERSION:
|
||||||
|
version = decodeVarint32();
|
||||||
|
if (version != 4){
|
||||||
|
Log.d(TAG, mTile + " invalid version "+ version);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Log.d(TAG, mTile + " invalid type for tile: " + tag);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean decodeTileTags(int numTags, short[] tagIdx, String[] keys, String[] vals) {
|
||||||
|
Tag tag;
|
||||||
|
|
||||||
|
for (int i = 0; i < numTags*2; i += 2){
|
||||||
|
int k = tagIdx[i];
|
||||||
|
int v = tagIdx[i+1];
|
||||||
|
String key, val;
|
||||||
|
|
||||||
|
if (k < Tags.ATTRIB_OFFSET){
|
||||||
|
if (k > Tags.MAX_KEY)
|
||||||
|
return false;
|
||||||
|
key = Tags.keys[k];
|
||||||
|
} else {
|
||||||
|
k -= Tags.ATTRIB_OFFSET;
|
||||||
|
if (k >= keys.length)
|
||||||
|
return false;
|
||||||
|
key = keys[k];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (v < Tags.ATTRIB_OFFSET){
|
||||||
|
if (v > Tags.MAX_VALUE)
|
||||||
|
return false;
|
||||||
|
val = Tags.values[v];
|
||||||
|
} else {
|
||||||
|
v -= Tags.ATTRIB_OFFSET;
|
||||||
|
if (v >= vals.length)
|
||||||
|
return false;
|
||||||
|
val = vals[v];
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME filter out all variable tags
|
||||||
|
// might depend on theme though
|
||||||
|
if (key == Tag.TAG_KEY_NAME || key == Tag.KEY_HEIGHT || key == Tag.KEY_MIN_HEIGHT)
|
||||||
|
tag = new Tag(key, val, false);
|
||||||
|
else
|
||||||
|
tag = new Tag(key, val, true);
|
||||||
|
|
||||||
|
curTags.add(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int decodeWayIndices(int indexCnt) throws IOException {
|
||||||
|
mElem.index = decodeShortArray(indexCnt, mElem.index);
|
||||||
|
|
||||||
|
short[] index = mElem.index;
|
||||||
|
int coordCnt = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < indexCnt; i++)
|
||||||
|
coordCnt += index[i] *= 2;
|
||||||
|
|
||||||
|
// set end marker
|
||||||
|
if (indexCnt < index.length)
|
||||||
|
index[indexCnt] = -1;
|
||||||
|
|
||||||
|
return coordCnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean decodeTileElement(int type) throws IOException {
|
||||||
|
|
||||||
|
int bytes = decodeVarint32();
|
||||||
|
Tag[] tags = null;
|
||||||
|
short[] index = null;
|
||||||
|
|
||||||
|
int end = conn.position() + bytes;
|
||||||
|
int numIndices = 1;
|
||||||
|
int numTags = 1;
|
||||||
|
|
||||||
|
boolean skip = false;
|
||||||
|
boolean fail = false;
|
||||||
|
|
||||||
|
int coordCnt = 0;
|
||||||
|
if (type == TAG_TILE_POINT) {
|
||||||
|
coordCnt = 2;
|
||||||
|
mElem.index[0] = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
mElem.layer = 5;
|
||||||
|
mElem.priority = 0;
|
||||||
|
mElem.height = 0;
|
||||||
|
mElem.minHeight = 0;
|
||||||
|
|
||||||
|
while (conn.position() < end) {
|
||||||
|
// read tag and wire type
|
||||||
|
int val = decodeVarint32();
|
||||||
|
if (val == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
int tag = (val >> 3);
|
||||||
|
|
||||||
|
switch (tag) {
|
||||||
|
case TAG_ELEM_TAGS:
|
||||||
|
tags = decodeElementTags(numTags);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_ELEM_NUM_INDICES:
|
||||||
|
numIndices = decodeVarint32();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_ELEM_NUM_TAGS:
|
||||||
|
numTags = decodeVarint32();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_ELEM_INDEX:
|
||||||
|
coordCnt = decodeWayIndices(numIndices);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_ELEM_COORDS:
|
||||||
|
if (coordCnt == 0) {
|
||||||
|
Log.d(TAG, mTile + " no coordinates");
|
||||||
|
skip = true;
|
||||||
|
}
|
||||||
|
int cnt = decodeWayCoordinates(skip, coordCnt);
|
||||||
|
|
||||||
|
if (cnt != coordCnt) {
|
||||||
|
Log.d(TAG, mTile + " wrong number of coordintes");
|
||||||
|
fail = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_ELEM_LAYER:
|
||||||
|
mElem.layer = decodeVarint32();
|
||||||
|
break;
|
||||||
|
|
||||||
|
// case TAG_ELEM_HEIGHT:
|
||||||
|
// mElem.height = decodeVarint32();
|
||||||
|
// break;
|
||||||
|
//
|
||||||
|
// case TAG_ELEM_MIN_HEIGHT:
|
||||||
|
// mElem.minHeight = decodeVarint32();
|
||||||
|
// break;
|
||||||
|
//
|
||||||
|
// case TAG_ELEM_PRIORITY:
|
||||||
|
// mElem.priority = decodeVarint32();
|
||||||
|
// break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Log.d(TAG, mTile + " invalid type for way: " + tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fail || tags == null || numIndices == 0) {
|
||||||
|
Log.d(TAG, mTile + " failed reading way: bytes:" + bytes + " index:"
|
||||||
|
+ (Arrays.toString(index)) + " tag:"
|
||||||
|
+ (tags != null ? Arrays.deepToString(tags) : "null") + " "
|
||||||
|
+ numIndices + " " + coordCnt);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mElem.tags = tags;
|
||||||
|
switch (type) {
|
||||||
|
case TAG_TILE_LINE:
|
||||||
|
mElem.type = GeometryType.LINE;
|
||||||
|
break;
|
||||||
|
case TAG_TILE_POLY:
|
||||||
|
mElem.type = GeometryType.POLY;
|
||||||
|
break;
|
||||||
|
case TAG_TILE_POINT:
|
||||||
|
mElem.type = GeometryType.POINT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
mMapGenerator.renderElement(mElem);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Tag[] decodeElementTags(int numTags) throws IOException {
|
||||||
|
short[] tagIds = mTmpShortArray = decodeShortArray(numTags, mTmpShortArray);
|
||||||
|
|
||||||
|
Tag[] tags;
|
||||||
|
|
||||||
|
if (numTags < 11)
|
||||||
|
tags = mElementTags[numTags - 1];
|
||||||
|
else
|
||||||
|
tags = new Tag[numTags];
|
||||||
|
|
||||||
|
int max = curTags.numTags;
|
||||||
|
|
||||||
|
for (int i = 0; i < numTags; i++){
|
||||||
|
int idx = tagIds[i];
|
||||||
|
|
||||||
|
if (idx < 0 || idx > max) {
|
||||||
|
Log.d(TAG, mTile + " invalid tag:" + idx + " " + i);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
tags[i] = curTags.tags[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
return tags;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final static int VARINT_LIMIT = 5;
|
||||||
|
private final static int VARINT_MAX = 10;
|
||||||
|
|
||||||
|
private int decodeWayCoordinates(boolean skip, int nodes) throws IOException {
|
||||||
|
int bytes = decodeVarint32();
|
||||||
|
|
||||||
|
conn.readBuffer(bytes);
|
||||||
|
|
||||||
|
if (skip) {
|
||||||
|
conn.bufferPos += bytes;
|
||||||
|
return nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cnt = 0;
|
||||||
|
|
||||||
|
int lastX = 0;
|
||||||
|
int lastY = 0;
|
||||||
|
boolean even = true;
|
||||||
|
|
||||||
|
float scale = mScaleFactor;
|
||||||
|
float[] coords = mElem.ensurePointSize(nodes, false);
|
||||||
|
|
||||||
|
byte[] buf = conn.buffer;
|
||||||
|
int pos = conn.bufferPos;
|
||||||
|
int end = pos + bytes;
|
||||||
|
int val;
|
||||||
|
|
||||||
|
while (pos < end) {
|
||||||
|
if (buf[pos] >= 0) {
|
||||||
|
val = buf[pos++];
|
||||||
|
|
||||||
|
} else if (buf[pos + 1] >= 0) {
|
||||||
|
val = (buf[pos++] & 0x7f)
|
||||||
|
| buf[pos++] << 7;
|
||||||
|
|
||||||
|
} else if (buf[pos + 2] >= 0) {
|
||||||
|
val = (buf[pos++] & 0x7f)
|
||||||
|
| (buf[pos++] & 0x7f) << 7
|
||||||
|
| (buf[pos++]) << 14;
|
||||||
|
|
||||||
|
} else if (buf[pos + 3] >= 0) {
|
||||||
|
val = (buf[pos++] & 0x7f)
|
||||||
|
| (buf[pos++] & 0x7f) << 7
|
||||||
|
| (buf[pos++] & 0x7f) << 14
|
||||||
|
| (buf[pos++]) << 21;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
val = (buf[pos++] & 0x7f)
|
||||||
|
| (buf[pos++] & 0x7f) << 7
|
||||||
|
| (buf[pos++] & 0x7f) << 14
|
||||||
|
| (buf[pos++] & 0x7f) << 21
|
||||||
|
| (buf[pos]) << 28;
|
||||||
|
|
||||||
|
int max = pos + VARINT_LIMIT;
|
||||||
|
while (pos < max)
|
||||||
|
if (buf[pos++] >= 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (pos == max)
|
||||||
|
throw new IOException("malformed VarInt32 in " + mTile);
|
||||||
|
}
|
||||||
|
|
||||||
|
// zigzag decoding
|
||||||
|
int s = ((val >>> 1) ^ -(val & 1));
|
||||||
|
|
||||||
|
if (even) {
|
||||||
|
lastX = lastX + s;
|
||||||
|
coords[cnt++] = lastX / scale;
|
||||||
|
even = false;
|
||||||
|
} else {
|
||||||
|
lastY = lastY + s;
|
||||||
|
coords[cnt++] = lastY / scale;
|
||||||
|
even = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
conn.bufferPos = pos;
|
||||||
|
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
private short[] decodeShortArray(int num, short[] array) throws IOException {
|
||||||
|
int bytes = decodeVarint32();
|
||||||
|
|
||||||
|
if (array.length < num)
|
||||||
|
array = new short[num];
|
||||||
|
|
||||||
|
conn.readBuffer(bytes);
|
||||||
|
|
||||||
|
int cnt = 0;
|
||||||
|
|
||||||
|
byte[] buf = conn.buffer;
|
||||||
|
int pos = conn.bufferPos;
|
||||||
|
int end = pos + bytes;
|
||||||
|
int val;
|
||||||
|
|
||||||
|
while (pos < end) {
|
||||||
|
if (buf[pos] >= 0) {
|
||||||
|
val = buf[pos++];
|
||||||
|
} else if (buf[pos + 1] >= 0) {
|
||||||
|
val = (buf[pos++] & 0x7f)
|
||||||
|
| buf[pos++] << 7;
|
||||||
|
} else if (buf[pos + 2] >= 0) {
|
||||||
|
val = (buf[pos++] & 0x7f)
|
||||||
|
| (buf[pos++] & 0x7f) << 7
|
||||||
|
| (buf[pos++]) << 14;
|
||||||
|
} else if (buf[pos + 3] >= 0) {
|
||||||
|
val = (buf[pos++] & 0x7f)
|
||||||
|
| (buf[pos++] & 0x7f) << 7
|
||||||
|
| (buf[pos++] & 0x7f) << 14
|
||||||
|
| (buf[pos++]) << 21;
|
||||||
|
} else if (buf[pos + 4] >= 0){
|
||||||
|
val = (buf[pos++] & 0x7f)
|
||||||
|
| (buf[pos++] & 0x7f) << 7
|
||||||
|
| (buf[pos++] & 0x7f) << 14
|
||||||
|
| (buf[pos++] & 0x7f) << 21
|
||||||
|
| (buf[pos++]) << 28;
|
||||||
|
} else
|
||||||
|
throw new IOException("malformed VarInt32 in " + mTile);
|
||||||
|
|
||||||
|
array[cnt++] = (short) val;
|
||||||
|
}
|
||||||
|
|
||||||
|
conn.bufferPos = pos;
|
||||||
|
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int decodeVarint32() throws IOException {
|
||||||
|
if (conn.bufferPos + VARINT_MAX > conn.bufferFill)
|
||||||
|
conn.readBuffer(4096);
|
||||||
|
|
||||||
|
byte[] buf = conn.buffer;
|
||||||
|
int pos = conn.bufferPos;
|
||||||
|
int val;
|
||||||
|
|
||||||
|
if (buf[pos] >= 0) {
|
||||||
|
val = buf[pos++];
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (buf[pos + 1] >= 0) {
|
||||||
|
val = (buf[pos++] & 0x7f)
|
||||||
|
| (buf[pos++]) << 7;
|
||||||
|
|
||||||
|
} else if (buf[pos + 2] >= 0) {
|
||||||
|
val = (buf[pos++] & 0x7f)
|
||||||
|
| (buf[pos++] & 0x7f) << 7
|
||||||
|
| (buf[pos++]) << 14;
|
||||||
|
|
||||||
|
} else if (buf[pos + 3] >= 0) {
|
||||||
|
val = (buf[pos++] & 0x7f)
|
||||||
|
| (buf[pos++] & 0x7f) << 7
|
||||||
|
| (buf[pos++] & 0x7f) << 14
|
||||||
|
| (buf[pos++]) << 21;
|
||||||
|
} else {
|
||||||
|
val = (buf[pos++] & 0x7f)
|
||||||
|
| (buf[pos++] & 0x7f) << 7
|
||||||
|
| (buf[pos++] & 0x7f) << 14
|
||||||
|
| (buf[pos++] & 0x7f) << 21
|
||||||
|
| (buf[pos]) << 28;
|
||||||
|
|
||||||
|
// 'Discard upper 32 bits'
|
||||||
|
int max = pos + VARINT_LIMIT;
|
||||||
|
while (pos < max)
|
||||||
|
if (buf[pos++] >= 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (pos == max)
|
||||||
|
throw new IOException("malformed VarInt32 in " + mTile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
conn.bufferPos = pos;
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String decodeString() throws IOException {
|
||||||
|
final int size = decodeVarint32();
|
||||||
|
conn.readBuffer(size);
|
||||||
|
final String result = mStringDecoder.decode(conn.buffer, conn.bufferPos, size);
|
||||||
|
|
||||||
|
conn.bufferPos += size;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
318
src/org/oscim/database/oscimap4/ProtobufDecoder.java
Normal file
318
src/org/oscim/database/oscimap4/ProtobufDecoder.java
Normal file
@@ -0,0 +1,318 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under the
|
||||||
|
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||||
|
* Foundation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||||
|
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.oscim.database.oscimap4;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
import org.oscim.utils.UTF8Decoder;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
public class ProtobufDecoder {
|
||||||
|
private final static String TAG = ProtobufDecoder.class.getName();
|
||||||
|
|
||||||
|
private final static int VARINT_LIMIT = 5;
|
||||||
|
private final static int VARINT_MAX = 10;
|
||||||
|
|
||||||
|
private final static int BUFFER_SIZE = 1 << 15; // 32kb
|
||||||
|
byte[] buffer = new byte[BUFFER_SIZE];
|
||||||
|
|
||||||
|
// position in buffer
|
||||||
|
int bufferPos;
|
||||||
|
|
||||||
|
// bytes available in buffer
|
||||||
|
int bufferFill;
|
||||||
|
|
||||||
|
// offset of buffer in message
|
||||||
|
private int mBufferOffset;
|
||||||
|
|
||||||
|
// max bytes to read: message = header + content
|
||||||
|
private long mReadEnd;
|
||||||
|
|
||||||
|
// overall bytes of message read
|
||||||
|
private int mReadPos;
|
||||||
|
|
||||||
|
private InputStream mInputStream;
|
||||||
|
|
||||||
|
private final UTF8Decoder mStringDecoder;
|
||||||
|
|
||||||
|
public ProtobufDecoder(){
|
||||||
|
mStringDecoder = new UTF8Decoder();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInputStream(InputStream is){
|
||||||
|
mInputStream = is;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void skip()throws IOException{
|
||||||
|
int bytes = decodeVarint32();
|
||||||
|
bufferPos += bytes;
|
||||||
|
}
|
||||||
|
public int readInterleavedPoints(float[] coords, int numPoints, float scale) throws IOException {
|
||||||
|
int bytes = decodeVarint32();
|
||||||
|
|
||||||
|
readBuffer(bytes);
|
||||||
|
|
||||||
|
int cnt = 0;
|
||||||
|
int lastX = 0;
|
||||||
|
int lastY = 0;
|
||||||
|
boolean even = true;
|
||||||
|
|
||||||
|
//float[] coords = mElem.ensurePointSize(nodes, false);
|
||||||
|
|
||||||
|
byte[] buf = buffer;
|
||||||
|
int pos = bufferPos;
|
||||||
|
int end = pos + bytes;
|
||||||
|
int val;
|
||||||
|
|
||||||
|
while (pos < end) {
|
||||||
|
if (buf[pos] >= 0) {
|
||||||
|
val = buf[pos++];
|
||||||
|
|
||||||
|
} else if (buf[pos + 1] >= 0) {
|
||||||
|
val = (buf[pos++] & 0x7f)
|
||||||
|
| buf[pos++] << 7;
|
||||||
|
|
||||||
|
} else if (buf[pos + 2] >= 0) {
|
||||||
|
val = (buf[pos++] & 0x7f)
|
||||||
|
| (buf[pos++] & 0x7f) << 7
|
||||||
|
| (buf[pos++]) << 14;
|
||||||
|
|
||||||
|
} else if (buf[pos + 3] >= 0) {
|
||||||
|
val = (buf[pos++] & 0x7f)
|
||||||
|
| (buf[pos++] & 0x7f) << 7
|
||||||
|
| (buf[pos++] & 0x7f) << 14
|
||||||
|
| (buf[pos++]) << 21;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
val = (buf[pos++] & 0x7f)
|
||||||
|
| (buf[pos++] & 0x7f) << 7
|
||||||
|
| (buf[pos++] & 0x7f) << 14
|
||||||
|
| (buf[pos++] & 0x7f) << 21
|
||||||
|
| (buf[pos]) << 28;
|
||||||
|
|
||||||
|
int max = pos + VARINT_LIMIT;
|
||||||
|
while (pos < max)
|
||||||
|
if (buf[pos++] >= 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (pos == max)
|
||||||
|
throw new IOException("malformed VarInt32");
|
||||||
|
}
|
||||||
|
|
||||||
|
// zigzag decoding
|
||||||
|
int s = ((val >>> 1) ^ -(val & 1));
|
||||||
|
|
||||||
|
if (even) {
|
||||||
|
lastX = lastX + s;
|
||||||
|
coords[cnt++] = lastX / scale;
|
||||||
|
even = false;
|
||||||
|
} else {
|
||||||
|
lastY = lastY + s;
|
||||||
|
coords[cnt++] = lastY / scale;
|
||||||
|
even = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pos != bufferPos + bytes)
|
||||||
|
throw new IOException("invalid array " + numPoints);
|
||||||
|
|
||||||
|
bufferPos = pos;
|
||||||
|
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void readVarintArray(int num, short[] array) throws IOException {
|
||||||
|
int bytes = decodeVarint32();
|
||||||
|
|
||||||
|
readBuffer(bytes);
|
||||||
|
|
||||||
|
int cnt = 0;
|
||||||
|
|
||||||
|
byte[] buf = buffer;
|
||||||
|
int pos = bufferPos;
|
||||||
|
int end = pos + bytes;
|
||||||
|
int val;
|
||||||
|
|
||||||
|
while (pos < end) {
|
||||||
|
if (cnt == num)
|
||||||
|
throw new IOException("invalid array size " + num);
|
||||||
|
|
||||||
|
if (buf[pos] >= 0) {
|
||||||
|
val = buf[pos++];
|
||||||
|
} else if (buf[pos + 1] >= 0) {
|
||||||
|
val = (buf[pos++] & 0x7f)
|
||||||
|
| buf[pos++] << 7;
|
||||||
|
} else if (buf[pos + 2] >= 0) {
|
||||||
|
val = (buf[pos++] & 0x7f)
|
||||||
|
| (buf[pos++] & 0x7f) << 7
|
||||||
|
| (buf[pos++]) << 14;
|
||||||
|
} else if (buf[pos + 3] >= 0) {
|
||||||
|
val = (buf[pos++] & 0x7f)
|
||||||
|
| (buf[pos++] & 0x7f) << 7
|
||||||
|
| (buf[pos++] & 0x7f) << 14
|
||||||
|
| (buf[pos++]) << 21;
|
||||||
|
} else if (buf[pos + 4] >= 0){
|
||||||
|
val = (buf[pos++] & 0x7f)
|
||||||
|
| (buf[pos++] & 0x7f) << 7
|
||||||
|
| (buf[pos++] & 0x7f) << 14
|
||||||
|
| (buf[pos++] & 0x7f) << 21
|
||||||
|
| (buf[pos++]) << 28;
|
||||||
|
} else
|
||||||
|
throw new IOException("malformed VarInt32");
|
||||||
|
|
||||||
|
array[cnt++] = (short) val;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pos != bufferPos + bytes)
|
||||||
|
throw new IOException("invalid array " + num);
|
||||||
|
|
||||||
|
bufferPos = pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int decodeVarint32() throws IOException {
|
||||||
|
if (bufferPos + VARINT_MAX > bufferFill)
|
||||||
|
readBuffer(4096);
|
||||||
|
|
||||||
|
byte[] buf = buffer;
|
||||||
|
int pos = bufferPos;
|
||||||
|
int val;
|
||||||
|
|
||||||
|
if (buf[pos] >= 0) {
|
||||||
|
val = buf[pos++];
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (buf[pos + 1] >= 0) {
|
||||||
|
val = (buf[pos++] & 0x7f)
|
||||||
|
| (buf[pos++]) << 7;
|
||||||
|
|
||||||
|
} else if (buf[pos + 2] >= 0) {
|
||||||
|
val = (buf[pos++] & 0x7f)
|
||||||
|
| (buf[pos++] & 0x7f) << 7
|
||||||
|
| (buf[pos++]) << 14;
|
||||||
|
|
||||||
|
} else if (buf[pos + 3] >= 0) {
|
||||||
|
val = (buf[pos++] & 0x7f)
|
||||||
|
| (buf[pos++] & 0x7f) << 7
|
||||||
|
| (buf[pos++] & 0x7f) << 14
|
||||||
|
| (buf[pos++]) << 21;
|
||||||
|
} else {
|
||||||
|
val = (buf[pos++] & 0x7f)
|
||||||
|
| (buf[pos++] & 0x7f) << 7
|
||||||
|
| (buf[pos++] & 0x7f) << 14
|
||||||
|
| (buf[pos++] & 0x7f) << 21
|
||||||
|
| (buf[pos]) << 28;
|
||||||
|
|
||||||
|
// 'Discard upper 32 bits'
|
||||||
|
int max = pos + VARINT_LIMIT;
|
||||||
|
while (pos < max)
|
||||||
|
if (buf[pos++] >= 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (pos == max)
|
||||||
|
throw new IOException("malformed VarInt32");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bufferPos = pos;
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String decodeString() throws IOException {
|
||||||
|
final int size = decodeVarint32();
|
||||||
|
readBuffer(size);
|
||||||
|
|
||||||
|
String result;
|
||||||
|
|
||||||
|
if (mStringDecoder == null)
|
||||||
|
result = new String(buffer,bufferPos, size, "UTF-8");
|
||||||
|
else
|
||||||
|
result = mStringDecoder.decode(buffer, bufferPos, size);
|
||||||
|
|
||||||
|
bufferPos += size;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
public boolean hasData() {
|
||||||
|
return mBufferOffset + bufferPos < mReadEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int position() {
|
||||||
|
return mBufferOffset + bufferPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void readBuffer(int size) throws IOException {
|
||||||
|
// check if buffer already contains the request bytes
|
||||||
|
if (bufferPos + size < bufferFill)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// check if inputstream is read to the end
|
||||||
|
if (mReadPos == mReadEnd)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int maxSize = buffer.length;
|
||||||
|
|
||||||
|
if (size > maxSize) {
|
||||||
|
Log.d(TAG, "increase read buffer to " + size + " bytes");
|
||||||
|
maxSize = size;
|
||||||
|
byte[] tmp = new byte[maxSize];
|
||||||
|
bufferFill -= bufferPos;
|
||||||
|
System.arraycopy(buffer, bufferPos, tmp, 0, bufferFill);
|
||||||
|
mBufferOffset += bufferPos;
|
||||||
|
bufferPos = 0;
|
||||||
|
buffer = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bufferFill == bufferPos) {
|
||||||
|
mBufferOffset += bufferPos;
|
||||||
|
bufferPos = 0;
|
||||||
|
bufferFill = 0;
|
||||||
|
} else if (bufferPos + size > maxSize) {
|
||||||
|
// copy bytes left to the beginning of buffer
|
||||||
|
bufferFill -= bufferPos;
|
||||||
|
System.arraycopy(buffer, bufferPos, buffer, 0, bufferFill);
|
||||||
|
mBufferOffset += bufferPos;
|
||||||
|
bufferPos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int max = maxSize - bufferFill;
|
||||||
|
|
||||||
|
while ((bufferFill - bufferPos) < size && max > 0) {
|
||||||
|
|
||||||
|
max = maxSize - bufferFill;
|
||||||
|
if (max > mReadEnd - mReadPos)
|
||||||
|
max = (int) (mReadEnd - mReadPos);
|
||||||
|
|
||||||
|
// read until requested size is available in buffer
|
||||||
|
int len = mInputStream.read(buffer, bufferFill, max);
|
||||||
|
|
||||||
|
if (len < 0) {
|
||||||
|
// finished reading, mark end
|
||||||
|
buffer[bufferFill] = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
mReadPos += len;
|
||||||
|
|
||||||
|
if (mReadPos == mReadEnd)
|
||||||
|
break;
|
||||||
|
|
||||||
|
bufferFill += len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
354
src/org/oscim/database/oscimap4/Tags.java
Normal file
354
src/org/oscim/database/oscimap4/Tags.java
Normal file
@@ -0,0 +1,354 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 Hannes Janetzek
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under the
|
||||||
|
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||||
|
* Foundation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||||
|
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.oscim.database.oscimap4;
|
||||||
|
|
||||||
|
public class Tags {
|
||||||
|
// TODO this should be retrieved from tile 0/0/0
|
||||||
|
|
||||||
|
public final static int ATTRIB_OFFSET = 256;
|
||||||
|
|
||||||
|
// the keys that were imported via osm2pgsql + some more
|
||||||
|
public final static String[] keys = {
|
||||||
|
"access",
|
||||||
|
"addr:housename",
|
||||||
|
"addr:housenumber",
|
||||||
|
"addr:interpolation",
|
||||||
|
"admin_level",
|
||||||
|
"aerialway",
|
||||||
|
"aeroway",
|
||||||
|
"amenity",
|
||||||
|
"area",
|
||||||
|
"barrier",
|
||||||
|
"bicycle",
|
||||||
|
"brand",
|
||||||
|
"bridge",
|
||||||
|
"boundary",
|
||||||
|
"building",
|
||||||
|
"construction",
|
||||||
|
"covered",
|
||||||
|
"culvert",
|
||||||
|
"cutting",
|
||||||
|
"denomination",
|
||||||
|
"disused",
|
||||||
|
"embankment",
|
||||||
|
"foot",
|
||||||
|
"generator:source",
|
||||||
|
"harbour",
|
||||||
|
"highway",
|
||||||
|
"historic",
|
||||||
|
"horse",
|
||||||
|
"intermittent",
|
||||||
|
"junction",
|
||||||
|
"landuse",
|
||||||
|
"layer",
|
||||||
|
"leisure",
|
||||||
|
"lock",
|
||||||
|
"man_made",
|
||||||
|
"military",
|
||||||
|
"motorcar",
|
||||||
|
"name",
|
||||||
|
"natural",
|
||||||
|
"oneway",
|
||||||
|
"operator",
|
||||||
|
"population",
|
||||||
|
"power",
|
||||||
|
"power_source",
|
||||||
|
"place",
|
||||||
|
"railway",
|
||||||
|
"ref",
|
||||||
|
"religion",
|
||||||
|
"route",
|
||||||
|
"service",
|
||||||
|
"shop",
|
||||||
|
"sport",
|
||||||
|
"surface",
|
||||||
|
"toll",
|
||||||
|
"tourism",
|
||||||
|
"tower:type",
|
||||||
|
"tracktype",
|
||||||
|
"tunnel",
|
||||||
|
"water",
|
||||||
|
"waterway",
|
||||||
|
"wetland",
|
||||||
|
"width",
|
||||||
|
"wood",
|
||||||
|
"height",
|
||||||
|
"min_height",
|
||||||
|
"scalerank"
|
||||||
|
};
|
||||||
|
public final static int MAX_KEY = keys.length - 1;
|
||||||
|
|
||||||
|
// most popular values for the selected key (created from taginfo db)
|
||||||
|
public final static String[] values = {
|
||||||
|
"yes",
|
||||||
|
"residential",
|
||||||
|
"service",
|
||||||
|
"unclassified",
|
||||||
|
"stream",
|
||||||
|
"track",
|
||||||
|
"water",
|
||||||
|
"footway",
|
||||||
|
"tertiary",
|
||||||
|
"private",
|
||||||
|
"tree",
|
||||||
|
"path",
|
||||||
|
"forest",
|
||||||
|
"secondary",
|
||||||
|
"house",
|
||||||
|
"no",
|
||||||
|
"asphalt",
|
||||||
|
"wood",
|
||||||
|
"grass",
|
||||||
|
"paved",
|
||||||
|
"primary",
|
||||||
|
"unpaved",
|
||||||
|
"bus_stop",
|
||||||
|
"parking",
|
||||||
|
"parking_aisle",
|
||||||
|
"rail",
|
||||||
|
"driveway",
|
||||||
|
"8",
|
||||||
|
"administrative",
|
||||||
|
"locality",
|
||||||
|
"turning_circle",
|
||||||
|
"crossing",
|
||||||
|
"village",
|
||||||
|
"fence",
|
||||||
|
"grade2",
|
||||||
|
"coastline",
|
||||||
|
"grade3",
|
||||||
|
"farmland",
|
||||||
|
"hamlet",
|
||||||
|
"hut",
|
||||||
|
"meadow",
|
||||||
|
"wetland",
|
||||||
|
"cycleway",
|
||||||
|
"river",
|
||||||
|
"school",
|
||||||
|
"trunk",
|
||||||
|
"gravel",
|
||||||
|
"place_of_worship",
|
||||||
|
"farm",
|
||||||
|
"grade1",
|
||||||
|
"traffic_signals",
|
||||||
|
"wall",
|
||||||
|
"garage",
|
||||||
|
"gate",
|
||||||
|
"motorway",
|
||||||
|
"living_street",
|
||||||
|
"pitch",
|
||||||
|
"grade4",
|
||||||
|
"industrial",
|
||||||
|
"road",
|
||||||
|
"ground",
|
||||||
|
"scrub",
|
||||||
|
"motorway_link",
|
||||||
|
"steps",
|
||||||
|
"ditch",
|
||||||
|
"swimming_pool",
|
||||||
|
"grade5",
|
||||||
|
"park",
|
||||||
|
"apartments",
|
||||||
|
"restaurant",
|
||||||
|
"designated",
|
||||||
|
"bench",
|
||||||
|
"survey_point",
|
||||||
|
"pedestrian",
|
||||||
|
"hedge",
|
||||||
|
"reservoir",
|
||||||
|
"riverbank",
|
||||||
|
"alley",
|
||||||
|
"farmyard",
|
||||||
|
"peak",
|
||||||
|
"level_crossing",
|
||||||
|
"roof",
|
||||||
|
"dirt",
|
||||||
|
"drain",
|
||||||
|
"garages",
|
||||||
|
"entrance",
|
||||||
|
"street_lamp",
|
||||||
|
"deciduous",
|
||||||
|
"fuel",
|
||||||
|
"trunk_link",
|
||||||
|
"information",
|
||||||
|
"playground",
|
||||||
|
"supermarket",
|
||||||
|
"primary_link",
|
||||||
|
"concrete",
|
||||||
|
"mixed",
|
||||||
|
"permissive",
|
||||||
|
"orchard",
|
||||||
|
"grave_yard",
|
||||||
|
"canal",
|
||||||
|
"garden",
|
||||||
|
"spur",
|
||||||
|
"paving_stones",
|
||||||
|
"rock",
|
||||||
|
"bollard",
|
||||||
|
"convenience",
|
||||||
|
"cemetery",
|
||||||
|
"post_box",
|
||||||
|
"commercial",
|
||||||
|
"pier",
|
||||||
|
"bank",
|
||||||
|
"hotel",
|
||||||
|
"cliff",
|
||||||
|
"retail",
|
||||||
|
"construction",
|
||||||
|
"-1",
|
||||||
|
"fast_food",
|
||||||
|
"coniferous",
|
||||||
|
"cafe",
|
||||||
|
"6",
|
||||||
|
"kindergarten",
|
||||||
|
"tower",
|
||||||
|
"hospital",
|
||||||
|
"yard",
|
||||||
|
"sand",
|
||||||
|
"public_building",
|
||||||
|
"cobblestone",
|
||||||
|
"destination",
|
||||||
|
"island",
|
||||||
|
"abandoned",
|
||||||
|
"vineyard",
|
||||||
|
"recycling",
|
||||||
|
"agricultural",
|
||||||
|
"isolated_dwelling",
|
||||||
|
"pharmacy",
|
||||||
|
"post_office",
|
||||||
|
"motorway_junction",
|
||||||
|
"pub",
|
||||||
|
"allotments",
|
||||||
|
"dam",
|
||||||
|
"secondary_link",
|
||||||
|
"lift_gate",
|
||||||
|
"siding",
|
||||||
|
"stop",
|
||||||
|
"main",
|
||||||
|
"farm_auxiliary",
|
||||||
|
"quarry",
|
||||||
|
"10",
|
||||||
|
"station",
|
||||||
|
"platform",
|
||||||
|
"taxiway",
|
||||||
|
"limited",
|
||||||
|
"sports_centre",
|
||||||
|
"cutline",
|
||||||
|
"detached",
|
||||||
|
"storage_tank",
|
||||||
|
"basin",
|
||||||
|
"bicycle_parking",
|
||||||
|
"telephone",
|
||||||
|
"terrace",
|
||||||
|
"town",
|
||||||
|
"suburb",
|
||||||
|
"bus",
|
||||||
|
"compacted",
|
||||||
|
"toilets",
|
||||||
|
"heath",
|
||||||
|
"works",
|
||||||
|
"tram",
|
||||||
|
"beach",
|
||||||
|
"culvert",
|
||||||
|
"fire_station",
|
||||||
|
"recreation_ground",
|
||||||
|
"bakery",
|
||||||
|
"police",
|
||||||
|
"atm",
|
||||||
|
"clothes",
|
||||||
|
"tertiary_link",
|
||||||
|
"waste_basket",
|
||||||
|
"attraction",
|
||||||
|
"viewpoint",
|
||||||
|
"bicycle",
|
||||||
|
"church",
|
||||||
|
"shelter",
|
||||||
|
"drinking_water",
|
||||||
|
"marsh",
|
||||||
|
"picnic_site",
|
||||||
|
"hairdresser",
|
||||||
|
"bridleway",
|
||||||
|
"retaining_wall",
|
||||||
|
"buffer_stop",
|
||||||
|
"nature_reserve",
|
||||||
|
"village_green",
|
||||||
|
"university",
|
||||||
|
"1",
|
||||||
|
"bar",
|
||||||
|
"townhall",
|
||||||
|
"mini_roundabout",
|
||||||
|
"camp_site",
|
||||||
|
"aerodrome",
|
||||||
|
"stile",
|
||||||
|
"9",
|
||||||
|
"car_repair",
|
||||||
|
"parking_space",
|
||||||
|
"library",
|
||||||
|
"pipeline",
|
||||||
|
"true",
|
||||||
|
"cycle_barrier",
|
||||||
|
"4",
|
||||||
|
"museum",
|
||||||
|
"spring",
|
||||||
|
"hunting_stand",
|
||||||
|
"disused",
|
||||||
|
"car",
|
||||||
|
"tram_stop",
|
||||||
|
"land",
|
||||||
|
"fountain",
|
||||||
|
"hiking",
|
||||||
|
"manufacture",
|
||||||
|
"vending_machine",
|
||||||
|
"kiosk",
|
||||||
|
"swamp",
|
||||||
|
"unknown",
|
||||||
|
"7",
|
||||||
|
"islet",
|
||||||
|
"shed",
|
||||||
|
"switch",
|
||||||
|
"rapids",
|
||||||
|
"office",
|
||||||
|
"bay",
|
||||||
|
"proposed",
|
||||||
|
"common",
|
||||||
|
"weir",
|
||||||
|
"grassland",
|
||||||
|
"customers",
|
||||||
|
"social_facility",
|
||||||
|
"hangar",
|
||||||
|
"doctors",
|
||||||
|
"stadium",
|
||||||
|
"give_way",
|
||||||
|
"greenhouse",
|
||||||
|
"guest_house",
|
||||||
|
"viaduct",
|
||||||
|
"doityourself",
|
||||||
|
"runway",
|
||||||
|
"bus_station",
|
||||||
|
"water_tower",
|
||||||
|
"golf_course",
|
||||||
|
"conservation",
|
||||||
|
"block",
|
||||||
|
"college",
|
||||||
|
"wastewater_plant",
|
||||||
|
"subway",
|
||||||
|
"halt",
|
||||||
|
"forestry",
|
||||||
|
"florist",
|
||||||
|
"butcher"
|
||||||
|
};
|
||||||
|
public final static int MAX_VALUE = values.length - 1;
|
||||||
|
|
||||||
|
}
|
||||||
91
src/org/oscim/database/oscimap4/TileData_v4.proto
Normal file
91
src/org/oscim/database/oscimap4/TileData_v4.proto
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
// Protocol Version 4
|
||||||
|
|
||||||
|
package org.oscim.database.oscimap4;
|
||||||
|
|
||||||
|
message Data {
|
||||||
|
message Element {
|
||||||
|
|
||||||
|
// number of geometry 'indices'
|
||||||
|
optional uint32 num_indices = 1 [default = 1];
|
||||||
|
|
||||||
|
// number of 'tags'
|
||||||
|
optional uint32 num_tags = 2 [default = 1];
|
||||||
|
|
||||||
|
// elevation per coordinate
|
||||||
|
// (pixel relative to ground meters)
|
||||||
|
// optional bool has_elevation = 3 [default = false];
|
||||||
|
|
||||||
|
// reference to tile.tags
|
||||||
|
repeated uint32 tags = 11 [packed = true];
|
||||||
|
|
||||||
|
// A list of number of coordinates for each geometry.
|
||||||
|
// - polygons are separated by one '0' index
|
||||||
|
// - for single points this can be omitted.
|
||||||
|
// e.g 2,2 for two lines with two points each, or
|
||||||
|
// 4,3,0,4,3 for two polygons with four points in
|
||||||
|
// the outer ring and 3 points in the inner.
|
||||||
|
|
||||||
|
repeated uint32 indices = 12 [packed = true];
|
||||||
|
|
||||||
|
// single delta encoded coordinate x,y pairs scaled
|
||||||
|
// to a tile size of 4096
|
||||||
|
// note: geometries start at x,y = tile size / 2
|
||||||
|
|
||||||
|
repeated sint32 coordinates = 13 [packed = true];
|
||||||
|
|
||||||
|
//---------------- optional items ---------------
|
||||||
|
// osm layer [-5 .. 5] -> [0 .. 10]
|
||||||
|
optional uint32 layer = 21 [default = 5];
|
||||||
|
|
||||||
|
// intended for symbol and label placement, not used
|
||||||
|
//optional uint32 rank = 32 [packed = true];
|
||||||
|
|
||||||
|
// elevation per coordinate
|
||||||
|
// (pixel relative to ground meters)
|
||||||
|
// repeated sint32 elevation = 33 [packed = true];
|
||||||
|
|
||||||
|
// building height, precision 1/10m
|
||||||
|
//repeated sint32 height = 34 [packed = true];
|
||||||
|
|
||||||
|
// building height, precision 1/10m
|
||||||
|
//repeated sint32 min_height = 35 [packed = true];
|
||||||
|
}
|
||||||
|
|
||||||
|
required uint32 version = 1;
|
||||||
|
|
||||||
|
// tile creation time
|
||||||
|
optional uint64 timestamp = 2;
|
||||||
|
|
||||||
|
// tile is completely water (not used yet)
|
||||||
|
optional bool water = 3;
|
||||||
|
|
||||||
|
// number of 'tags'
|
||||||
|
required uint32 num_tags = 11;
|
||||||
|
optional uint32 num_keys = 12 [default = 0];
|
||||||
|
optional uint32 num_vals = 13 [default = 0];
|
||||||
|
|
||||||
|
// strings referenced by tags
|
||||||
|
repeated string keys = 14;
|
||||||
|
// separate common attributes from label to
|
||||||
|
// allow
|
||||||
|
repeated string values = 15;
|
||||||
|
|
||||||
|
// (key[0xfffffffc] | type[0x03]), value pairs
|
||||||
|
// key: uint32 -> reference to key-strings
|
||||||
|
// type 0: attribute -> uint32 reference to value-strings
|
||||||
|
// type 1: string -> uint32 reference to label-strings
|
||||||
|
// type 2: sint32
|
||||||
|
// type 3: float
|
||||||
|
// value: uint32 interpreted according to 'type'
|
||||||
|
|
||||||
|
repeated uint32 tags = 16 [packed = true];
|
||||||
|
|
||||||
|
// linestring
|
||||||
|
repeated Element lines = 21;
|
||||||
|
|
||||||
|
// polygons (MUST be implicitly closed)
|
||||||
|
repeated Element polygons = 22;
|
||||||
|
|
||||||
|
// points (POIs)
|
||||||
|
repeated Element points = 23;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user