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> {
|
public static class BoxNode<T extends BoxItem<?>> extends TreeNode<BoxNode<T>, T> {
|
||||||
// TODO this is redundant - use tile ids
|
// TODO this is redundant - use tile ids
|
||||||
public int x1;
|
public int x1, x2, y1, y2;
|
||||||
public int y1;
|
|
||||||
public int x2;
|
|
||||||
public int y2;
|
|
||||||
|
|
||||||
// inherits BoxItem<E> item;
|
/* inherits BoxItem<E> item; */
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
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 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) {
|
public BoxItem(int x1, int y1, int x2, int y2) {
|
||||||
this.x1 = x1;
|
this.x1 = x1;
|
||||||
this.y1 = y1;
|
this.y1 = y1;
|
||||||
@ -80,6 +84,13 @@ public class BoxTree<T extends BoxItem<E>, E> extends TileIndex<BoxNode<T>, T> {
|
|||||||
this.y2 = y2;
|
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) {
|
public BoxItem(org.oscim.core.Box box, T item) {
|
||||||
this.x1 = (int) box.minX;
|
this.x1 = (int) box.minX;
|
||||||
this.y1 = (int) box.minY;
|
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;
|
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
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return x1 + "," + y1 + "/" + x2 + "," + y2;
|
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));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,12 +145,18 @@ public class BoxTree<T extends BoxItem<E>, E> extends TileIndex<BoxNode<T>, T> {
|
|||||||
return ((x > 0) && (x & (x - 1)) == 0);
|
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) {
|
public BoxTree(int extents, int maxDepth) {
|
||||||
super();
|
super();
|
||||||
if (!isPowerOfTwo(extents))
|
if (!isPowerOfTwo(extents))
|
||||||
throw new IllegalArgumentException("Extents must be power of two!");
|
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.x1 = -extents;
|
||||||
this.root.y1 = -extents;
|
this.root.y1 = -extents;
|
||||||
this.root.x2 = 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;
|
BoxNode<T> n;
|
||||||
|
|
||||||
Stack<BoxNode<T>> stack = stackPool.get();
|
Stack<BoxNode<T>> stack = stackPool.get();
|
||||||
stack.push(root);
|
stack.push(root);
|
||||||
|
|
||||||
O: while (!stack.empty()) {
|
while (!stack.empty()) {
|
||||||
|
|
||||||
n = stack.pop();
|
n = stack.pop();
|
||||||
|
|
||||||
/* process overlapping items from cur node */
|
/* process overlapping items from cur node */
|
||||||
for (BoxItem<E> it = n.item; it != null; it = it.next) {
|
for (BoxItem<E> it = n.item; it != null; it = it.next) {
|
||||||
if (it.overlaps(box)) {
|
if (it.overlaps(box)) {
|
||||||
if (!cb.call(it.item, ctxt))
|
if (!cb.call(it.item, ctxt)) {
|
||||||
break O;
|
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))
|
else if (overlaps(n.child11, box))
|
||||||
stack.push(n.child11);
|
stack.push(n.child11);
|
||||||
}
|
}
|
||||||
|
|
||||||
stackPool.release(stack);
|
stackPool.release(stack);
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface SearchBoxCb<T extends BoxItem<?>> {
|
public interface SearchBoxCb<T extends BoxItem<?>> {
|
||||||
boolean call(T item);
|
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> n;
|
||||||
BoxNode<T> start = getNode(box, false);
|
|
||||||
if (start == null)
|
if (root.refs == 0) {
|
||||||
return false;
|
//log.debug("emtpy");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
Stack<BoxNode<T>> stack = stackPool.get();
|
Stack<BoxNode<T>> stack = stackPool.get();
|
||||||
stack.push(start);
|
stack.push(root);
|
||||||
|
|
||||||
while (!stack.empty()) {
|
while (!stack.empty()) {
|
||||||
n = stack.pop();
|
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 */
|
/* push next level child onto stack */
|
||||||
if (overlaps(n.child00, box))
|
if (overlaps(n.child00, box))
|
||||||
stack.push(n.child00);
|
stack.push(n.child00);
|
||||||
|
|
||||||
else if (overlaps(n.child01, box))
|
else if (overlaps(n.child01, box))
|
||||||
stack.push(n.child01);
|
stack.push(n.child01);
|
||||||
|
|
||||||
else if (overlaps(n.child10, box))
|
else if (overlaps(n.child10, box))
|
||||||
stack.push(n.child10);
|
stack.push(n.child10);
|
||||||
|
|
||||||
else if (overlaps(n.child11, box))
|
else if (overlaps(n.child11, box))
|
||||||
stack.push(n.child11);
|
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);
|
boolean call(E item);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean collect(SearchNodeCb<BoxNode<T>> cb) {
|
public void collect(SearchNodeCb<BoxNode<T>> cb) {
|
||||||
BoxNode<T> n;
|
BoxNode<T> n;
|
||||||
|
|
||||||
Stack<BoxNode<T>> stack = stackPool.get();
|
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);
|
stack.push(n.child11);
|
||||||
}
|
}
|
||||||
stackPool.release(stack);
|
stackPool.release(stack);
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public BoxNode<T> create(BoxNode<T> parent, int i) {
|
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) {
|
if (pool != null) {
|
||||||
node = pool;
|
node = pool;
|
||||||
pool = pool.parent;
|
pool = pool.parent;
|
||||||
|
node.refs = 0;
|
||||||
} else
|
} else
|
||||||
node = new BoxNode<T>();
|
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 (level < maxDepth) {
|
||||||
if (x2 < cx) {
|
if (x2 < cx) {
|
||||||
if (y2 < cy) {
|
if (y2 < cy) {
|
||||||
if ((child = cur.child00) == null)
|
child = cur.child00;
|
||||||
return false;
|
|
||||||
} else if (y1 >= cy) {
|
} else if (y1 >= cy) {
|
||||||
if ((child = cur.child01) == null)
|
child = cur.child01;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
} else if (x1 >= cx) {
|
} else if (x1 >= cx) {
|
||||||
if (y2 < cy) {
|
if (y2 < cy) {
|
||||||
if ((child = cur.child10) == null)
|
child = cur.child10;
|
||||||
return false;
|
|
||||||
} else if (y1 >= cy) {
|
} else if (y1 >= cy) {
|
||||||
if ((child = cur.child11) == null)
|
child = cur.child11;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (child == null) {
|
if (child == null) {
|
||||||
/* push item onto list of this node */
|
|
||||||
BoxItem<E> prev = cur.item;
|
BoxItem<E> prev = cur.item;
|
||||||
|
|
||||||
for (BoxItem<E> it = cur.item; it != null; it = it.next) {
|
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
|
} else
|
||||||
prev.next = it.next;
|
prev.next = it.next;
|
||||||
|
|
||||||
|
it.next = null;
|
||||||
remove(cur);
|
remove(cur);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
prev = it;
|
prev = it;
|
||||||
@ -565,6 +608,70 @@ public class BoxTree<T extends BoxItem<E>, E> extends TileIndex<BoxNode<T>, T> {
|
|||||||
root.refs = 0;
|
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() {
|
public int size() {
|
||||||
return root.refs;
|
return root.refs;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user