- more work on generic pools

- generic inlist
This commit is contained in:
Hannes Janetzek 2013-04-10 01:56:38 +02:00
parent ab56cc4b18
commit 129a780c41
7 changed files with 151 additions and 125 deletions

View File

@ -16,10 +16,11 @@ package org.oscim.renderer.layer;
import java.nio.ShortBuffer; import java.nio.ShortBuffer;
import org.oscim.utils.pool.Inlist;
/** /**
* @authorHannes Janetzek * @authorHannes Janetzek
*/ */
public abstract class Layer { public abstract class Layer extends Inlist<Layer>{
public final static byte LINE = 0; public final static byte LINE = 0;
public final static byte POLYGON = 1; public final static byte POLYGON = 1;
public final static byte TEXLINE = 2; public final static byte TEXLINE = 2;
@ -31,8 +32,6 @@ public abstract class Layer {
public byte type = -1; public byte type = -1;
public Layer next;
// drawing order from bottom to top // drawing order from bottom to top
int level; int level;

View File

@ -43,8 +43,6 @@ public class TextItem extends Inlist<TextItem> {
TextItem ti = pool.get(); TextItem ti = pool.get();
ti.next = null;
ti.x = orig.x; ti.x = orig.x;
ti.y = orig.y; ti.y = orig.y;
@ -56,6 +54,22 @@ public class TextItem extends Inlist<TextItem> {
return ti; 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) { public TextItem set(float x, float y, String string, Text text) {
this.x = x; this.x = x;
this.y = y; this.y = y;

View File

@ -21,11 +21,15 @@ package org.oscim.renderer.overlays;
// 2. compare previous to current state // 2. compare previous to current state
// 2.1 test for new labels to be placed // 2.1 test for new labels to be placed
// 2.2 handle collisions // 2.2 handle collisions
// 2.3 try to place labels along a way
// 2.4 use 4 point labeling
// 3 join segments that belong to one feature // 3 join segments that belong to one feature
// 4 handle zoom-level changes // 4 handle zoom-level changes
// 5 R-Tree might be handy // 5 R-Tree might be handy
// //
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;
@ -47,6 +51,7 @@ import org.oscim.theme.renderinstruction.Line;
import org.oscim.utils.FastMath; import org.oscim.utils.FastMath;
import org.oscim.utils.OBB2D; import org.oscim.utils.OBB2D;
import org.oscim.utils.PausableThread; import org.oscim.utils.PausableThread;
import org.oscim.utils.pool.LList;
import org.oscim.utils.pool.Pool; import org.oscim.utils.pool.Pool;
import org.oscim.view.MapView; import org.oscim.view.MapView;
import org.oscim.view.MapViewPosition; import org.oscim.view.MapViewPosition;
@ -72,34 +77,46 @@ public class TextOverlay extends BasicOverlay {
// TextLayer that is ready to be added to 'layers' // TextLayer that is ready to be added to 'layers'
private TextLayer mNextLayer; private TextLayer mNextLayer;
// local pool, avoids synchronized TextItem.get()/release() // thread local pool
class LabelPool extends Pool<TextItem> {
Label releaseAndGetNext(Label l) {
class LabelPool extends Pool<TextItem>{ if (l.item != null)
Label releaseAndGetNext(Label l){
if (l.item != null){
TextItem.pool.release(l.item); TextItem.pool.release(l.item);
l.item = null;
} // drop references
l.item = null;
l.tile = null;
l.string = null;
Label ret = (Label) l.next; Label ret = (Label) l.next;
super.release(l); super.release(l);
return ret; return ret;
} }
@Override
protected TextItem createItem() {
return new Label();
}
} }
private final LabelPool mPool = new LabelPool(); private final LabelPool mPool = new LabelPool();
// list of previous labels
private Label mPrevLabels; private Label mPrevLabels;
// list of current labels
private Label mLabels; private Label mLabels;
private final float[] mTmpCoords = new float[8]; private final float[] mTmpCoords = new float[8];
//private HashMap<MapTile, Label> mItemMap; private final HashMap<MapTile, LabelTile> mActiveTiles;
//private Label mNewLabels;
//private final HashMap<MapTile, Link> mActiveTiles; class LabelTile {
Tile tile;
LList<Label> labels;
}
class Label extends TextItem { class Label extends TextItem {
TextItem item; TextItem item;
@ -141,16 +158,9 @@ public class TextOverlay extends BasicOverlay {
this.x2 = x + width / 2; this.x2 = x + width / 2;
this.y2 = y + text.fontHeight / 2; this.y2 = y + text.fontHeight / 2;
} }
//
} }
// class Link {
// Link next;
// Link prev;
// Label it;
// }
//
// class ActiveTile { // class ActiveTile {
// MapTile tile; // MapTile tile;
// int activeLabels; // int activeLabels;
@ -196,7 +206,7 @@ public class TextOverlay extends BasicOverlay {
layers.textureLayers = new TextLayer(); layers.textureLayers = new TextLayer();
mTmpLayer = new TextLayer(); mTmpLayer = new TextLayer();
//mActiveTiles = new HashMap<MapTile, Link>(); mActiveTiles = new HashMap<MapTile, LabelTile>();
mTmpPos = new MapPosition(); mTmpPos = new MapPosition();
mThread = new LabelThread(); mThread = new LabelThread();
mThread.start(); mThread.start();
@ -206,90 +216,84 @@ public class TextOverlay extends BasicOverlay {
// remove Label l from mLabels and return l.next // remove Label l from mLabels and return l.next
private Label removeLabel(Label l) { private Label removeLabel(Label l) {
Label ret = (Label)l.next; Label ret = (Label) l.next;
mPool.release(mLabels, l); mLabels = (Label)mPool.release(mLabels, l);
return ret; return ret;
} }
public void addLabel(Label item) { public void addLabel(Label l) {
TextItem it = mLabels; TextItem ll = mLabels;
for (; it != null; it = it.next) { for (; ll != null; ll = ll.next) {
// find other label with same text style
if (item.text == it.text) { if (l.text == ll.text) {
while (it.next != null while (ll.next != null
// break if next item uses different text style // break if next item uses different text style
&& item.text == it.next.text && l.text == ll.next.text
// check same string instance // check same string instance
&& item.string != it.string && l.string != ll.string
// check same string // check same string
&& !item.string.equals(it.string)) && !l.string.equals(ll.string))
it = it.next; ll = ll.next;
// unify duplicate string :)
// Note: this is required for 'packing test' in prepare to work! // Note: this is required for 'packing test' in prepare to work!
if (item.string != it.string && item.string.equals(it.string)) TextItem.shareText(l, ll);
item.string = it.string;
// insert after text of same type and/or before same string // insert after text of same type and/or before same string
item.next = it.next; l.next = ll.next;
it.next = item; ll.next = l;
return; return;
} }
} }
item.next = mLabels; l.next = mLabels;
mLabels = item; mLabels = l;
} }
private byte checkOverlap(Label ti) { private byte checkOverlap(Label l) {
for (Label lp = mLabels; lp != null;) {
for (Label ll = mLabels; ll != null;) {
// check bounding box // check bounding box
if (!TextItem.bboxOverlaps(ti, lp, 150)) { if (!TextItem.bboxOverlaps(l, ll, 150)) {
lp = (Label) lp.next; ll = (Label) ll.next;
continue; continue;
} }
if (lp.text == ti.text && (lp.string == ti.string || lp.string.equals(ti.string))) { if (TextItem.shareText(l, ll)) {
// make strings unique, should be done only once..
ti.string = lp.string;
// keep the label that was active earlier // keep the label that was active earlier
if (lp.active <= ti.active) if (ll.active <= l.active)
return 1; return 1;
// keep the label with longer segment // keep the label with longer segment
if (lp.length < ti.length) { if (ll.length < l.length) {
lp = removeLabel(lp); ll = removeLabel(ll);
continue; continue;
} }
return 2; return 2;
} }
boolean intersect = ti.bbox.overlaps(lp.bbox); boolean intersect = l.bbox.overlaps(ll.bbox);
if (intersect) { if (intersect) {
if (ll.active <= l.active)
if (lp.active <= ti.active)
return 1; return 1;
//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.text.caption if (!ll.text.caption
&& (lp.text.priority > ti.text.priority || lp.length < ti.length)) { && (ll.text.priority > l.text.priority || ll.length < l.length)) {
lp = removeLabel(lp); ll = removeLabel(ll);
continue; continue;
} }
return 1; return 1;
} }
lp = (Label) lp.next; ll = (Label) ll.next;
} }
return 0; return 0;
} }
@ -324,11 +328,7 @@ public class TextOverlay extends BasicOverlay {
private final static float[] mDebugPoints = new float[4]; private final static float[] mDebugPoints = new float[4];
private Label getLabel() { private Label getLabel() {
Label l = (Label)mPool.get(); Label l = (Label) mPool.get();
if (l == null)
l = new Label();
l.active = Integer.MAX_VALUE; l.active = Integer.MAX_VALUE;
return l; return l;
@ -384,7 +384,6 @@ public class TextOverlay extends BasicOverlay {
int maxx = Tile.SIZE << (zoom - 1); int maxx = Tile.SIZE << (zoom - 1);
Label l = null;
if (dbg != null) if (dbg != null)
addDebugLayers(dbg); addDebugLayers(dbg);
@ -394,7 +393,7 @@ public class TextOverlay extends BasicOverlay {
double tileX = (pos.x * (Tile.SIZE << zoom)); double tileX = (pos.x * (Tile.SIZE << zoom));
double tileY = (pos.y * (Tile.SIZE << zoom)); double tileY = (pos.y * (Tile.SIZE << zoom));
for (l = mPrevLabels; l != null;) { for (Label l = mPrevLabels; l != null;) {
if (l.text.caption) { if (l.text.caption) {
l = mPool.releaseAndGetNext(l); l = mPool.releaseAndGetNext(l);
continue; continue;
@ -445,20 +444,20 @@ public class TextOverlay extends BasicOverlay {
addDebugBox(dbg, l, l.item, overlaps, true, sscale); addDebugBox(dbg, l, l.item, overlaps, true, sscale);
if (overlaps == 0) { if (overlaps == 0) {
Label tmp = l; Label ll = l;
l = (Label) l.next; l = (Label) l.next;
tmp.next = null; ll.next = null;
addLabel(tmp); addLabel(ll);
continue; continue;
} }
l = mPool.releaseAndGetNext(l); l = mPool.releaseAndGetNext(l);
} }
Label l = null;
/* add way labels */ /* add way labels */
for (int i = 0, n = mTileSet.cnt; i < n; i++) { for (int i = 0, n = mTileSet.cnt; i < n; i++) {
MapTile t = tiles[i]; MapTile t = tiles[i];
if (t.state != JobTile.STATE_READY) if (t.state != JobTile.STATE_READY)
continue; continue;
@ -737,11 +736,12 @@ public class TextOverlay extends BasicOverlay {
@Override @Override
public synchronized void render(MapPosition pos, Matrices m) { 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); GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, layers.vbo.id);
GLState.test(false, false); GLState.test(false, false);
float scale = (float) (mMapPosition.scale / pos.scale);
if (layers.baseLayers != null) { if (layers.baseLayers != null) {
setMatrix(pos, m, true); setMatrix(pos, m, true);
@ -749,47 +749,16 @@ public class TextOverlay extends BasicOverlay {
if (l.type == Layer.POLYGON) { if (l.type == Layer.POLYGON) {
l = PolygonRenderer.draw(pos, l, m, true, false); l = PolygonRenderer.draw(pos, l, m, true, false);
} else { } else {
//float scale = pos.getScale() * div; float div = scale * (float) (pos.scale / (1 << pos.zoomLevel));
l = LineRenderer.draw(layers, l, pos, m, div, 0);
float scale = (float) ((1 << mMapPosition.zoomLevel) / pos.scale);
l = LineRenderer.draw(layers, l, pos, m, scale, 0);
} }
} }
} }
setMatrix(pos, m); setMatrix(pos, m, false);
for (Layer l = layers.textureLayers; l != null;) {
float scale = (float) (mMapPosition.scale / pos.scale);
//float scale = (mMapPosition.getScale() / pos.getScale()) * div;
for (Layer l = layers.textureLayers; l != null;)
l = TextureRenderer.draw(l, scale, m); l = TextureRenderer.draw(l, scale, m);
}
}
@Override
protected void setMatrix(MapPosition curPos, Matrices m) {
MapPosition oPos = mMapPosition;
double tileScale = Tile.SIZE * curPos.scale;
double scale = (curPos.scale / oPos.scale);
float x = (float) ((oPos.x - curPos.x) * tileScale);
float y = (float) ((oPos.y - curPos.y) * tileScale);
m.mvp.setTransScale(x, y, (float) (scale / GLRenderer.COORD_SCALE));
// 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.getScale() / oPos.getScale()) / div;
// float s = curPos.getScale() / div;
// m.mvp.setTransScale(x * s, y * s,
// scale / GLRenderer.COORD_SCALE);
m.mvp.multiplyMM(m.view, m.mvp);
} }
private boolean mHolding; private boolean mHolding;

View File

@ -112,8 +112,8 @@ public final class GeometryUtils {
// The lines are parallel. // The lines are parallel.
// Check if they're collinear. // Check if they're collinear.
double y3LessY1 = y3 - y1; double y3LessY1 = y3 - y1;
double collinearityTestForP3 = x1 * (y2 - y3) + x2 * (y3LessY1) + x3 * (y1 - y2); // see // see http://mathworld.wolfram.com/Collinear.html
// http://mathworld.wolfram.com/Collinear.html double collinearityTestForP3 = x1 * (y2 - y3) + x2 * (y3LessY1) + x3 * (y1 - y2);
// If p3 is collinear with p1 and p2 then p4 will also be collinear, // If p3 is collinear with p1 and p2 then p4 will also be collinear,
// since p1-p2 is parallel with p3-p4 // since p1-p2 is parallel with p3-p4
if (collinearityTestForP3 == 0) { if (collinearityTestForP3 == 0) {

View File

@ -0,0 +1,19 @@
/*
* Copyright 2013 Hannes Janetzek
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.oscim.utils.pool;
public class LList<T> extends Inlist<LList<T>> {
T data;
}

View File

@ -14,26 +14,44 @@
*/ */
package org.oscim.utils.pool; package org.oscim.utils.pool;
public class Pool<T extends Inlist<T>> { public abstract class Pool<T extends Inlist<T>> {
T pool; T pool;
/**
* @param item release resources
*/
protected void clearItem(T item) {
}
// release 'item' to pool.
// make sure that item is not in any other Inlist!
public void release(T item) { public void release(T item) {
if (item == null) if (item == null)
return; return;
clearItem(item);
item.next = pool; item.next = pool;
pool = item; pool = item;
} }
// remove 'item' from 'list' and add back to pool // remove 'item' from 'list' and add back to pool
public void release(T list, T item) { public T release(T list, T item) {
if (item == null) if (item == null)
return; return list;
clearItem(item);
if (item == list) { if (item == list) {
T ret = item.next;
item.next = pool; item.next = pool;
pool = item; pool = item;
return;
return ret;
} }
for (T prev = list, it = list.next; it != null; it = it.next) { for (T prev = list, it = list.next; it != null; it = it.next) {
@ -43,15 +61,20 @@ public class Pool<T extends Inlist<T>> {
item.next = pool; item.next = pool;
pool = item; pool = item;
return; break;
} }
prev = it; prev = it;
} }
return list;
} }
protected abstract T createItem();
public T get() { public T get() {
if (pool == null) if (pool == null)
return null; return createItem();
T ret = pool; T ret = pool;
pool = pool.next; pool = pool.next;

View File

@ -71,6 +71,7 @@ public abstract class SyncPool<T extends Inlist<T>> {
if (fill > maxFill) if (fill > maxFill)
while (item != null) { while (item != null) {
clearItem(item); clearItem(item);
item = item.next; item = item.next;
count--; count--;
} }
@ -99,6 +100,8 @@ public abstract class SyncPool<T extends Inlist<T>> {
T ret = list; T ret = list;
clearItem(item);
if (item == list) { if (item == list) {
ret = item.next; ret = item.next;
} else { } else {
@ -110,8 +113,6 @@ public abstract class SyncPool<T extends Inlist<T>> {
} }
} }
clearItem(item);
if (fill < maxFill) { if (fill < maxFill) {
synchronized (this) { synchronized (this) {
fill++; fill++;
@ -127,12 +128,13 @@ public abstract class SyncPool<T extends Inlist<T>> {
} }
public T get() { public T get() {
if (pool == null){
count++;
return createItem();
}
synchronized (this) { synchronized (this) {
if (pool == null){
count++;
return createItem();
}
fill--; fill--;
T ret = pool; T ret = pool;