mv TextOverlayExp to TextOverlay
This commit is contained in:
parent
e1ce1b056b
commit
9b54d81dab
@ -14,7 +14,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.oscim.overlay;
|
package org.oscim.overlay;
|
||||||
|
|
||||||
import org.oscim.renderer.overlays.TextOverlayExp;
|
import org.oscim.renderer.overlays.TextOverlay;
|
||||||
import org.oscim.view.MapView;
|
import org.oscim.view.MapView;
|
||||||
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
@ -25,11 +25,11 @@ import android.view.MotionEvent;
|
|||||||
*/
|
*/
|
||||||
public class LabelingOverlay extends Overlay {
|
public class LabelingOverlay extends Overlay {
|
||||||
private final static String TAG = LabelingOverlay.class.getName();
|
private final static String TAG = LabelingOverlay.class.getName();
|
||||||
final TextOverlayExp mTextLayer;
|
final TextOverlay mTextLayer;
|
||||||
|
|
||||||
public LabelingOverlay(MapView mapView) {
|
public LabelingOverlay(MapView mapView) {
|
||||||
super();
|
super();
|
||||||
mTextLayer = new TextOverlayExp(mapView);
|
mTextLayer = new TextOverlay(mapView);
|
||||||
mLayer = mTextLayer;
|
mLayer = mTextLayer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2013 Hannes Janetzek
|
* Copyright 2012 Hannes Janetzek
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify it under the
|
* 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
|
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||||
@ -28,9 +28,14 @@ package org.oscim.renderer.overlays;
|
|||||||
|
|
||||||
import org.oscim.core.MapPosition;
|
import org.oscim.core.MapPosition;
|
||||||
import org.oscim.core.Tile;
|
import org.oscim.core.Tile;
|
||||||
|
import org.oscim.renderer.BufferObject;
|
||||||
import org.oscim.renderer.GLRenderer;
|
import org.oscim.renderer.GLRenderer;
|
||||||
import org.oscim.renderer.GLRenderer.Matrices;
|
import org.oscim.renderer.GLRenderer.Matrices;
|
||||||
|
import org.oscim.renderer.GLState;
|
||||||
|
import org.oscim.renderer.LineRenderer;
|
||||||
import org.oscim.renderer.MapTile;
|
import org.oscim.renderer.MapTile;
|
||||||
|
import org.oscim.renderer.PolygonRenderer;
|
||||||
|
import org.oscim.renderer.TextureRenderer;
|
||||||
import org.oscim.renderer.TileSet;
|
import org.oscim.renderer.TileSet;
|
||||||
import org.oscim.renderer.layer.Layer;
|
import org.oscim.renderer.layer.Layer;
|
||||||
import org.oscim.renderer.layer.Layers;
|
import org.oscim.renderer.layer.Layers;
|
||||||
@ -39,30 +44,30 @@ import org.oscim.renderer.layer.TextItem;
|
|||||||
import org.oscim.renderer.layer.TextLayer;
|
import org.oscim.renderer.layer.TextLayer;
|
||||||
import org.oscim.theme.renderinstruction.Line;
|
import org.oscim.theme.renderinstruction.Line;
|
||||||
import org.oscim.utils.FastMath;
|
import org.oscim.utils.FastMath;
|
||||||
import org.oscim.utils.GeometryUtils;
|
|
||||||
import org.oscim.utils.GlUtils;
|
import org.oscim.utils.GlUtils;
|
||||||
|
import org.oscim.utils.OBB2D;
|
||||||
import org.oscim.utils.PausableThread;
|
import org.oscim.utils.PausableThread;
|
||||||
import org.oscim.view.MapView;
|
import org.oscim.view.MapView;
|
||||||
|
import org.oscim.view.MapViewPosition;
|
||||||
|
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.Paint.Cap;
|
import android.graphics.Paint.Cap;
|
||||||
|
import android.opengl.GLES20;
|
||||||
import android.opengl.Matrix;
|
import android.opengl.Matrix;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Hannes Janetzek
|
|
||||||
*/
|
|
||||||
public class TextOverlay extends BasicOverlay {
|
public class TextOverlay extends BasicOverlay {
|
||||||
private final static String TAG = TextOverlay.class.getName();
|
private final static String TAG = TextOverlay.class.getName();
|
||||||
|
|
||||||
private TileSet mTiles;
|
private final MapViewPosition mMapViewPosition;
|
||||||
|
private TileSet mTileSet;
|
||||||
private final LabelThread mThread;
|
private final LabelThread mThread;
|
||||||
|
|
||||||
private MapPosition mWorkPos;
|
private MapPosition mTmpPos;
|
||||||
|
|
||||||
|
// TextLayer that is updating
|
||||||
|
private TextLayer mTmpLayer;
|
||||||
// TextLayer that is ready to be added to 'layers'
|
// TextLayer that is ready to be added to 'layers'
|
||||||
private TextLayer mCurLayer;
|
|
||||||
private TextLayer mNextLayer;
|
private TextLayer mNextLayer;
|
||||||
|
|
||||||
// local pool, avoids synchronized TextItem.get()/release()
|
// local pool, avoids synchronized TextItem.get()/release()
|
||||||
@ -90,9 +95,10 @@ public class TextOverlay extends BasicOverlay {
|
|||||||
public OBB2D bbox;
|
public OBB2D bbox;
|
||||||
}
|
}
|
||||||
|
|
||||||
// class Conflict {
|
// class Link {
|
||||||
// Conflict next;
|
// Link next;
|
||||||
// Label other;
|
// Link prev;
|
||||||
|
// Label it;
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// class ActiveTile {
|
// class ActiveTile {
|
||||||
@ -102,19 +108,22 @@ public class TextOverlay extends BasicOverlay {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
/* package */boolean mRun;
|
/* package */boolean mRun;
|
||||||
/* package */boolean mRerun;
|
|
||||||
|
|
||||||
class LabelThread extends PausableThread {
|
class LabelThread extends PausableThread {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doWork() {
|
protected void doWork() {
|
||||||
SystemClock.sleep(400);
|
SystemClock.sleep(500);
|
||||||
if (!mRun)
|
if (!mRun)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mRun = false;
|
mRun = false;
|
||||||
updateLabels();
|
|
||||||
mMapView.redrawMap(false);
|
if (updateLabels()) {
|
||||||
|
mMapView.redrawMap(true);
|
||||||
|
} else {
|
||||||
|
mRun = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -124,264 +133,389 @@ public class TextOverlay extends BasicOverlay {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean hasWork() {
|
protected boolean hasWork() {
|
||||||
return mRun || mRerun;
|
return mRun;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private float mSquareRadius;
|
||||||
|
private int mRelabelCnt;
|
||||||
|
|
||||||
public TextOverlay(MapView mapView) {
|
public TextOverlay(MapView mapView) {
|
||||||
super(mapView);
|
super(mapView);
|
||||||
|
mMapViewPosition = mapView.getMapViewPosition();
|
||||||
|
|
||||||
mWorkPos = new MapPosition();
|
layers.textureLayers = new TextLayer();
|
||||||
|
mTmpLayer = new TextLayer();
|
||||||
|
//mActiveTiles = new HashMap<MapTile, Link>();
|
||||||
|
mTmpPos = new MapPosition();
|
||||||
mThread = new LabelThread();
|
mThread = new LabelThread();
|
||||||
mThread.start();
|
mThread.start();
|
||||||
|
|
||||||
|
mRelabelCnt = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private TextItem mPool;
|
private Label removeLabel(TextLayer tl, Label l) {
|
||||||
|
Label tmp = l;
|
||||||
|
l = (Label) l.next;
|
||||||
|
|
||||||
private byte checkOverlap(TextLayer tl, TextItem ti) {
|
TextItem.release(tmp.item);
|
||||||
|
tl.removeText(tmp);
|
||||||
|
|
||||||
for (TextItem lp = tl.labels; lp != null;) {
|
tmp.next = mPool;
|
||||||
if (lp.text.caption) {
|
mPool = tmp;
|
||||||
lp = lp.next;
|
|
||||||
continue;
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private byte checkOverlap(TextLayer tl, Label ti) {
|
||||||
|
|
||||||
|
for (Label lp = (Label) tl.labels; lp != null;) {
|
||||||
|
|
||||||
// check bounding box
|
// check bounding box
|
||||||
if (!TextItem.bboxOverlaps(ti, lp, 80)) {
|
if (!TextItem.bboxOverlaps(ti, lp, 150)) {
|
||||||
lp = lp.next;
|
lp = (Label) lp.next;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lp.text == ti.text && (lp.string == ti.string || lp.string.equals(ti.string))) {
|
if (lp.text == ti.text && (lp.string == ti.string || lp.string.equals(ti.string))) {
|
||||||
// make strings unique
|
|
||||||
|
// make strings unique, should be done only once..
|
||||||
ti.string = lp.string;
|
ti.string = lp.string;
|
||||||
|
|
||||||
Log.d(TAG, "overlap, same label in bbox " + lp.string
|
// keep the label that was active earlier
|
||||||
+ " at " + ti.x + ":" + ti.y + ", " + lp.x + ":" + lp.y);
|
if (lp.active <= ti.active)
|
||||||
return 3;
|
return 1;
|
||||||
}
|
|
||||||
|
|
||||||
if (!TextItem.bboxOverlaps(ti, lp, 10)) {
|
// keep the label with longer segment
|
||||||
lp = lp.next;
|
if (lp.length < ti.length) {
|
||||||
continue;
|
lp = removeLabel(tl, lp);
|
||||||
}
|
|
||||||
|
|
||||||
byte intersect = GeometryUtils.linesIntersect(
|
|
||||||
ti.x1, ti.y1, ti.x2, ti.y2,
|
|
||||||
lp.x1, lp.y1, lp.x2, lp.y2);
|
|
||||||
|
|
||||||
if (intersect != 0) {
|
|
||||||
//Log.d(TAG, "overlap " + lp.string + " <> " + ti.string
|
|
||||||
//+ " at " + ti.x + ":" + ti.y);
|
|
||||||
|
|
||||||
if ((lp.n1 != null && lp.n1 == ti.n2) ||
|
|
||||||
(lp.n2 != null && lp.n2 == ti.n1)) {
|
|
||||||
//Log.d(TAG, "overlap with adjacent label " + lp.string
|
|
||||||
// + " at " + ti.x + ":" + ti.y + ", " + lp.x + ":" + lp.y);
|
|
||||||
|
|
||||||
return intersect;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((ti.n1 != null || ti.n2 != null) && (lp.n1 == null && lp.n2 == null)) {
|
|
||||||
Log.d(TAG, "overlap, other is unique " + lp.string + " " + ti.string
|
|
||||||
+ " at " + ti.x + ":" + ti.y + ", " + lp.x + ":" + lp.y);
|
|
||||||
return intersect;
|
|
||||||
}
|
|
||||||
// just to make it more deterministic
|
|
||||||
if (lp.x > ti.x) {
|
|
||||||
//Log.d(TAG, "drop " + lp.string);
|
|
||||||
|
|
||||||
TextItem tmp = lp;
|
|
||||||
lp = lp.next;
|
|
||||||
|
|
||||||
tl.removeText(tmp);
|
|
||||||
|
|
||||||
tmp.next = mPool;
|
|
||||||
mPool = tmp;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
return intersect;
|
|
||||||
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
lp = lp.next;
|
boolean intersect = ti.bbox.overlaps(lp.bbox);
|
||||||
|
|
||||||
|
if (intersect) {
|
||||||
|
|
||||||
|
if (lp.active <= ti.active)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
//Log.d(TAG, "intersection " + lp.string + " <> " + ti.string
|
||||||
|
// + " at " + ti.x + ":" + ti.y);
|
||||||
|
|
||||||
|
if (!lp.text.caption
|
||||||
|
&& (lp.text.priority > ti.text.priority || lp.length < ti.length)) {
|
||||||
|
|
||||||
|
lp = removeLabel(tl, lp);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
lp = (Label) lp.next;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Layers mDebugLayer = null; //new Layers();
|
private boolean nodeIsVisible(TextItem ti) {
|
||||||
|
// rough filter
|
||||||
|
float dist = ti.x * ti.x + ti.y * ti.y;
|
||||||
|
if (dist > mSquareRadius)
|
||||||
|
return false;
|
||||||
|
|
||||||
void updateLabels() {
|
return true;
|
||||||
mTiles = mMapView.getTileManager().getActiveTiles(mTiles);
|
}
|
||||||
|
|
||||||
// Log.d("...", "relabel " + mRerun + " " + x + " " + y);
|
private boolean wayIsVisible(TextItem ti) {
|
||||||
if (mTiles.cnt == 0)
|
// rough filter
|
||||||
return;
|
float dist = ti.x * ti.x + ti.y * ti.y;
|
||||||
|
if (dist < mSquareRadius)
|
||||||
|
return true;
|
||||||
|
|
||||||
mMapView.getMapViewPosition().getMapPosition(mWorkPos);
|
dist = ti.x1 * ti.x1 + ti.y1 * ti.y1;
|
||||||
|
if (dist < mSquareRadius)
|
||||||
|
return true;
|
||||||
|
|
||||||
TextLayer tl = mWorkLayer;
|
dist = ti.x2 * ti.x2 + ti.y2 * ti.y2;
|
||||||
|
if (dist < mSquareRadius)
|
||||||
|
return true;
|
||||||
|
|
||||||
if (tl == null)
|
return false;
|
||||||
tl = new TextLayer();
|
}
|
||||||
|
|
||||||
|
private Layers mDebugLayer;
|
||||||
|
private final static float[] mDebugPoints = new float[4];
|
||||||
|
private final float[] mMVP = new float[16];
|
||||||
|
|
||||||
|
void addTile(MapTile t) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private Label addToPool(Label l) {
|
||||||
|
TextItem.release(l.item);
|
||||||
|
l.item = null;
|
||||||
|
|
||||||
|
Label next = (Label) l.next;
|
||||||
|
l.next = mPool;
|
||||||
|
mPool = l;
|
||||||
|
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Label getLabel() {
|
||||||
|
Label l;
|
||||||
|
|
||||||
|
if (mPool == null)
|
||||||
|
l = new Label();
|
||||||
|
else {
|
||||||
|
l = mPool;
|
||||||
|
mPool = (Label) mPool.next;
|
||||||
|
l.next = null;
|
||||||
|
}
|
||||||
|
l.active = Integer.MAX_VALUE;
|
||||||
|
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean updateLabels() {
|
||||||
|
if (mTmpLayer == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// get current tiles
|
||||||
|
mTileSet = GLRenderer.getVisibleTiles(mTileSet);
|
||||||
|
|
||||||
|
if (mTileSet.cnt == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// reuse text layer
|
||||||
|
TextLayer tl = mTmpLayer;
|
||||||
|
mTmpLayer = null;
|
||||||
|
|
||||||
|
//mNewLabels = null;
|
||||||
|
|
||||||
|
Layers dbg = null;
|
||||||
|
if (mMapView.getDebugSettings().debugLabels)
|
||||||
|
dbg = new Layers();
|
||||||
|
|
||||||
|
float[] coords = mTmpCoords;
|
||||||
|
MapPosition pos = mTmpPos;
|
||||||
|
|
||||||
|
synchronized (mMapViewPosition) {
|
||||||
|
mMapViewPosition.getMapPosition(pos);
|
||||||
|
mMapViewPosition.getMapViewProjection(coords);
|
||||||
|
mMapViewPosition.getMatrix(null, null, mMVP);
|
||||||
|
}
|
||||||
|
int mw = (mMapView.getWidth() + Tile.TILE_SIZE) / 2;
|
||||||
|
int mh = (mMapView.getHeight() + Tile.TILE_SIZE) / 2;
|
||||||
|
mSquareRadius = mw * mw + mh * mh;
|
||||||
|
|
||||||
// mTiles might be from another zoomlevel than the current:
|
// mTiles might be from another zoomlevel than the current:
|
||||||
// this scales MapPosition to the zoomlevel of mTiles...
|
// this scales MapPosition to the zoomlevel of mTiles...
|
||||||
// TODO create a helper function in MapPosition
|
// TODO create a helper function in MapPosition
|
||||||
int diff = mTiles.tiles[0].zoomLevel - mWorkPos.zoomLevel;
|
MapTile[] tiles = mTileSet.tiles;
|
||||||
|
int diff = tiles[0].zoomLevel - pos.zoomLevel;
|
||||||
|
float div = FastMath.pow(diff);
|
||||||
|
float scale = pos.scale * div;
|
||||||
|
|
||||||
// only relabel when tiles belong to the current zoomlevel or its parent
|
double angle = Math.toRadians(pos.angle);
|
||||||
if (diff > 1 || diff < -2) {
|
|
||||||
// pass back the current layer
|
|
||||||
synchronized (this) {
|
|
||||||
Log.d(TAG, "drop labels: diff " + diff);
|
|
||||||
mCurLayer = tl;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
float scale = mWorkPos.scale;
|
|
||||||
double angle = Math.toRadians(mWorkPos.angle);
|
|
||||||
float cos = (float) Math.cos(angle);
|
float cos = (float) Math.cos(angle);
|
||||||
float sin = (float) Math.sin(angle);
|
float sin = (float) Math.sin(angle);
|
||||||
|
|
||||||
int maxx = Tile.TILE_SIZE << (mWorkPos.zoomLevel - 1);
|
int maxx = Tile.TILE_SIZE << (pos.zoomLevel - 1);
|
||||||
|
|
||||||
MapTile[] tiles = mTiles.tiles;
|
Label l = null;
|
||||||
TextItem ti2 = null;
|
|
||||||
|
|
||||||
if (mDebugLayer != null) {
|
if (dbg != null)
|
||||||
mDebugLayer.clear();
|
addDebugLayers(dbg);
|
||||||
LineLayer ll = (LineLayer) mDebugLayer.getLayer(0, Layer.LINE);
|
|
||||||
ll.line = new Line(Color.BLUE, 1, Cap.BUTT);
|
mRelabelCnt++;
|
||||||
ll.width = 2;
|
|
||||||
ll = (LineLayer) mDebugLayer.getLayer(3, Layer.LINE);
|
for (l = mPrevLabels; l != null;) {
|
||||||
ll.line = new Line(Color.YELLOW, 1, Cap.BUTT);
|
|
||||||
ll.width = 2;
|
// transform screen coordinates to tile coordinates
|
||||||
ll = (LineLayer) mDebugLayer.getLayer(1, Layer.LINE);
|
float s = FastMath.pow(l.tile.zoomLevel - pos.zoomLevel);
|
||||||
ll.line = new Line(Color.RED, 1, Cap.BUTT);
|
float sscale = pos.scale / s;
|
||||||
ll.width = 2;
|
|
||||||
ll = (LineLayer) mDebugLayer.getLayer(2, Layer.LINE);
|
if (l.width > l.length * sscale) {
|
||||||
ll.line = new Line(Color.GREEN, 1, Cap.BUTT);
|
//Log.d(TAG, "- scale " + lp + " " + s + " " + sscale + " " + lp.length + " " + lp.width);
|
||||||
ll.width = 2;
|
l = addToPool(l);
|
||||||
}
|
|
||||||
// TODO more sophisticated placement :)
|
|
||||||
for (int i = 0, n = mTiles.cnt; i < n; i++) {
|
|
||||||
MapTile t = tiles[i];
|
|
||||||
if (!t.isVisible)
|
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Log.d(TAG, "add: " + t);
|
float dx = (float) (l.tile.pixelX - pos.x * s);
|
||||||
|
float dy = (float) (l.tile.pixelY - pos.y * s);
|
||||||
float dx = (float) (t.pixelX - mWorkPos.x);
|
|
||||||
float dy = (float) (t.pixelY - mWorkPos.y);
|
|
||||||
|
|
||||||
// flip around date-line
|
// flip around date-line
|
||||||
if (dx > maxx) {
|
if (dx > maxx)
|
||||||
dx = dx - maxx * 2;
|
dx = dx - maxx * 2;
|
||||||
} else if (dx < -maxx) {
|
else if (dx < -maxx)
|
||||||
dx = dx + maxx * 2;
|
dx = dx + maxx * 2;
|
||||||
|
|
||||||
|
l.move(l.item, dx, dy, sscale);
|
||||||
|
|
||||||
|
if (!l.text.caption) {
|
||||||
|
// set line endpoints relative to view to be able to
|
||||||
|
// check intersections with label from other tiles
|
||||||
|
float width = (l.item.x2 - l.item.x1) / 2f;
|
||||||
|
float height = (l.item.y2 - l.item.y1) / 2f;
|
||||||
|
|
||||||
|
l.x2 = (l.x + width);
|
||||||
|
l.x1 = (l.x - width);
|
||||||
|
l.y2 = (l.y + height);
|
||||||
|
l.y1 = (l.y - height);
|
||||||
|
|
||||||
|
if (!wayIsVisible(l)) {
|
||||||
|
l = addToPool(l);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte overlaps = -1;
|
||||||
|
|
||||||
|
l.bbox.set(l.x, l.y, l.x1, l.y1, l.width + 5, l.text.fontHeight + 5);
|
||||||
|
|
||||||
|
overlaps = checkOverlap(tl, l);
|
||||||
|
|
||||||
|
if (dbg != null)
|
||||||
|
addDebugBox(dbg, l, l.item, overlaps, true, sscale);
|
||||||
|
|
||||||
|
if (overlaps == 0) {
|
||||||
|
|
||||||
|
Label tmp = l;
|
||||||
|
l = (Label) l.next;
|
||||||
|
|
||||||
|
tmp.next = null;
|
||||||
|
tl.addText(tmp);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
dx *= scale;
|
|
||||||
dy *= scale;
|
l = addToPool(l);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add way labels */
|
||||||
|
for (int i = 0, n = mTileSet.cnt; i < n; i++) {
|
||||||
|
|
||||||
|
MapTile t = tiles[i];
|
||||||
|
|
||||||
|
float dx = (float) (t.pixelX - pos.x);
|
||||||
|
float dy = (float) (t.pixelY - pos.y);
|
||||||
|
|
||||||
|
// flip around date-line
|
||||||
|
if (dx > maxx)
|
||||||
|
dx = dx - maxx * 2;
|
||||||
|
else if (dx < -maxx)
|
||||||
|
dx = dx + maxx * 2;
|
||||||
|
|
||||||
for (TextItem ti = t.labels; ti != null; ti = ti.next) {
|
for (TextItem ti = t.labels; ti != null; ti = ti.next) {
|
||||||
|
|
||||||
// acquire a TextItem to add to TextLayer
|
if (ti.text.caption)
|
||||||
if (ti2 == null) {
|
|
||||||
if (mPool == null)
|
|
||||||
ti2 = TextItem.get();
|
|
||||||
else {
|
|
||||||
ti2 = mPool;
|
|
||||||
mPool = mPool.next;
|
|
||||||
ti2.next = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ti.text.caption) {
|
|
||||||
ti2.move(ti, dx, dy, scale);
|
|
||||||
int tx = (int) (ti2.x);
|
|
||||||
int ty = (int) (ti2.y);
|
|
||||||
int tw = (int) (ti2.width / 2);
|
|
||||||
int th = (int) (ti2.text.fontHeight / 2);
|
|
||||||
|
|
||||||
boolean overlaps = false;
|
|
||||||
for (TextItem lp = tl.labels; lp != null;) {
|
|
||||||
int px = (int) (lp.x);
|
|
||||||
int py = (int) (lp.y);
|
|
||||||
int ph = (int) (lp.text.fontHeight / 2);
|
|
||||||
int pw = (int) (lp.width / 2);
|
|
||||||
|
|
||||||
if ((tx - tw) < (px + pw)
|
|
||||||
&& (px - pw) < (tx + tw)
|
|
||||||
&& (ty - th) < (py + ph)
|
|
||||||
&& (py - ph) < (ty + th)) {
|
|
||||||
|
|
||||||
overlaps = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
lp = lp.next;
|
|
||||||
}
|
|
||||||
if (!overlaps) {
|
|
||||||
tl.addText(ti2);
|
|
||||||
ti2 = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
/* text is way label */
|
// acquire a TextItem to add to TextLayer
|
||||||
|
if (l == null)
|
||||||
|
l = getLabel();
|
||||||
|
|
||||||
// check if path at current scale is long enough for text
|
// check if path at current scale is long enough for text
|
||||||
if (mDebugLayer == null && ti.width > ti.length * scale)
|
if (dbg == null && ti.width > ti.length * scale)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
l.clone(ti);
|
||||||
|
l.move(ti, dx, dy, scale);
|
||||||
|
|
||||||
// set line endpoints relative to view to be able to
|
// set line endpoints relative to view to be able to
|
||||||
// check intersections with label from other tiles
|
// check intersections with label from other tiles
|
||||||
float width = (ti.x2 - ti.x1) / 2f;
|
float width = (ti.x2 - ti.x1) / 2f;
|
||||||
float height = (ti.y2 - ti.y1) / 2f;
|
float height = (ti.y2 - ti.y1) / 2f;
|
||||||
|
l.bbox = null;
|
||||||
|
l.x1 = (l.x - width);
|
||||||
|
l.y1 = (l.y - height);
|
||||||
|
l.x2 = (l.x + width);
|
||||||
|
l.y2 = (l.y + height);
|
||||||
|
|
||||||
ti2.move(ti, dx, dy, scale);
|
if (!wayIsVisible(l))
|
||||||
ti2.x2 = (ti2.x + width);
|
continue;
|
||||||
ti2.x1 = (ti2.x - width);
|
|
||||||
ti2.y2 = (ti2.y + height);
|
|
||||||
ti2.y1 = (ti2.y - height);
|
|
||||||
|
|
||||||
byte overlaps = checkOverlap(tl, ti2);
|
byte overlaps = -1;
|
||||||
|
|
||||||
if (mDebugLayer != null) {
|
if (l.bbox == null)
|
||||||
|
l.bbox = new OBB2D(l.x, l.y, l.x1, l.y1, l.width + 5, l.text.fontHeight + 5);
|
||||||
|
else
|
||||||
|
l.bbox.set(l.x, l.y, l.x1, l.y1, l.width + 5, l.text.fontHeight + 5);
|
||||||
|
|
||||||
LineLayer ll;
|
if (dbg == null || ti.width < ti.length * scale)
|
||||||
if (ti.width > ti.length * scale) {
|
overlaps = checkOverlap(tl, l);
|
||||||
ll = (LineLayer) mDebugLayer.getLayer(1, Layer.LINE);
|
|
||||||
overlaps = 3;
|
|
||||||
}
|
|
||||||
else if (overlaps == 1)
|
|
||||||
ll = (LineLayer) mDebugLayer.getLayer(0, Layer.LINE);
|
|
||||||
else if (overlaps == 2)
|
|
||||||
ll = (LineLayer) mDebugLayer.getLayer(3, Layer.LINE);
|
|
||||||
else
|
|
||||||
ll = (LineLayer) mDebugLayer.getLayer(2, Layer.LINE);
|
|
||||||
|
|
||||||
float[] points = new float[4];
|
if (dbg != null)
|
||||||
short[] indices = { 4 };
|
addDebugBox(dbg, l, ti, overlaps, false, scale);
|
||||||
points[0] = ti2.x1 / scale;
|
|
||||||
points[1] = ti2.y1 / scale;
|
|
||||||
points[2] = ti2.x2 / scale;
|
|
||||||
points[3] = ti2.y2 / scale;
|
|
||||||
ll.addLine(points, indices, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (overlaps == 0) {
|
if (overlaps == 0) {
|
||||||
tl.addText(ti2);
|
tl.addText(l);
|
||||||
ti2 = null;
|
l.item = TextItem.copy(ti);
|
||||||
|
l.tile = t;
|
||||||
|
l.active = mRelabelCnt;
|
||||||
|
l = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (TextItem ti = tl.labels; ti != null; ti = ti.next) {
|
/* add caption */
|
||||||
// scale back to fixed zoom-level. could be done in setMatrix
|
for (int i = 0, n = mTileSet.cnt; i < n; i++) {
|
||||||
ti.x /= scale;
|
|
||||||
ti.y /= scale;
|
MapTile t = tiles[i];
|
||||||
|
|
||||||
|
float dx = (float) (t.pixelX - pos.x);
|
||||||
|
float dy = (float) (t.pixelY - pos.y);
|
||||||
|
|
||||||
|
// flip around date-line
|
||||||
|
if (dx > maxx)
|
||||||
|
dx = dx - maxx * 2;
|
||||||
|
else if (dx < -maxx)
|
||||||
|
dx = dx + maxx * 2;
|
||||||
|
|
||||||
|
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, 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 + 6,
|
||||||
|
l.text.fontHeight + 6);
|
||||||
|
|
||||||
|
boolean overlaps = false;
|
||||||
|
for (Label lp = (Label) tl.labels; lp != null; lp = (Label) lp.next) {
|
||||||
|
|
||||||
|
if (l.bbox.overlaps(lp.bbox)) {
|
||||||
|
//Log.d(TAG, "overlap > " + ti2.string + " " + lp.string);
|
||||||
|
//if (TextItem.bboxOverlaps(ti2, lp, 4)) {
|
||||||
|
overlaps = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!overlaps) {
|
||||||
|
tl.addText(l);
|
||||||
|
l.item = TextItem.copy(ti);
|
||||||
|
l.tile = t;
|
||||||
|
l.active = mRelabelCnt;
|
||||||
|
l = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Label ti = (Label) tl.labels; ti != null; ti = (Label) ti.next) {
|
||||||
|
|
||||||
if (ti.text.caption)
|
if (ti.text.caption)
|
||||||
continue;
|
continue;
|
||||||
@ -398,66 +532,176 @@ public class TextOverlay extends BasicOverlay {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// release temporarily used TextItems
|
// keep temporarily used Label
|
||||||
if (ti2 != null) {
|
if (l != null) {
|
||||||
ti2.next = mPool;
|
l.next = mPool;
|
||||||
mPool = ti2;
|
mPool = l;
|
||||||
}
|
|
||||||
if (mPool != null) {
|
|
||||||
TextItem.release(mPool);
|
|
||||||
mPool = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// draw text to bitmaps and create vertices
|
// draw text to bitmaps and create vertices
|
||||||
tl.prepare();
|
tl.prepare();
|
||||||
|
|
||||||
// everything synchronized?
|
// after 'prepare' TextLayer does not need TextItems any longer
|
||||||
|
mPrevLabels = (Label) tl.labels;
|
||||||
|
tl.labels = null;
|
||||||
|
|
||||||
|
// remove tile locks
|
||||||
|
GLRenderer.releaseTiles(mTileSet);
|
||||||
|
|
||||||
|
// pass new labels for rendering
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
mCurLayer = tl;
|
mNextLayer = tl;
|
||||||
|
mDebugLayer = dbg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void addDebugBox(Layers dbg, Label l, TextItem ti, int overlaps, boolean prev,
|
||||||
|
float scale) {
|
||||||
|
|
||||||
|
LineLayer ll;
|
||||||
|
if (prev) {
|
||||||
|
if (overlaps == 1)
|
||||||
|
ll = (LineLayer) dbg.getLayer(4, Layer.LINE);
|
||||||
|
else
|
||||||
|
ll = (LineLayer) dbg.getLayer(5, Layer.LINE);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (ti.width > ti.length * scale) {
|
||||||
|
ll = (LineLayer) dbg.getLayer(1, Layer.LINE);
|
||||||
|
overlaps = 3;
|
||||||
|
}
|
||||||
|
else if (overlaps == 1)
|
||||||
|
ll = (LineLayer) dbg.getLayer(0, Layer.LINE);
|
||||||
|
else if (overlaps == 2)
|
||||||
|
ll = (LineLayer) dbg.getLayer(3, Layer.LINE);
|
||||||
|
else
|
||||||
|
ll = (LineLayer) dbg.getLayer(2, Layer.LINE);
|
||||||
|
}
|
||||||
|
float[] points = mDebugPoints;
|
||||||
|
float width = (ti.x2 - ti.x1) / 2f;
|
||||||
|
float height = (ti.y2 - ti.y1) / 2f;
|
||||||
|
points[0] = (l.x - width * scale);
|
||||||
|
points[1] = (l.y - height * scale);
|
||||||
|
points[2] = (l.x + width * scale);
|
||||||
|
points[3] = (l.y + height * scale);
|
||||||
|
ll.addLine(points, null, false);
|
||||||
|
|
||||||
|
if (l.bbox != null && overlaps != 3) {
|
||||||
|
ll.addLine(l.bbox.corner, null, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void addDebugLayers(Layers dbg) {
|
||||||
|
dbg.clear();
|
||||||
|
LineLayer ll = (LineLayer) dbg.getLayer(0, Layer.LINE);
|
||||||
|
ll.line = new Line((Color.BLUE & 0xaaffffff), 1, Cap.BUTT);
|
||||||
|
ll.width = 2;
|
||||||
|
ll = (LineLayer) dbg.getLayer(3, Layer.LINE);
|
||||||
|
ll.line = new Line((Color.YELLOW & 0xaaffffff), 1, Cap.BUTT);
|
||||||
|
ll.width = 2;
|
||||||
|
ll = (LineLayer) dbg.getLayer(1, Layer.LINE);
|
||||||
|
ll.line = new Line((Color.RED & 0xaaffffff), 1, Cap.BUTT);
|
||||||
|
ll.width = 2;
|
||||||
|
ll = (LineLayer) dbg.getLayer(2, Layer.LINE);
|
||||||
|
ll.line = new Line((Color.GREEN & 0xaaffffff), 1, Cap.BUTT);
|
||||||
|
ll.width = 2;
|
||||||
|
ll = (LineLayer) dbg.getLayer(4, Layer.LINE);
|
||||||
|
ll.line = new Line((Color.CYAN & 0xaaffffff), 1, Cap.BUTT);
|
||||||
|
ll.width = 2;
|
||||||
|
ll = (LineLayer) dbg.getLayer(5, Layer.LINE);
|
||||||
|
ll.line = new Line((Color.MAGENTA & 0xaaffffff), 1, Cap.BUTT);
|
||||||
|
ll.width = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void update(MapPosition curPos, boolean positionChanged,
|
public synchronized void update(MapPosition curPos, boolean positionChanged,
|
||||||
boolean tilesChanged) {
|
boolean tilesChanged) {
|
||||||
// Log.d("...", "update " + tilesChanged + " " + positionChanged);
|
|
||||||
if (mHolding)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (mCurLayer != null) {
|
if (mNextLayer != null) {
|
||||||
// keep text layer, not recrating its canvas each time
|
// keep text layer, not recrating its canvas each time
|
||||||
mWorkLayer = (TextLayer) layers.textureLayers;
|
mTmpLayer = (TextLayer) layers.textureLayers;
|
||||||
|
|
||||||
// clear textures and text items from previous layer
|
// clear textures and text items from previous layer
|
||||||
layers.clear();
|
layers.clear();
|
||||||
|
|
||||||
if (mDebugLayer != null) {
|
if (mDebugLayer != null) {
|
||||||
layers.baseLayers = mDebugLayer.baseLayers;
|
layers.baseLayers = mDebugLayer.baseLayers;
|
||||||
mDebugLayer.baseLayers = null;
|
mDebugLayer = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set new TextLayer to be uploaded and used
|
// set new TextLayer to be uploaded and rendered
|
||||||
layers.textureLayers = mCurLayer;
|
layers.textureLayers = mNextLayer;
|
||||||
|
|
||||||
mCurLayer = null;
|
|
||||||
|
|
||||||
// make the 'labeled' MapPosition current
|
// make the 'labeled' MapPosition current
|
||||||
MapPosition tmp = mMapPosition;
|
MapPosition tmp = mMapPosition;
|
||||||
mMapPosition = mWorkPos;
|
mMapPosition = mTmpPos;
|
||||||
mWorkPos = tmp;
|
mTmpPos = tmp;
|
||||||
|
|
||||||
// TODO should return true instead
|
|
||||||
newData = true;
|
newData = true;
|
||||||
|
mNextLayer = null;
|
||||||
|
if (!(positionChanged || tilesChanged))
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tilesChanged || positionChanged) {
|
if (mHolding)
|
||||||
if (!mRun) {
|
return;
|
||||||
mRun = true;
|
|
||||||
synchronized (mThread) {
|
if (!mRun) {
|
||||||
mThread.notify();
|
mRun = true;
|
||||||
|
synchronized (mThread) {
|
||||||
|
mThread.notify();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void compile() {
|
||||||
|
int newSize = layers.getSize();
|
||||||
|
|
||||||
|
if (newSize == 0) {
|
||||||
|
isReady = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (layers.vbo == null) {
|
||||||
|
layers.vbo = BufferObject.get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newSize > 0) {
|
||||||
|
if (GLRenderer.uploadLayers(layers, newSize, true))
|
||||||
|
isReady = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void render(MapPosition pos, Matrices m) {
|
||||||
|
float div = FastMath.pow(mMapPosition.zoomLevel - pos.zoomLevel);
|
||||||
|
|
||||||
|
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, layers.vbo.id);
|
||||||
|
GLState.test(false, false);
|
||||||
|
|
||||||
|
if (layers.baseLayers != null) {
|
||||||
|
setMatrix(pos, m, true);
|
||||||
|
|
||||||
|
for (Layer l = layers.baseLayers; l != null;) {
|
||||||
|
if (l.type == Layer.POLYGON) {
|
||||||
|
l = PolygonRenderer.draw(pos, l, m.mvp, true, false);
|
||||||
|
} else {
|
||||||
|
float scale = pos.scale * div;
|
||||||
|
l = LineRenderer.draw(layers, l, pos, m.mvp, scale, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setMatrix(pos, m);
|
||||||
|
for (Layer l = layers.textureLayers; l != null;) {
|
||||||
|
float scale = (mMapPosition.scale / pos.scale) * div;
|
||||||
|
|
||||||
|
l = TextureRenderer.draw(l, scale, m.proj, m.mvp);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -478,6 +722,9 @@ public class TextOverlay extends BasicOverlay {
|
|||||||
|
|
||||||
private boolean mHolding;
|
private boolean mHolding;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param enable layer updates
|
||||||
|
*/
|
||||||
public synchronized void hold(boolean enable) {
|
public synchronized void hold(boolean enable) {
|
||||||
// mHolding = enable;
|
// mHolding = enable;
|
||||||
// if (!enable && !mRun) {
|
// if (!enable && !mRun) {
|
||||||
@ -485,6 +732,7 @@ public class TextOverlay extends BasicOverlay {
|
|||||||
// synchronized (mThread) {
|
// synchronized (mThread) {
|
||||||
// mThread.notify();
|
// mThread.notify();
|
||||||
// }
|
// }
|
||||||
|
// }
|
||||||
// } else {
|
// } else {
|
||||||
// mRun = false;
|
// mRun = false;
|
||||||
// }
|
// }
|
||||||
|
|||||||
@ -1,740 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.renderer.overlays;
|
|
||||||
|
|
||||||
// TODO
|
|
||||||
// 1. rewrite :)
|
|
||||||
// 1.1 test if label is actually visible
|
|
||||||
// 2. compare previous to current state
|
|
||||||
// 2.1 test for new labels to be placed
|
|
||||||
// 2.2 handle collisions
|
|
||||||
// 3 join segments that belong to one feature
|
|
||||||
// 4 handle zoom-level changes
|
|
||||||
// 5 R-Tree might be handy
|
|
||||||
//
|
|
||||||
|
|
||||||
import org.oscim.core.MapPosition;
|
|
||||||
import org.oscim.core.Tile;
|
|
||||||
import org.oscim.renderer.BufferObject;
|
|
||||||
import org.oscim.renderer.GLRenderer;
|
|
||||||
import org.oscim.renderer.GLRenderer.Matrices;
|
|
||||||
import org.oscim.renderer.GLState;
|
|
||||||
import org.oscim.renderer.LineRenderer;
|
|
||||||
import org.oscim.renderer.MapTile;
|
|
||||||
import org.oscim.renderer.PolygonRenderer;
|
|
||||||
import org.oscim.renderer.TextureRenderer;
|
|
||||||
import org.oscim.renderer.TileSet;
|
|
||||||
import org.oscim.renderer.layer.Layer;
|
|
||||||
import org.oscim.renderer.layer.Layers;
|
|
||||||
import org.oscim.renderer.layer.LineLayer;
|
|
||||||
import org.oscim.renderer.layer.TextItem;
|
|
||||||
import org.oscim.renderer.layer.TextLayer;
|
|
||||||
import org.oscim.theme.renderinstruction.Line;
|
|
||||||
import org.oscim.utils.FastMath;
|
|
||||||
import org.oscim.utils.GlUtils;
|
|
||||||
import org.oscim.utils.OBB2D;
|
|
||||||
import org.oscim.utils.PausableThread;
|
|
||||||
import org.oscim.view.MapView;
|
|
||||||
import org.oscim.view.MapViewPosition;
|
|
||||||
|
|
||||||
import android.graphics.Color;
|
|
||||||
import android.graphics.Paint.Cap;
|
|
||||||
import android.opengl.GLES20;
|
|
||||||
import android.opengl.Matrix;
|
|
||||||
import android.os.SystemClock;
|
|
||||||
|
|
||||||
public class TextOverlayExp extends BasicOverlay {
|
|
||||||
private final static String TAG = TextOverlayExp.class.getName();
|
|
||||||
|
|
||||||
private final MapViewPosition mMapViewPosition;
|
|
||||||
private TileSet mTileSet;
|
|
||||||
private final LabelThread mThread;
|
|
||||||
|
|
||||||
private MapPosition mTmpPos;
|
|
||||||
|
|
||||||
// TextLayer that is updating
|
|
||||||
private TextLayer mTmpLayer;
|
|
||||||
// TextLayer that is ready to be added to 'layers'
|
|
||||||
private TextLayer mNextLayer;
|
|
||||||
|
|
||||||
// local pool, avoids synchronized TextItem.get()/release()
|
|
||||||
private Label mPool;
|
|
||||||
private Label mPrevLabels;
|
|
||||||
|
|
||||||
private final float[] mTmpCoords = new float[8];
|
|
||||||
|
|
||||||
//private HashMap<MapTile, Label> mItemMap;
|
|
||||||
//private Label mNewLabels;
|
|
||||||
//private final HashMap<MapTile, Link> mActiveTiles;
|
|
||||||
|
|
||||||
class Label extends TextItem {
|
|
||||||
TextItem item;
|
|
||||||
|
|
||||||
//Link blocking;
|
|
||||||
//Link blockedBy;
|
|
||||||
// shared list of all label for a tile
|
|
||||||
//Link siblings;
|
|
||||||
|
|
||||||
MapTile tile;
|
|
||||||
|
|
||||||
public byte origin;
|
|
||||||
public int active;
|
|
||||||
public OBB2D bbox;
|
|
||||||
}
|
|
||||||
|
|
||||||
// class Link {
|
|
||||||
// Link next;
|
|
||||||
// Link prev;
|
|
||||||
// Label it;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// class ActiveTile {
|
|
||||||
// MapTile tile;
|
|
||||||
// int activeLabels;
|
|
||||||
// Label labels;
|
|
||||||
// }
|
|
||||||
|
|
||||||
/* package */boolean mRun;
|
|
||||||
|
|
||||||
class LabelThread extends PausableThread {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doWork() {
|
|
||||||
SystemClock.sleep(500);
|
|
||||||
if (!mRun)
|
|
||||||
return;
|
|
||||||
|
|
||||||
mRun = false;
|
|
||||||
|
|
||||||
if (updateLabels()) {
|
|
||||||
mMapView.redrawMap(true);
|
|
||||||
} else {
|
|
||||||
mRun = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String getThreadName() {
|
|
||||||
return "Labeling";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean hasWork() {
|
|
||||||
return mRun;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private float mSquareRadius;
|
|
||||||
private int mRelabelCnt;
|
|
||||||
|
|
||||||
public TextOverlayExp(MapView mapView) {
|
|
||||||
super(mapView);
|
|
||||||
mMapViewPosition = mapView.getMapViewPosition();
|
|
||||||
|
|
||||||
layers.textureLayers = new TextLayer();
|
|
||||||
mTmpLayer = new TextLayer();
|
|
||||||
//mActiveTiles = new HashMap<MapTile, Link>();
|
|
||||||
mTmpPos = new MapPosition();
|
|
||||||
mThread = new LabelThread();
|
|
||||||
mThread.start();
|
|
||||||
|
|
||||||
mRelabelCnt = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Label removeLabel(TextLayer tl, Label l) {
|
|
||||||
Label tmp = l;
|
|
||||||
l = (Label) l.next;
|
|
||||||
|
|
||||||
TextItem.release(tmp.item);
|
|
||||||
tl.removeText(tmp);
|
|
||||||
|
|
||||||
tmp.next = mPool;
|
|
||||||
mPool = tmp;
|
|
||||||
|
|
||||||
return l;
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte checkOverlap(TextLayer tl, Label ti) {
|
|
||||||
|
|
||||||
for (Label lp = (Label) tl.labels; lp != null;) {
|
|
||||||
|
|
||||||
// check bounding box
|
|
||||||
if (!TextItem.bboxOverlaps(ti, lp, 150)) {
|
|
||||||
lp = (Label) lp.next;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lp.text == ti.text && (lp.string == ti.string || lp.string.equals(ti.string))) {
|
|
||||||
|
|
||||||
// make strings unique, should be done only once..
|
|
||||||
ti.string = lp.string;
|
|
||||||
|
|
||||||
// keep the label that was active earlier
|
|
||||||
if (lp.active <= ti.active)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
// keep the label with longer segment
|
|
||||||
if (lp.length < ti.length) {
|
|
||||||
lp = removeLabel(tl, lp);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean intersect = ti.bbox.overlaps(lp.bbox);
|
|
||||||
|
|
||||||
if (intersect) {
|
|
||||||
|
|
||||||
if (lp.active <= ti.active)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
//Log.d(TAG, "intersection " + lp.string + " <> " + ti.string
|
|
||||||
// + " at " + ti.x + ":" + ti.y);
|
|
||||||
|
|
||||||
if (!lp.text.caption
|
|
||||||
&& (lp.text.priority > ti.text.priority || lp.length < ti.length)) {
|
|
||||||
|
|
||||||
lp = removeLabel(tl, lp);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
lp = (Label) lp.next;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean nodeIsVisible(TextItem ti) {
|
|
||||||
// rough filter
|
|
||||||
float dist = ti.x * ti.x + ti.y * ti.y;
|
|
||||||
if (dist > mSquareRadius)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean wayIsVisible(TextItem ti) {
|
|
||||||
// rough filter
|
|
||||||
float dist = ti.x * ti.x + ti.y * ti.y;
|
|
||||||
if (dist < mSquareRadius)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
dist = ti.x1 * ti.x1 + ti.y1 * ti.y1;
|
|
||||||
if (dist < mSquareRadius)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
dist = ti.x2 * ti.x2 + ti.y2 * ti.y2;
|
|
||||||
if (dist < mSquareRadius)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Layers mDebugLayer;
|
|
||||||
private final static float[] mDebugPoints = new float[4];
|
|
||||||
private final float[] mMVP = new float[16];
|
|
||||||
|
|
||||||
void addTile(MapTile t) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private Label addToPool(Label l) {
|
|
||||||
TextItem.release(l.item);
|
|
||||||
l.item = null;
|
|
||||||
|
|
||||||
Label next = (Label) l.next;
|
|
||||||
l.next = mPool;
|
|
||||||
mPool = l;
|
|
||||||
|
|
||||||
return next;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Label getLabel() {
|
|
||||||
Label l;
|
|
||||||
|
|
||||||
if (mPool == null)
|
|
||||||
l = new Label();
|
|
||||||
else {
|
|
||||||
l = mPool;
|
|
||||||
mPool = (Label) mPool.next;
|
|
||||||
l.next = null;
|
|
||||||
}
|
|
||||||
l.active = Integer.MAX_VALUE;
|
|
||||||
|
|
||||||
return l;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean updateLabels() {
|
|
||||||
if (mTmpLayer == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// get current tiles
|
|
||||||
mTileSet = GLRenderer.getVisibleTiles(mTileSet);
|
|
||||||
|
|
||||||
if (mTileSet.cnt == 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// reuse text layer
|
|
||||||
TextLayer tl = mTmpLayer;
|
|
||||||
mTmpLayer = null;
|
|
||||||
|
|
||||||
//mNewLabels = null;
|
|
||||||
|
|
||||||
Layers dbg = null;
|
|
||||||
if (mMapView.getDebugSettings().debugLabels)
|
|
||||||
dbg = new Layers();
|
|
||||||
|
|
||||||
float[] coords = mTmpCoords;
|
|
||||||
MapPosition pos = mTmpPos;
|
|
||||||
|
|
||||||
synchronized (mMapViewPosition) {
|
|
||||||
mMapViewPosition.getMapPosition(pos);
|
|
||||||
mMapViewPosition.getMapViewProjection(coords);
|
|
||||||
mMapViewPosition.getMatrix(null, null, mMVP);
|
|
||||||
}
|
|
||||||
int mw = (mMapView.getWidth() + Tile.TILE_SIZE) / 2;
|
|
||||||
int mh = (mMapView.getHeight() + Tile.TILE_SIZE) / 2;
|
|
||||||
mSquareRadius = mw * mw + mh * mh;
|
|
||||||
|
|
||||||
// mTiles might be from another zoomlevel than the current:
|
|
||||||
// this scales MapPosition to the zoomlevel of mTiles...
|
|
||||||
// TODO create a helper function in MapPosition
|
|
||||||
MapTile[] tiles = mTileSet.tiles;
|
|
||||||
int diff = tiles[0].zoomLevel - pos.zoomLevel;
|
|
||||||
float div = FastMath.pow(diff);
|
|
||||||
float scale = pos.scale * div;
|
|
||||||
|
|
||||||
double angle = Math.toRadians(pos.angle);
|
|
||||||
float cos = (float) Math.cos(angle);
|
|
||||||
float sin = (float) Math.sin(angle);
|
|
||||||
|
|
||||||
int maxx = Tile.TILE_SIZE << (pos.zoomLevel - 1);
|
|
||||||
|
|
||||||
Label l = null;
|
|
||||||
|
|
||||||
if (dbg != null)
|
|
||||||
addDebugLayers(dbg);
|
|
||||||
|
|
||||||
mRelabelCnt++;
|
|
||||||
|
|
||||||
for (l = mPrevLabels; l != null;) {
|
|
||||||
|
|
||||||
// transform screen coordinates to tile coordinates
|
|
||||||
float s = FastMath.pow(l.tile.zoomLevel - pos.zoomLevel);
|
|
||||||
float sscale = pos.scale / s;
|
|
||||||
|
|
||||||
if (l.width > l.length * sscale) {
|
|
||||||
//Log.d(TAG, "- scale " + lp + " " + s + " " + sscale + " " + lp.length + " " + lp.width);
|
|
||||||
l = addToPool(l);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
float dx = (float) (l.tile.pixelX - pos.x * s);
|
|
||||||
float dy = (float) (l.tile.pixelY - pos.y * s);
|
|
||||||
|
|
||||||
// flip around date-line
|
|
||||||
if (dx > maxx)
|
|
||||||
dx = dx - maxx * 2;
|
|
||||||
else if (dx < -maxx)
|
|
||||||
dx = dx + maxx * 2;
|
|
||||||
|
|
||||||
l.move(l.item, dx, dy, sscale);
|
|
||||||
|
|
||||||
if (!l.text.caption) {
|
|
||||||
// set line endpoints relative to view to be able to
|
|
||||||
// check intersections with label from other tiles
|
|
||||||
float width = (l.item.x2 - l.item.x1) / 2f;
|
|
||||||
float height = (l.item.y2 - l.item.y1) / 2f;
|
|
||||||
|
|
||||||
l.x2 = (l.x + width);
|
|
||||||
l.x1 = (l.x - width);
|
|
||||||
l.y2 = (l.y + height);
|
|
||||||
l.y1 = (l.y - height);
|
|
||||||
|
|
||||||
if (!wayIsVisible(l)) {
|
|
||||||
l = addToPool(l);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte overlaps = -1;
|
|
||||||
|
|
||||||
l.bbox.set(l.x, l.y, l.x1, l.y1, l.width + 5, l.text.fontHeight + 5);
|
|
||||||
|
|
||||||
overlaps = checkOverlap(tl, l);
|
|
||||||
|
|
||||||
if (dbg != null)
|
|
||||||
addDebugBox(dbg, l, l.item, overlaps, true, sscale);
|
|
||||||
|
|
||||||
if (overlaps == 0) {
|
|
||||||
|
|
||||||
Label tmp = l;
|
|
||||||
l = (Label) l.next;
|
|
||||||
|
|
||||||
tmp.next = null;
|
|
||||||
tl.addText(tmp);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
l = addToPool(l);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* add way labels */
|
|
||||||
for (int i = 0, n = mTileSet.cnt; i < n; i++) {
|
|
||||||
|
|
||||||
MapTile t = tiles[i];
|
|
||||||
|
|
||||||
float dx = (float) (t.pixelX - pos.x);
|
|
||||||
float dy = (float) (t.pixelY - pos.y);
|
|
||||||
|
|
||||||
// flip around date-line
|
|
||||||
if (dx > maxx)
|
|
||||||
dx = dx - maxx * 2;
|
|
||||||
else if (dx < -maxx)
|
|
||||||
dx = dx + maxx * 2;
|
|
||||||
|
|
||||||
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, scale);
|
|
||||||
|
|
||||||
// set line endpoints relative to view to be able to
|
|
||||||
// check intersections with label from other tiles
|
|
||||||
float width = (ti.x2 - ti.x1) / 2f;
|
|
||||||
float height = (ti.y2 - ti.y1) / 2f;
|
|
||||||
l.bbox = null;
|
|
||||||
l.x1 = (l.x - width);
|
|
||||||
l.y1 = (l.y - height);
|
|
||||||
l.x2 = (l.x + width);
|
|
||||||
l.y2 = (l.y + height);
|
|
||||||
|
|
||||||
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 + 5, l.text.fontHeight + 5);
|
|
||||||
else
|
|
||||||
l.bbox.set(l.x, l.y, l.x1, l.y1, l.width + 5, l.text.fontHeight + 5);
|
|
||||||
|
|
||||||
if (dbg == null || ti.width < ti.length * scale)
|
|
||||||
overlaps = checkOverlap(tl, l);
|
|
||||||
|
|
||||||
if (dbg != null)
|
|
||||||
addDebugBox(dbg, l, ti, overlaps, false, scale);
|
|
||||||
|
|
||||||
if (overlaps == 0) {
|
|
||||||
tl.addText(l);
|
|
||||||
l.item = TextItem.copy(ti);
|
|
||||||
l.tile = t;
|
|
||||||
l.active = mRelabelCnt;
|
|
||||||
l = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* add caption */
|
|
||||||
for (int i = 0, n = mTileSet.cnt; i < n; i++) {
|
|
||||||
|
|
||||||
MapTile t = tiles[i];
|
|
||||||
|
|
||||||
float dx = (float) (t.pixelX - pos.x);
|
|
||||||
float dy = (float) (t.pixelY - pos.y);
|
|
||||||
|
|
||||||
// flip around date-line
|
|
||||||
if (dx > maxx)
|
|
||||||
dx = dx - maxx * 2;
|
|
||||||
else if (dx < -maxx)
|
|
||||||
dx = dx + maxx * 2;
|
|
||||||
|
|
||||||
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, 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 + 6,
|
|
||||||
l.text.fontHeight + 6);
|
|
||||||
|
|
||||||
boolean overlaps = false;
|
|
||||||
for (Label lp = (Label) tl.labels; lp != null; lp = (Label) lp.next) {
|
|
||||||
|
|
||||||
if (l.bbox.overlaps(lp.bbox)) {
|
|
||||||
//Log.d(TAG, "overlap > " + ti2.string + " " + lp.string);
|
|
||||||
//if (TextItem.bboxOverlaps(ti2, lp, 4)) {
|
|
||||||
overlaps = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!overlaps) {
|
|
||||||
tl.addText(l);
|
|
||||||
l.item = TextItem.copy(ti);
|
|
||||||
l.tile = t;
|
|
||||||
l.active = mRelabelCnt;
|
|
||||||
l = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Label ti = (Label) tl.labels; ti != null; ti = (Label) ti.next) {
|
|
||||||
|
|
||||||
if (ti.text.caption)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// flip label upside-down
|
|
||||||
if (cos * (ti.x2 - ti.x1) - sin * (ti.y2 - ti.y1) < 0) {
|
|
||||||
float tmp = ti.x1;
|
|
||||||
ti.x1 = ti.x2;
|
|
||||||
ti.x2 = tmp;
|
|
||||||
|
|
||||||
tmp = ti.y1;
|
|
||||||
ti.y1 = ti.y2;
|
|
||||||
ti.y2 = tmp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// keep temporarily used Label
|
|
||||||
if (l != null) {
|
|
||||||
l.next = mPool;
|
|
||||||
mPool = l;
|
|
||||||
}
|
|
||||||
|
|
||||||
// draw text to bitmaps and create vertices
|
|
||||||
tl.prepare();
|
|
||||||
|
|
||||||
// after 'prepare' TextLayer does not need TextItems any longer
|
|
||||||
mPrevLabels = (Label) tl.labels;
|
|
||||||
tl.labels = null;
|
|
||||||
|
|
||||||
// remove tile locks
|
|
||||||
GLRenderer.releaseTiles(mTileSet);
|
|
||||||
|
|
||||||
// pass new labels for rendering
|
|
||||||
synchronized (this) {
|
|
||||||
mNextLayer = tl;
|
|
||||||
mDebugLayer = dbg;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void addDebugBox(Layers dbg, Label l, TextItem ti, int overlaps, boolean prev,
|
|
||||||
float scale) {
|
|
||||||
|
|
||||||
LineLayer ll;
|
|
||||||
if (prev) {
|
|
||||||
if (overlaps == 1)
|
|
||||||
ll = (LineLayer) dbg.getLayer(4, Layer.LINE);
|
|
||||||
else
|
|
||||||
ll = (LineLayer) dbg.getLayer(5, Layer.LINE);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
if (ti.width > ti.length * scale) {
|
|
||||||
ll = (LineLayer) dbg.getLayer(1, Layer.LINE);
|
|
||||||
overlaps = 3;
|
|
||||||
}
|
|
||||||
else if (overlaps == 1)
|
|
||||||
ll = (LineLayer) dbg.getLayer(0, Layer.LINE);
|
|
||||||
else if (overlaps == 2)
|
|
||||||
ll = (LineLayer) dbg.getLayer(3, Layer.LINE);
|
|
||||||
else
|
|
||||||
ll = (LineLayer) dbg.getLayer(2, Layer.LINE);
|
|
||||||
}
|
|
||||||
float[] points = mDebugPoints;
|
|
||||||
float width = (ti.x2 - ti.x1) / 2f;
|
|
||||||
float height = (ti.y2 - ti.y1) / 2f;
|
|
||||||
points[0] = (l.x - width * scale);
|
|
||||||
points[1] = (l.y - height * scale);
|
|
||||||
points[2] = (l.x + width * scale);
|
|
||||||
points[3] = (l.y + height * scale);
|
|
||||||
ll.addLine(points, null, false);
|
|
||||||
|
|
||||||
if (l.bbox != null && overlaps != 3) {
|
|
||||||
ll.addLine(l.bbox.corner, null, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void addDebugLayers(Layers dbg) {
|
|
||||||
dbg.clear();
|
|
||||||
LineLayer ll = (LineLayer) dbg.getLayer(0, Layer.LINE);
|
|
||||||
ll.line = new Line((Color.BLUE & 0xaaffffff), 1, Cap.BUTT);
|
|
||||||
ll.width = 2;
|
|
||||||
ll = (LineLayer) dbg.getLayer(3, Layer.LINE);
|
|
||||||
ll.line = new Line((Color.YELLOW & 0xaaffffff), 1, Cap.BUTT);
|
|
||||||
ll.width = 2;
|
|
||||||
ll = (LineLayer) dbg.getLayer(1, Layer.LINE);
|
|
||||||
ll.line = new Line((Color.RED & 0xaaffffff), 1, Cap.BUTT);
|
|
||||||
ll.width = 2;
|
|
||||||
ll = (LineLayer) dbg.getLayer(2, Layer.LINE);
|
|
||||||
ll.line = new Line((Color.GREEN & 0xaaffffff), 1, Cap.BUTT);
|
|
||||||
ll.width = 2;
|
|
||||||
ll = (LineLayer) dbg.getLayer(4, Layer.LINE);
|
|
||||||
ll.line = new Line((Color.CYAN & 0xaaffffff), 1, Cap.BUTT);
|
|
||||||
ll.width = 2;
|
|
||||||
ll = (LineLayer) dbg.getLayer(5, Layer.LINE);
|
|
||||||
ll.line = new Line((Color.MAGENTA & 0xaaffffff), 1, Cap.BUTT);
|
|
||||||
ll.width = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized void update(MapPosition curPos, boolean positionChanged,
|
|
||||||
boolean tilesChanged) {
|
|
||||||
|
|
||||||
if (mNextLayer != null) {
|
|
||||||
// keep text layer, not recrating its canvas each time
|
|
||||||
mTmpLayer = (TextLayer) layers.textureLayers;
|
|
||||||
|
|
||||||
// clear textures and text items from previous layer
|
|
||||||
layers.clear();
|
|
||||||
|
|
||||||
if (mDebugLayer != null) {
|
|
||||||
layers.baseLayers = mDebugLayer.baseLayers;
|
|
||||||
mDebugLayer = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// set new TextLayer to be uploaded and rendered
|
|
||||||
layers.textureLayers = mNextLayer;
|
|
||||||
|
|
||||||
// make the 'labeled' MapPosition current
|
|
||||||
MapPosition tmp = mMapPosition;
|
|
||||||
mMapPosition = mTmpPos;
|
|
||||||
mTmpPos = tmp;
|
|
||||||
|
|
||||||
newData = true;
|
|
||||||
mNextLayer = null;
|
|
||||||
if (!(positionChanged || tilesChanged))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mHolding)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!mRun) {
|
|
||||||
mRun = true;
|
|
||||||
synchronized (mThread) {
|
|
||||||
mThread.notify();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void compile() {
|
|
||||||
int newSize = layers.getSize();
|
|
||||||
|
|
||||||
if (newSize == 0) {
|
|
||||||
isReady = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (layers.vbo == null) {
|
|
||||||
layers.vbo = BufferObject.get(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newSize > 0) {
|
|
||||||
if (GLRenderer.uploadLayers(layers, newSize, true))
|
|
||||||
isReady = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized void render(MapPosition pos, Matrices m) {
|
|
||||||
float div = FastMath.pow(mMapPosition.zoomLevel - pos.zoomLevel);
|
|
||||||
|
|
||||||
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, layers.vbo.id);
|
|
||||||
GLState.test(false, false);
|
|
||||||
|
|
||||||
if (layers.baseLayers != null) {
|
|
||||||
setMatrix(pos, m, true);
|
|
||||||
|
|
||||||
for (Layer l = layers.baseLayers; l != null;) {
|
|
||||||
if (l.type == Layer.POLYGON) {
|
|
||||||
l = PolygonRenderer.draw(pos, l, m.mvp, true, false);
|
|
||||||
} else {
|
|
||||||
float scale = pos.scale * div;
|
|
||||||
l = LineRenderer.draw(layers, l, pos, m.mvp, scale, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setMatrix(pos, m);
|
|
||||||
for (Layer l = layers.textureLayers; l != null;) {
|
|
||||||
float scale = (mMapPosition.scale / pos.scale) * div;
|
|
||||||
|
|
||||||
l = TextureRenderer.draw(l, scale, m.proj, m.mvp);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void setMatrix(MapPosition curPos, Matrices m) {
|
|
||||||
MapPosition oPos = mMapPosition;
|
|
||||||
|
|
||||||
float div = FastMath.pow(oPos.zoomLevel - curPos.zoomLevel);
|
|
||||||
float x = (float) (oPos.x - curPos.x * div);
|
|
||||||
float y = (float) (oPos.y - curPos.y * div);
|
|
||||||
|
|
||||||
float scale = (curPos.scale / mMapPosition.scale) / div;
|
|
||||||
float s = curPos.scale / div;
|
|
||||||
GlUtils.setMatrix(m.mvp, x * s, y * s,
|
|
||||||
scale / GLRenderer.COORD_MULTIPLIER);
|
|
||||||
|
|
||||||
Matrix.multiplyMM(m.mvp, 0, m.view, 0, m.mvp, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean mHolding;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param enable layer updates
|
|
||||||
*/
|
|
||||||
public synchronized void hold(boolean enable) {
|
|
||||||
// mHolding = enable;
|
|
||||||
// if (!enable && !mRun) {
|
|
||||||
// mRun = true;
|
|
||||||
// synchronized (mThread) {
|
|
||||||
// mThread.notify();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// mRun = false;
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
x
Reference in New Issue
Block a user