start quad tree for bounding boxes
This commit is contained in:
parent
59e6240766
commit
3ea697763f
@ -30,6 +30,10 @@ import org.oscim.utils.quadtree.Node;
|
||||
*/
|
||||
public class MapTile extends Tile {
|
||||
|
||||
public static class TileNode extends Node<TileNode, MapTile> {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* To be removed: used by GWT backend
|
||||
* */
|
||||
@ -98,7 +102,7 @@ public class MapTile extends Tile {
|
||||
/**
|
||||
* Pointer to access relatives in QuadTree
|
||||
*/
|
||||
public Node<MapTile> node;
|
||||
public TileNode node;
|
||||
|
||||
/**
|
||||
* to avoid drawing a tile twice per frame
|
||||
|
||||
@ -29,9 +29,9 @@ import org.oscim.core.Tile;
|
||||
import org.oscim.map.Map;
|
||||
import org.oscim.map.Viewport;
|
||||
import org.oscim.renderer.BufferObject;
|
||||
import org.oscim.tiling.MapTile.TileNode;
|
||||
import org.oscim.utils.FastMath;
|
||||
import org.oscim.utils.ScanBox;
|
||||
import org.oscim.utils.quadtree.Node;
|
||||
import org.oscim.utils.quadtree.QuadTree;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@ -85,11 +85,11 @@ public class TileManager {
|
||||
// job queue filled in TileManager and polled by TileLoaders
|
||||
private final JobQueue jobQueue;
|
||||
|
||||
private final QuadTree<MapTile> mIndex = new QuadTree<MapTile>() {
|
||||
private final QuadTree<TileNode, MapTile> mIndex = new QuadTree<TileNode, MapTile>() {
|
||||
|
||||
@Override
|
||||
public MapTile create(int x, int y, int z) {
|
||||
Node<MapTile> t = super.add(x, y, z);
|
||||
TileNode t = super.add(x, y, z);
|
||||
t.item = new MapTile(x, y, (byte) z);
|
||||
t.item.node = t;
|
||||
|
||||
@ -97,7 +97,7 @@ public class TileManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(MapTile t) {
|
||||
public void removeItem(MapTile t) {
|
||||
if (t.node == null) {
|
||||
log.debug("BUG already removed " + t);
|
||||
return;
|
||||
@ -108,6 +108,11 @@ public class TileManager {
|
||||
t.node.item = null;
|
||||
t.node = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileNode create() {
|
||||
return new TileNode();
|
||||
}
|
||||
};
|
||||
|
||||
private final float[] mMapPlane = new float[8];
|
||||
@ -324,11 +329,9 @@ public class TileManager {
|
||||
tileSet.releaseTiles();
|
||||
}
|
||||
|
||||
/* package */MapTile addTile(int x, int y, int zoomLevel) {
|
||||
MapTile tile;
|
||||
|
||||
// tile = QuadTree.getTile(x, y, zoomLevel);
|
||||
tile = mIndex.getTile(x, y, zoomLevel);
|
||||
/* package */
|
||||
MapTile addTile(int x, int y, int zoomLevel) {
|
||||
MapTile tile = mIndex.getTile(x, y, zoomLevel);
|
||||
|
||||
if (tile == null) {
|
||||
tile = mIndex.create(x, y, zoomLevel);
|
||||
@ -393,7 +396,7 @@ public class TileManager {
|
||||
t.clear();
|
||||
|
||||
t.state = STATE_CANCEL;
|
||||
mIndex.remove(t);
|
||||
mIndex.removeItem(t);
|
||||
}
|
||||
mTilesCount--;
|
||||
}
|
||||
|
||||
@ -40,9 +40,9 @@ import org.oscim.renderer.elements.LineTexLayer;
|
||||
import org.oscim.renderer.elements.MeshLayer;
|
||||
import org.oscim.renderer.elements.PolygonLayer;
|
||||
import org.oscim.renderer.elements.RenderElement;
|
||||
import org.oscim.tiling.MapTile.TileNode;
|
||||
import org.oscim.utils.FastMath;
|
||||
import org.oscim.utils.ScanBox;
|
||||
import org.oscim.utils.quadtree.Node;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@ -91,7 +91,7 @@ public class TileRenderer extends LayerRenderer {
|
||||
* synced with clearTiles, setOverdrawColor and setBitmapAlpha
|
||||
*/
|
||||
@Override
|
||||
protected synchronized void update(MapPosition pos, boolean positionChanged, Matrices m) {
|
||||
protected synchronized void update(MapPosition pos, boolean changed, Matrices m) {
|
||||
|
||||
if (mAlpha == 0) {
|
||||
mTileManager.releaseTiles(mDrawTiles);
|
||||
@ -123,7 +123,7 @@ public class TileRenderer extends LayerRenderer {
|
||||
int tileCnt = mDrawTiles.cnt;
|
||||
MapTile[] tiles = mDrawTiles.tiles;
|
||||
|
||||
if (tilesChanged || positionChanged) {
|
||||
if (tilesChanged || changed) {
|
||||
updateTileVisibility(pos, m.mapPlane);
|
||||
}
|
||||
|
||||
@ -162,17 +162,17 @@ public class TileRenderer extends LayerRenderer {
|
||||
if (mClipMode > 1) {
|
||||
mClipMode = 3;
|
||||
//GL.glClear(GL20.GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
GL.glDepthFunc(GL20.GL_LESS);
|
||||
|
||||
double scale = pos.getZoomScale();
|
||||
/** draw child or parent proxies */
|
||||
boolean preferParent = (pos.getZoomScale() < 1.5)
|
||||
|| (pos.zoomLevel < tiles[0].zoomLevel);
|
||||
|
||||
for (int i = 0; i < tileCnt; i++) {
|
||||
MapTile t = tiles[i];
|
||||
if (t.isVisible
|
||||
&& (t.state != STATE_READY)
|
||||
&& (t.holder == null)) {
|
||||
boolean preferParent = (scale > 1.5)
|
||||
|| (pos.zoomLevel - t.zoomLevel < 0);
|
||||
drawProxyTile(t, pos, true, preferParent);
|
||||
}
|
||||
}
|
||||
@ -235,9 +235,9 @@ public class TileRenderer extends LayerRenderer {
|
||||
|
||||
// check near relatives than can serve as proxy
|
||||
if ((tile.proxies & MapTile.PROXY_PARENT) != 0) {
|
||||
MapTile rel = tile.node.parent.item;
|
||||
if (rel.state == STATE_NEW_DATA)
|
||||
uploadCnt += uploadTileData(rel);
|
||||
MapTile t = tile.node.parent.item;
|
||||
if (t.state == STATE_NEW_DATA)
|
||||
uploadCnt += uploadTileData(t);
|
||||
|
||||
// dont load child proxies
|
||||
continue;
|
||||
@ -247,9 +247,9 @@ public class TileRenderer extends LayerRenderer {
|
||||
if ((tile.proxies & 1 << c) == 0)
|
||||
continue;
|
||||
|
||||
MapTile rel = tile.node.child(i);
|
||||
if (rel != null && rel.state == STATE_NEW_DATA)
|
||||
uploadCnt += uploadTileData(rel);
|
||||
MapTile t = tile.node.child(i);
|
||||
if (t != null && t.state == STATE_NEW_DATA)
|
||||
uploadCnt += uploadTileData(t);
|
||||
}
|
||||
}
|
||||
return uploadCnt;
|
||||
@ -270,7 +270,7 @@ public class TileRenderer extends LayerRenderer {
|
||||
tile.layers.vbo = BufferObject.get(GL20.GL_ARRAY_BUFFER, newSize);
|
||||
|
||||
if (!ElementRenderer.uploadLayers(tile.layers, newSize, true)) {
|
||||
log.debug("BUG uploadTileData " + tile + " failed!");
|
||||
log.error("{} uploadTileData failed!", tile);
|
||||
|
||||
tile.layers.vbo = BufferObject.release(tile.layers.vbo);
|
||||
tile.layers.clear();
|
||||
@ -550,10 +550,10 @@ public class TileRenderer extends LayerRenderer {
|
||||
return drawn;
|
||||
}
|
||||
|
||||
private void drawProxyTile(MapTile tile, MapPosition pos, boolean parent,
|
||||
boolean preferParent) {
|
||||
protected void drawProxyTile(MapTile tile, MapPosition pos,
|
||||
boolean parent, boolean preferParent) {
|
||||
|
||||
Node<MapTile> r = tile.node;
|
||||
TileNode r = tile.node;
|
||||
MapTile proxy;
|
||||
|
||||
if (!preferParent) {
|
||||
|
||||
424
vtm/src/org/oscim/utils/quadtree/BoxTree.java
Normal file
424
vtm/src/org/oscim/utils/quadtree/BoxTree.java
Normal file
@ -0,0 +1,424 @@
|
||||
package org.oscim.utils.quadtree;
|
||||
|
||||
import org.oscim.utils.pool.Inlist;
|
||||
import org.oscim.utils.quadtree.BoxTree.BoxItem;
|
||||
import org.oscim.utils.quadtree.BoxTree.BoxNode;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* A BoxTree is made of BoxNodes which hold a list of
|
||||
* generic BoxItems which can hold a custom data item.
|
||||
*
|
||||
* ... in case this generic isnt obvious at first sight.
|
||||
* */
|
||||
public abstract class BoxTree<Box extends BoxItem<E>, E>
|
||||
extends QuadTree<BoxNode<Box>, Box> {
|
||||
|
||||
final static Logger log = LoggerFactory.getLogger(BoxTree.class);
|
||||
static boolean dbg = false;
|
||||
|
||||
int extents;
|
||||
int maxDepth;
|
||||
|
||||
public static class BoxNode<T extends BoxItem<?>> extends Node<BoxNode<T>, T> {
|
||||
// for non-recursive traversal
|
||||
BoxNode<T> next;
|
||||
public int x;
|
||||
public int y;
|
||||
public int size;
|
||||
|
||||
//BoxItem<T> list;
|
||||
|
||||
public boolean overlaps(T it) {
|
||||
return (x < it.x2) &&
|
||||
(y < it.y2) &&
|
||||
(it.x1 < x + size) &&
|
||||
(it.y1 < y + size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return x + ":" + y + ":" + size;
|
||||
}
|
||||
}
|
||||
|
||||
public static class BoxItem<T> extends Inlist<BoxItem<T>> {
|
||||
public BoxItem(int x1, int y1, int x2, int y2) {
|
||||
this.x1 = x1;
|
||||
this.x2 = x2;
|
||||
this.y1 = y1;
|
||||
this.y2 = y2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return x1 + "," + y1 + "/" + x2 + "," + y2;
|
||||
}
|
||||
|
||||
public T item;
|
||||
|
||||
public BoxItem() {
|
||||
|
||||
}
|
||||
|
||||
public int x1;
|
||||
public int x2;
|
||||
public int y1;
|
||||
public int y2;
|
||||
|
||||
public boolean overlaps(BoxItem<T> it) {
|
||||
return (x1 < it.x2)
|
||||
&& (it.x1 < x2)
|
||||
&& (y1 < it.y2)
|
||||
&& (it.y1 < y2);
|
||||
}
|
||||
}
|
||||
|
||||
public interface Visitor<T> {
|
||||
boolean process(T item);
|
||||
}
|
||||
|
||||
// public class NodeVistor<T> implements Visitor<BoxNode<T>> {
|
||||
//
|
||||
// @Override
|
||||
// public boolean process(BoxNode<T> item) {
|
||||
//
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// }
|
||||
|
||||
public BoxTree(int extents, int maxDepth) {
|
||||
super();
|
||||
// size is -extents to +extents
|
||||
this.root.size = extents * 2;
|
||||
this.root.x = -extents;
|
||||
this.root.y = -extents;
|
||||
|
||||
this.extents = extents;
|
||||
this.maxDepth = maxDepth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Box create(int x, int y, int z) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BoxNode<Box> create() {
|
||||
BoxNode<Box> node = new BoxNode<Box>();
|
||||
return node;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeItem(Box item) {
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public int query(Box box) {
|
||||
if (box.x1 > box.x2 || box.y1 > box.y2)
|
||||
throw new IllegalArgumentException();
|
||||
|
||||
int x1 = box.x1;
|
||||
int x2 = box.x2;
|
||||
int y1 = box.y1;
|
||||
int y2 = box.y2;
|
||||
|
||||
BoxNode<Box> cur, c;
|
||||
BoxNode<Box> stack = root;
|
||||
int result = 0;
|
||||
|
||||
boolean drop = false;
|
||||
|
||||
//O:
|
||||
while (stack != null) {
|
||||
|
||||
/** pop cur from stack */
|
||||
cur = stack;
|
||||
stack = stack.next;
|
||||
|
||||
/** process overlapping items from cur node */
|
||||
Box prev = cur.item;
|
||||
|
||||
for (Box it = cur.item; it != null; it = (Box) it.next) {
|
||||
if ((x1 <= it.x2) && (x2 >= it.x1) &&
|
||||
(y1 <= it.y2) && (y2 >= it.y1)) {
|
||||
|
||||
result = process(box, it);
|
||||
|
||||
if (result > 0) {
|
||||
if (dbg)
|
||||
log.debug("{} overlap {} {}", result, box, it);
|
||||
drop = true;
|
||||
//break O;
|
||||
}
|
||||
|
||||
if (result < 0) {
|
||||
result = 0;
|
||||
if (dbg)
|
||||
log.debug("remove overlap {} {}", box, it);
|
||||
// remove this itemchild = cur.child11;
|
||||
//cur.item = Inlist.remove(cur.item, it);
|
||||
if (it == cur.item)
|
||||
prev = cur.item = it;
|
||||
else
|
||||
prev.next = it.next;
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
prev = it;
|
||||
}
|
||||
|
||||
/** put children on stack which overlap with box */
|
||||
if ((c = cur.child00) != null && c.overlaps(box)) {
|
||||
c.next = stack;
|
||||
stack = c;
|
||||
}
|
||||
|
||||
if ((c = cur.child01) != null && c.overlaps(box)) {
|
||||
c.next = stack;
|
||||
stack = c;
|
||||
}
|
||||
|
||||
if ((c = cur.child10) != null && c.overlaps(box)) {
|
||||
c.next = stack;
|
||||
stack = c;
|
||||
}
|
||||
|
||||
if ((c = cur.child11) != null && c.overlaps(box)) {
|
||||
c.next = stack;
|
||||
stack = c;
|
||||
}
|
||||
}
|
||||
|
||||
/** dont keep dangling references */
|
||||
while (stack != null)
|
||||
stack = stack.next;
|
||||
|
||||
return drop ? 1 : 0;
|
||||
}
|
||||
|
||||
public abstract boolean collectAll(BoxNode<Box> node);
|
||||
|
||||
public int all() {
|
||||
return all(root);
|
||||
}
|
||||
|
||||
public int all(BoxNode<Box> node) {
|
||||
|
||||
BoxNode<Box> cur, c;
|
||||
BoxNode<Box> stack = node;
|
||||
|
||||
while (stack != null) {
|
||||
cur = stack;
|
||||
stack = stack.next;
|
||||
|
||||
if (cur.item != null && !collectAll(cur))
|
||||
break;
|
||||
|
||||
if ((c = cur.child00) != null) {
|
||||
c.next = stack;
|
||||
stack = c;
|
||||
}
|
||||
if ((c = cur.child01) != null) {
|
||||
c.next = stack;
|
||||
stack = c;
|
||||
}
|
||||
if ((c = cur.child10) != null) {
|
||||
c.next = stack;
|
||||
stack = c;
|
||||
}
|
||||
if ((c = cur.child11) != null) {
|
||||
c.next = stack;
|
||||
stack = c;
|
||||
}
|
||||
}
|
||||
|
||||
// dont keep dangling references
|
||||
while (stack != null)
|
||||
stack = stack.next;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public abstract int process(Box box, Box it);
|
||||
|
||||
public BoxNode<Box> create(BoxNode<Box> parent, int i) {
|
||||
BoxNode<Box> node = new BoxNode<Box>();
|
||||
int size = parent.size >> 1;
|
||||
node.x = parent.x;
|
||||
node.y = parent.y;
|
||||
node.size = size;
|
||||
|
||||
if (i == 0) {
|
||||
// top-left
|
||||
parent.child00 = node;
|
||||
} else if (i == 1) {
|
||||
// bottom-left
|
||||
parent.child10 = node;
|
||||
node.y += size;
|
||||
} else if (i == 2) {
|
||||
// top-right
|
||||
parent.child01 = node;
|
||||
node.x += size;
|
||||
} else {
|
||||
// bottom-right
|
||||
parent.child11 = node;
|
||||
node.x += size;
|
||||
node.y += size;
|
||||
}
|
||||
|
||||
node.parent = parent;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
public void insert(Box box) {
|
||||
if (box.x1 > box.x2 || box.y1 > box.y2)
|
||||
throw new IllegalArgumentException();
|
||||
|
||||
BoxNode<Box> cur = root;
|
||||
BoxNode<Box> child = null;
|
||||
|
||||
// tile position in tree
|
||||
//int px = 0, py = 0;
|
||||
int idX = 0, idY = 0;
|
||||
int x1 = box.x1;
|
||||
int x2 = box.x2;
|
||||
int y1 = box.y1;
|
||||
int y2 = box.y2;
|
||||
|
||||
for (int level = 0; level <= maxDepth; level++) {
|
||||
// half size of tile at current z
|
||||
//int hsize = (extents >> level);
|
||||
int hsize = cur.size >> 1;
|
||||
|
||||
// center of tile (shift by -extents)
|
||||
//int cx = px + hsize - extents;
|
||||
//int cy = py + hsize - extents;
|
||||
int cx = cur.x + hsize;
|
||||
int cy = cur.y + hsize;
|
||||
|
||||
child = null;
|
||||
//int childPos = -1;
|
||||
//log.debug(cx + ":" + cy + " " + hsize);
|
||||
if (x2 <= cx) {
|
||||
if (y2 <= cy) {
|
||||
if ((child = cur.child00) == null)
|
||||
child = create(cur, 0);
|
||||
}
|
||||
// should be else?
|
||||
if (y1 >= cy) {
|
||||
if ((child = cur.child10) == null)
|
||||
child = create(cur, 1);
|
||||
idX++;
|
||||
}
|
||||
}
|
||||
if (x1 >= cx) {
|
||||
if (y2 <= cy) {
|
||||
if ((child = cur.child01) == null)
|
||||
child = create(cur, 2);
|
||||
idY++;
|
||||
}
|
||||
if (y1 >= cy) {
|
||||
if ((child = cur.child11) == null)
|
||||
child = create(cur, 3);
|
||||
idX++;
|
||||
idY++;
|
||||
}
|
||||
}
|
||||
|
||||
//log.debug("child {}", child);
|
||||
|
||||
if (child == null || level == maxDepth) {
|
||||
// push item onto list of this node
|
||||
box.next = cur.item;
|
||||
cur.item = box;
|
||||
|
||||
if (dbg)
|
||||
log.debug("insert at: " + level + " / " + idX + ":"
|
||||
+ idY + " -- " + x1 + ":" + y1
|
||||
+ " /" + (x2) + "x" + (y2));
|
||||
|
||||
break;
|
||||
}
|
||||
cur = child;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public abstract boolean process(BoxNode<Box> nodes);
|
||||
|
||||
public void clear() {
|
||||
root.child00 = null;
|
||||
root.child01 = null;
|
||||
root.child10 = null;
|
||||
root.child11 = null;
|
||||
root.item = null;
|
||||
|
||||
//root = create();
|
||||
//root.parent = root;
|
||||
}
|
||||
|
||||
static class Item extends BoxItem<Integer> {
|
||||
public Item(int x1, int y1, int x2, int y2) {
|
||||
super(x1, y1, x2, y2);
|
||||
}
|
||||
|
||||
public Item() {
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
}
|
||||
|
||||
// static {
|
||||
// System.setProperty(org.slf4j.impl.SimpleLogger.DEFAULT_LOG_LEVEL_KEY, "TRACE");
|
||||
//}
|
||||
// public static void main(String[] args) {
|
||||
//
|
||||
// BoxTree<Item, Integer> tree = new BoxTree<Item, Integer>(4096, 12) {
|
||||
//
|
||||
// @Override
|
||||
// public int process(Item box, Item it) {
|
||||
// System.out.println("found ... " + box + "\t\t" + it);
|
||||
// return 1;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public boolean process(BoxNode<Item> nodes) {
|
||||
// System.out.println("found ... ");
|
||||
// //for (BoxItem it = nodes.item; it != null; it = it.next) {
|
||||
// // System.out.println("it: " + it.x1 + "/" + it.y1);
|
||||
// //}
|
||||
//
|
||||
// // TODO Auto-generated method stub
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public boolean collectAll(BoxNode<Item> nodes) {
|
||||
// for (Item it = nodes.item; it != null; it = (Item) it.next) {
|
||||
// System.out.println("all: " + it);
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// };
|
||||
// //[VtmAsyncExecutor] DEBUG org.oscim.utils.quadtree.BoxTree - insert at: 8 / 9:0 -- -631:266 /106x187
|
||||
//
|
||||
// tree.insert(new Item(-631, 266, -631 + 106, 266 + 187));
|
||||
//
|
||||
// //tree.insert(new Item(-40, -40, -32, -32));
|
||||
// // tree.insert(new Item(-60, -60, -40, -40));
|
||||
// // tree.insert(new Item(100, 10, 200, 100));
|
||||
// // tree.insert(new Item(100, 200, 200, 300));
|
||||
// // tree.insert(new Item(100, 200, 1000, 1000));
|
||||
// //
|
||||
// // tree.query(new Item(-100, -100, 10, 10));
|
||||
// //tree.query(new Item(10, 10, 100, 100));
|
||||
//
|
||||
// tree.all();
|
||||
// }
|
||||
}
|
||||
@ -16,14 +16,14 @@
|
||||
*/
|
||||
package org.oscim.utils.quadtree;
|
||||
|
||||
public class Node<T> {
|
||||
public Node<T> parent;
|
||||
public Node<T> child00;
|
||||
public Node<T> child10;
|
||||
public Node<T> child01;
|
||||
public Node<T> child11;
|
||||
public class Node<T extends Node<T, E>, E> {
|
||||
public T parent;
|
||||
public T child00;
|
||||
public T child10;
|
||||
public T child01;
|
||||
public T child11;
|
||||
|
||||
public T item;
|
||||
public E item;
|
||||
|
||||
// id of this child relative to parent
|
||||
byte id;
|
||||
@ -31,11 +31,26 @@ public class Node<T> {
|
||||
// number of children and grandchildren
|
||||
int refs = 0;
|
||||
|
||||
public T parent() {
|
||||
// public byte getId() {
|
||||
// if (parent.child00 == this)
|
||||
// return 0;
|
||||
// if (parent.child01 == this)
|
||||
// return 1;
|
||||
// if (parent.child10 == this)
|
||||
// return 2;
|
||||
// if (parent.child00 == this)
|
||||
// return 3;
|
||||
//
|
||||
// // is root node
|
||||
// //if (parent == this)
|
||||
// return -1;
|
||||
// }
|
||||
|
||||
public E parent() {
|
||||
return parent.item;
|
||||
}
|
||||
|
||||
public T child(int i) {
|
||||
public E child(int i) {
|
||||
switch (i) {
|
||||
case 0:
|
||||
return (child00 != null) ? child00.item : null;
|
||||
|
||||
@ -16,32 +16,38 @@
|
||||
*/
|
||||
package org.oscim.utils.quadtree;
|
||||
|
||||
public abstract class QuadTree<T> {
|
||||
/**
|
||||
* A quad tree for the standard map tiling schema.
|
||||
*/
|
||||
public abstract class QuadTree<T extends Node<T, E>, E> {
|
||||
|
||||
Node<T> pool;
|
||||
protected final T root;
|
||||
|
||||
Node<T> root;
|
||||
protected T pool;
|
||||
|
||||
public QuadTree() {
|
||||
root = new Node<T>();
|
||||
root = create();
|
||||
root.parent = root;
|
||||
}
|
||||
|
||||
static void checkIndex(int x, int y, int max) {
|
||||
if (x < 0 || x >= max || y < 0 || y >= max) {
|
||||
throw new IllegalArgumentException("invalid position " + x + '/' + y + '/' + (max >> 1));
|
||||
throw new IllegalArgumentException("invalid position "
|
||||
+ x + '/' + y + '/' + (max >> 1));
|
||||
}
|
||||
}
|
||||
|
||||
public abstract T create(int x, int y, int z);
|
||||
public abstract E create(int x, int y, int z);
|
||||
|
||||
public abstract void remove(T item);
|
||||
public abstract T create();
|
||||
|
||||
public Node<T> add(int x, int y, int z) {
|
||||
public abstract void removeItem(E item);
|
||||
|
||||
public T add(int x, int y, int z) {
|
||||
|
||||
checkIndex(x, y, 1 << z);
|
||||
|
||||
Node<T> leaf = root;
|
||||
T leaf = root;
|
||||
|
||||
for (int level = z - 1; level >= 0; level--) {
|
||||
|
||||
@ -49,7 +55,7 @@ public abstract class QuadTree<T> {
|
||||
|
||||
leaf.refs++;
|
||||
|
||||
Node<T> cur = null;
|
||||
T cur = null;
|
||||
|
||||
switch (id) {
|
||||
case 0:
|
||||
@ -75,7 +81,7 @@ public abstract class QuadTree<T> {
|
||||
cur = pool;
|
||||
pool = pool.parent;
|
||||
} else {
|
||||
cur = new Node<T>();
|
||||
cur = create();
|
||||
}
|
||||
|
||||
cur.refs = 0;
|
||||
@ -105,11 +111,11 @@ public abstract class QuadTree<T> {
|
||||
return leaf;
|
||||
}
|
||||
|
||||
public T getTile(int x, int y, int z) {
|
||||
public E getTile(int x, int y, int z) {
|
||||
|
||||
checkIndex(x, y, 1 << z);
|
||||
|
||||
Node<T> leaf = root;
|
||||
T leaf = root;
|
||||
|
||||
for (int level = z - 1; level >= 0; level--) {
|
||||
|
||||
@ -140,14 +146,14 @@ public abstract class QuadTree<T> {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean remove(Node<T> item) {
|
||||
public boolean remove(T item) {
|
||||
|
||||
Node<T> cur = item;
|
||||
Node<T> next;
|
||||
T cur = item;
|
||||
T next;
|
||||
|
||||
while (cur != root) {
|
||||
if (cur == null)
|
||||
throw new IllegalArgumentException("QuadTree.remove: item not in index");
|
||||
throw new IllegalArgumentException("item not in index");
|
||||
|
||||
// keep pointer to parent
|
||||
next = cur.parent;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user