add async replacement for oscim UrlTileSource/TileLoader
This commit is contained in:
parent
d7c412f74f
commit
6f18e804e6
@ -15,7 +15,7 @@ public class GwtCanvas implements org.oscim.backend.canvas.Canvas {
|
|||||||
@Override
|
@Override
|
||||||
public void setBitmap(Bitmap bitmap) {
|
public void setBitmap(Bitmap bitmap) {
|
||||||
this.bitmap = (GwtBitmap) bitmap;
|
this.bitmap = (GwtBitmap) bitmap;
|
||||||
this.bitmap.pixmap.setColor(0);
|
//this.bitmap.pixmap.setColor(0x00ffffff);
|
||||||
this.bitmap.pixmap.getContext().clearRect(0, 0, this.bitmap.getWidth(), this.bitmap.getHeight());
|
this.bitmap.pixmap.getContext().clearRect(0, 0, this.bitmap.getWidth(), this.bitmap.getHeight());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,11 +30,11 @@ public class GwtCanvas implements org.oscim.backend.canvas.Canvas {
|
|||||||
ctx.setFont(p.font);
|
ctx.setFont(p.font);
|
||||||
|
|
||||||
if (p.stroke){
|
if (p.stroke){
|
||||||
Log.d("", "stroke " + p.stroke + " " + p.color + " " + p.font + " "+ string);
|
//Log.d("", "stroke " + p.stroke + " " + p.color + " " + p.font + " "+ string);
|
||||||
ctx.setStrokeStyle(p.color);
|
ctx.setStrokeStyle(p.color);
|
||||||
ctx.strokeText(string, x, y);
|
ctx.strokeText(string, x, y);
|
||||||
} else{
|
} else{
|
||||||
Log.d("", "fill " + p.stroke + " " + p.color + " " + p.font + " "+ string);
|
//Log.d("", "fill " + p.stroke + " " + p.color + " " + p.font + " "+ string);
|
||||||
ctx.setFillStyle(p.color);
|
ctx.setFillStyle(p.color);
|
||||||
ctx.fillText(string, x, y);
|
ctx.fillText(string, x, y);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,564 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012, 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.layers.tile.vector;
|
||||||
|
|
||||||
|
import static org.oscim.layers.tile.MapTile.STATE_NONE;
|
||||||
|
|
||||||
|
import org.oscim.core.GeometryBuffer.GeometryType;
|
||||||
|
import org.oscim.core.MapElement;
|
||||||
|
import org.oscim.core.MercatorProjection;
|
||||||
|
import org.oscim.core.Tag;
|
||||||
|
import org.oscim.core.TagSet;
|
||||||
|
import org.oscim.core.Tile;
|
||||||
|
import org.oscim.layers.tile.MapTile;
|
||||||
|
import org.oscim.layers.tile.TileLoader;
|
||||||
|
import org.oscim.layers.tile.TileManager;
|
||||||
|
import org.oscim.renderer.sublayers.ExtrusionLayer;
|
||||||
|
import org.oscim.renderer.sublayers.Layers;
|
||||||
|
import org.oscim.renderer.sublayers.LineLayer;
|
||||||
|
import org.oscim.renderer.sublayers.LineTexLayer;
|
||||||
|
import org.oscim.renderer.sublayers.PolygonLayer;
|
||||||
|
import org.oscim.renderer.sublayers.SymbolItem;
|
||||||
|
import org.oscim.renderer.sublayers.TextItem;
|
||||||
|
import org.oscim.theme.IRenderCallback;
|
||||||
|
import org.oscim.theme.IRenderTheme;
|
||||||
|
import org.oscim.theme.renderinstruction.Area;
|
||||||
|
import org.oscim.theme.renderinstruction.Circle;
|
||||||
|
import org.oscim.theme.renderinstruction.Line;
|
||||||
|
import org.oscim.theme.renderinstruction.LineSymbol;
|
||||||
|
import org.oscim.theme.renderinstruction.RenderInstruction;
|
||||||
|
import org.oscim.theme.renderinstruction.Symbol;
|
||||||
|
import org.oscim.theme.renderinstruction.Text;
|
||||||
|
import org.oscim.tilesource.ITileDataSink;
|
||||||
|
import org.oscim.tilesource.ITileDataSource;
|
||||||
|
import org.oscim.tilesource.ITileDataSource.QueryResult;
|
||||||
|
import org.oscim.utils.LineClipper;
|
||||||
|
import org.oscim.utils.pool.Inlist;
|
||||||
|
import org.oscim.view.DebugSettings;
|
||||||
|
|
||||||
|
import org.oscim.backend.Log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @note
|
||||||
|
* 1. The MapWorkers call MapTileLoader.execute() to load a tile.
|
||||||
|
* 2. The tile data will be loaded from current MapDatabase
|
||||||
|
* 3. MapDatabase calls the IMapDataSink functions
|
||||||
|
* implemented by MapTileLoader for WAY and POI items.
|
||||||
|
* 4. these callbacks then call RenderTheme to get the matching style.
|
||||||
|
* 5. RenderTheme calls IRenderCallback functions with style information
|
||||||
|
* 6. Styled items become added to MapTile.layers... roughly
|
||||||
|
*/
|
||||||
|
public class MapTileLoader extends TileLoader implements IRenderCallback, ITileDataSink {
|
||||||
|
|
||||||
|
private static final String TAG = MapTileLoader.class.getName();
|
||||||
|
|
||||||
|
private static final double STROKE_INCREASE = Math.sqrt(2.5);
|
||||||
|
private static final byte LAYERS = 11;
|
||||||
|
|
||||||
|
public static final byte STROKE_MIN_ZOOM_LEVEL = 12;
|
||||||
|
public static final byte STROKE_MAX_ZOOM_LEVEL = 17;
|
||||||
|
|
||||||
|
private static final Tag[] debugTagWay = { new Tag("debug", "way") };
|
||||||
|
private static final Tag[] debugTagArea = { new Tag("debug", "area") };
|
||||||
|
|
||||||
|
// replacement for variable value tags that should not be matched by RenderTheme
|
||||||
|
// FIXME make this general, maybe subclass tags
|
||||||
|
private static final Tag mTagEmptyName = new Tag(Tag.TAG_KEY_NAME, null, false);
|
||||||
|
private static final Tag mTagEmptyHouseNr = new Tag(Tag.TAG_KEY_HOUSE_NUMBER, null, false);
|
||||||
|
|
||||||
|
// private final MapElement mDebugWay, mDebugPoint;
|
||||||
|
|
||||||
|
private static DebugSettings debug;
|
||||||
|
|
||||||
|
private IRenderTheme renderTheme;
|
||||||
|
private int renderLevels;
|
||||||
|
|
||||||
|
// current TileDataSource used by this MapTileLoader
|
||||||
|
private ITileDataSource mTileDataSource;
|
||||||
|
|
||||||
|
// currently processed tile
|
||||||
|
private MapTile mTile;
|
||||||
|
|
||||||
|
// currently processed MapElement
|
||||||
|
private MapElement mElement;
|
||||||
|
|
||||||
|
// current line layer (will be used for following outline layers)
|
||||||
|
private LineLayer mCurLineLayer;
|
||||||
|
|
||||||
|
private int mDrawingLayer;
|
||||||
|
|
||||||
|
private float mStrokeScale = 1.0f;
|
||||||
|
private float mLatScaleFactor;
|
||||||
|
private float mGroundResolution;
|
||||||
|
|
||||||
|
private Tag mTagName;
|
||||||
|
private Tag mTagHouseNr;
|
||||||
|
|
||||||
|
private final LineClipper mClipper;
|
||||||
|
|
||||||
|
public void setRenderTheme(IRenderTheme theme) {
|
||||||
|
renderTheme = theme;
|
||||||
|
renderLevels = theme.getLevels();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setDebugSettings(DebugSettings debugSettings) {
|
||||||
|
debug = debugSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public MapTileLoader(TileManager tileManager) {
|
||||||
|
super(tileManager);
|
||||||
|
|
||||||
|
mClipper = new LineClipper(0, 0, Tile.SIZE, Tile.SIZE, true);
|
||||||
|
|
||||||
|
// MapElement m = mDebugWay = new MapElement();
|
||||||
|
// m.startLine();
|
||||||
|
// int s = Tile.SIZE;
|
||||||
|
// m.addPoint(0, 0);
|
||||||
|
// m.addPoint(0, s);
|
||||||
|
// m.addPoint(s, s);
|
||||||
|
// m.addPoint(s, 0);
|
||||||
|
// m.addPoint(0, 0);
|
||||||
|
// m.tags = new Tag[] { new Tag("debug", "box") };
|
||||||
|
// m.type = GeometryType.LINE;
|
||||||
|
//
|
||||||
|
// m = mDebugPoint = new MapElement();
|
||||||
|
// m.startPoints();
|
||||||
|
// m.addPoint(s >> 1, 10);
|
||||||
|
// m.type = GeometryType.POINT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cleanup() {
|
||||||
|
mTileDataSource.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean executeJob(MapTile mapTile) {
|
||||||
|
|
||||||
|
if (mTileDataSource == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
mTile = mapTile;
|
||||||
|
|
||||||
|
if (mTile.layers != null) {
|
||||||
|
// should be fixed now.
|
||||||
|
Log.d(TAG, "BUG tile already loaded " + mTile + " " + mTile.state);
|
||||||
|
mTile = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
setScaleStrokeWidth(mTile.zoomLevel);
|
||||||
|
|
||||||
|
// account for area changes with latitude
|
||||||
|
double latitude = MercatorProjection.toLatitude(mTile.y);
|
||||||
|
|
||||||
|
mLatScaleFactor = 0.4f + 0.6f * ((float) Math.sin(Math.abs(latitude) * (Math.PI / 180)));
|
||||||
|
|
||||||
|
mGroundResolution = (float) (Math.cos(latitude * (Math.PI / 180))
|
||||||
|
* MercatorProjection.EARTH_CIRCUMFERENCE
|
||||||
|
/ ((long) Tile.SIZE << mTile.zoomLevel));
|
||||||
|
|
||||||
|
mTile.layers = new Layers();
|
||||||
|
|
||||||
|
// query database, which calls renderWay and renderPOI
|
||||||
|
// callbacks while processing map tile data.
|
||||||
|
if (mTileDataSource.executeQuery(mTile, this) != QueryResult.SUCCESS) {
|
||||||
|
|
||||||
|
//Log.d(TAG, "Failed loading: " + tile);
|
||||||
|
// mTile.layers.clear();
|
||||||
|
// mTile.layers = null;
|
||||||
|
// TextItem.pool.releaseAll(mTile.labels);
|
||||||
|
// mTile.labels = null;
|
||||||
|
// // FIXME add STATE_FAILED?
|
||||||
|
// // in passTile everything but STATE_LOADING is considered failed.
|
||||||
|
// mTile.state = STATE_NONE;
|
||||||
|
// mTile.loader.jobCompleted(mTile, false);
|
||||||
|
// mTile = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (debug.drawTileFrames) {
|
||||||
|
// // draw tile coordinate
|
||||||
|
// mTagName = new Tag("name", mTile.toString(), false);
|
||||||
|
// mElement = mDebugPoint;
|
||||||
|
// RenderInstruction[] ri;
|
||||||
|
// ri = renderTheme.matchNode(debugTagWay, (byte) 0);
|
||||||
|
// renderNode(ri);
|
||||||
|
//
|
||||||
|
// // draw tile box
|
||||||
|
// mElement = mDebugWay;
|
||||||
|
// mDrawingLayer = 100 * renderLevels;
|
||||||
|
// ri = renderTheme.matchWay(mDebugWay.tags, (byte) 0, false);
|
||||||
|
// renderWay(ri);
|
||||||
|
// }
|
||||||
|
//mTile.loader.jobCompleted(mTile, true);
|
||||||
|
//mTile = null;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void completed(boolean success){
|
||||||
|
Log.d(TAG, mTile + "completed " + success);
|
||||||
|
|
||||||
|
if (success){
|
||||||
|
mTile.loader.jobCompleted(mTile, true);
|
||||||
|
mTile = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mTile.layers.clear();
|
||||||
|
mTile.layers = null;
|
||||||
|
TextItem.pool.releaseAll(mTile.labels);
|
||||||
|
mTile.labels = null;
|
||||||
|
// FIXME add STATE_FAILED?
|
||||||
|
// in passTile everything but STATE_LOADING is considered failed.
|
||||||
|
mTile.state = STATE_NONE;
|
||||||
|
mTile.loader.jobCompleted(mTile, false);
|
||||||
|
mTile = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Tag[] mFilterTags = new Tag[1];
|
||||||
|
|
||||||
|
private static int getValidLayer(int layer) {
|
||||||
|
if (layer < 0) {
|
||||||
|
return 0;
|
||||||
|
} else if (layer >= LAYERS) {
|
||||||
|
return LAYERS - 1;
|
||||||
|
} else {
|
||||||
|
return layer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the scale stroke factor for the given zoom level.
|
||||||
|
*
|
||||||
|
* @param zoomLevel
|
||||||
|
* the zoom level for which the scale stroke factor should be
|
||||||
|
* set.
|
||||||
|
*/
|
||||||
|
private void setScaleStrokeWidth(byte zoomLevel) {
|
||||||
|
mStrokeScale = (float) Math.pow(STROKE_INCREASE, zoomLevel - STROKE_MIN_ZOOM_LEVEL);
|
||||||
|
if (mStrokeScale < 1)
|
||||||
|
mStrokeScale = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTileDataSource(ITileDataSource mapDatabase) {
|
||||||
|
if (mTileDataSource != null)
|
||||||
|
mTileDataSource.destroy();
|
||||||
|
|
||||||
|
mTileDataSource = mapDatabase;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ITileDataSource getMapDatabase() {
|
||||||
|
return mTileDataSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean mRenderBuildingModel;
|
||||||
|
|
||||||
|
// Replace tags that should only be matched by key in RenderTheme
|
||||||
|
// to avoid caching RenderInstructions for each way of the same type
|
||||||
|
// only with different name.
|
||||||
|
// Maybe this should be done within RenderTheme, also allowing
|
||||||
|
// to set these replacement rules in theme file.
|
||||||
|
private boolean filterTags(TagSet in) {
|
||||||
|
mRenderBuildingModel = false;
|
||||||
|
Tag[] tags = in.tags;
|
||||||
|
|
||||||
|
for (int i = 0; i < in.numTags; i++) {
|
||||||
|
String key = tags[i].key;
|
||||||
|
if (key == Tag.TAG_KEY_NAME) {
|
||||||
|
if (tags[i].value != null) {
|
||||||
|
mTagName = tags[i];
|
||||||
|
tags[i] = mTagEmptyName;
|
||||||
|
}
|
||||||
|
} else if (key == Tag.TAG_KEY_HOUSE_NUMBER) {
|
||||||
|
if (tags[i].value != null) {
|
||||||
|
mTagHouseNr = tags[i];
|
||||||
|
tags[i] = mTagEmptyHouseNr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*else if (mTile.zoomLevel > 16) {
|
||||||
|
// FIXME, allow overlays to intercept
|
||||||
|
// this, or use a theme option for this
|
||||||
|
if (key == Tag.TAG_KEY_BUILDING)
|
||||||
|
mRenderBuildingModel = true;
|
||||||
|
|
||||||
|
else if (key == Tag.KEY_HEIGHT) {
|
||||||
|
try {
|
||||||
|
mElement.height = Integer.parseInt(tags[i].value);
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (key == Tag.KEY_MIN_HEIGHT) {
|
||||||
|
try {
|
||||||
|
mElement.minHeight = Integer.parseInt(tags[i].value);
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void process(MapElement element) {
|
||||||
|
clearState();
|
||||||
|
|
||||||
|
mElement = element;
|
||||||
|
|
||||||
|
if (element.type == GeometryType.POINT) {
|
||||||
|
// remove tags that should not be cached in Rendertheme
|
||||||
|
filterTags(element.tags);
|
||||||
|
|
||||||
|
// get render instructions
|
||||||
|
RenderInstruction[] ri = renderTheme.matchElement(element, mTile.zoomLevel);
|
||||||
|
|
||||||
|
if (ri != null)
|
||||||
|
renderNode(ri);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// replace tags that should not be cached in Rendertheme (e.g. name)
|
||||||
|
if (!filterTags(element.tags))
|
||||||
|
return;
|
||||||
|
|
||||||
|
boolean closed = element.type == GeometryType.POLY;
|
||||||
|
|
||||||
|
mDrawingLayer = getValidLayer(element.layer) * renderLevels;
|
||||||
|
|
||||||
|
RenderInstruction[] ri = renderTheme.matchElement(element, mTile.zoomLevel);
|
||||||
|
|
||||||
|
renderWay(ri);
|
||||||
|
|
||||||
|
if (debug.debugTheme && ri == null)
|
||||||
|
debugUnmatched(closed, element.tags);
|
||||||
|
|
||||||
|
mCurLineLayer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
mElement = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void debugUnmatched(boolean closed, TagSet tags) {
|
||||||
|
// Log.d(TAG, "DBG way not matched: " + closed + " "
|
||||||
|
// + Arrays.deepToString(tags));
|
||||||
|
//
|
||||||
|
// mTagName = new Tag("name", tags[0].key + ":"
|
||||||
|
// + tags[0].value, false);
|
||||||
|
//
|
||||||
|
// mElement.tags = closed ? debugTagArea : debugTagWay;
|
||||||
|
// RenderInstruction[] ri = renderTheme.matchElement(mElement, mTile.zoomLevel);
|
||||||
|
// renderWay(ri);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderWay(RenderInstruction[] ri) {
|
||||||
|
if (ri == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (int i = 0, n = ri.length; i < n; i++)
|
||||||
|
ri[i].renderWay(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderNode(RenderInstruction[] ri) {
|
||||||
|
if (ri == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (int i = 0, n = ri.length; i < n; i++)
|
||||||
|
ri[i].renderNode(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clearState() {
|
||||||
|
mTagName = null;
|
||||||
|
mTagHouseNr = null;
|
||||||
|
mCurLineLayer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Override
|
||||||
|
// public void renderWaterBackground() {
|
||||||
|
// }
|
||||||
|
|
||||||
|
// ----------------- RenderThemeCallback -----------------
|
||||||
|
@Override
|
||||||
|
public void renderWay(Line line, int level) {
|
||||||
|
int numLayer = mDrawingLayer + level;
|
||||||
|
|
||||||
|
if (line.stipple == 0) {
|
||||||
|
if (line.outline && mCurLineLayer == null) {
|
||||||
|
Log.e(TAG, "BUG in theme: line must come before outline!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LineLayer lineLayer = mTile.layers.getLineLayer(numLayer);
|
||||||
|
|
||||||
|
if (lineLayer == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (lineLayer.line == null) {
|
||||||
|
lineLayer.line = line;
|
||||||
|
|
||||||
|
float w = line.width;
|
||||||
|
if (!line.fixed) {
|
||||||
|
w *= mStrokeScale;
|
||||||
|
w *= mLatScaleFactor;
|
||||||
|
}
|
||||||
|
lineLayer.width = w;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line.outline) {
|
||||||
|
lineLayer.addOutline(mCurLineLayer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lineLayer.addLine(mElement.points, mElement.index,
|
||||||
|
mElement.type == GeometryType.POLY);
|
||||||
|
|
||||||
|
// keep reference for outline layer
|
||||||
|
mCurLineLayer = lineLayer;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
LineTexLayer lineLayer = mTile.layers.getLineTexLayer(numLayer);
|
||||||
|
|
||||||
|
if (lineLayer == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (lineLayer.line == null) {
|
||||||
|
lineLayer.line = line;
|
||||||
|
|
||||||
|
float w = line.width;
|
||||||
|
if (!line.fixed) {
|
||||||
|
w *= mStrokeScale;
|
||||||
|
w *= mLatScaleFactor;
|
||||||
|
}
|
||||||
|
lineLayer.width = w;
|
||||||
|
}
|
||||||
|
|
||||||
|
lineLayer.addLine(mElement.points, mElement.index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderArea(Area area, int level) {
|
||||||
|
int numLayer = mDrawingLayer + level;
|
||||||
|
|
||||||
|
if (mRenderBuildingModel) {
|
||||||
|
//Log.d(TAG, "add buildings: " + mTile + " " + mPriority);
|
||||||
|
if (mTile.layers.extrusionLayers == null)
|
||||||
|
mTile.layers.extrusionLayers = new ExtrusionLayer(0, mGroundResolution);
|
||||||
|
|
||||||
|
((ExtrusionLayer) mTile.layers.extrusionLayers).addBuildings(mElement);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (debug.disablePolygons)
|
||||||
|
return;
|
||||||
|
|
||||||
|
PolygonLayer layer = mTile.layers.getPolygonLayer(numLayer);
|
||||||
|
|
||||||
|
if (layer == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
//if (layer.area == null)
|
||||||
|
layer.area = area;
|
||||||
|
|
||||||
|
layer.addPolygon(mElement.points, mElement.index);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String textValueForKey(Text text) {
|
||||||
|
String value = null;
|
||||||
|
|
||||||
|
if (text.textKey == Tag.TAG_KEY_NAME) {
|
||||||
|
if (mTagName != null)
|
||||||
|
value = mTagName.value;
|
||||||
|
} else if (text.textKey == Tag.TAG_KEY_HOUSE_NUMBER) {
|
||||||
|
if (mTagHouseNr != null)
|
||||||
|
value = mTagHouseNr.value;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderAreaCaption(Text text) {
|
||||||
|
// TODO place somewhere on polygon
|
||||||
|
|
||||||
|
String value = textValueForKey(text);
|
||||||
|
if (value == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
float x = mElement.points[0];
|
||||||
|
float y = mElement.points[1];
|
||||||
|
|
||||||
|
mTile.addLabel(TextItem.pool.get().set(x, y, value, text));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderPointOfInterestCaption(Text text) {
|
||||||
|
String value = textValueForKey(text);
|
||||||
|
if (value == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (int i = 0, n = mElement.index[0]; i < n; i += 2) {
|
||||||
|
float x = mElement.points[i];
|
||||||
|
float y = mElement.points[i + 1];
|
||||||
|
mTile.addLabel(TextItem.pool.get().set(x, y, value, text));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderWayText(Text text) {
|
||||||
|
String value = textValueForKey(text);
|
||||||
|
if (value == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int offset = 0;
|
||||||
|
for (int i = 0, n = mElement.index.length; i < n; i++) {
|
||||||
|
int length = mElement.index[i];
|
||||||
|
if (length < 4)
|
||||||
|
break;
|
||||||
|
|
||||||
|
WayDecorator.renderText(mClipper, mElement.points, value, text,
|
||||||
|
offset, length, mTile);
|
||||||
|
offset += length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderPointOfInterestCircle(Circle circle, int level) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderPointOfInterestSymbol(Symbol symbol) {
|
||||||
|
if (symbol.texture == null){
|
||||||
|
Log.d(TAG, "missing symbol for " + mElement.tags.asString());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SymbolItem it = SymbolItem.pool.get();
|
||||||
|
it.x = mElement.points[0];
|
||||||
|
it.y = mElement.points[1];
|
||||||
|
it.symbol = symbol.texture;
|
||||||
|
it.billboard = true;
|
||||||
|
|
||||||
|
mTile.symbols = Inlist.push(mTile.symbols, it);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderAreaSymbol(Symbol symbol) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderWaySymbol(LineSymbol symbol) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,76 @@
|
|||||||
|
package org.oscim.theme;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
import org.oscim.core.MapElement;
|
||||||
|
import org.oscim.core.Tag;
|
||||||
|
import org.oscim.theme.renderinstruction.Area;
|
||||||
|
import org.oscim.theme.renderinstruction.Line;
|
||||||
|
import org.oscim.theme.renderinstruction.RenderInstruction;
|
||||||
|
|
||||||
|
public class RenderThemeHandler2 {
|
||||||
|
private final static int AREA_WATER = 0;
|
||||||
|
private final static int AREA_WOOD = 1;
|
||||||
|
private final static int LINE_HIGHWAY = 2;
|
||||||
|
private final static Tag TAG_WATER = new Tag("natural", "water");
|
||||||
|
private final static Tag TAG_WOOD = new Tag("natural", "wood");
|
||||||
|
private final static Tag TAG_FOREST= new Tag("landuse", "forest");
|
||||||
|
|
||||||
|
private static RenderInstruction[][] instructions = {
|
||||||
|
// water
|
||||||
|
{ new Area(2, 0xffafc5e3) },
|
||||||
|
// wood
|
||||||
|
{ new Area(1, 0xffd1dbc7) },
|
||||||
|
// highway
|
||||||
|
{ new Line(0, 0xffaaaaaa, 1.2f) }
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
public static IRenderTheme getRenderTheme(InputStream is) {
|
||||||
|
return new StaticTheme();
|
||||||
|
}
|
||||||
|
|
||||||
|
static class StaticTheme implements IRenderTheme {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RenderInstruction[] matchElement(MapElement e, int zoomLevel) {
|
||||||
|
if (e.isPoly()) {
|
||||||
|
if (e.tags.contains(TAG_WATER))
|
||||||
|
return instructions[AREA_WATER];
|
||||||
|
|
||||||
|
if (e.tags.contains(TAG_WOOD) ||e.tags.contains(TAG_FOREST))
|
||||||
|
return instructions[AREA_WOOD];
|
||||||
|
|
||||||
|
} else if (e.isLine()) {
|
||||||
|
if (e.tags.containsKey("highway"))
|
||||||
|
return instructions[LINE_HIGHWAY];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getLevels() {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMapBackground() {
|
||||||
|
return 0xfafafa;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void scaleStrokeWidth(float scaleFactor) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void scaleTextSize(float scaleFactor) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,180 @@
|
|||||||
|
/*
|
||||||
|
* 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.tilesource.common;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
import org.oscim.core.Tile;
|
||||||
|
|
||||||
|
import com.google.gwt.typedarrays.client.Uint8ArrayNative;
|
||||||
|
import com.google.gwt.typedarrays.shared.Uint8Array;
|
||||||
|
import com.google.gwt.xhr.client.ReadyStateChangeHandler;
|
||||||
|
import com.google.gwt.xhr.client.XMLHttpRequest;
|
||||||
|
import com.google.gwt.xhr.client.XMLHttpRequest.ResponseType;
|
||||||
|
|
||||||
|
public class LwHttp {
|
||||||
|
//private static final String TAG = LwHttp.class.getName();
|
||||||
|
|
||||||
|
private final byte[] EXTENSION;
|
||||||
|
private final byte[] mRequestBuffer;
|
||||||
|
|
||||||
|
final boolean mInflateContent;
|
||||||
|
final String mContentType;
|
||||||
|
|
||||||
|
private int mContentLength = -1;
|
||||||
|
private XMLHttpRequest mHttpRequest;
|
||||||
|
|
||||||
|
private ReadyStateChangeHandler mResponseHandler;
|
||||||
|
|
||||||
|
public LwHttp(URL url, String contentType, String extension, boolean deflate) {
|
||||||
|
mContentType = contentType;
|
||||||
|
mInflateContent = deflate;
|
||||||
|
|
||||||
|
EXTENSION = ("." + extension).getBytes();
|
||||||
|
mRequestBuffer = new byte[1024];
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Buffer extends InputStream {
|
||||||
|
Uint8Array mBuffer;
|
||||||
|
int mPos;
|
||||||
|
int mEnd;
|
||||||
|
public Buffer(Uint8Array buf) {
|
||||||
|
mBuffer = buf;
|
||||||
|
mPos = 0;
|
||||||
|
mEnd = buf.byteLength();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized int read() throws IOException {
|
||||||
|
if (mPos < mEnd)
|
||||||
|
return mBuffer.get(mPos++);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() {
|
||||||
|
if (mHttpRequest != null)
|
||||||
|
mHttpRequest.abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
private PbfTileDataSource mDataSource;
|
||||||
|
public boolean sendRequest(Tile tile, PbfTileDataSource dataSource) throws IOException {
|
||||||
|
mDataSource = dataSource;
|
||||||
|
|
||||||
|
byte[] request = mRequestBuffer;
|
||||||
|
int pos = 0;
|
||||||
|
int newPos = 0;
|
||||||
|
|
||||||
|
if ((newPos = formatTilePath(tile, request, pos)) == 0) {
|
||||||
|
request[pos++] = '/';
|
||||||
|
pos = writeInt(tile.zoomLevel, pos, request);
|
||||||
|
request[pos++] = '/';
|
||||||
|
pos = writeInt(tile.tileX, pos, request);
|
||||||
|
request[pos++] = '/';
|
||||||
|
pos = writeInt(tile.tileY, pos, request);
|
||||||
|
} else {
|
||||||
|
pos = newPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
int len = EXTENSION.length;
|
||||||
|
System.arraycopy(EXTENSION, 0, request, pos, len);
|
||||||
|
|
||||||
|
String url = "/tiles" + (new String(request, 0, pos + len));
|
||||||
|
//Log.d(TAG, "load " + url);
|
||||||
|
|
||||||
|
mHttpRequest = XMLHttpRequest.create();
|
||||||
|
mHttpRequest.open("GET", url);
|
||||||
|
mHttpRequest.setResponseType(ResponseType.ArrayBuffer);
|
||||||
|
|
||||||
|
mResponseHandler = new ReadyStateChangeHandler() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onReadyStateChange(XMLHttpRequest xhr) {
|
||||||
|
int status = xhr.getStatus();
|
||||||
|
int state = xhr.getReadyState();
|
||||||
|
//Log.d(TAG, mCurrentUrl + "response " + status + "/" + state);
|
||||||
|
|
||||||
|
if (state == XMLHttpRequest.DONE && status == 200){
|
||||||
|
Uint8Array buf = Uint8ArrayNative.create(xhr.getResponseArrayBuffer());
|
||||||
|
|
||||||
|
mDataSource.process(new Buffer(buf), buf.byteLength());
|
||||||
|
} else if (state == XMLHttpRequest.DONE){
|
||||||
|
mDataSource.process(null, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
mHttpRequest.setOnReadyStateChange(mResponseHandler);
|
||||||
|
mHttpRequest.send();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// write (positive) integer to byte array
|
||||||
|
protected 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse (positive) integer from byte array
|
||||||
|
protected static int parseInt(byte[] buf, int pos, int end) {
|
||||||
|
int val = 0;
|
||||||
|
for (; pos < end; pos++)
|
||||||
|
val = val * 10 + (buf[pos]) - '0';
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void requestCompleted() {
|
||||||
|
|
||||||
|
mHttpRequest.clearOnReadyStateChange();
|
||||||
|
mHttpRequest = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getContentLength() {
|
||||||
|
return mContentLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write custom tile url
|
||||||
|
*
|
||||||
|
* @param tile Tile
|
||||||
|
* @param path to write url string
|
||||||
|
* @param curPos current position
|
||||||
|
* @return new position
|
||||||
|
*/
|
||||||
|
protected int formatTilePath(Tile tile, byte[] path, int curPos) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
* 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.tilesource.common;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.net.SocketException;
|
||||||
|
import java.net.SocketTimeoutException;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
|
||||||
|
import org.oscim.layers.tile.MapTile;
|
||||||
|
import org.oscim.tilesource.ITileDataSink;
|
||||||
|
import org.oscim.tilesource.ITileDataSource;
|
||||||
|
|
||||||
|
import org.oscim.backend.Log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public abstract class PbfTileDataSource implements ITileDataSource {
|
||||||
|
private static final String TAG = PbfTileDataSource.class.getName();
|
||||||
|
|
||||||
|
protected LwHttp mConn;
|
||||||
|
protected final PbfDecoder mTileDecoder;
|
||||||
|
|
||||||
|
public PbfTileDataSource(PbfDecoder tileDecoder) {
|
||||||
|
mTileDecoder = tileDecoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ITileDataSink mSink;
|
||||||
|
private MapTile mTile;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public QueryResult executeQuery(MapTile tile, ITileDataSink sink) {
|
||||||
|
QueryResult result = QueryResult.SUCCESS;
|
||||||
|
mTile = tile;
|
||||||
|
mSink = sink;
|
||||||
|
try {
|
||||||
|
mConn.sendRequest(tile, this);
|
||||||
|
//InputStream is;
|
||||||
|
// if (!mConn.sendRequest(tile, this)) {
|
||||||
|
// Log.d(TAG, tile + " Request Failed");
|
||||||
|
// result = QueryResult.FAILED;
|
||||||
|
// } else if ((is = mConn.readHeader()) != null) {
|
||||||
|
// boolean win = mTileDecoder.decode(tile, sink, is, mConn.getContentLength());
|
||||||
|
// if (!win)
|
||||||
|
// Log.d(TAG, tile + " failed");
|
||||||
|
// } else {
|
||||||
|
// Log.d(TAG, tile + " Network Error");
|
||||||
|
// result = QueryResult.FAILED;
|
||||||
|
// }
|
||||||
|
// } catch (SocketException e) {
|
||||||
|
// Log.d(TAG, tile + " Socket exception: " + e.getMessage());
|
||||||
|
// result = QueryResult.FAILED;
|
||||||
|
// } catch (SocketTimeoutException e) {
|
||||||
|
// Log.d(TAG, tile + " Socket Timeout");
|
||||||
|
// result = QueryResult.FAILED;
|
||||||
|
// } catch (UnknownHostException e) {
|
||||||
|
// Log.d(TAG, tile + " No Network");
|
||||||
|
// result = QueryResult.FAILED;
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
result = QueryResult.FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
//mConn.requestCompleted();
|
||||||
|
|
||||||
|
//if (result != QueryResult.SUCCESS)
|
||||||
|
// mConn.close();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void process(InputStream is, int length) {
|
||||||
|
//Log.d(TAG, mTile + " process " + is + " " + length + " " + mSink);
|
||||||
|
|
||||||
|
boolean win = false;
|
||||||
|
if (length >= 0) {
|
||||||
|
try {
|
||||||
|
win = mTileDecoder.decode(mTile, mSink, is, length);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!win)
|
||||||
|
Log.d(TAG, mTile + " failed");
|
||||||
|
|
||||||
|
mConn.requestCompleted();
|
||||||
|
mSink.completed(win);
|
||||||
|
|
||||||
|
//mTile = null;
|
||||||
|
//mSink = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy() {
|
||||||
|
mConn.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user