use OBBs for label collision detections

This commit is contained in:
Hannes Janetzek 2013-02-11 10:08:41 +01:00
parent f2f93d180b
commit e69bebb2c5
2 changed files with 119 additions and 81 deletions

View File

@ -15,6 +15,7 @@
package org.oscim.renderer.layer; package org.oscim.renderer.layer;
import org.oscim.theme.renderinstruction.Text; import org.oscim.theme.renderinstruction.Text;
import org.oscim.utils.OBB2D;
import android.util.Log; import android.util.Log;
@ -120,6 +121,9 @@ public class TextItem {
return this; return this;
} }
/* copy properties from 'ti' and add offset
*
* */
public TextItem move(TextItem ti, float dx, float dy, float scale) { public TextItem move(TextItem ti, float dx, float dy, float scale) {
this.x = dx + (ti.x * scale); this.x = dx + (ti.x * scale);
this.y = dy + (ti.y * scale); this.y = dy + (ti.y * scale);
@ -129,6 +133,13 @@ public class TextItem {
return this; return this;
} }
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;
}
public static boolean bboxOverlaps(TextItem it1, TextItem it2, float add) { public static boolean bboxOverlaps(TextItem it1, TextItem it2, float add) {
if (it1.y1 < it1.y2) { if (it1.y1 < it1.y2) {
if (it2.y1 < it2.y2) if (it2.y1 < it2.y2)
@ -174,4 +185,5 @@ public class TextItem {
public byte origin; public byte origin;
public int active; public int active;
public OBB2D bbox;
} }

View File

@ -15,6 +15,8 @@
package org.oscim.renderer.overlays; package org.oscim.renderer.overlays;
import java.util.HashMap;
import org.oscim.core.MapPosition; import org.oscim.core.MapPosition;
import org.oscim.core.Tile; import org.oscim.core.Tile;
import org.oscim.generator.JobTile; import org.oscim.generator.JobTile;
@ -33,8 +35,8 @@ 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;
@ -43,9 +45,10 @@ import android.graphics.Paint.Cap;
import android.opengl.GLES20; import android.opengl.GLES20;
import android.opengl.Matrix; import android.opengl.Matrix;
import android.os.SystemClock; import android.os.SystemClock;
import android.util.Log;
public class TextOverlayExp extends BasicOverlay { public class TextOverlayExp extends BasicOverlay {
// private final static String TAG = TextOverlayExp.class.getName(); private final static String TAG = TextOverlayExp.class.getName();
private TileSet mTileSet; private TileSet mTileSet;
private final LabelThread mThread; private final LabelThread mThread;
@ -98,24 +101,24 @@ public class TextOverlayExp extends BasicOverlay {
mThread.start(); mThread.start();
} }
// private HashMap<TextItem, PlacementItem> mItemMap; private HashMap<MapTile, PlacementItem> mItemMap;
//
// class PlacementItem extends TextItem { class PlacementItem extends TextItem {
// int tileX; int tileX;
// int tileY; int tileY;
//
// boolean isTileNeighbour(PlacementItem other) { boolean isTileNeighbour(PlacementItem other) {
// int dx = other.tileX - tileX; int dx = other.tileX - tileX;
// if (dx > 1 || dx < -1) if (dx > 1 || dx < -1)
// return false; return false;
//
// int dy = other.tileY - tileY; int dy = other.tileY - tileY;
// if (dy > 1 || dy < -1) if (dy > 1 || dy < -1)
// return false; return false;
//
// return true; return true;
// } }
// } }
// local pool, avoids synchronized TextItem.get()/release() // local pool, avoids synchronized TextItem.get()/release()
private TextItem mPool; private TextItem mPool;
@ -158,20 +161,32 @@ public class TextOverlayExp extends BasicOverlay {
return 3; return 3;
} }
if (!TextItem.bboxOverlaps(ti, lp, 10)) { // if (!TextItem.bboxOverlaps(ti, lp, 10)) {
lp = lp.next; // lp = lp.next;
continue; // continue;
} // }
byte intersect = GeometryUtils.linesIntersect( if (ti.bbox == null) {
ti.x1, ti.y1, ti.x2, ti.y2, ti.bbox = new OBB2D(ti.x, ti.y, ti.x1, ti.y1, ti.width + 10,
lp.x1, lp.y1, lp.x2, lp.y2); ti.text.fontHeight + 10);
//Log.d(TAG,"add > " + ti.string + " " + Arrays.toString(ti.bbox.axis)+ " / " + Arrays.toString(ti.bbox.origin));
}
if (lp.bbox == null) {
lp.bbox = new OBB2D(lp.x, lp.y, lp.x1, lp.y1, lp.width + 10,
lp.text.fontHeight + 10);
//Log.d(TAG,"add > " + lp.string + " " + Arrays.toString(lp.bbox.axis) + " / " + Arrays.toString(lp.bbox.origin));
}
byte intersect = (byte) (ti.bbox.overlaps(lp.bbox) ? 1 : 0);
// byte intersect = GeometryUtils.linesIntersect(
// ti.x1, ti.y1, ti.x2, ti.y2,
// lp.x1, lp.y1, lp.x2, lp.y2);
if (intersect != 0) { if (intersect != 0) {
//Log.d(TAG, "intersection " + lp.string + " <> " + ti.string Log.d(TAG, "intersection " + lp.string + " <> " + ti.string
// + " at " + ti.x + ":" + ti.y); + " at " + ti.x + ":" + ti.y);
if (lp.active < ti.active) { if (lp.text.priority > ti.text.priority || lp.active < ti.active) {
//if (lp.length > ti.length) { //if (lp.length > ti.length) {
//Log.d(TAG, "drop " + lp.string); //Log.d(TAG, "drop " + lp.string);
TextItem tmp = lp; TextItem tmp = lp;
@ -187,21 +202,21 @@ public class TextOverlayExp extends BasicOverlay {
return intersect; return intersect;
// if ((lp.n1 != null && lp.n1 == ti.n2) || // if ((lp.n1 != null && lp.n1 == ti.n2) ||
// (lp.n2 != null && lp.n2 == ti.n1)) { // (lp.n2 != null && lp.n2 == ti.n1)) {
// Log.d(TAG, "overlap with adjacent label " + lp.string // Log.d(TAG, "overlap with adjacent label " + lp.string
// + " at " + ti.x + ":" + ti.y + ", " + lp.x + ":" + lp.y); // + " at " + ti.x + ":" + ti.y + ", " + lp.x + ":" + lp.y);
// //
// return intersect; // return intersect;
// } // }
// //
// if ((ti.n1 != null || ti.n2 != null) && (lp.n1 == null && lp.n2 == null)) { // if ((ti.n1 != null || ti.n2 != null) && (lp.n1 == null && lp.n2 == null)) {
// Log.d(TAG, "overlap, other is unique " + lp.string + " " + ti.string // Log.d(TAG, "overlap, other is unique " + lp.string + " " + ti.string
// + " at " + ti.x + ":" + ti.y + ", " + lp.x + ":" + lp.y); // + " at " + ti.x + ":" + ti.y + ", " + lp.x + ":" + lp.y);
// return intersect; // return intersect;
// } // }
// //
// return intersect; // return intersect;
} }
lp = lp.next; lp = lp.next;
@ -223,7 +238,7 @@ public class TextOverlayExp extends BasicOverlay {
TextLayer tl = mTmpLayer; TextLayer tl = mTmpLayer;
mTmpLayer = null; mTmpLayer = null;
//mDebugLayer = new Layers(); Layers dbg = null; //new Layers();
// 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...
@ -241,23 +256,24 @@ public class TextOverlayExp extends BasicOverlay {
double angle = Math.toRadians(mTmpPos.angle); double angle = Math.toRadians(mTmpPos.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);
Log.d(TAG, "angle " + mTmpPos.angle + " " + cos + " " + sin);
int maxx = Tile.TILE_SIZE << (mTmpPos.zoomLevel - 1); int maxx = Tile.TILE_SIZE << (mTmpPos.zoomLevel - 1);
TextItem ti2 = null; TextItem ti2 = null;
if (mDebugLayer != null) { if (dbg != null) {
mDebugLayer.clear(); dbg.clear();
LineLayer ll = (LineLayer) mDebugLayer.getLayer(0, Layer.LINE); LineLayer ll = (LineLayer) dbg.getLayer(0, Layer.LINE);
ll.line = new Line((Color.BLUE & 0xaaffffff), 1, Cap.BUTT); ll.line = new Line((Color.BLUE & 0xaaffffff), 1, Cap.BUTT);
ll.width = 2; ll.width = 2;
ll = (LineLayer) mDebugLayer.getLayer(3, Layer.LINE); ll = (LineLayer) dbg.getLayer(3, Layer.LINE);
ll.line = new Line((Color.YELLOW & 0xaaffffff), 1, Cap.BUTT); ll.line = new Line((Color.YELLOW & 0xaaffffff), 1, Cap.BUTT);
ll.width = 2; ll.width = 2;
ll = (LineLayer) mDebugLayer.getLayer(1, Layer.LINE); ll = (LineLayer) dbg.getLayer(1, Layer.LINE);
ll.line = new Line((Color.RED & 0xaaffffff), 1, Cap.BUTT); ll.line = new Line((Color.RED & 0xaaffffff), 1, Cap.BUTT);
ll.width = 2; ll.width = 2;
ll = (LineLayer) mDebugLayer.getLayer(2, Layer.LINE); ll = (LineLayer) dbg.getLayer(2, Layer.LINE);
ll.line = new Line((Color.GREEN & 0xaaffffff), 1, Cap.BUTT); ll.line = new Line((Color.GREEN & 0xaaffffff), 1, Cap.BUTT);
ll.width = 2; ll.width = 2;
} }
@ -299,27 +315,21 @@ public class TextOverlayExp extends BasicOverlay {
if (ti.text.caption) { if (ti.text.caption) {
ti2.move(ti, dx, dy, scale); ti2.move(ti, dx, dy, scale);
int tx = (int) (ti2.x); ti2.setAxisAlignedBBox();
int ty = (int) (ti2.y); ti2.bbox = new OBB2D(ti2.x, ti2.y, cos, -sin, ti2.width + 6,
int tw = (int) (ti2.width / 2); ti2.text.fontHeight + 6, true);
int th = (int) (ti2.text.fontHeight / 2);
boolean overlaps = false; boolean overlaps = false;
for (TextItem lp = tl.labels; lp != null;) { for (TextItem lp = tl.labels; lp != null; lp = lp.next) {
int px = (int) (lp.x); if (!lp.text.caption)
int py = (int) (lp.y); continue;
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)) {
if (ti2.bbox.overlaps(lp.bbox)) {
Log.d(TAG, "overlap > " + ti2.string + " " + lp.string);
//if (TextItem.bboxOverlaps(ti2, lp, 4)) {
overlaps = true; overlaps = true;
break; break;
} }
lp = lp.next;
} }
if (!overlaps) { if (!overlaps) {
tl.addText(ti2); tl.addText(ti2);
@ -332,13 +342,14 @@ public class TextOverlayExp extends BasicOverlay {
/* text is way label */ /* text is way label */
// 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;
// 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;
ti2.bbox = null;
ti2.move(ti, dx, dy, scale); ti2.move(ti, dx, dy, scale);
ti2.x2 = (ti2.x + width); ti2.x2 = (ti2.x + width);
@ -348,30 +359,44 @@ public class TextOverlayExp extends BasicOverlay {
byte overlaps = -1; byte overlaps = -1;
if (mDebugLayer == null || ti.width < ti.length * scale) if (dbg == null || ti.width < ti.length * scale)
overlaps = checkOverlap(tl, ti2); overlaps = checkOverlap(tl, ti2);
if (mDebugLayer != null) { if (dbg != null) {
LineLayer ll; LineLayer ll;
if (ti.width > ti.length * scale) { if (ti.width > ti.length * scale) {
ll = (LineLayer) mDebugLayer.getLayer(1, Layer.LINE); ll = (LineLayer) dbg.getLayer(1, Layer.LINE);
overlaps = 3; overlaps = 3;
} }
else if (overlaps == 1) else if (overlaps == 1)
ll = (LineLayer) mDebugLayer.getLayer(0, Layer.LINE); ll = (LineLayer) dbg.getLayer(0, Layer.LINE);
else if (overlaps == 2) else if (overlaps == 2)
ll = (LineLayer) mDebugLayer.getLayer(3, Layer.LINE); ll = (LineLayer) dbg.getLayer(3, Layer.LINE);
else else
ll = (LineLayer) mDebugLayer.getLayer(2, Layer.LINE); ll = (LineLayer) dbg.getLayer(2, Layer.LINE);
float[] points = new float[4]; // if (ti2.bbox == null)
short[] indices = { 4 }; // ti2.bbox = new OBB2D(ti2.x, ti2.y, ti2.x1, ti2.y1, ti.width + 10,
points[0] = ti2.x1 / scale; // ti.text.fontHeight + 10);
points[1] = ti2.y1 / scale;
points[2] = ti2.x2 / scale; {
points[3] = ti2.y2 / scale; float[] points = new float[4];
ll.addLine(points, indices, false); short[] indices = { 4 };
points[0] = (ti2.x - width * scale) / scale;
points[1] = (ti2.y - height * scale) / scale;
points[2] = (ti2.x + width * scale) / scale;
points[3] = (ti2.y + height * scale) / scale;
ll.addLine(points, indices, false);
}
if (ti2.bbox != null) {
short[] indices = { 8 };
float[] points = new float[8];
for (int p = 0; p < 8; p++)
points[p] = ti2.bbox.corner[p] / scale;
ll.addLine(points, indices, true);
}
} }
if (overlaps == 0) { if (overlaps == 0) {
ti.active++; ti.active++;
@ -424,6 +449,7 @@ public class TextOverlayExp extends BasicOverlay {
// pass new labels for rendering // pass new labels for rendering
synchronized (this) { synchronized (this) {
mNextLayer = tl; mNextLayer = tl;
mDebugLayer = dbg;
} }
return true; return true;
} }
@ -441,7 +467,7 @@ public class TextOverlayExp extends BasicOverlay {
if (mDebugLayer != null) { if (mDebugLayer != null) {
layers.layers = mDebugLayer.layers; layers.layers = mDebugLayer.layers;
mDebugLayer.layers = null; mDebugLayer = null;
} }
// set new TextLayer to be uploaded and rendered // set new TextLayer to be uploaded and rendered
@ -511,9 +537,9 @@ public class TextOverlayExp extends BasicOverlay {
} }
for (Layer l = layers.textureLayers; l != null;) { for (Layer l = layers.textureLayers; l != null;) {
l = TextureRenderer.draw(l, (mMapPosition.scale / pos.scale) * div l = TextureRenderer.draw(l, (mMapPosition.scale / pos.scale) * div, proj, mv);
, proj, mv);
} }
} }
@Override @Override