org.oscim.tiling.source.oscimap4.TileDecoder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of vtm Show documentation
Show all versions of vtm Show documentation
OpenGL vector map library written in Java - running on Android, iOS, Desktop and within the browser.
/*
* Copyright 2013 Hannes Janetzek
* Copyright 2016-2017 devemux86
* Copyright 2017 Gustl22
*
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
*
* 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 .
*/
package org.oscim.tiling.source.oscimap4;
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.tiling.ITileDataSink;
import org.oscim.tiling.source.PbfDecoder;
import org.oscim.utils.FastMath;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
public class TileDecoder extends PbfDecoder {
static final Logger log = LoggerFactory.getLogger(TileDecoder.class);
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;
/**
* since version 5
*/
private static final int TAG_TILE_MESH = 24;
private static final int TAG_ELEM_NUM_INDICES = 1;
private static final int TAG_ELEM_NUM_TAGS = 2;
/**
* since version 5
*/
private static final int TAG_ELEM_NUM_COORDINATES = 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 int[] mSArray = new int[100];
private Tile mTile;
private final MapElement mElem;
private final TagSet mTileTags;
private ITileDataSink mMapDataSink;
private int mVersion;
// scale coordinates to tile size
private static final float REF_TILE_SIZE = 4096.0f;
private final float mScaleFactor = REF_TILE_SIZE / Tile.SIZE;
public TileDecoder() {
mElem = new MapElement();
mTileTags = new TagSet(100);
}
@Override
public boolean decode(Tile tile, ITileDataSink sink, InputStream is)
throws IOException {
readUnsignedInt(is, buffer);
setInputStream(is);
mTile = tile;
mMapDataSink = sink;
mTileTags.clearAndNullTags();
int val;
int numTags = 0;
int numKeys = -1;
int numValues = -1;
int curKey = 0;
int curValue = 0;
String[] keys = null;
String[] values = null;
while (hasData() && (val = decodeVarint32()) > 0) {
// read tag and wire type
int tag = (val >> 3);
//log.debug("tag: " + tag);
switch (tag) {
case TAG_TILE_LINE:
case TAG_TILE_POLY:
case TAG_TILE_POINT:
case TAG_TILE_MESH:
decodeTileElement(tag);
break;
case TAG_TILE_TAG_KEYS:
if (keys == null || curKey >= numKeys) {
log.debug("{} wrong number of keys {}",
mTile, numKeys);
return false;
}
keys[curKey++] = decodeString().intern();
break;
case TAG_TILE_TAG_VALUES:
if (values == null || curValue >= numValues) {
log.debug("{} wrong number of values {}",
mTile, numValues);
return false;
}
values[curValue++] = decodeString();
break;
case TAG_TILE_NUM_TAGS:
numTags = decodeVarint32();
//log.debug("num tags " + numTags);
break;
case TAG_TILE_NUM_KEYS:
numKeys = decodeVarint32();
//log.debug("num keys " + numKeys);
keys = new String[numKeys];
break;
case TAG_TILE_NUM_VALUES:
numValues = decodeVarint32();
//log.debug("num values " + numValues);
values = new String[numValues];
break;
case TAG_TILE_TAGS:
int len = numTags * 2;
if (mSArray.length < len)
mSArray = new int[len];
decodeVarintArray(len, mSArray);
if (!decodeTileTags(numTags, mSArray, keys, values)) {
log.debug("{} invalid tags", mTile);
return false;
}
break;
case TAG_TILE_VERSION:
int version = decodeVarint32();
if (version < 4 || mVersion > 5) {
log.debug("{} invalid version:{}",
mTile, version);
return false;
}
break;
default:
log.debug("{} invalid type for tile:{}",
mTile, tag);
return false;
}
}
return true;
}
private boolean decodeTileTags(int numTags, int[] tagIdx,
String[] keys, String[] vals) {
Tag tag;
for (int i = 0, n = (numTags << 1); i < n; 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 (Tag.KEY_NAME.equals(key)
|| Tag.KEY_HOUSE_NUMBER.equals(key)
|| Tag.KEY_REF.equals(key)
|| Tag.KEY_ELE.equals(key))
tag = new Tag(key, val, false);
else if (Tag.KEY_HEIGHT.equals(key)
|| Tag.KEY_MIN_HEIGHT.equals(key)) {
// Reformat values to established meters in OSM
tag = new Tag(key, String.valueOf(FastMath.round2(Float.valueOf(val) / 100)), false);
} else
tag = new Tag(key, val, false, true);
mTileTags.add(tag);
}
return true;
}
private int decodeWayIndices(int indexCnt, boolean shift) throws IOException {
mElem.ensureIndexSize(indexCnt, false);
decodeVarintArray(indexCnt, mElem.index);
int[] index = mElem.index;
int coordCnt = 0;
if (shift) {
for (int i = 0; i < indexCnt; i++) {
coordCnt += index[i];
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();
int end = position() + bytes;
int numIndices = 1;
int numTags = 1;
//boolean skip = false;
boolean fail = false;
int coordCnt = 0;
if (type == TAG_TILE_POINT) {
coordCnt = 1;
mElem.index[0] = 2;
}
mElem.layer = 5;
while (position() < end) {
// read tag and wire type
int val = decodeVarint32();
if (val == 0)
break;
int tag = (val >> 3);
switch (tag) {
case TAG_ELEM_TAGS:
if (!decodeElementTags(numTags))
return false;
break;
case TAG_ELEM_NUM_INDICES:
numIndices = decodeVarint32();
break;
case TAG_ELEM_NUM_TAGS:
numTags = decodeVarint32();
break;
case TAG_ELEM_NUM_COORDINATES:
coordCnt = decodeVarint32();
break;
case TAG_ELEM_INDEX:
if (type == TAG_TILE_MESH) {
decodeWayIndices(numIndices, false);
} else {
coordCnt = decodeWayIndices(numIndices, true);
// otherwise using TAG_ELEM_NUM_COORDINATES
}
break;
case TAG_ELEM_COORDS:
if (coordCnt == 0) {
log.debug("{} no coordinates", mTile);
}
if (type == TAG_TILE_MESH) {
mElem.ensurePointSize((coordCnt * 3 / 2), false);
int cnt = decodeInterleavedPoints3D(mElem.points, 1);
if (cnt != (3 * coordCnt)) {
log.debug("{} wrong number of coordintes {}/{}", mTile,
Integer.valueOf(coordCnt),
Integer.valueOf(cnt));
fail = true;
}
mElem.pointNextPos = cnt;
} else {
mElem.ensurePointSize(coordCnt, false);
int cnt = decodeInterleavedPoints(mElem, mScaleFactor);
if (cnt != coordCnt) {
log.debug("{} wrong number of coordintes {}/{}", mTile,
Integer.valueOf(coordCnt),
Integer.valueOf(cnt));
fail = true;
}
}
break;
case TAG_ELEM_LAYER:
mElem.layer = decodeVarint32();
break;
default:
log.debug("{} invalid type for way: {}", mTile, tag);
}
}
if (fail || numTags == 0 || numIndices == 0) {
log.debug("{} failed: bytes:{} tags:{} ({},{})",
mTile, Integer.valueOf(bytes),
mElem.tags,
Integer.valueOf(numIndices),
Integer.valueOf(coordCnt));
return false;
}
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;
case TAG_TILE_MESH:
mElem.type = GeometryType.TRIS;
break;
}
mMapDataSink.process(mElem);
return true;
}
private boolean decodeElementTags(int numTags) throws IOException {
if (mSArray.length < numTags)
mSArray = new int[numTags];
int[] tagIds = mSArray;
decodeVarintArray(numTags, tagIds);
mElem.tags.clear();
int max = mTileTags.size() - 1;
for (int i = 0; i < numTags; i++) {
int idx = tagIds[i];
if (idx < 0 || idx > max) {
log.debug("{} invalid tag:{}", mTile,
Integer.valueOf(idx),
Integer.valueOf(i));
return false;
}
mElem.tags.add(mTileTags.get(idx));
}
return true;
}
}