Merge branch 'wip_sync'
This commit is contained in:
commit
2c7cd1c880
@ -23,16 +23,10 @@ import android.widget.RelativeLayout.LayoutParams;
|
|||||||
public class AndroidMap extends Map {
|
public class AndroidMap extends Map {
|
||||||
|
|
||||||
private final MapView mMapView;
|
private final MapView mMapView;
|
||||||
private boolean mWaitRedraw;
|
|
||||||
final GLView mGLView;
|
final GLView mGLView;
|
||||||
boolean mPausing = false;
|
|
||||||
|
|
||||||
private final Runnable mRedrawRequest = new Runnable() {
|
private volatile boolean mWaitRedraw;
|
||||||
@Override
|
private volatile boolean mPausing;
|
||||||
public void run() {
|
|
||||||
redrawMapInternal(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public AndroidMap(MapView mapView) {
|
public AndroidMap(MapView mapView) {
|
||||||
super();
|
super();
|
||||||
@ -45,8 +39,6 @@ public class AndroidMap extends Map {
|
|||||||
android.view.ViewGroup.LayoutParams.MATCH_PARENT);
|
android.view.ViewGroup.LayoutParams.MATCH_PARENT);
|
||||||
|
|
||||||
mapView.addView(mGLView, params);
|
mapView.addView(mGLView, params);
|
||||||
|
|
||||||
//mGestureDetector =
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -60,9 +52,9 @@ public class AndroidMap extends Map {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void updateMap(boolean requestRender) {
|
public void updateMap(boolean redraw) {
|
||||||
if (requestRender && !mClearMap && !mPausing) // && mInitialized)
|
//if (redraw && !mClearMap && !mPausing)
|
||||||
mGLView.requestRender();
|
// mGLView.requestRender();
|
||||||
|
|
||||||
if (!mWaitRedraw) {
|
if (!mWaitRedraw) {
|
||||||
mWaitRedraw = true;
|
mWaitRedraw = true;
|
||||||
@ -71,26 +63,29 @@ public class AndroidMap extends Map {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void render() {
|
public void render() {
|
||||||
|
if (mPausing)
|
||||||
|
return;
|
||||||
|
|
||||||
if (mClearMap)
|
if (mClearMap)
|
||||||
updateMap(false);
|
updateMap(false);
|
||||||
else
|
else
|
||||||
mGLView.requestRender();
|
mGLView.requestRender();
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized void redrawMapInternal(boolean forceRedraw) {
|
private final Runnable mRedrawRequest = new Runnable() {
|
||||||
boolean clear = mClearMap;
|
@Override
|
||||||
mWaitRedraw = false;
|
public void run() {
|
||||||
|
redrawMapInternal();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (forceRedraw && !clear)
|
void redrawMapInternal() {
|
||||||
mGLView.requestRender();
|
mWaitRedraw = false;
|
||||||
|
|
||||||
updateLayers();
|
updateLayers();
|
||||||
|
|
||||||
if (clear) {
|
mGLView.requestRender();
|
||||||
mGLView.requestRender();
|
|
||||||
mClearMap = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -103,9 +98,7 @@ public class AndroidMap extends Map {
|
|||||||
return mMapView.postDelayed(action, delay);
|
return mMapView.postDelayed(action, delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void pause(boolean pause) {
|
||||||
public synchronized void pause(boolean pause) {
|
mPausing = pause;
|
||||||
mPausing = pause;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -24,9 +24,12 @@ import org.oscim.map.Map;
|
|||||||
import org.oscim.tiling.TileLoader;
|
import org.oscim.tiling.TileLoader;
|
||||||
import org.oscim.tiling.TileManager;
|
import org.oscim.tiling.TileManager;
|
||||||
import org.oscim.tiling.TileRenderer;
|
import org.oscim.tiling.TileRenderer;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
public abstract class TileLayer<T extends TileLoader> extends Layer implements Map.UpdateListener {
|
public abstract class TileLayer<T extends TileLoader> extends Layer implements Map.UpdateListener {
|
||||||
//static final Logger log = LoggerFactory.getLogger(TileLayer.class);
|
static final Logger log = LoggerFactory.getLogger(TileLayer.class);
|
||||||
|
|
||||||
private final static int MAX_ZOOMLEVEL = 17;
|
private final static int MAX_ZOOMLEVEL = 17;
|
||||||
private final static int MIN_ZOOMLEVEL = 2;
|
private final static int MIN_ZOOMLEVEL = 2;
|
||||||
private final static int CACHE_LIMIT = 250;
|
private final static int CACHE_LIMIT = 250;
|
||||||
@ -37,8 +40,6 @@ public abstract class TileLayer<T extends TileLoader> extends Layer implements M
|
|||||||
protected final int mNumTileLoader = 4;
|
protected final int mNumTileLoader = 4;
|
||||||
protected final ArrayList<T> mTileLoader;
|
protected final ArrayList<T> mTileLoader;
|
||||||
|
|
||||||
protected boolean mInitial = true;
|
|
||||||
|
|
||||||
public TileLayer(Map map) {
|
public TileLayer(Map map) {
|
||||||
this(map, MIN_ZOOMLEVEL, MAX_ZOOMLEVEL, CACHE_LIMIT);
|
this(map, MIN_ZOOMLEVEL, MAX_ZOOMLEVEL, CACHE_LIMIT);
|
||||||
}
|
}
|
||||||
@ -71,10 +72,13 @@ public abstract class TileLayer<T extends TileLoader> extends Layer implements M
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMapUpdate(MapPosition mapPosition, boolean changed, boolean clear) {
|
public void onMapUpdate(MapPosition mapPosition, boolean changed, boolean clear) {
|
||||||
if (clear || mInitial) {
|
if (clear) {
|
||||||
mRenderLayer.clearTiles();
|
// sync with TileRenderer
|
||||||
mTileManager.init(mInitial);
|
synchronized (mRenderLayer) {
|
||||||
mInitial = false;
|
mRenderLayer.clearTiles();
|
||||||
|
mTileManager.init();
|
||||||
|
}
|
||||||
|
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,16 +91,13 @@ public abstract class TileLayer<T extends TileLoader> extends Layer implements M
|
|||||||
for (T loader : mTileLoader) {
|
for (T loader : mTileLoader) {
|
||||||
loader.pause();
|
loader.pause();
|
||||||
loader.interrupt();
|
loader.interrupt();
|
||||||
|
try {
|
||||||
|
loader.join();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
loader.cleanup();
|
loader.cleanup();
|
||||||
|
|
||||||
//try {
|
|
||||||
// tileWorker.join(10000);
|
|
||||||
//} catch (InterruptedException e) {
|
|
||||||
// // restore the interrupted status
|
|
||||||
// Thread.currentThread().interrupt();
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
mTileManager.destroy();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void notifyLoaders() {
|
void notifyLoaders() {
|
||||||
@ -110,11 +111,12 @@ public abstract class TileLayer<T extends TileLoader> extends Layer implements M
|
|||||||
if (!loader.isPausing())
|
if (!loader.isPausing())
|
||||||
loader.pause();
|
loader.pause();
|
||||||
}
|
}
|
||||||
if (wait) {
|
if (!wait)
|
||||||
for (T loader : mTileLoader) {
|
return;
|
||||||
if (!loader.isPausing())
|
|
||||||
loader.awaitPausing();
|
for (T loader : mTileLoader) {
|
||||||
}
|
if (!loader.isPausing())
|
||||||
|
loader.awaitPausing();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.oscim.layers.tile.vector;
|
package org.oscim.layers.tile.vector;
|
||||||
|
|
||||||
|
import java.util.concurrent.CancellationException;
|
||||||
|
|
||||||
import org.oscim.core.GeometryBuffer.GeometryType;
|
import org.oscim.core.GeometryBuffer.GeometryType;
|
||||||
import org.oscim.core.MapElement;
|
import org.oscim.core.MapElement;
|
||||||
import org.oscim.core.MercatorProjection;
|
import org.oscim.core.MercatorProjection;
|
||||||
@ -131,14 +133,18 @@ public class VectorTileLoader extends TileLoader implements IRenderTheme.Callbac
|
|||||||
|
|
||||||
mTile = tile;
|
mTile = tile;
|
||||||
mTile.layers = new ElementLayers();
|
mTile.layers = new ElementLayers();
|
||||||
|
QueryResult result = null;
|
||||||
// query database, which calls 'process' callback
|
try {
|
||||||
QueryResult result = mTileDataSource.executeQuery(mTile, this);
|
// query database, which calls 'process' callback
|
||||||
|
result = mTileDataSource.executeQuery(mTile, this);
|
||||||
mTile = null;
|
} catch (CancellationException e) {
|
||||||
|
log.debug("canceled {}", mTile);
|
||||||
clearState();
|
} catch (Exception e) {
|
||||||
|
log.debug("{}", e);
|
||||||
|
} finally {
|
||||||
|
mTile = null;
|
||||||
|
clearState();
|
||||||
|
}
|
||||||
return (result == QueryResult.SUCCESS);
|
return (result == QueryResult.SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,8 +211,12 @@ public class VectorTileLoader extends TileLoader implements IRenderTheme.Callbac
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void process(MapElement element) {
|
public void process(MapElement element) {
|
||||||
|
|
||||||
clearState();
|
clearState();
|
||||||
|
|
||||||
|
if (isCanceled())
|
||||||
|
throw new CancellationException();
|
||||||
|
|
||||||
mElement = element;
|
mElement = element;
|
||||||
|
|
||||||
if (element.type == GeometryType.POINT) {
|
if (element.type == GeometryType.POINT) {
|
||||||
|
@ -28,7 +28,7 @@ public class LabelLayer extends Layer implements Map.InputListener, Map.UpdateLi
|
|||||||
static final Logger log = LoggerFactory.getLogger(LabelLayer.class);
|
static final Logger log = LoggerFactory.getLogger(LabelLayer.class);
|
||||||
private final TextRenderer mTextRenderer;
|
private final TextRenderer mTextRenderer;
|
||||||
|
|
||||||
private int multi;
|
//private int multi;
|
||||||
|
|
||||||
public LabelLayer(Map map, TileRenderer tileRenderLayer) {
|
public LabelLayer(Map map, TileRenderer tileRenderLayer) {
|
||||||
super(map);
|
super(map);
|
||||||
@ -49,19 +49,19 @@ public class LabelLayer extends Layer implements Map.InputListener, Map.UpdateLi
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMotionEvent(MotionEvent e) {
|
public void onMotionEvent(MotionEvent e) {
|
||||||
int action = e.getAction() & MotionEvent.ACTION_MASK;
|
// int action = e.getAction() & MotionEvent.ACTION_MASK;
|
||||||
if (action == MotionEvent.ACTION_POINTER_DOWN) {
|
// if (action == MotionEvent.ACTION_POINTER_DOWN) {
|
||||||
multi++;
|
// multi++;
|
||||||
mTextRenderer.hold(true);
|
// mTextRenderer.hold(true);
|
||||||
} else if (action == MotionEvent.ACTION_POINTER_UP) {
|
// } else if (action == MotionEvent.ACTION_POINTER_UP) {
|
||||||
multi--;
|
// multi--;
|
||||||
if (multi == 0)
|
// if (multi == 0)
|
||||||
mTextRenderer.hold(false);
|
// mTextRenderer.hold(false);
|
||||||
} else if (action == MotionEvent.ACTION_CANCEL) {
|
// } else if (action == MotionEvent.ACTION_CANCEL) {
|
||||||
multi = 0;
|
// multi = 0;
|
||||||
log.debug("cancel " + multi);
|
// log.debug("cancel " + multi);
|
||||||
mTextRenderer.hold(false);
|
// mTextRenderer.hold(false);
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -51,6 +51,7 @@ import org.oscim.tiling.TileRenderer;
|
|||||||
import org.oscim.tiling.TileSet;
|
import org.oscim.tiling.TileSet;
|
||||||
import org.oscim.utils.FastMath;
|
import org.oscim.utils.FastMath;
|
||||||
import org.oscim.utils.OBB2D;
|
import org.oscim.utils.OBB2D;
|
||||||
|
import org.oscim.utils.async.ContinuousTask;
|
||||||
import org.oscim.utils.pool.Pool;
|
import org.oscim.utils.pool.Pool;
|
||||||
|
|
||||||
class TextRenderer extends ElementRenderer {
|
class TextRenderer extends ElementRenderer {
|
||||||
@ -143,6 +144,8 @@ class TextRenderer extends ElementRenderer {
|
|||||||
|
|
||||||
//mActiveTiles = new HashMap<MapTile, LabelTile>();
|
//mActiveTiles = new HashMap<MapTile, LabelTile>();
|
||||||
mRelabelCnt = 0;
|
mRelabelCnt = 0;
|
||||||
|
|
||||||
|
mLabelTask = new LabelTask(map);
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove Label l from mLabels and return l.next
|
// remove Label l from mLabels and return l.next
|
||||||
@ -274,6 +277,108 @@ class TextRenderer extends ElementRenderer {
|
|||||||
return dx;
|
return dx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Label updateWayLabels(MapTile t, Label l, float dx, float dy, double scale,
|
||||||
|
ElementLayers dbg) {
|
||||||
|
|
||||||
|
for (TextItem ti = t.labels; ti != null; ti = ti.next) {
|
||||||
|
if (ti.text.caption)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// acquire a TextItem to add to TextLayer
|
||||||
|
if (l == null)
|
||||||
|
l = getLabel();
|
||||||
|
|
||||||
|
// check if path at current scale is long enough for text
|
||||||
|
if (dbg == null && ti.width > ti.length * scale)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
l.clone(ti);
|
||||||
|
l.move(ti, dx, dy, (float) scale);
|
||||||
|
|
||||||
|
// set line endpoints relative to view to be able to
|
||||||
|
// check intersections with label from other tiles
|
||||||
|
float w = (ti.x2 - ti.x1) / 2f;
|
||||||
|
float h = (ti.y2 - ti.y1) / 2f;
|
||||||
|
l.bbox = null;
|
||||||
|
l.x1 = l.x - w;
|
||||||
|
l.y1 = l.y - h;
|
||||||
|
l.x2 = l.x + w;
|
||||||
|
l.y2 = l.y + h;
|
||||||
|
|
||||||
|
if (!wayIsVisible(l))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
byte overlaps = -1;
|
||||||
|
|
||||||
|
if (l.bbox == null)
|
||||||
|
l.bbox = new OBB2D(l.x, l.y, l.x1, l.y1,
|
||||||
|
l.width + MIN_WAY_DIST,
|
||||||
|
l.text.fontHeight + MIN_WAY_DIST);
|
||||||
|
else
|
||||||
|
l.bbox.set(l.x, l.y, l.x1, l.y1,
|
||||||
|
l.width + MIN_WAY_DIST,
|
||||||
|
l.text.fontHeight + MIN_WAY_DIST);
|
||||||
|
|
||||||
|
if (dbg == null || ti.width < ti.length * scale)
|
||||||
|
overlaps = checkOverlap(l);
|
||||||
|
|
||||||
|
if (dbg != null)
|
||||||
|
Debug.addDebugBox(dbg, l, ti, overlaps, false, (float) scale);
|
||||||
|
|
||||||
|
if (overlaps == 0) {
|
||||||
|
addLabel(l);
|
||||||
|
l.item = TextItem.copy(ti);
|
||||||
|
l.tile = t;
|
||||||
|
l.active = mRelabelCnt;
|
||||||
|
l = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Label updateNodeLabels(MapTile t, Label l, float dx, float dy, double scale, float cos,
|
||||||
|
float sin) {
|
||||||
|
O: for (TextItem ti = t.labels; ti != null; ti = ti.next) {
|
||||||
|
if (!ti.text.caption)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// acquire a TextItem to add to TextLayer
|
||||||
|
if (l == null)
|
||||||
|
l = getLabel();
|
||||||
|
|
||||||
|
l.clone(ti);
|
||||||
|
l.move(ti, dx, dy, (float) scale);
|
||||||
|
if (!nodeIsVisible(l))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (l.bbox == null)
|
||||||
|
l.bbox = new OBB2D();
|
||||||
|
|
||||||
|
l.bbox.setNormalized(l.x, l.y, cos, -sin,
|
||||||
|
l.width + MIN_CAPTION_DIST,
|
||||||
|
l.text.fontHeight + MIN_CAPTION_DIST,
|
||||||
|
l.text.dy);
|
||||||
|
|
||||||
|
for (Label lp = mLabels; lp != null;) {
|
||||||
|
if (l.bbox.overlaps(lp.bbox)) {
|
||||||
|
if (l.text.priority < lp.text.priority) {
|
||||||
|
lp = removeLabel(lp);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
continue O;
|
||||||
|
}
|
||||||
|
lp = (Label) lp.next;
|
||||||
|
}
|
||||||
|
|
||||||
|
addLabel(l);
|
||||||
|
l.item = TextItem.copy(ti);
|
||||||
|
l.tile = t;
|
||||||
|
l.active = mRelabelCnt;
|
||||||
|
l = null;
|
||||||
|
}
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
boolean updateLabels() {
|
boolean updateLabels() {
|
||||||
// nextLayer is not loaded yet
|
// nextLayer is not loaded yet
|
||||||
if (mNextLayer.ready)
|
if (mNextLayer.ready)
|
||||||
@ -400,118 +505,30 @@ class TextRenderer extends ElementRenderer {
|
|||||||
/* add way labels */
|
/* add way labels */
|
||||||
for (int i = 0, n = mTileSet.cnt; i < n; i++) {
|
for (int i = 0, n = mTileSet.cnt; i < n; i++) {
|
||||||
MapTile t = tiles[i];
|
MapTile t = tiles[i];
|
||||||
if (!t.state(MapTile.STATE_READY))
|
synchronized (t) {
|
||||||
continue;
|
if (!t.state(MapTile.STATE_READY))
|
||||||
|
|
||||||
float dx = (float) (t.tileX * Tile.SIZE - tileX);
|
|
||||||
float dy = (float) (t.tileY * Tile.SIZE - tileY);
|
|
||||||
dx = flipLongitude(dx, maxx);
|
|
||||||
|
|
||||||
for (TextItem ti = t.labels; ti != null; ti = ti.next) {
|
|
||||||
|
|
||||||
if (ti.text.caption)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// acquire a TextItem to add to TextLayer
|
float dx = (float) (t.tileX * Tile.SIZE - tileX);
|
||||||
if (l == null)
|
float dy = (float) (t.tileY * Tile.SIZE - tileY);
|
||||||
l = getLabel();
|
dx = flipLongitude(dx, maxx);
|
||||||
|
|
||||||
// check if path at current scale is long enough for text
|
l = updateWayLabels(t, l, dx, dy, scale, dbg);
|
||||||
if (dbg == null && ti.width > ti.length * scale)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
l.clone(ti);
|
|
||||||
l.move(ti, dx, dy, (float) scale);
|
|
||||||
|
|
||||||
// set line endpoints relative to view to be able to
|
|
||||||
// check intersections with label from other tiles
|
|
||||||
float w = (ti.x2 - ti.x1) / 2f;
|
|
||||||
float h = (ti.y2 - ti.y1) / 2f;
|
|
||||||
l.bbox = null;
|
|
||||||
l.x1 = l.x - w;
|
|
||||||
l.y1 = l.y - h;
|
|
||||||
l.x2 = l.x + w;
|
|
||||||
l.y2 = l.y + h;
|
|
||||||
|
|
||||||
if (!wayIsVisible(l))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
byte overlaps = -1;
|
|
||||||
|
|
||||||
if (l.bbox == null)
|
|
||||||
l.bbox = new OBB2D(l.x, l.y, l.x1, l.y1,
|
|
||||||
l.width + MIN_WAY_DIST,
|
|
||||||
l.text.fontHeight + MIN_WAY_DIST);
|
|
||||||
else
|
|
||||||
l.bbox.set(l.x, l.y, l.x1, l.y1,
|
|
||||||
l.width + MIN_WAY_DIST,
|
|
||||||
l.text.fontHeight + MIN_WAY_DIST);
|
|
||||||
|
|
||||||
if (dbg == null || ti.width < ti.length * scale)
|
|
||||||
overlaps = checkOverlap(l);
|
|
||||||
|
|
||||||
if (dbg != null)
|
|
||||||
Debug.addDebugBox(dbg, l, ti, overlaps, false, (float) scale);
|
|
||||||
|
|
||||||
if (overlaps == 0) {
|
|
||||||
addLabel(l);
|
|
||||||
l.item = TextItem.copy(ti);
|
|
||||||
l.tile = t;
|
|
||||||
l.active = mRelabelCnt;
|
|
||||||
l = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* add caption */
|
/* add caption */
|
||||||
for (int i = 0, n = mTileSet.cnt; i < n; i++) {
|
for (int i = 0, n = mTileSet.cnt; i < n; i++) {
|
||||||
MapTile t = tiles[i];
|
MapTile t = tiles[i];
|
||||||
if (!t.state(MapTile.STATE_READY))
|
synchronized (t) {
|
||||||
continue;
|
if (!t.state(MapTile.STATE_READY))
|
||||||
|
|
||||||
float dx = (float) (t.tileX * Tile.SIZE - tileX);
|
|
||||||
float dy = (float) (t.tileY * Tile.SIZE - tileY);
|
|
||||||
dx = flipLongitude(dx, maxx);
|
|
||||||
|
|
||||||
O: for (TextItem ti = t.labels; ti != null; ti = ti.next) {
|
|
||||||
if (!ti.text.caption)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// acquire a TextItem to add to TextLayer
|
float dx = (float) (t.tileX * Tile.SIZE - tileX);
|
||||||
if (l == null)
|
float dy = (float) (t.tileY * Tile.SIZE - tileY);
|
||||||
l = getLabel();
|
dx = flipLongitude(dx, maxx);
|
||||||
|
|
||||||
l.clone(ti);
|
l = updateNodeLabels(t, l, dx, dy, scale, cos, sin);
|
||||||
l.move(ti, dx, dy, (float) scale);
|
|
||||||
if (!nodeIsVisible(l))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
//l.setAxisAlignedBBox();
|
|
||||||
|
|
||||||
if (l.bbox == null)
|
|
||||||
l.bbox = new OBB2D();
|
|
||||||
|
|
||||||
l.bbox.setNormalized(l.x, l.y, cos, -sin,
|
|
||||||
l.width + MIN_CAPTION_DIST,
|
|
||||||
l.text.fontHeight + MIN_CAPTION_DIST,
|
|
||||||
l.text.dy);
|
|
||||||
|
|
||||||
for (Label lp = mLabels; lp != null;) {
|
|
||||||
if (l.bbox.overlaps(lp.bbox)) {
|
|
||||||
if (l.text.priority < lp.text.priority) {
|
|
||||||
lp = removeLabel(lp);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
continue O;
|
|
||||||
}
|
|
||||||
lp = (Label) lp.next;
|
|
||||||
}
|
|
||||||
|
|
||||||
addLabel(l);
|
|
||||||
l.item = TextItem.copy(ti);
|
|
||||||
l.tile = t;
|
|
||||||
l.active = mRelabelCnt;
|
|
||||||
l = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -541,25 +558,27 @@ class TextRenderer extends ElementRenderer {
|
|||||||
|
|
||||||
for (int i = 0, n = mTileSet.cnt; i < n; i++) {
|
for (int i = 0, n = mTileSet.cnt; i < n; i++) {
|
||||||
MapTile t = tiles[i];
|
MapTile t = tiles[i];
|
||||||
if (!t.state(MapTile.STATE_READY))
|
synchronized (t) {
|
||||||
continue;
|
if (!t.state(MapTile.STATE_READY))
|
||||||
|
|
||||||
float dx = (float) (t.tileX * Tile.SIZE - tileX);
|
|
||||||
float dy = (float) (t.tileY * Tile.SIZE - tileY);
|
|
||||||
dx = flipLongitude(dx, maxx);
|
|
||||||
|
|
||||||
for (SymbolItem ti = t.symbols; ti != null; ti = ti.next) {
|
|
||||||
if (ti.texRegion == null)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
SymbolItem s = SymbolItem.pool.get();
|
float dx = (float) (t.tileX * Tile.SIZE - tileX);
|
||||||
|
float dy = (float) (t.tileY * Tile.SIZE - tileY);
|
||||||
|
dx = flipLongitude(dx, maxx);
|
||||||
|
|
||||||
s.texRegion = ti.texRegion;
|
for (SymbolItem ti = t.symbols; ti != null; ti = ti.next) {
|
||||||
s.x = (float) ((dx + ti.x) * scale);
|
if (ti.texRegion == null)
|
||||||
s.y = (float) ((dy + ti.y) * scale);
|
continue;
|
||||||
s.billboard = true;
|
|
||||||
|
|
||||||
sl.addSymbol(s);
|
SymbolItem s = SymbolItem.pool.get();
|
||||||
|
|
||||||
|
s.texRegion = ti.texRegion;
|
||||||
|
s.x = (float) ((dx + ti.x) * scale);
|
||||||
|
s.y = (float) ((dy + ti.y) * scale);
|
||||||
|
s.billboard = true;
|
||||||
|
|
||||||
|
sl.addSymbol(s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -588,11 +607,6 @@ class TextRenderer extends ElementRenderer {
|
|||||||
public synchronized void update(MapPosition pos, boolean changed,
|
public synchronized void update(MapPosition pos, boolean changed,
|
||||||
Matrices matrices) {
|
Matrices matrices) {
|
||||||
|
|
||||||
//if (System.currentTimeMillis() - lastDraw > 1000){
|
|
||||||
// updateLabels();
|
|
||||||
// lastDraw = System.currentTimeMillis();
|
|
||||||
//
|
|
||||||
//}
|
|
||||||
if (mNextLayer.ready) {
|
if (mNextLayer.ready) {
|
||||||
// exchange current with next layers
|
// exchange current with next layers
|
||||||
TextureLayers tmp = mCurLayer;
|
TextureLayers tmp = mCurLayer;
|
||||||
@ -615,127 +629,68 @@ class TextRenderer extends ElementRenderer {
|
|||||||
compile();
|
compile();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mRequestClear)
|
mLabelTask.submit((mLastRun + MAX_RELABEL_DELAY) - System.currentTimeMillis());
|
||||||
cleanup();
|
|
||||||
|
|
||||||
//if (!mHolding)
|
|
||||||
postLabelTask();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* private */LabelTask mLabelTask;
|
|
||||||
/* private */long mLastRun;
|
|
||||||
/* private */boolean mRequestRun;
|
|
||||||
/* private */boolean mRequestClear;
|
|
||||||
/* private */boolean mRelabel;
|
|
||||||
|
|
||||||
class LabelTask implements Runnable {
|
|
||||||
private boolean isCancelled;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
boolean labelsChanged = false;
|
|
||||||
if (isCancelled) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
//log.debug("relabel after " + (now - mLastRun));
|
|
||||||
mLastRun = now;
|
|
||||||
|
|
||||||
labelsChanged = updateLabels();
|
|
||||||
|
|
||||||
if (!isCancelled && labelsChanged)
|
|
||||||
mMap.render();
|
|
||||||
|
|
||||||
mLabelTask = null;
|
|
||||||
mRequestRun = false;
|
|
||||||
isCancelled = false;
|
|
||||||
|
|
||||||
if (mRelabel) {
|
|
||||||
mRelabel = false;
|
|
||||||
postLabelTask();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void cancel() {
|
|
||||||
isCancelled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* private */void cleanup() {
|
|
||||||
mLabels = (Label) mPool.releaseAll(mLabels);
|
|
||||||
mTileSet.releaseTiles();
|
|
||||||
mLabelTask = null;
|
|
||||||
mRequestClear = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Runnable mLabelUpdate = new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
if (mLabelTask == null) {
|
|
||||||
mLabelTask = new LabelTask();
|
|
||||||
mMap.addTask(mLabelTask);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/* private */void postLabelTask() {
|
|
||||||
synchronized (mLabelUpdate) {
|
|
||||||
if (mRequestRun) {
|
|
||||||
mRelabel = true;
|
|
||||||
} else {
|
|
||||||
mRequestRun = true;
|
|
||||||
long delay = (mLastRun + MAX_RELABEL_DELAY) - System.currentTimeMillis();
|
|
||||||
//log.debug("relabel in: " + delay);
|
|
||||||
mMap.postDelayed(mLabelUpdate, Math.max(delay, 0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void render(MapPosition pos, Matrices m) {
|
public synchronized void render(MapPosition pos, Matrices m) {
|
||||||
|
|
||||||
layers.vbo.bind();
|
|
||||||
GLState.test(false, false);
|
GLState.test(false, false);
|
||||||
|
|
||||||
float scale = (float) (mMapPosition.scale / pos.scale);
|
float scale = (float) (mMapPosition.scale / pos.scale);
|
||||||
|
|
||||||
setMatrix(pos, m, true);
|
setMatrix(pos, m, true);
|
||||||
|
|
||||||
if (layers.baseLayers != null) {
|
synchronized (layers) {
|
||||||
for (RenderElement l = layers.baseLayers; l != null;) {
|
layers.vbo.bind();
|
||||||
if (l.type == RenderElement.POLYGON) {
|
if (layers.baseLayers != null) {
|
||||||
l = PolygonLayer.Renderer.draw(pos, l, m, true, 1, false);
|
for (RenderElement l = layers.baseLayers; l != null;) {
|
||||||
} else {
|
if (l.type == RenderElement.POLYGON) {
|
||||||
float div = scale * (float) (pos.scale / (1 << pos.zoomLevel));
|
l = PolygonLayer.Renderer.draw(pos, l, m, true, 1, false);
|
||||||
l = LineLayer.Renderer.draw(layers, l, pos, m, div, 0);
|
} else {
|
||||||
|
float div = scale * (float) (pos.scale / (1 << pos.zoomLevel));
|
||||||
|
l = LineLayer.Renderer.draw(layers, l, pos, m, div, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setMatrix(pos, m, false);
|
||||||
|
|
||||||
|
for (RenderElement l = layers.textureLayers; l != null;)
|
||||||
|
l = TextureLayer.Renderer.draw(l, scale, m);
|
||||||
}
|
}
|
||||||
|
|
||||||
setMatrix(pos, m, false);
|
|
||||||
|
|
||||||
for (RenderElement l = layers.textureLayers; l != null;)
|
|
||||||
l = TextureLayer.Renderer.draw(l, scale, m);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//private boolean mHolding;
|
final class LabelTask extends ContinuousTask {
|
||||||
|
|
||||||
/**
|
public LabelTask(Map map) {
|
||||||
* @param enable layer updates
|
super(map, 10);
|
||||||
*/
|
}
|
||||||
public synchronized void hold(boolean enable) {
|
|
||||||
// mHolding = enable;
|
@Override
|
||||||
// if (!enable)
|
public void doWork() {
|
||||||
// runLabelTask();
|
|
||||||
|
if (updateLabels())
|
||||||
|
mMap.render();
|
||||||
|
|
||||||
|
mLastRun = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cleanup() {
|
||||||
|
clearLabelsInternal();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void clearLabels() {
|
private final LabelTask mLabelTask;
|
||||||
if (mRequestRun) {
|
|
||||||
mRequestClear = true;
|
/* private */long mLastRun;
|
||||||
//mRelabel = true;
|
|
||||||
} else {
|
/* private */void clearLabelsInternal() {
|
||||||
cleanup();
|
mLabels = (Label) mPool.releaseAll(mLabels);
|
||||||
//postLabelTask();
|
mTileSet.releaseTiles();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void clearLabels() {
|
||||||
|
mLabelTask.cancel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -90,10 +90,6 @@ public class MapRenderer {
|
|||||||
|
|
||||||
private static volatile boolean mUpdateColor = false;
|
private static volatile boolean mUpdateColor = false;
|
||||||
|
|
||||||
// drawlock to synchronize Main- and GL-Thread
|
|
||||||
// static ReentrantLock tilelock = new ReentrantLock();
|
|
||||||
public static Object drawlock = new Object();
|
|
||||||
|
|
||||||
public static long frametime;
|
public static long frametime;
|
||||||
|
|
||||||
// Do not use the same buffer to upload data within a frame twice
|
// Do not use the same buffer to upload data within a frame twice
|
||||||
@ -210,13 +206,8 @@ public class MapRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void onDrawFrame() {
|
public void onDrawFrame() {
|
||||||
|
frametime = System.currentTimeMillis();
|
||||||
// prevent main thread recreating all tiles (updateMap)
|
draw();
|
||||||
// while rendering is going on.
|
|
||||||
synchronized (drawlock) {
|
|
||||||
frametime = System.currentTimeMillis();
|
|
||||||
draw();
|
|
||||||
}
|
|
||||||
|
|
||||||
mBufferPool.releaseBuffers();
|
mBufferPool.releaseBuffers();
|
||||||
}
|
}
|
||||||
|
@ -61,6 +61,8 @@ public class MapTile extends Tile {
|
|||||||
*/
|
*/
|
||||||
public final static byte STATE_ERROR = 1 << 3;
|
public final static byte STATE_ERROR = 1 << 3;
|
||||||
|
|
||||||
|
public final static byte STATE_CANCEL = 1 << 4;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* absolute tile coordinates: tileX,Y / Math.pow(2, zoomLevel)
|
* absolute tile coordinates: tileX,Y / Math.pow(2, zoomLevel)
|
||||||
*/
|
*/
|
||||||
@ -89,7 +91,7 @@ public class MapTile extends Tile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tile is in view region. Set by GLRenderer.
|
* Tile is in view region. Set by TileRenderer.
|
||||||
*/
|
*/
|
||||||
public boolean isVisible;
|
public boolean isVisible;
|
||||||
|
|
||||||
@ -100,7 +102,6 @@ public class MapTile extends Tile {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* to avoid drawing a tile twice per frame
|
* to avoid drawing a tile twice per frame
|
||||||
* FIXME what if multiple layers use the same tile?
|
|
||||||
*/
|
*/
|
||||||
int lastDraw = 0;
|
int lastDraw = 0;
|
||||||
|
|
||||||
|
@ -42,6 +42,7 @@ public abstract class TileLoader extends PausableThread {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doWork() {
|
protected void doWork() {
|
||||||
|
|
||||||
MapTile tile = mTileManager.getTileJob();
|
MapTile tile = mTileManager.getTileJob();
|
||||||
|
|
||||||
if (tile == null)
|
if (tile == null)
|
||||||
@ -53,7 +54,7 @@ public abstract class TileLoader extends PausableThread {
|
|||||||
success = executeJob(tile);
|
success = executeJob(tile);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
return;
|
success = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isInterrupted())
|
if (isInterrupted())
|
||||||
|
@ -17,9 +17,9 @@
|
|||||||
|
|
||||||
package org.oscim.tiling;
|
package org.oscim.tiling;
|
||||||
|
|
||||||
|
import static org.oscim.tiling.MapTile.STATE_CANCEL;
|
||||||
import static org.oscim.tiling.MapTile.STATE_LOADING;
|
import static org.oscim.tiling.MapTile.STATE_LOADING;
|
||||||
import static org.oscim.tiling.MapTile.STATE_NEW_DATA;
|
import static org.oscim.tiling.MapTile.STATE_NEW_DATA;
|
||||||
import static org.oscim.tiling.MapTile.STATE_NONE;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@ -29,7 +29,6 @@ import org.oscim.core.Tile;
|
|||||||
import org.oscim.map.Map;
|
import org.oscim.map.Map;
|
||||||
import org.oscim.map.Viewport;
|
import org.oscim.map.Viewport;
|
||||||
import org.oscim.renderer.BufferObject;
|
import org.oscim.renderer.BufferObject;
|
||||||
import org.oscim.renderer.MapRenderer;
|
|
||||||
import org.oscim.utils.FastMath;
|
import org.oscim.utils.FastMath;
|
||||||
import org.oscim.utils.ScanBox;
|
import org.oscim.utils.ScanBox;
|
||||||
import org.oscim.utils.quadtree.QuadTree;
|
import org.oscim.utils.quadtree.QuadTree;
|
||||||
@ -132,11 +131,6 @@ public class TileManager {
|
|||||||
mUpdateSerial = 0;
|
mUpdateSerial = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void destroy() {
|
|
||||||
// there might be some leaks in here
|
|
||||||
// ... free static pools
|
|
||||||
}
|
|
||||||
|
|
||||||
private int[] mZoomTable;
|
private int[] mZoomTable;
|
||||||
|
|
||||||
public void setZoomTable(int[] zoomLevel) {
|
public void setZoomTable(int[] zoomLevel) {
|
||||||
@ -144,40 +138,23 @@ public class TileManager {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void init(boolean first) {
|
public void init() {
|
||||||
|
// pass VBOs and VertexItems back to pools
|
||||||
|
for (int i = 0; i < mTilesSize; i++)
|
||||||
|
clearTile(mTiles[i]);
|
||||||
|
|
||||||
// sync with GLRender thread
|
// clear references to cached MapTiles
|
||||||
// ... and labeling thread?
|
Arrays.fill(mTiles, null);
|
||||||
synchronized (MapRenderer.drawlock) {
|
mTilesSize = 0;
|
||||||
|
mTilesCount = 0;
|
||||||
|
|
||||||
if (!first) {
|
// set up TileSet large enough to hold current tiles
|
||||||
// pass VBOs and VertexItems back to pools
|
int num = Math.max(mMap.getWidth(), mMap.getHeight());
|
||||||
for (int i = 0; i < mTilesSize; i++)
|
int size = Tile.SIZE >> 1;
|
||||||
clearTile(mTiles[i]);
|
int numTiles = (num * num) / (size * size) * 4;
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME any of this still needed?
|
mNewTiles = new TileSet(numTiles);
|
||||||
// mInitialized is set when surface changed
|
mCurrentTiles = new TileSet(numTiles);
|
||||||
// and VBOs might be lost
|
|
||||||
// VertexPool.init();
|
|
||||||
// clear cache index
|
|
||||||
// QuadTree.init();
|
|
||||||
|
|
||||||
// clear references to cached MapTiles
|
|
||||||
Arrays.fill(mTiles, null);
|
|
||||||
mTilesSize = 0;
|
|
||||||
mTilesCount = 0;
|
|
||||||
|
|
||||||
// set up TileSet large enough to hold current tiles
|
|
||||||
int num = Math.max(mMap.getWidth(), mMap.getHeight());
|
|
||||||
int size = Tile.SIZE >> 1;
|
|
||||||
int numTiles = (num * num) / (size * size) * 4;
|
|
||||||
|
|
||||||
mNewTiles = new TileSet(numTiles);
|
|
||||||
mCurrentTiles = new TileSet(numTiles);
|
|
||||||
log.debug("max tiles: " + numTiles);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -187,7 +164,7 @@ public class TileManager {
|
|||||||
* @param pos
|
* @param pos
|
||||||
* current MapPosition
|
* current MapPosition
|
||||||
*/
|
*/
|
||||||
public synchronized boolean update(MapPosition pos) {
|
public boolean update(MapPosition pos) {
|
||||||
// clear JobQueue and set tiles to state == NONE.
|
// clear JobQueue and set tiles to state == NONE.
|
||||||
// one could also append new tiles and sort in JobQueue
|
// one could also append new tiles and sort in JobQueue
|
||||||
// but this has the nice side-effect that MapWorkers dont
|
// but this has the nice side-effect that MapWorkers dont
|
||||||
@ -405,13 +382,14 @@ public class TileManager {
|
|||||||
if (t == null)
|
if (t == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
t.clear();
|
synchronized (t) {
|
||||||
|
// still belongs to TileLoader thread
|
||||||
mIndex.remove(t);
|
if (t.state != STATE_LOADING)
|
||||||
|
t.clear();
|
||||||
// QuadTree.remove(t);
|
|
||||||
t.state = STATE_NONE;
|
|
||||||
|
|
||||||
|
t.state = STATE_CANCEL;
|
||||||
|
mIndex.remove(t);
|
||||||
|
}
|
||||||
mTilesCount--;
|
mTilesCount--;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -549,8 +527,7 @@ public class TileManager {
|
|||||||
* @return caller does not care
|
* @return caller does not care
|
||||||
*/
|
*/
|
||||||
public void jobCompleted(MapTile tile, boolean success) {
|
public void jobCompleted(MapTile tile, boolean success) {
|
||||||
|
if (!success || tile.state == STATE_CANCEL) {
|
||||||
if (!success) {
|
|
||||||
tile.clear();
|
tile.clear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -64,8 +64,11 @@ public class TileRenderer extends LayerRenderer {
|
|||||||
mAlpha = alpha;
|
mAlpha = alpha;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* synced with clearTiles
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void update(MapPosition pos, boolean positionChanged, Matrices m) {
|
protected synchronized void update(MapPosition pos, boolean positionChanged, Matrices m) {
|
||||||
|
|
||||||
if (mAlpha == 0) {
|
if (mAlpha == 0) {
|
||||||
mTileManager.releaseTiles(mDrawTiles);
|
mTileManager.releaseTiles(mDrawTiles);
|
||||||
@ -106,9 +109,7 @@ public class TileRenderer extends LayerRenderer {
|
|||||||
public void clearTiles() {
|
public void clearTiles() {
|
||||||
// Clear all references to MapTiles as all current
|
// Clear all references to MapTiles as all current
|
||||||
// tiles will also be removed from TileManager.
|
// tiles will also be removed from TileManager.
|
||||||
synchronized (MapRenderer.drawlock) {
|
mDrawTiles = new TileSet();
|
||||||
mDrawTiles = new TileSet();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** compile tile layer data and upload to VBOs */
|
/** compile tile layer data and upload to VBOs */
|
||||||
|
@ -56,6 +56,7 @@ public class LwHttp {
|
|||||||
private Socket mSocket;
|
private Socket mSocket;
|
||||||
private OutputStream mCommandStream;
|
private OutputStream mCommandStream;
|
||||||
private InputStream mResponseStream;
|
private InputStream mResponseStream;
|
||||||
|
private OutputStream mCacheOutputStream;
|
||||||
private long mLastRequest = 0;
|
private long mLastRequest = 0;
|
||||||
private SocketAddress mSockAddr;
|
private SocketAddress mSockAddr;
|
||||||
|
|
||||||
@ -106,40 +107,34 @@ public class LwHttp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static class Buffer extends BufferedInputStream {
|
static class Buffer extends BufferedInputStream {
|
||||||
final OutputStream mCache;
|
final OutputStream mCacheOutputstream;
|
||||||
|
|
||||||
public Buffer(InputStream is, OutputStream cache) {
|
public Buffer(InputStream is, OutputStream cache) {
|
||||||
super(is, 4096);
|
super(is, 4096);
|
||||||
mCache = cache;
|
mCacheOutputstream = cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized int read() throws IOException {
|
public int read() throws IOException {
|
||||||
int data = super.read();
|
int data = super.read();
|
||||||
if (data >= 0)
|
if (data >= 0)
|
||||||
mCache.write(data);
|
mCacheOutputstream.write(data);
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized int read(byte[] buffer, int offset, int byteCount)
|
public int read(byte[] buffer, int offset, int byteCount)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
int len = super.read(buffer, offset, byteCount);
|
int len = super.read(buffer, offset, byteCount);
|
||||||
|
|
||||||
if (len >= 0)
|
if (len >= 0)
|
||||||
mCache.write(buffer, offset, len);
|
mCacheOutputstream.write(buffer, offset, len);
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
OutputStream mCacheOutputStream;
|
|
||||||
|
|
||||||
public void setOutputStream(OutputStream outputStream) {
|
|
||||||
mCacheOutputStream = outputStream;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void close() {
|
public void close() {
|
||||||
if (mSocket != null) {
|
if (mSocket != null) {
|
||||||
try {
|
try {
|
||||||
@ -177,6 +172,10 @@ public class LwHttp {
|
|||||||
while (end < read && (buf[end] != '\n'))
|
while (end < read && (buf[end] != '\n'))
|
||||||
end++;
|
end++;
|
||||||
|
|
||||||
|
if (end == BUFFER_SIZE) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
if (buf[end] != '\n')
|
if (buf[end] != '\n')
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -209,7 +208,7 @@ public class LwHttp {
|
|||||||
|
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
String line = new String(buf, pos, end - pos - 1);
|
String line = new String(buf, pos, end - pos - 1);
|
||||||
log.debug(">" + line + "< ");
|
log.debug("> {} <", line);
|
||||||
}
|
}
|
||||||
|
|
||||||
pos += (end - pos) + 1;
|
pos += (end - pos) + 1;
|
||||||
@ -255,12 +254,14 @@ public class LwHttp {
|
|||||||
mMaxReq = RESPONSE_EXPECTED_LIVES;
|
mMaxReq = RESPONSE_EXPECTED_LIVES;
|
||||||
// log.debug("create connection");
|
// log.debug("create connection");
|
||||||
} else {
|
} else {
|
||||||
// FIXME not sure if this is correct way to drain socket
|
|
||||||
int avail = mResponseStream.available();
|
int avail = mResponseStream.available();
|
||||||
if (avail > 0) {
|
if (avail > 0) {
|
||||||
log.debug("Consume left-over bytes: " + avail);
|
log.debug("left-over bytes: " + avail);
|
||||||
while ((avail = mResponseStream.available()) > 0)
|
close();
|
||||||
mResponseStream.read(buffer);
|
lwHttpConnect();
|
||||||
|
// FIXME not sure if this is correct way to drain socket
|
||||||
|
//while ((avail = mResponseStream.available()) > 0)
|
||||||
|
// mResponseStream.read(buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -353,8 +354,16 @@ public class LwHttp {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void requestCompleted() {
|
public void setOutputStream(OutputStream outputStream) {
|
||||||
|
mCacheOutputStream = outputStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void requestCompleted(boolean keepConnection) {
|
||||||
mLastRequest = System.nanoTime();
|
mLastRequest = System.nanoTime();
|
||||||
|
mCacheOutputStream = null;
|
||||||
|
|
||||||
|
if (!keepConnection)
|
||||||
|
close();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getContentLength() {
|
public int getContentLength() {
|
||||||
|
@ -30,10 +30,6 @@ import org.oscim.utils.IOUtils;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public abstract class PbfTileDataSource implements ITileDataSource {
|
public abstract class PbfTileDataSource implements ITileDataSource {
|
||||||
static final Logger log = LoggerFactory.getLogger(PbfTileDataSource.class);
|
static final Logger log = LoggerFactory.getLogger(PbfTileDataSource.class);
|
||||||
|
|
||||||
@ -48,66 +44,55 @@ public abstract class PbfTileDataSource implements ITileDataSource {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public QueryResult executeQuery(MapTile tile, ITileDataSink sink) {
|
public QueryResult executeQuery(MapTile tile, ITileDataSink sink) {
|
||||||
boolean success = true;
|
|
||||||
|
|
||||||
ITileCache.TileWriter cacheWriter = null;
|
ITileCache.TileWriter cacheWriter = null;
|
||||||
|
|
||||||
if (mTileCache != null) {
|
if (mTileCache != null) {
|
||||||
ITileCache.TileReader c = mTileCache.getTile(tile);
|
ITileCache.TileReader c = mTileCache.getTile(tile);
|
||||||
if (c == null) {
|
if (c == null) {
|
||||||
// create new cache entry
|
|
||||||
cacheWriter = mTileCache.writeTile(tile);
|
cacheWriter = mTileCache.writeTile(tile);
|
||||||
mConn.setOutputStream(cacheWriter.getOutputStream());
|
|
||||||
} else {
|
} else {
|
||||||
|
InputStream is = c.getInputStream();
|
||||||
try {
|
try {
|
||||||
InputStream is = c.getInputStream();
|
|
||||||
if (mTileDecoder.decode(tile, sink, is, c.getBytes())) {
|
if (mTileDecoder.decode(tile, sink, is, c.getBytes())) {
|
||||||
IOUtils.closeQuietly(is);
|
|
||||||
return QueryResult.SUCCESS;
|
return QueryResult.SUCCESS;
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
IOUtils.closeQuietly(is);
|
||||||
}
|
}
|
||||||
log.debug(tile + " Cache read failed");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean success = false;
|
||||||
try {
|
try {
|
||||||
|
if (cacheWriter != null)
|
||||||
|
mConn.setOutputStream(cacheWriter.getOutputStream());
|
||||||
|
|
||||||
InputStream is;
|
InputStream is;
|
||||||
if (!mConn.sendRequest(tile)) {
|
if (!mConn.sendRequest(tile)) {
|
||||||
log.debug(tile + " Request failed");
|
log.debug("{} Request failed", tile);
|
||||||
success = false;
|
} else if ((is = mConn.readHeader()) == null) {
|
||||||
} else if ((is = mConn.readHeader()) != null) {
|
log.debug("{} Network Error", tile);
|
||||||
|
} else {
|
||||||
int bytes = mConn.getContentLength();
|
int bytes = mConn.getContentLength();
|
||||||
success = mTileDecoder.decode(tile, sink, is, bytes);
|
success = mTileDecoder.decode(tile, sink, is, bytes);
|
||||||
if (!success)
|
|
||||||
log.debug(tile + " Decoding failed");
|
|
||||||
} else {
|
|
||||||
log.debug(tile + " Network Error");
|
|
||||||
success = false;
|
|
||||||
}
|
}
|
||||||
} catch (SocketException e) {
|
} catch (SocketException e) {
|
||||||
log.debug(tile + " Socket exception: " + e.getMessage());
|
log.debug("{} Socket exception: {}", tile, e.getMessage());
|
||||||
success = false;
|
|
||||||
} catch (SocketTimeoutException e) {
|
} catch (SocketTimeoutException e) {
|
||||||
log.debug(tile + " Socket Timeout");
|
log.debug("{} Socket Timeout", tile);
|
||||||
success = false;
|
|
||||||
} catch (UnknownHostException e) {
|
} catch (UnknownHostException e) {
|
||||||
log.debug(tile + " No Network");
|
log.debug("{} No Network", tile);
|
||||||
success = false;
|
} catch (IOException e) {
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
success = false;
|
} finally {
|
||||||
|
mConn.requestCompleted(success);
|
||||||
|
|
||||||
|
if (cacheWriter != null)
|
||||||
|
cacheWriter.complete(success);
|
||||||
}
|
}
|
||||||
|
|
||||||
mConn.requestCompleted();
|
|
||||||
|
|
||||||
if (cacheWriter != null)
|
|
||||||
cacheWriter.complete(success);
|
|
||||||
|
|
||||||
if (success)
|
|
||||||
mConn.close();
|
|
||||||
|
|
||||||
return success ? QueryResult.SUCCESS : QueryResult.FAILED;
|
return success ? QueryResult.SUCCESS : QueryResult.FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,12 +17,18 @@
|
|||||||
*/
|
*/
|
||||||
package org.oscim.utils;
|
package org.oscim.utils;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An abstract base class for threads which support pausing and resuming.
|
* An abstract base class for threads which support pausing and resuming.
|
||||||
*/
|
*/
|
||||||
public abstract class PausableThread extends Thread {
|
public abstract class PausableThread extends Thread {
|
||||||
|
private final static Logger log = LoggerFactory.getLogger(PausableThread.class);
|
||||||
|
private final static boolean DEBUG = false;
|
||||||
|
|
||||||
private boolean mPausing = true;
|
private boolean mPausing = true;
|
||||||
private boolean mShouldPause;
|
private boolean mShouldPause = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Causes the current thread to wait until this thread is pausing.
|
* Causes the current thread to wait until this thread is pausing.
|
||||||
@ -30,8 +36,10 @@ public abstract class PausableThread extends Thread {
|
|||||||
public final void awaitPausing() {
|
public final void awaitPausing() {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
while (!isInterrupted() && !isPausing()) {
|
while (!isInterrupted() && !isPausing()) {
|
||||||
|
if (DEBUG)
|
||||||
|
log.debug("await {}", getThreadName());
|
||||||
try {
|
try {
|
||||||
wait(100);
|
wait(10);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
// restore the interrupted status
|
// restore the interrupted status
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
@ -42,17 +50,13 @@ public abstract class PausableThread extends Thread {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void interrupt() {
|
public void interrupt() {
|
||||||
|
if (DEBUG)
|
||||||
|
log.debug("interrupt {}", getThreadName());
|
||||||
|
|
||||||
// first acquire the monitor which is used to call wait()
|
// first acquire the monitor which is used to call wait()
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
super.interrupt();
|
super.interrupt();
|
||||||
}
|
}
|
||||||
|
|
||||||
//try {
|
|
||||||
// this.join(10000);
|
|
||||||
//} catch (InterruptedException e) {
|
|
||||||
// // restore the interrupted status
|
|
||||||
// Thread.currentThread().interrupt();
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -72,14 +76,16 @@ public abstract class PausableThread extends Thread {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final synchronized boolean isCanceled() {
|
||||||
|
return mShouldPause;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The paused thread should continue with its work.
|
* The paused thread should continue with its work.
|
||||||
*/
|
*/
|
||||||
public final synchronized void proceed() {
|
public final synchronized void proceed() {
|
||||||
if (mShouldPause) {
|
if (mShouldPause) {
|
||||||
mShouldPause = false;
|
mShouldPause = false;
|
||||||
mPausing = false;
|
|
||||||
afterPause();
|
|
||||||
notify();
|
notify();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -102,6 +108,14 @@ public abstract class PausableThread extends Thread {
|
|||||||
interrupt();
|
interrupt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mPausing) {
|
||||||
|
mPausing = false;
|
||||||
|
afterPause();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DEBUG)
|
||||||
|
log.debug("resume {}", getThreadName());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isInterrupted()) {
|
if (isInterrupted()) {
|
||||||
@ -116,6 +130,11 @@ public abstract class PausableThread extends Thread {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (DEBUG)
|
||||||
|
log.debug("finish {}", getThreadName());
|
||||||
|
|
||||||
|
mPausing = true;
|
||||||
|
|
||||||
afterRun();
|
afterRun();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
91
vtm/src/org/oscim/utils/async/ContinuousTask.java
Normal file
91
vtm/src/org/oscim/utils/async/ContinuousTask.java
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
package org.oscim.utils.async;
|
||||||
|
|
||||||
|
import org.oscim.map.Map;
|
||||||
|
|
||||||
|
public abstract class ContinuousTask implements Runnable {
|
||||||
|
private final Map mMap;
|
||||||
|
|
||||||
|
protected boolean mRunning;
|
||||||
|
protected boolean mWait;
|
||||||
|
protected boolean mCancel;
|
||||||
|
protected boolean mDelayed;
|
||||||
|
|
||||||
|
protected long mMinDelay;
|
||||||
|
|
||||||
|
public ContinuousTask(Map map, long minDelay) {
|
||||||
|
mMap = map;
|
||||||
|
mMinDelay = minDelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
|
||||||
|
synchronized (this) {
|
||||||
|
//System.out.println("run " + mRunning + " "
|
||||||
|
// + mCancel + " " + mDelayed + " " + mWait);
|
||||||
|
|
||||||
|
if (mCancel) {
|
||||||
|
mCancel = false;
|
||||||
|
mRunning = false;
|
||||||
|
mDelayed = false;
|
||||||
|
mWait = false;
|
||||||
|
cleanup();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mDelayed) {
|
||||||
|
// entered on main-loop
|
||||||
|
mDelayed = false;
|
||||||
|
mWait = false;
|
||||||
|
// unset running temporarily
|
||||||
|
mRunning = false;
|
||||||
|
submit(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
doWork();
|
||||||
|
|
||||||
|
synchronized (this) {
|
||||||
|
mRunning = false;
|
||||||
|
|
||||||
|
if (mCancel)
|
||||||
|
cleanup();
|
||||||
|
else if (mWait)
|
||||||
|
submit(mMinDelay);
|
||||||
|
|
||||||
|
mCancel = false;
|
||||||
|
mWait = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void doWork();
|
||||||
|
|
||||||
|
public abstract void cleanup();
|
||||||
|
|
||||||
|
public synchronized void submit(long delay) {
|
||||||
|
//System.out.println("submit " + mRunning + " " + mCancel + " " + delay);
|
||||||
|
|
||||||
|
if (mRunning) {
|
||||||
|
mWait = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mRunning = true;
|
||||||
|
if (delay <= 0) {
|
||||||
|
mMap.addTask(this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mDelayed = true;
|
||||||
|
mMap.postDelayed(this, delay);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void cancel() {
|
||||||
|
if (mRunning) {
|
||||||
|
mCancel = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup();
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user