diff --git a/vtm-gdx-html/src/org/oscim/gdx/emu/org/oscim/layers/tile/vector/VectorTileLoader.java b/vtm-gdx-html/src/org/oscim/gdx/emu/org/oscim/layers/tile/vector/VectorTileLoader.java
index a72a2aee..60ad366f 100644
--- a/vtm-gdx-html/src/org/oscim/gdx/emu/org/oscim/layers/tile/vector/VectorTileLoader.java
+++ b/vtm-gdx-html/src/org/oscim/gdx/emu/org/oscim/layers/tile/vector/VectorTileLoader.java
@@ -22,7 +22,6 @@ import org.oscim.core.PointF;
import org.oscim.core.Tag;
import org.oscim.core.TagSet;
import org.oscim.core.Tile;
-import org.oscim.layers.tile.vector.labeling.WayDecorator;
import org.oscim.renderer.elements.ElementLayers;
import org.oscim.renderer.elements.ExtrusionLayer;
import org.oscim.renderer.elements.LineLayer;
diff --git a/vtm/src/org/oscim/layers/tile/vector/VectorTileLoader.java b/vtm/src/org/oscim/layers/tile/vector/VectorTileLoader.java
index 3aadc0b4..bc584d4a 100644
--- a/vtm/src/org/oscim/layers/tile/vector/VectorTileLoader.java
+++ b/vtm/src/org/oscim/layers/tile/vector/VectorTileLoader.java
@@ -26,7 +26,6 @@ import org.oscim.core.PointF;
import org.oscim.core.Tag;
import org.oscim.core.TagSet;
import org.oscim.core.Tile;
-import org.oscim.layers.tile.vector.labeling.WayDecorator;
import org.oscim.renderer.elements.ElementLayers;
import org.oscim.renderer.elements.ExtrusionLayer;
import org.oscim.renderer.elements.LineLayer;
diff --git a/vtm/src/org/oscim/layers/tile/vector/labeling/WayDecorator.java b/vtm/src/org/oscim/layers/tile/vector/WayDecorator.java
similarity index 70%
rename from vtm/src/org/oscim/layers/tile/vector/labeling/WayDecorator.java
rename to vtm/src/org/oscim/layers/tile/vector/WayDecorator.java
index a3248b2a..060c6432 100644
--- a/vtm/src/org/oscim/layers/tile/vector/labeling/WayDecorator.java
+++ b/vtm/src/org/oscim/layers/tile/vector/WayDecorator.java
@@ -15,7 +15,7 @@
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see .
*/
-package org.oscim.layers.tile.vector.labeling;
+package org.oscim.layers.tile.vector;
import org.oscim.core.Tile;
import org.oscim.renderer.elements.TextItem;
@@ -32,11 +32,11 @@ public final class WayDecorator {
TextItem t = null;
// calculate the way name length plus some margin of safety
- float wayNameWidth = -1;
+ float labelWidth = -1;
float minWidth = Tile.SIZE / 10;
- final int min = 0;
- final int max = Tile.SIZE;
+ //final int min = 0;
+ //final int max = Tile.SIZE;
// find way segments long enough to draw the way name on them
for (int i = pos; i < pos + len - 2; i += 2) {
@@ -45,42 +45,41 @@ public final class WayDecorator {
float prevY = coordinates[i + 1];
byte edge = 0;
-
- clipper.clipStart(prevX, prevY);
+ //clipper.clipStart(prevX, prevY);
// get the current way point coordinates
float curX = coordinates[i + 2];
float curY = coordinates[i + 3];
- int clip;
- if ((clip = clipper.clipNext(curX, curY)) != 0) {
- if (clip < 0) {
- prevX = clipper.out[0];
- prevY = clipper.out[1];
- curX = clipper.out[2];
- curY = clipper.out[3];
-
- if (prevX == min)
- edge |= 1 << 0;
- else if (prevX == max)
- edge |= 1 << 1;
-
- if (prevY == min)
- edge |= 1 << 2;
- else if (prevY == max)
- edge |= 1 << 3;
-
- if (curX == min)
- edge |= 1 << 4;
- else if (curX == max)
- edge |= 1 << 5;
-
- if (curY == min)
- edge |= 1 << 5;
- else if (curY == max)
- edge |= 1 << 6;
- }
- }
+ //int clip;
+ //if ((clip = clipper.clipNext(curX, curY)) != 0) {
+ // if (clip < 0) {
+ // prevX = clipper.out[0];
+ // prevY = clipper.out[1];
+ // curX = clipper.out[2];
+ // curY = clipper.out[3];
+ //
+ // if (prevX == min)
+ // edge |= 1 << 0;
+ // else if (prevX == max)
+ // edge |= 1 << 1;
+ //
+ // if (prevY == min)
+ // edge |= 1 << 2;
+ // else if (prevY == max)
+ // edge |= 1 << 3;
+ //
+ // if (curX == min)
+ // edge |= 1 << 4;
+ // else if (curX == max)
+ // edge |= 1 << 5;
+ //
+ // if (curY == min)
+ // edge |= 1 << 5;
+ // else if (curY == max)
+ // edge |= 1 << 6;
+ // }
+ //}
int last = i;
@@ -102,15 +101,15 @@ public final class WayDecorator {
float nextX = coordinates[j + 0];
float nextY = coordinates[j + 1];
- if ((clip = clipper.clipNext(nextX, nextY)) != 0) {
- if (clip < 0) {
- curX = clipper.out[0];
- curY = clipper.out[1];
- // TODO break when cur has changed
- nextX = clipper.out[2];
- nextY = clipper.out[3];
- }
- }
+ //if ((clip = clipper.clipNext(nextX, nextY)) != 0) {
+ // if (clip < 0) {
+ // curX = clipper.out[0];
+ // curY = clipper.out[1];
+ // // TODO break when cur has changed
+ // nextX = clipper.out[2];
+ // nextY = clipper.out[3];
+ // }
+ //}
float wx = nextX - curX;
float wy = nextY - curY;
@@ -147,17 +146,17 @@ public final class WayDecorator {
curY = nextY;
last = j - 2;
- if (clip < 0) {
- if (nextX == min)
- edge |= 1 << 4;
- else if (nextX == max)
- edge |= 1 << 5;
-
- if (nextY == min)
- edge |= 1 << 6;
- else if (nextY == max)
- edge |= 1 << 7;
- }
+ //if (clip < 0) {
+ // if (nextX == min)
+ // edge |= 1 << 4;
+ // else if (nextX == max)
+ // edge |= 1 << 5;
+ //
+ // if (nextY == min)
+ // edge |= 1 << 6;
+ // else if (nextY == max)
+ // edge |= 1 << 7;
+ //}
}
vx = curX - prevX;
@@ -172,15 +171,15 @@ public final class WayDecorator {
continue;
}
- if (wayNameWidth < 0) {
- wayNameWidth = text.paint.measureText(string);
+ if (labelWidth < 0) {
+ labelWidth = text.paint.measureText(string);
}
- if (segmentLength < wayNameWidth * 0.50) {
+ if (segmentLength < labelWidth * 0.50) {
continue;
}
- } else if (wayNameWidth < 0) {
- wayNameWidth = text.paint.measureText(string);
+ } else if (labelWidth < 0) {
+ labelWidth = text.paint.measureText(string);
}
float x1, y1, x2, y2;
@@ -199,17 +198,17 @@ public final class WayDecorator {
TextItem n = TextItem.pool.get();
// link items together
- if (t != null) {
- t.n1 = n;
- n.n2 = t;
- }
+ //if (t != null) {
+ // t.n1 = n;
+ // n.n2 = t;
+ //}
t = n;
t.x = x1 + (x2 - x1) / 2f;
t.y = y1 + (y2 - y1) / 2f;
t.string = string;
t.text = text;
- t.width = wayNameWidth;
+ t.width = labelWidth;
t.x1 = x1;
t.y1 = y1;
t.x2 = x2;
diff --git a/vtm/src/org/oscim/layers/tile/vector/labeling/Debug.java b/vtm/src/org/oscim/layers/tile/vector/labeling/Debug.java
index 8c0932b0..b3fdf70c 100644
--- a/vtm/src/org/oscim/layers/tile/vector/labeling/Debug.java
+++ b/vtm/src/org/oscim/layers/tile/vector/labeling/Debug.java
@@ -17,6 +17,8 @@
package org.oscim.layers.tile.vector.labeling;
import org.oscim.backend.canvas.Color;
+import org.oscim.core.MapPosition;
+import org.oscim.renderer.MapRenderer.Matrices;
import org.oscim.renderer.elements.ElementLayers;
import org.oscim.renderer.elements.LineLayer;
import org.oscim.renderer.elements.TextItem;
@@ -25,8 +27,10 @@ import org.oscim.theme.styles.Line;
class Debug {
private final static float[] mDebugPoints = new float[8];
+ // TODO Auto-generated method stub
+ static ElementLayers dbg;
- static void addDebugBox(ElementLayers dbg, Label l, TextItem ti, int overlaps, boolean prev,
+ static void addDebugBox(Label l, TextItem ti, int overlaps, boolean prev,
float scale) {
LineLayer ll;
@@ -75,4 +79,19 @@ class Debug {
dbg.addLineLayer(5, new Line((Color.MAGENTA & alpha), 2));
}
+ public static void draw(MapPosition pos, Matrices m, ElementLayers layers) {
+ // if (layers.baseLayers != null) {
+ // //setMatrix(pos, m, true);
+ //
+ // for (RenderElement l = layers.baseLayers; l != null;) {
+ // if (l.type == RenderElement.POLYGON) {
+ // l = PolygonLayer.Renderer.draw(pos, l, m, true, 1, false);
+ // } else {
+ // //float div = (float) (mMapPosition.scale / (1 << pos.zoomLevel));
+ // l = LineLayer.Renderer.draw(layers, l, pos, m, div);
+ // }
+ // }
+ // }
+ }
+
}
diff --git a/vtm/src/org/oscim/layers/tile/vector/labeling/Label.java b/vtm/src/org/oscim/layers/tile/vector/labeling/Label.java
index 56bfced5..d95a301b 100644
--- a/vtm/src/org/oscim/layers/tile/vector/labeling/Label.java
+++ b/vtm/src/org/oscim/layers/tile/vector/labeling/Label.java
@@ -17,10 +17,9 @@
package org.oscim.layers.tile.vector.labeling;
import org.oscim.renderer.elements.TextItem;
-import org.oscim.tiling.MapTile;
import org.oscim.utils.OBB2D;
-class Label extends TextItem {
+final class Label extends TextItem {
TextItem item;
//Link blocking;
@@ -28,34 +27,75 @@ class Label extends TextItem {
// shared list of all label for a tile
//Link siblings;
- MapTile tile;
+ int tileX;
+ int tileY;
+ int tileZ;
- //public byte origin;
public int active;
public OBB2D bbox;
- public TextItem move(TextItem ti, float dx, float dy, float scale) {
- this.x = (dx + ti.x) * scale;
- this.y = (dy + ti.y) * scale;
- return this;
- }
-
- public void clone(TextItem ti) {
+ public Label clone(TextItem ti) {
this.string = ti.string;
this.text = ti.text;
this.width = ti.width;
this.length = ti.length;
- }
-
- public void setAxisAlignedBBox() {
- this.x1 = x - width / 2;
- this.y1 = y - text.fontHeight / 2;
- this.x2 = x + width / 2;
- this.y2 = y + text.fontHeight / 2;
+ return this;
}
static int comparePriority(Label l1, Label l2) {
return 0;
}
+
+ public static boolean shareText(Label l, Label ll) {
+ if (l.text != ll.text)
+ return false;
+
+ if (l.string == ll.string)
+ return true;
+
+ if (l.string.equals(ll.string)) {
+ // make strings unique, should be done only once..
+ l.string = ll.string;
+ return true;
+ }
+
+ return false;
+ }
+
+ public static boolean bboxOverlaps(TextItem it1, TextItem it2, float add) {
+ if (it1.y1 < it1.y2) {
+ if (it2.y1 < it2.y2)
+ return (it1.x1 - add < it2.x2)
+ && (it2.x1 < it1.x2 + add)
+ && (it1.y1 - add < it2.y2)
+ && (it2.y1 < it1.y2 + add);
+
+ // flip it2
+ return (it1.x1 - add < it2.x2)
+ && (it2.x1 < it1.x2 + add)
+ && (it1.y1 - add < it2.y1)
+ && (it2.y2 < it1.y2 + add);
+ }
+
+ // flip it1
+ if (it2.y1 < it2.y2)
+ return (it1.x1 - add < it2.x2)
+ && (it2.x1 < it1.x2 + add)
+ && (it1.y2 - add < it2.y2)
+ && (it2.y1 < it1.y1 + add);
+
+ // flip both
+ return (it1.x1 - add < it2.x2)
+ && (it2.x1 < it1.x2 + add)
+ && (it1.y2 - add < it2.y1)
+ && (it2.y2 < it1.y1 + add);
+ }
+
+ public void setAxisAlignedBBox() {
+ this.x1 = (int) (x - width / 2);
+ this.y1 = (int) (y - text.fontHeight / 2);
+ this.x2 = (int) (x + width / 2);
+ this.y2 = (int) (y + text.fontHeight / 2);
+ }
}
diff --git a/vtm/src/org/oscim/layers/tile/vector/labeling/LabelLayer.java b/vtm/src/org/oscim/layers/tile/vector/labeling/LabelLayer.java
index dd336e34..230113b6 100644
--- a/vtm/src/org/oscim/layers/tile/vector/labeling/LabelLayer.java
+++ b/vtm/src/org/oscim/layers/tile/vector/labeling/LabelLayer.java
@@ -21,32 +21,83 @@ import org.oscim.event.MotionEvent;
import org.oscim.layers.Layer;
import org.oscim.map.Map;
import org.oscim.tiling.TileRenderer;
+import org.oscim.utils.async.SimpleWorker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LabelLayer extends Layer implements Map.InputListener, Map.UpdateListener {
static final Logger log = LoggerFactory.getLogger(LabelLayer.class);
- private final TextRenderer mTextRenderer;
- //private int multi;
+ private final static long MAX_RELABEL_DELAY = 100;
- public LabelLayer(Map map, TileRenderer tileRenderLayer) {
+ private final LabelPlacement mLabelPlacer;
+ private final Worker mWorker;
+
+ public LabelLayer(Map map, TileRenderer tileRenderer) {
super(map);
+ mLabelPlacer = new LabelPlacement(map, tileRenderer);
+ mWorker = new Worker(map);
+ mRenderer = new TextRenderer(mWorker);
+ }
- //mTextLayer = new org.oscim.renderer.layers.TextRenderLayer(map, tileRenderLayer);
- mTextRenderer = new TextRenderer(map, tileRenderLayer);
- mRenderer = mTextRenderer;
+ class Worker extends SimpleWorker {
+
+ public Worker(Map map) {
+ super(map, 50, new LabelTask(), new LabelTask());
+ }
+
+ @Override
+ public boolean doWork(LabelTask t) {
+
+ if (mLabelPlacer.updateLabels(t)) {
+ mMap.render();
+ return true;
+ }
+
+ return false;
+ }
+
+ @Override
+ public void cleanup(LabelTask t) {
+ }
+
+ @Override
+ public void finish() {
+ mLabelPlacer.cleanup();
+ }
+
+ public synchronized boolean isRunning() {
+ return mRunning;
+ }
+ }
+
+ public void clearLabels() {
+ mWorker.cancel(true);
+ }
+
+ public void update() {
+ mWorker.submit(MAX_RELABEL_DELAY);
}
@Override
public void onDetach() {
// TODO stop and clear labeling thread
log.debug("DETACH");
- mTextRenderer.clearLabels();
+
+ // clear labels
+ mWorker.cancel(true);
super.onDetach();
}
+ @Override
+ public void onMapUpdate(MapPosition mapPosition, boolean changed, boolean clear) {
+ if (clear)
+ mWorker.cancel(true);
+
+ mWorker.submit(MAX_RELABEL_DELAY);
+ }
+
@Override
public void onMotionEvent(MotionEvent e) {
// int action = e.getAction() & MotionEvent.ACTION_MASK;
@@ -64,31 +115,4 @@ public class LabelLayer extends Layer implements Map.InputListener, Map.UpdateLi
// }
}
- @Override
- public void onMapUpdate(MapPosition mapPosition, boolean changed, boolean clear) {
- if (clear)
- mTextRenderer.clearLabels();
-
- mTextRenderer.update();
- }
-
- // @Override
- // public boolean onTouchEvent(MotionEvent e) {
- // int action = e.getAction() & MotionEvent.ACTION_MASK;
- // if (action == MotionEvent.ACTION_POINTER_DOWN) {
- // multi++;
- // mTextRenderer.hold(true);
- // } else if (action == MotionEvent.ACTION_POINTER_UP) {
- // multi--;
- // if (multi == 0)
- // mTextRenderer.hold(false);
- // } else if (action == MotionEvent.ACTION_CANCEL) {
- // multi = 0;
- // log.debug("cancel " + multi);
- // mTextRenderer.hold(false);
- // }
- //
- // return false;
- // }
-
}
diff --git a/vtm/src/org/oscim/layers/tile/vector/labeling/LabelPlacement.java b/vtm/src/org/oscim/layers/tile/vector/labeling/LabelPlacement.java
new file mode 100644
index 00000000..240ee162
--- /dev/null
+++ b/vtm/src/org/oscim/layers/tile/vector/labeling/LabelPlacement.java
@@ -0,0 +1,483 @@
+package org.oscim.layers.tile.vector.labeling;
+
+import org.oscim.core.MapPosition;
+import org.oscim.core.Tile;
+import org.oscim.map.Map;
+import org.oscim.renderer.elements.SymbolItem;
+import org.oscim.renderer.elements.SymbolLayer;
+import org.oscim.renderer.elements.TextItem;
+import org.oscim.tiling.MapTile;
+import org.oscim.tiling.TileRenderer;
+import org.oscim.tiling.TileSet;
+import org.oscim.utils.FastMath;
+import org.oscim.utils.OBB2D;
+
+public class LabelPlacement {
+ static final boolean dbg = false;
+
+ private final static float MIN_CAPTION_DIST = 5;
+ private final static float MIN_WAY_DIST = 3;
+
+ /** thread local pool of for unused label items */
+ private final LabelPool mPool = new LabelPool();
+
+ private final TileSet mTileSet = new TileSet();
+ private final TileRenderer mTileRenderer;
+ private final Map mMap;
+
+ /** list of current labels */
+ private Label mLabels;
+
+ private float mSquareRadius;
+
+ /**
+ * incremented each update, to prioritize labels
+ * that became visible ealier.
+ */
+ private int mRelabelCnt;
+
+ public LabelPlacement(Map map, TileRenderer tileRenderer) {
+ mMap = map;
+ mTileRenderer = tileRenderer;
+ }
+
+ /** remove Label l from mLabels and return l.next */
+ private Label removeLabel(Label l) {
+ Label ret = (Label) l.next;
+ mLabels = (Label) mPool.release(mLabels, l);
+
+ return ret;
+ }
+
+ public void addLabel(Label l) {
+ for (Label o = mLabels; o != null; o = (Label) o.next) {
+ /* find other label with same text style */
+ if (l.text == o.text) {
+ while (o.next != null
+ /* break if next item uses different text style */
+ && l.text == o.next.text
+ /* check same string instance */
+ && l.string != o.string
+ /* check same string */
+ && !l.string.equals(o.string))
+ o = (Label) o.next;
+
+ /* Note: required for 'packing test' in prepare to work */
+ Label.shareText(l, o);
+ /* insert after text of same type or before same string */
+ l.next = o.next;
+ o.next = l;
+ return;
+ }
+ }
+ l.next = mLabels;
+ mLabels = l;
+ }
+
+ private byte checkOverlap(Label l) {
+
+ for (Label o = mLabels; o != null;) {
+ //check bounding box
+ if (!Label.bboxOverlaps(l, o, 150)) {
+ o = (Label) o.next;
+ continue;
+ }
+
+ if (Label.shareText(l, o)) {
+ // keep the label that was active earlier
+ if (o.active <= l.active)
+ return 1;
+
+ // keep the label with longer segment
+ if (o.length < l.length) {
+ o = removeLabel(o);
+ continue;
+ }
+ // keep other
+ return 2;
+ }
+ if (l.bbox.overlaps(o.bbox)) {
+ if (o.active <= l.active)
+ return 1;
+
+ if (!o.text.caption
+ && (o.text.priority > l.text.priority
+ || o.length < l.length)) {
+
+ o = removeLabel(o);
+ continue;
+ }
+ // keep other
+ return 1;
+ }
+ o = (Label) o.next;
+ }
+ return 0;
+ }
+
+ private boolean isVisible(float x, float y) {
+ // rough filter
+ float dist = x * x + y * y;
+ if (dist > mSquareRadius)
+ return false;
+
+ return true;
+ }
+
+ private boolean wayIsVisible(Label 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 Label getLabel() {
+ Label l = (Label) mPool.get();
+ l.active = Integer.MAX_VALUE;
+
+ return l;
+ }
+
+ private static float flipLongitude(float dx, int max) {
+ // flip around date-line
+ if (dx > max)
+ dx = dx - max * 2;
+ else if (dx < -max)
+ dx = dx + max * 2;
+
+ return dx;
+ }
+
+ private void placeLabelFrom(Label l, TextItem ti) {
+ // 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.x1 = (int) (l.x - w);
+ l.y1 = (int) (l.y - h);
+ l.x2 = (int) (l.x + w);
+ l.y2 = (int) (l.y + h);
+ }
+
+ private Label addWayLabels(MapTile t, Label l, float dx, float dy,
+ double scale) {
+
+ 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 */
+ if (!dbg && ti.width > ti.length * scale)
+ continue;
+
+ l.clone(ti);
+ l.x = (float) ((dx + ti.x) * scale);
+ l.y = (float) ((dy + ti.y) * scale);
+ placeLabelFrom(l, ti);
+
+ 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 || ti.width < ti.length * scale)
+ overlaps = checkOverlap(l);
+
+ if (dbg)
+ Debug.addDebugBox(l, ti, overlaps, false, (float) scale);
+
+ if (overlaps == 0) {
+ addLabel(l);
+ l.item = TextItem.copy(ti);
+ l.tileX = t.tileX;
+ l.tileY = t.tileY;
+ l.tileZ = t.zoomLevel;
+ l.active = mRelabelCnt;
+ l = null;
+ }
+ }
+ return l;
+ }
+
+ private Label addNodeLabels(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.x = (float) ((dx + ti.x) * scale);
+ l.y = (float) ((dy + ti.y) * scale);
+ if (!isVisible(l.x, l.y))
+ 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 o = mLabels; o != null;) {
+ if (l.bbox.overlaps(o.bbox)) {
+ if (l.text.priority < o.text.priority) {
+ o = removeLabel(o);
+ continue;
+ }
+ continue O;
+ }
+ o = (Label) o.next;
+ }
+
+ addLabel(l);
+ l.item = TextItem.copy(ti);
+ l.tileX = t.tileX;
+ l.tileY = t.tileY;
+ l.tileZ = t.zoomLevel;
+ l.active = mRelabelCnt;
+ l = null;
+ }
+ return l;
+ }
+
+ boolean updateLabels(LabelTask work) {
+
+ /* get current tiles */
+ boolean changedTiles = mTileRenderer.getVisibleTiles(mTileSet);
+
+ if (mTileSet.cnt == 0) {
+ //log.debug("no tiles "+ mTileSet.getSerial());
+ return false;
+ }
+
+ MapPosition pos = work.pos;
+ boolean changedPos = mMap.getViewport().getMapPosition(pos);
+
+ /* do not loop! */
+ if (!changedTiles && !changedPos)
+ return false;
+
+ mRelabelCnt++;
+
+ MapTile[] tiles = mTileSet.tiles;
+ int zoom = tiles[0].zoomLevel;
+
+ /* estimation for visible area to be labeled */
+ int mw = (mMap.getWidth() + Tile.SIZE) / 2;
+ int mh = (mMap.getHeight() + Tile.SIZE) / 2;
+ mSquareRadius = mw * mw + mh * mh;
+
+ /* scale of tiles zoom-level relative to current position */
+ double scale = pos.scale / (1 << zoom);
+
+ double angle = Math.toRadians(pos.angle);
+ float cos = (float) Math.cos(angle);
+ float sin = (float) Math.sin(angle);
+
+ int maxx = Tile.SIZE << (zoom - 1);
+
+ // FIXME ???
+ SymbolLayer sl = work.symbolLayer;
+ sl.clearItems();
+
+ double tileX = (pos.x * (Tile.SIZE << zoom));
+ double tileY = (pos.y * (Tile.SIZE << zoom));
+
+ /* put current label to previous label */
+ Label prevLabels = mLabels;
+
+ /* new labels */
+ mLabels = null;
+ Label l = null;
+
+ /* add currently active labels first */
+ for (l = prevLabels; l != null;) {
+
+ if (l.text.caption) {
+ // TODO!!!
+ l = mPool.releaseAndGetNext(l);
+ continue;
+ }
+
+ int diff = l.tileZ - zoom;
+ if (diff > 1 || diff < -1) {
+ l = mPool.releaseAndGetNext(l);
+ continue;
+ }
+
+ float div = FastMath.pow(diff);
+ float sscale = (float) (pos.scale / (1 << l.tileZ));
+
+ if (l.width > l.length * sscale) {
+ l = mPool.releaseAndGetNext(l);
+ continue;
+ }
+
+ float dx = (float) (l.tileX * Tile.SIZE - tileX * div);
+ float dy = (float) (l.tileY * Tile.SIZE - tileY * div);
+
+ dx = flipLongitude(dx, maxx);
+ l.x = (float) ((dx + l.item.x) * sscale);
+ l.y = (float) ((dy + l.item.y) * sscale);
+ placeLabelFrom(l, l.item);
+
+ if (!wayIsVisible(l)) {
+ l = mPool.releaseAndGetNext(l);
+ continue;
+ }
+
+ l.bbox.set(l.x, l.y, l.x1, l.y1,
+ l.width + MIN_WAY_DIST,
+ l.text.fontHeight + MIN_WAY_DIST);
+
+ byte overlaps = checkOverlap(l);
+
+ if (dbg)
+ Debug.addDebugBox(l, l.item, overlaps, true, sscale);
+
+ if (overlaps == 0) {
+ Label ll = l;
+ l = (Label) l.next;
+
+ ll.next = null;
+ addLabel(ll);
+ continue;
+ }
+ l = mPool.releaseAndGetNext(l);
+ }
+
+ /* add way labels */
+ for (int i = 0, n = mTileSet.cnt; i < n; i++) {
+ MapTile t = tiles[i];
+ synchronized (t) {
+ if (!t.state(MapTile.STATE_READY))
+ continue;
+
+ float dx = (float) (t.tileX * Tile.SIZE - tileX);
+ float dy = (float) (t.tileY * Tile.SIZE - tileY);
+ dx = flipLongitude(dx, maxx);
+
+ l = addWayLabels(t, l, dx, dy, scale);
+ }
+ }
+
+ /* add caption */
+ for (int i = 0, n = mTileSet.cnt; i < n; i++) {
+ MapTile t = tiles[i];
+ synchronized (t) {
+ if (!t.state(MapTile.STATE_READY))
+ continue;
+
+ float dx = (float) (t.tileX * Tile.SIZE - tileX);
+ float dy = (float) (t.tileY * Tile.SIZE - tileY);
+ dx = flipLongitude(dx, maxx);
+
+ l = addNodeLabels(t, l, dx, dy, scale, cos, sin);
+ }
+ }
+
+ for (Label ti = mLabels; ti != null; ti = (Label) ti.next) {
+ /* add caption symbols */
+ if (ti.text.caption) {
+ if (ti.text.texture != null) {
+ SymbolItem s = SymbolItem.pool.get();
+ s.texRegion = ti.text.texture;
+ s.x = ti.x;
+ s.y = ti.y;
+ s.billboard = true;
+ sl.addSymbol(s);
+ }
+ continue;
+ }
+
+ /* flip way label orientation */
+ 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;
+ }
+ }
+
+ /* add symbol items */
+ for (int i = 0, n = mTileSet.cnt; i < n; i++) {
+ MapTile t = tiles[i];
+ synchronized (t) {
+ if (!t.state(MapTile.STATE_READY))
+ continue;
+
+ 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;
+
+ int x = (int) ((dx + ti.x) * scale);
+ int y = (int) ((dy + ti.y) * scale);
+
+ if (!isVisible(x, y))
+ continue;
+
+ SymbolItem s = SymbolItem.pool.get();
+ s.texRegion = ti.texRegion;
+ s.x = x;
+ s.y = y;
+ s.billboard = true;
+ sl.addSymbol(s);
+ }
+ }
+ }
+
+ /* temporary used Label */
+ l = (Label) mPool.release(l);
+
+ /* draw text to bitmaps and create vertices */
+ work.textLayer.labels = mLabels;
+ work.textLayer.prepare();
+ work.textLayer.labels = null;
+
+ /* remove tile locks */
+ mTileRenderer.releaseTiles(mTileSet);
+
+ return true;
+ }
+
+ public void cleanup() {
+ mLabels = (Label) mPool.releaseAll(mLabels);
+ mTileSet.releaseTiles();
+ }
+}
diff --git a/vtm/src/org/oscim/layers/tile/vector/labeling/LabelPool.java b/vtm/src/org/oscim/layers/tile/vector/labeling/LabelPool.java
new file mode 100644
index 00000000..b81d8505
--- /dev/null
+++ b/vtm/src/org/oscim/layers/tile/vector/labeling/LabelPool.java
@@ -0,0 +1,25 @@
+package org.oscim.layers.tile.vector.labeling;
+
+import org.oscim.renderer.elements.TextItem;
+import org.oscim.utils.pool.Pool;
+
+final class LabelPool extends Pool {
+ Label releaseAndGetNext(Label l) {
+ if (l.item != null)
+ l.item = TextItem.pool.release(l.item);
+
+ // drop references
+ l.item = null;
+ l.string = null;
+ Label ret = (Label) l.next;
+
+ // ignore warning
+ super.release(l);
+ return ret;
+ }
+
+ @Override
+ protected Label createItem() {
+ return new Label();
+ }
+}
diff --git a/vtm/src/org/oscim/layers/tile/vector/labeling/LabelTask.java b/vtm/src/org/oscim/layers/tile/vector/labeling/LabelTask.java
new file mode 100644
index 00000000..19a5596f
--- /dev/null
+++ b/vtm/src/org/oscim/layers/tile/vector/labeling/LabelTask.java
@@ -0,0 +1,26 @@
+package org.oscim.layers.tile.vector.labeling;
+
+import org.oscim.core.MapPosition;
+import org.oscim.renderer.elements.SymbolLayer;
+import org.oscim.renderer.elements.TextLayer;
+import org.oscim.renderer.elements.TextureLayer;
+
+final class LabelTask {
+
+ final TextureLayer layers;
+ final TextLayer textLayer;
+ final SymbolLayer symbolLayer;
+
+ final MapPosition pos;
+
+ LabelTask() {
+ pos = new MapPosition();
+
+ symbolLayer = new SymbolLayer();
+ textLayer = new TextLayer();
+
+ layers = symbolLayer;
+ symbolLayer.next = textLayer;
+ }
+
+}
diff --git a/vtm/src/org/oscim/layers/tile/vector/labeling/TextRenderer.java b/vtm/src/org/oscim/layers/tile/vector/labeling/TextRenderer.java
index d15a0603..551b48a0 100644
--- a/vtm/src/org/oscim/layers/tile/vector/labeling/TextRenderer.java
+++ b/vtm/src/org/oscim/layers/tile/vector/labeling/TextRenderer.java
@@ -27,582 +27,27 @@ package org.oscim.layers.tile.vector.labeling;
// 2.4 use 4 point labeling
// 3 join segments that belong to one feature
// 4 handle zoom-level changes
-// 5 R-Tree might be handy
+// 5 QuadTree might be handy
//
import org.oscim.core.MapPosition;
-import org.oscim.core.Tile;
-import org.oscim.map.Map;
-import org.oscim.map.Viewport;
+import org.oscim.layers.tile.vector.labeling.LabelLayer.Worker;
import org.oscim.renderer.ElementRenderer;
import org.oscim.renderer.GLState;
import org.oscim.renderer.MapRenderer.Matrices;
-import org.oscim.renderer.elements.ElementLayers;
-import org.oscim.renderer.elements.LineLayer;
-import org.oscim.renderer.elements.PolygonLayer;
import org.oscim.renderer.elements.RenderElement;
-import org.oscim.renderer.elements.SymbolItem;
-import org.oscim.renderer.elements.SymbolLayer;
-import org.oscim.renderer.elements.TextItem;
-import org.oscim.renderer.elements.TextLayer;
import org.oscim.renderer.elements.TextureLayer;
-import org.oscim.tiling.MapTile;
-import org.oscim.tiling.TileRenderer;
-import org.oscim.tiling.TileSet;
-import org.oscim.utils.FastMath;
-import org.oscim.utils.OBB2D;
-import org.oscim.utils.async.SimpleWorker;
-import org.oscim.utils.pool.Pool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
class TextRenderer extends ElementRenderer {
static final Logger log = LoggerFactory.getLogger(TextRenderer.class);
+ static final boolean dbg = false;
- private final static float MIN_CAPTION_DIST = 5;
- private final static float MIN_WAY_DIST = 3;
-
- private final static long MAX_RELABEL_DELAY = 200;
-
- private final Viewport mViewport;
- private final TileSet mTileSet;
-
- //private ElementLayers mDebugLayer;
-
- class LabelTask {
- final TextureLayer layers;
- final TextLayer textLayer;
- final SymbolLayer symbolLayer;
-
- final MapPosition pos;
-
- LabelTask() {
- pos = new MapPosition();
-
- symbolLayer = new SymbolLayer();
- textLayer = new TextLayer();
-
- layers = symbolLayer;
- symbolLayer.next = textLayer;
-
- }
- }
-
- // thread local pool (labeling)
- class LabelPool extends Pool {
- Label releaseAndGetNext(Label l) {
- if (l.item != null)
- l.item = TextItem.pool.release(l.item);
-
- // drop references
- l.item = null;
- l.tile = null;
- l.string = null;
-
- Label ret = (Label) l.next;
-
- // ignore warning
- super.release(l);
-
- return ret;
- }
-
- @Override
- protected TextItem createItem() {
- return new Label();
- }
- }
-
- private final LabelPool mPool = new LabelPool();
-
- // list of current labels
- private Label mLabels;
-
- //private final float[] mTmpCoords = new float[8];
-
- //private final HashMap mActiveTiles;
-
- private float mSquareRadius;
- private int mRelabelCnt;
- private final TileRenderer mTileLayer;
- private final Map mMap;
private final Worker mWorker;
- public TextRenderer(Map map, TileRenderer baseLayer) {
- mMap = map;
- mViewport = map.getViewport();
- mTileLayer = baseLayer;
- mTileSet = new TileSet();
-
- layers.textureLayers = new TextLayer();
- layers.textureLayers.next = new SymbolLayer();
-
- //mActiveTiles = new HashMap();
- mRelabelCnt = 0;
-
- mWorker = new Worker(map);
- }
-
- // remove Label l from mLabels and return l.next
- private Label removeLabel(Label l) {
- Label ret = (Label) l.next;
- mLabels = (Label) mPool.release(mLabels, l);
-
- return ret;
- }
-
- public void addLabel(Label l) {
- TextItem ll = mLabels;
-
- for (; ll != null; ll = ll.next) {
- // find other label with same text style
- if (l.text == ll.text) {
- while (ll.next != null
- // break if next item uses different text style
- && l.text == ll.next.text
- // check same string instance
- && l.string != ll.string
- // check same string
- && !l.string.equals(ll.string))
- ll = ll.next;
-
- // Note: this is required for 'packing test' in prepare to work!
- TextItem.shareText(l, ll);
-
- // insert after text of same type and/or before same string
- l.next = ll.next;
- ll.next = l;
- return;
- }
- }
-
- l.next = mLabels;
- mLabels = l;
- }
-
- private byte checkOverlap(Label l) {
-
- for (Label ll = mLabels; ll != null;) {
- // check bounding box
- if (!TextItem.bboxOverlaps(l, ll, 150)) {
- ll = (Label) ll.next;
- continue;
- }
-
- if (TextItem.shareText(l, ll)) {
-
- // keep the label that was active earlier
- if (ll.active <= l.active)
- return 1;
-
- // keep the label with longer segment
- if (ll.length < l.length) {
- ll = removeLabel(ll);
- continue;
- }
-
- return 2;
- }
-
- boolean intersect = l.bbox.overlaps(ll.bbox);
-
- if (intersect) {
- if (ll.active <= l.active)
- return 1;
-
- //log.debug("intersection " + lp.string + " <> " + ti.string
- // + " at " + ti.x + ":" + ti.y);
-
- if (!ll.text.caption
- && (ll.text.priority > l.text.priority || ll.length < l.length)) {
-
- ll = removeLabel(ll);
- continue;
- }
-
- return 1;
- }
- ll = (Label) ll.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 iconIsVisible(int x, int y) {
- // rough filter
- float dist = x * x + y * 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 Label getLabel() {
- Label l = (Label) mPool.get();
- l.active = Integer.MAX_VALUE;
-
- return l;
- }
-
- private static float flipLongitude(float dx, int max) {
- // flip around date-line
- if (dx > max)
- dx = dx - max * 2;
- else if (dx < -max)
- dx = dx + max * 2;
-
- 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(LabelTask work) {
- // nextLayer is not loaded yet
- //if (mNextLayer.ready)
- // return false;
-
- // get current tiles
- boolean changedTiles = mTileLayer.getVisibleTiles(mTileSet);
- boolean changedPos;
-
- if (mTileSet.cnt == 0) {
- //log.debug("no tiles "+ mTileSet.getSerial());
- return false;
- }
-
- MapPosition pos = work.pos;
-
- synchronized (mViewport) {
- changedPos = mViewport.getMapPosition(pos);
- //mViewport.getMapViewProjection(coords);
- }
-
- if (!changedTiles && !changedPos) {
- //log.debug("not changed " + changedTiles + " " + changedPos);
- return false;
- }
-
- ElementLayers dbg = null;
- //if (mMap.getDebugSettings().debugLabels)
- // dbg = new ElementLayers();
-
- int mw = (mMap.getWidth() + Tile.SIZE) / 2;
- int mh = (mMap.getHeight() + Tile.SIZE) / 2;
- mSquareRadius = mw * mw + mh * mh;
-
- MapTile[] tiles = mTileSet.tiles;
- int zoom = tiles[0].zoomLevel;
-
- // scale of tiles zoom-level relative to current position
- double scale = pos.scale / (1 << zoom);
-
- double angle = Math.toRadians(pos.angle);
- float cos = (float) Math.cos(angle);
- float sin = (float) Math.sin(angle);
-
- int maxx = Tile.SIZE << (zoom - 1);
-
- //if (dbg != null)
- // Debug.addDebugLayers(dbg);
-
- SymbolLayer sl = work.symbolLayer;
- sl.clearItems();
-
- mRelabelCnt++;
-
- double tileX = (pos.x * (Tile.SIZE << zoom));
- double tileY = (pos.y * (Tile.SIZE << zoom));
-
- Label prevLabels = mLabels;
- mLabels = null;
-
- for (Label l = prevLabels; l != null;) {
- if (l.text.caption) {
- l = mPool.releaseAndGetNext(l);
- continue;
- }
-
- int diff = l.tile.zoomLevel - zoom;
- if (diff > 1 || diff < -1) {
- l = mPool.releaseAndGetNext(l);
- continue;
- }
-
- float div = FastMath.pow(diff);
- float sscale = (float) (pos.scale / (1 << l.tile.zoomLevel));
-
- if (l.width > l.length * sscale) {
- l = mPool.releaseAndGetNext(l);
- continue;
- }
-
- float dx = (float) (l.tile.tileX * Tile.SIZE - tileX * div);
- float dy = (float) (l.tile.tileY * Tile.SIZE - tileY * div);
-
- dx = flipLongitude(dx, maxx);
-
- l.move(l.item, dx, dy, sscale);
-
- // set line endpoints relative to view to be able to
- // check intersections with label from other tiles
- float w = (l.item.x2 - l.item.x1) / 2f;
- float h = (l.item.y2 - l.item.y1) / 2f;
- l.x1 = l.x - w;
- l.y1 = l.y - h;
- l.x2 = l.x + w;
- l.y2 = l.y + h;
-
- if (!wayIsVisible(l)) {
- l = mPool.releaseAndGetNext(l);
- continue;
- }
-
- l.bbox.set(l.x, l.y, l.x1, l.y1,
- l.width + MIN_WAY_DIST,
- l.text.fontHeight + MIN_WAY_DIST);
-
- byte overlaps = checkOverlap(l);
-
- if (dbg != null)
- Debug.addDebugBox(dbg, l, l.item, overlaps, true, sscale);
-
- if (overlaps == 0) {
- Label ll = l;
- l = (Label) l.next;
-
- ll.next = null;
- addLabel(ll);
- continue;
- }
- l = mPool.releaseAndGetNext(l);
- }
-
- Label l = null;
-
- /* add way labels */
- for (int i = 0, n = mTileSet.cnt; i < n; i++) {
- MapTile t = tiles[i];
- synchronized (t) {
- if (!t.state(MapTile.STATE_READY))
- continue;
-
- float dx = (float) (t.tileX * Tile.SIZE - tileX);
- float dy = (float) (t.tileY * Tile.SIZE - tileY);
- dx = flipLongitude(dx, maxx);
-
- l = updateWayLabels(t, l, dx, dy, scale, dbg);
- }
- }
-
- /* add caption */
- for (int i = 0, n = mTileSet.cnt; i < n; i++) {
- MapTile t = tiles[i];
- synchronized (t) {
- if (!t.state(MapTile.STATE_READY))
- continue;
-
- float dx = (float) (t.tileX * Tile.SIZE - tileX);
- float dy = (float) (t.tileY * Tile.SIZE - tileY);
- dx = flipLongitude(dx, maxx);
-
- l = updateNodeLabels(t, l, dx, dy, scale, cos, sin);
- }
- }
-
- for (Label ti = mLabels; ti != null; ti = (Label) ti.next) {
- if (ti.text.caption) {
- if (ti.text.texture != null) {
- SymbolItem s = SymbolItem.pool.get();
- s.texRegion = ti.text.texture;
- s.x = ti.x;
- s.y = ti.y;
- s.billboard = true;
- sl.addSymbol(s);
- }
- 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;
- }
- }
-
- for (int i = 0, n = mTileSet.cnt; i < n; i++) {
- MapTile t = tiles[i];
- synchronized (t) {
- if (!t.state(MapTile.STATE_READY))
- continue;
-
- 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;
-
- int x = (int) ((dx + ti.x) * scale);
- int y = (int) ((dy + ti.y) * scale);
-
- if (!iconIsVisible(x, y))
- continue;
-
- SymbolItem s = SymbolItem.pool.get();
- s.texRegion = ti.texRegion;
- s.x = x;
- s.y = y;
- s.billboard = true;
- sl.addSymbol(s);
- }
- }
- }
-
- // temporary used Label
- l = (Label) mPool.release(l);
-
- // draw text to bitmaps and create vertices
- work.textLayer.labels = mLabels;
- work.textLayer.prepare();
- work.textLayer.labels = null;
-
- // remove tile locks
- mTileLayer.releaseTiles(mTileSet);
-
- //mDebugLayer = dbg;
- //mNextLayer.ready = true;
-
- return true;
+ public TextRenderer(Worker worker) {
+ mWorker = worker;
}
long lastDraw = 0;
@@ -613,12 +58,13 @@ class TextRenderer extends ElementRenderer {
LabelTask t;
synchronized (mWorker) {
-
t = mWorker.poll();
-
- if (t == null)
+ if (t == null) {
+ if (!mWorker.isRunning()) {
+ mWorker.submit(50);
+ }
return;
-
+ }
layers.clear();
}
@@ -626,70 +72,21 @@ class TextRenderer extends ElementRenderer {
layers.textureLayers = t.layers;
mMapPosition = t.pos;
compile();
-
- update();
}
@Override
public synchronized void render(MapPosition pos, Matrices m) {
GLState.test(false, false);
+ //Debug.draw(pos, layers);
layers.vbo.bind();
float scale = (float) (mMapPosition.scale / pos.scale);
- if (layers.baseLayers != null) {
- setMatrix(pos, m, true);
-
- for (RenderElement l = layers.baseLayers; l != null;) {
- if (l.type == RenderElement.POLYGON) {
- l = PolygonLayer.Renderer.draw(pos, l, m, true, 1, false);
- } else {
- float div = (float) (mMapPosition.scale / (1 << pos.zoomLevel));
- l = LineLayer.Renderer.draw(layers, l, pos, m, div);
- }
- }
- }
-
setMatrix(pos, m, false);
for (RenderElement l = layers.textureLayers; l != null;)
l = TextureLayer.Renderer.draw(l, scale, m);
}
- final class Worker extends SimpleWorker {
-
- public Worker(Map map) {
- super(map, 10, new LabelTask(), new LabelTask());
- }
-
- @Override
- public boolean doWork(LabelTask t) {
-
- if (updateLabels(t)) {
- mMap.render();
- return true;
- }
-
- return false;
- }
-
- @Override
- public void cleanup(LabelTask t) {
- }
-
- @Override
- public void finish() {
- mLabels = (Label) mPool.releaseAll(mLabels);
- mTileSet.releaseTiles();
- }
- }
-
- public void clearLabels() {
- mWorker.cancel(true);
- }
-
- public void update() {
- mWorker.submit(MAX_RELABEL_DELAY);
- }
}
diff --git a/vtm/src/org/oscim/renderer/elements/TextItem.java b/vtm/src/org/oscim/renderer/elements/TextItem.java
index c6e5a479..1c48a99f 100644
--- a/vtm/src/org/oscim/renderer/elements/TextItem.java
+++ b/vtm/src/org/oscim/renderer/elements/TextItem.java
@@ -36,8 +36,8 @@ public class TextItem extends Inlist {
// drop references
ti.string = null;
ti.text = null;
- ti.n1 = null;
- ti.n2 = null;
+ //ti.n1 = null;
+ //ti.n2 = null;
return true;
}
};
@@ -57,22 +57,6 @@ public class TextItem extends Inlist {
return ti;
}
- public static boolean shareText(TextItem ti1, TextItem ti2) {
- if (ti1.text != ti2.text)
- return false;
-
- if (ti1.string == ti2.string)
- return true;
-
- if (ti1.string.equals(ti2.string)) {
- // make strings unique, should be done only once..
- ti1.string = ti2.string;
- return true;
- }
-
- return false;
- }
-
public TextItem set(float x, float y, String string, Text text) {
this.x = x;
this.y = y;
@@ -86,38 +70,6 @@ public class TextItem extends Inlist {
return this;
}
- public static boolean bboxOverlaps(TextItem it1, TextItem it2, float add) {
- if (it1.y1 < it1.y2) {
- if (it2.y1 < it2.y2)
- return (it1.x1 - add < it2.x2)
- && (it2.x1 < it1.x2 + add)
- && (it1.y1 - add < it2.y2)
- && (it2.y1 < it1.y2 + add);
-
- // flip it2
- return (it1.x1 - add < it2.x2)
- && (it2.x1 < it1.x2 + add)
- && (it1.y1 - add < it2.y1)
- && (it2.y2 < it1.y2 + add);
- }
-
- // flip it1
- if (it2.y1 < it2.y2)
- return (it1.x1 - add < it2.x2)
- && (it2.x1 < it1.x2 + add)
- && (it1.y2 - add < it2.y2)
- && (it2.y1 < it1.y1 + add);
-
- // flip both
- return (it1.x1 - add < it2.x2)
- && (it2.x1 < it1.x2 + add)
- && (it1.y2 - add < it2.y1)
- && (it2.y2 < it1.y1 + add);
- }
-
- // link to next node
- //public TextItem next;
-
// center
public float x, y;
@@ -137,8 +89,8 @@ public class TextItem extends Inlist {
public short length;
// link to next/prev label of the way
- public TextItem n1;
- public TextItem n2;
+ //public TextItem n1;
+ //public TextItem n2;
public byte edges;
diff --git a/vtm/src/org/oscim/renderer/elements/TextLayer.java b/vtm/src/org/oscim/renderer/elements/TextLayer.java
index 13fbb4c6..aa20b99e 100644
--- a/vtm/src/org/oscim/renderer/elements/TextLayer.java
+++ b/vtm/src/org/oscim/renderer/elements/TextLayer.java
@@ -38,7 +38,6 @@ public final class TextLayer extends TextureLayer {
public TextLayer() {
super(RenderElement.SYMBOL);
- //mCanvas = Graphics.res.getCanvas();
mCanvas = CanvasAdapter.g.getCanvas();
fixed = true;
}
@@ -58,7 +57,7 @@ public final class TextLayer extends TextureLayer {
&& !item.string.equals(it.string))
it = it.next;
- // unify duplicate string :)
+ // unify duplicate string
// Note: this is required for 'packing test' in prepare to work!
if (item.string != it.string && item.string.equals(it.string))
item.string = it.string;
@@ -139,117 +138,22 @@ public final class TextLayer extends TextureLayer {
if (width > TEXTURE_WIDTH)
width = TEXTURE_WIDTH;
- float hw = width / 2.0f;
- float hh = height / 2.0f;
-
- float hh2 = hh;
- //if (!it.text.caption) {
- // // displace by baseline
- // float desc = 0; //(hh - (height - it.text.fontDescent) / 2);
- //
- // //float desc = it.text.fontDescent / 2;
- // hh2 = hh + desc;
- // hh = hh - desc;
- //}
-
- // texture coordinates
- short u1 = (short) (COORD_SCALE * x);
- short v1 = (short) (COORD_SCALE * y);
- short u2 = (short) (COORD_SCALE * (x + width));
- short v2 = (short) (COORD_SCALE * (y + height));
-
while (it != null) {
-
- short x1, x2, x3, x4, y1, y3, y2, y4;
-
- if (it.text.caption) {
- //if (it.origin == 0) {
- x1 = x3 = (short) (COORD_SCALE * -hw);
- x2 = x4 = (short) (COORD_SCALE * hw);
- y1 = y2 = (short) (COORD_SCALE * (it.text.dy + hh));
- y3 = y4 = (short) (COORD_SCALE * (it.text.dy - hh));
- //} else {
- // x1 = x3 = (short) (SCALE * 0);
- // x2 = x4 = (short) (SCALE * width);
- // y1 = y2 = (short) (SCALE * 0);
- // y3 = y4 = (short) (SCALE * -height);
- //}
- } else {
- float vx = it.x1 - it.x2;
- float vy = it.y1 - it.y2;
- float a = (float) Math.sqrt(vx * vx + vy * vy);
- vx = vx / a;
- vy = vy / a;
-
- float ux = -vy * hh;
- float uy = vx * hh;
-
- float ux2 = -vy * hh2;
- float uy2 = vx * hh2;
-
- vx *= hw;
- vy *= hw;
-
- // top-left
- x1 = (short) (COORD_SCALE * (vx - ux));
- y1 = (short) (COORD_SCALE * (vy - uy));
- // top-right
- x2 = (short) (COORD_SCALE * (-vx - ux));
- y2 = (short) (COORD_SCALE * (-vy - uy));
- // bot-right
- x4 = (short) (COORD_SCALE * (-vx + ux2));
- y4 = (short) (COORD_SCALE * (-vy + uy2));
- // bot-left
- x3 = (short) (COORD_SCALE * (vx + ux2));
- y3 = (short) (COORD_SCALE * (vy + uy2));
- }
-
- // add vertices
- int tmp = (int) (COORD_SCALE * it.x) & LBIT_MASK;
- short tx = (short) (tmp | (it.text.caption ? 1 : 0));
- short ty = (short) (COORD_SCALE * it.y);
-
if (pos == VertexItem.SIZE) {
vi.used = VertexItem.SIZE;
vi = VertexItem.pool.getNext(vi);
buf = vi.vertices;
pos = 0;
}
-
- // top-left
- buf[pos++] = tx;
- buf[pos++] = ty;
- buf[pos++] = x1;
- buf[pos++] = y1;
- buf[pos++] = u1;
- buf[pos++] = v2;
- // bot-left
- buf[pos++] = tx;
- buf[pos++] = ty;
- buf[pos++] = x3;
- buf[pos++] = y3;
- buf[pos++] = u1;
- buf[pos++] = v1;
- // top-right
- buf[pos++] = tx;
- buf[pos++] = ty;
- buf[pos++] = x2;
- buf[pos++] = y2;
- buf[pos++] = u2;
- buf[pos++] = v2;
- // bot-right
- buf[pos++] = tx;
- buf[pos++] = ty;
- buf[pos++] = x4;
- buf[pos++] = y4;
- buf[pos++] = u2;
- buf[pos++] = v1;
+ addItem(buf, pos, it, width, height, x, y);
+ pos += 24;
// six indices to draw the four vertices
numIndices += TextureLayer.INDICES_PER_SPRITE;
numVertices += 4;
- if (it.next == null || (it.next.text != it.text)
+ if (it.next == null
+ || (it.next.text != it.text)
|| (it.next.string != it.string)) {
it = it.next;
break;
@@ -268,6 +172,86 @@ public final class TextLayer extends TextureLayer {
return true;
}
+ void addItem(short[] buf, int pos, TextItem it, float width, float height, float x, float y) {
+ // texture coordinates
+ short u1 = (short) (COORD_SCALE * x);
+ short v1 = (short) (COORD_SCALE * y);
+ short u2 = (short) (COORD_SCALE * (x + width));
+ short v2 = (short) (COORD_SCALE * (y + height));
+
+ short x1, x2, x3, x4, y1, y3, y2, y4;
+ float hw = width / 2.0f;
+ float hh = height / 2.0f;
+ if (it.text.caption) {
+ x1 = x3 = (short) (COORD_SCALE * -hw);
+ x2 = x4 = (short) (COORD_SCALE * hw);
+ y1 = y2 = (short) (COORD_SCALE * (it.text.dy + hh));
+ y3 = y4 = (short) (COORD_SCALE * (it.text.dy - hh));
+ } else {
+ float vx = it.x1 - it.x2;
+ float vy = it.y1 - it.y2;
+ float a = (float) Math.sqrt(vx * vx + vy * vy);
+ vx = vx / a;
+ vy = vy / a;
+
+ float ux = -vy * hh;
+ float uy = vx * hh;
+
+ float ux2 = -vy * hh;
+ float uy2 = vx * hh;
+
+ vx *= hw;
+ vy *= hw;
+
+ // top-left
+ x1 = (short) (COORD_SCALE * (vx - ux));
+ y1 = (short) (COORD_SCALE * (vy - uy));
+ // top-right
+ x2 = (short) (COORD_SCALE * (-vx - ux));
+ y2 = (short) (COORD_SCALE * (-vy - uy));
+ // bot-right
+ x4 = (short) (COORD_SCALE * (-vx + ux2));
+ y4 = (short) (COORD_SCALE * (-vy + uy2));
+ // bot-left
+ x3 = (short) (COORD_SCALE * (vx + ux2));
+ y3 = (short) (COORD_SCALE * (vy + uy2));
+ }
+
+ // add vertices
+ int tmp = (int) (COORD_SCALE * it.x) & LBIT_MASK;
+ short tx = (short) (tmp | (it.text.caption ? 1 : 0));
+ short ty = (short) (COORD_SCALE * it.y);
+
+ // top-left
+ buf[pos++] = tx;
+ buf[pos++] = ty;
+ buf[pos++] = x1;
+ buf[pos++] = y1;
+ buf[pos++] = u1;
+ buf[pos++] = v2;
+ // bot-left
+ buf[pos++] = tx;
+ buf[pos++] = ty;
+ buf[pos++] = x3;
+ buf[pos++] = y3;
+ buf[pos++] = u1;
+ buf[pos++] = v1;
+ // top-right
+ buf[pos++] = tx;
+ buf[pos++] = ty;
+ buf[pos++] = x2;
+ buf[pos++] = y2;
+ buf[pos++] = u2;
+ buf[pos++] = v2;
+ // bot-right
+ buf[pos++] = tx;
+ buf[pos++] = ty;
+ buf[pos++] = x4;
+ buf[pos++] = y4;
+ buf[pos++] = u2;
+ buf[pos++] = v1;
+ }
+
@Override
public void clear() {
// release textures