- return false from search() when search callback returned false
- fix removal: unlink next item
- add clearToPool()
This commit is contained in:
Hannes Janetzek 2014-09-11 20:19:09 +02:00
parent 64068730db
commit c48c620963

View File

@ -59,12 +59,9 @@ public class BoxTree<T extends BoxItem<E>, E> extends TileIndex<BoxNode<T>, T> {
public static class BoxNode<T extends BoxItem<?>> extends TreeNode<BoxNode<T>, T> {
// TODO this is redundant - use tile ids
public int x1;
public int y1;
public int x2;
public int y2;
public int x1, x2, y1, y2;
// inherits BoxItem<E> item;
/* inherits BoxItem<E> item; */
@Override
public String toString() {
@ -73,6 +70,13 @@ public class BoxTree<T extends BoxItem<E>, E> extends TileIndex<BoxNode<T>, T> {
}
public static class BoxItem<T> extends Inlist<BoxItem<T>> {
public int x1, x2, y1, y2;
public T item;
public BoxItem() {
}
public BoxItem(int x1, int y1, int x2, int y2) {
this.x1 = x1;
this.y1 = y1;
@ -80,6 +84,13 @@ public class BoxTree<T extends BoxItem<E>, E> extends TileIndex<BoxNode<T>, T> {
this.y2 = y2;
}
public BoxItem(float x1, float y1, float x2, float y2) {
this.x1 = (int) x1;
this.y1 = (int) y1;
this.x2 = (int) x2;
this.y2 = (int) y2;
}
public BoxItem(org.oscim.core.Box box, T item) {
this.x1 = (int) box.minX;
this.y1 = (int) box.minY;
@ -88,24 +99,41 @@ public class BoxTree<T extends BoxItem<E>, E> extends TileIndex<BoxNode<T>, T> {
this.item = item;
}
public boolean overlaps(BoxItem<?> it) {
return !((x1 > it.x2) || (it.x1 > x2) || (y1 > it.y2) || (it.y1 > y2));
}
public void setExtents(float[] obb, float add) {
setExtents(obb, add, obb.length);
}
public void setExtents(float[] obb, float add, int length) {
float x1, y1, x2, y2;
x1 = x2 = obb[0];
y1 = y2 = obb[1];
for (int i = 2, n = length; i < n; i += 2) {
float x = obb[i];
if (x < x1)
x1 = x;
else if (x > x2)
x2 = x;
float y = obb[i + 1];
if (y < y1)
y1 = y;
else if (y > y2)
y2 = y;
}
this.x1 = (int) (x1 - add);
this.y1 = (int) (y1 - add);
this.x2 = (int) (x2 + add);
this.y2 = (int) (y2 + add);
}
@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));
return "[" + x1 + ',' + y1 + '/' + x2 + ',' + y2 + ']';
}
}
@ -117,12 +145,18 @@ public class BoxTree<T extends BoxItem<E>, E> extends TileIndex<BoxNode<T>, T> {
return ((x > 0) && (x & (x - 1)) == 0);
}
/**
* BoxTreee for the range [-extents, extents]
*
* @param extents must be power of two
* @param maxDepth must be <= 30
*/
public BoxTree(int extents, int maxDepth) {
super();
if (!isPowerOfTwo(extents))
throw new IllegalArgumentException("Extents must be power of two!");
//size is -extents to +extents
/* size is -extents to +extents */
this.root.x1 = -extents;
this.root.y1 = -extents;
this.root.x2 = extents;
@ -157,21 +191,26 @@ public class BoxTree<T extends BoxItem<E>, E> extends TileIndex<BoxNode<T>, T> {
};
};
public boolean search(T box, SearchCb<E> cb, Object ctxt) {
/**
* @return false when search was aborted
*/
public boolean search(BoxItem<?> box, SearchCb<E> cb, Object ctxt) {
BoxNode<T> n;
Stack<BoxNode<T>> stack = stackPool.get();
stack.push(root);
O: while (!stack.empty()) {
while (!stack.empty()) {
n = stack.pop();
/* process overlapping items from cur node */
for (BoxItem<E> it = n.item; it != null; it = it.next) {
if (it.overlaps(box)) {
if (!cb.call(it.item, ctxt))
break O;
if (!cb.call(it.item, ctxt)) {
stackPool.release(stack);
return false;
}
}
}
@ -207,22 +246,25 @@ public class BoxTree<T extends BoxItem<E>, E> extends TileIndex<BoxNode<T>, T> {
else if (overlaps(n.child11, box))
stack.push(n.child11);
}
stackPool.release(stack);
return false;
return true;
}
public interface SearchBoxCb<T extends BoxItem<?>> {
boolean call(T item);
}
public boolean search(T box, SearchBoxCb<T> cb) {
public boolean search(BoxItem<?> box, SearchBoxCb<T> cb) {
BoxNode<T> n;
BoxNode<T> start = getNode(box, false);
if (start == null)
return false;
if (root.refs == 0) {
//log.debug("emtpy");
return true;
}
Stack<BoxNode<T>> stack = stackPool.get();
stack.push(start);
stack.push(root);
while (!stack.empty()) {
n = stack.pop();
@ -265,10 +307,13 @@ public class BoxTree<T extends BoxItem<E>, E> extends TileIndex<BoxNode<T>, T> {
/* push next level child onto stack */
if (overlaps(n.child00, box))
stack.push(n.child00);
else if (overlaps(n.child01, box))
stack.push(n.child01);
else if (overlaps(n.child10, box))
stack.push(n.child10);
else if (overlaps(n.child11, box))
stack.push(n.child11);
}
@ -285,7 +330,7 @@ public class BoxTree<T extends BoxItem<E>, E> extends TileIndex<BoxNode<T>, T> {
boolean call(E item);
}
public boolean collect(SearchNodeCb<BoxNode<T>> cb) {
public void collect(SearchNodeCb<BoxNode<T>> cb) {
BoxNode<T> n;
Stack<BoxNode<T>> stack = stackPool.get();
@ -332,7 +377,6 @@ public class BoxTree<T extends BoxItem<E>, E> extends TileIndex<BoxNode<T>, T> {
stack.push(n.child11);
}
stackPool.release(stack);
return false;
}
public BoxNode<T> create(BoxNode<T> parent, int i) {
@ -340,6 +384,7 @@ public class BoxTree<T extends BoxItem<E>, E> extends TileIndex<BoxNode<T>, T> {
if (pool != null) {
node = pool;
pool = pool.parent;
node.refs = 0;
} else
node = new BoxNode<T>();
@ -457,24 +502,20 @@ public class BoxTree<T extends BoxItem<E>, E> extends TileIndex<BoxNode<T>, T> {
if (level < maxDepth) {
if (x2 < cx) {
if (y2 < cy) {
if ((child = cur.child00) == null)
return false;
child = cur.child00;
} else if (y1 >= cy) {
if ((child = cur.child01) == null)
return false;
child = cur.child01;
}
} else if (x1 >= cx) {
if (y2 < cy) {
if ((child = cur.child10) == null)
return false;
child = cur.child10;
} else if (y1 >= cy) {
if ((child = cur.child11) == null)
return false;
child = cur.child11;
}
}
}
if (child == null) {
/* push item onto list of this node */
BoxItem<E> prev = cur.item;
for (BoxItem<E> it = cur.item; it != null; it = it.next) {
@ -492,7 +533,9 @@ public class BoxTree<T extends BoxItem<E>, E> extends TileIndex<BoxNode<T>, T> {
} else
prev.next = it.next;
it.next = null;
remove(cur);
return true;
}
prev = it;
@ -565,6 +608,70 @@ public class BoxTree<T extends BoxItem<E>, E> extends TileIndex<BoxNode<T>, T> {
root.refs = 0;
}
public void clearToPool() {
BoxNode<T> node = root;
while (true) {
/* traverse down */
if (node.child00 != null) {
node = node.child00;
continue;
}
if (node.child01 != null) {
node = node.child01;
continue;
}
if (node.child10 != null) {
node = node.child10;
continue;
}
if (node.child11 != null) {
node = node.child11;
continue;
}
if (node == root)
break;
/* traverse up */
BoxNode<T> parent = node.parent;
/* unlink from parent */
switch (node.id) {
case 0:
parent.child00 = null;
break;
case 1:
parent.child01 = null;
break;
case 2:
parent.child10 = null;
break;
case 3:
parent.child11 = null;
break;
}
/* release items */
node.item = null;
node.refs = 0;
/* add n back to pool */
node.parent = pool;
pool = node;
/* continue with parent node */
node = parent;
}
root.child00 = null;
root.child01 = null;
root.child10 = null;
root.child11 = null;
root.item = null;
root.refs = 0;
}
public int size() {
return root.refs;
}