BoxTree:
- return false from search() when search callback returned false - fix removal: unlink next item - add clearToPool()
This commit is contained in:
parent
64068730db
commit
c48c620963
@ -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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user