diff --git a/vtm-tests/test/org/oscim/utils/QuadTreeTest.java b/vtm-tests/test/org/oscim/utils/QuadTreeTest.java
new file mode 100644
index 00000000..d0553c9d
--- /dev/null
+++ b/vtm-tests/test/org/oscim/utils/QuadTreeTest.java
@@ -0,0 +1,234 @@
+package org.oscim.utils;
+
+import static java.lang.System.currentTimeMillis;
+import static java.lang.System.out;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.oscim.core.Box;
+import org.oscim.utils.SpatialIndex.SearchCb;
+
+public class QuadTreeTest {
+	final static Random rand = new Random((long) (Math.PI * 10000000));
+
+	public class Item {
+		final int val;
+		final Box bbox;;
+
+		Item(Box bbox, int val) {
+			this.val = val;
+			this.bbox = new Box(bbox);
+		}
+
+		@Override
+		public String toString() {
+			return String.valueOf(val) + ' ' + bbox;
+		}
+	}
+
+	ArrayList<Item> fillRandomTree(SpatialIndex<Item> q, int numItems) {
+		Box box = new Box();
+		ArrayList<Item> items = new ArrayList<Item>(numItems + 16);
+
+		for (int i = 0; i < numItems; i++) {
+			box.minX = (int) (rand.nextDouble() * 10000 - 5000);
+			box.minY = (int) (rand.nextDouble() * 10000 - 5000);
+			box.maxX = (int) (box.minX + rand.nextDouble() * 500);
+			box.maxY = (int) (box.minY + rand.nextDouble() * 500);
+
+			Item it = new Item(box, i);
+			q.insert(box, it);
+
+			items.add(it);
+
+		}
+		return items;
+	}
+
+	@Test
+	public void shouldWork0() {
+
+		SpatialIndex<Item> q = new QuadTree<Item>(Short.MAX_VALUE + 1, 16);
+		//SpatialIndex<Item> q = new RTree<Item>();
+
+		int numItems = 10000;
+
+		List<Item> items = fillRandomTree(q, numItems);
+
+		final int[] found = { 0 };
+		final int[] matched = { 0 };
+
+		for (Item it : items) {
+			int f = matched[0];
+			q.search(it.bbox, new SearchCb<Item>() {
+				@Override
+				public boolean call(Item item, Object context) {
+					found[0]++;
+					if (context == item) {
+						matched[0]++;
+						return false;
+					}
+					return true;
+				}
+			}, it);
+
+			if (f == matched[0])
+				out.println((it.bbox.maxX - it.bbox.minX)
+				        + " x " + (it.bbox.maxY - it.bbox.minY)
+				        + " ==> " + it);
+		}
+
+		//out.println("m:" + matched[0] + "  f:" + found[0]);
+		Assert.assertEquals(numItems, matched[0]);
+		Assert.assertEquals(numItems, q.size());
+	}
+
+	@Test
+	public void shouldWork1() {
+		long time = currentTimeMillis();
+
+		for (int i = 0; i < 10; i++) {
+			shouldWork0();
+		}
+
+		long now = currentTimeMillis();
+		out.println("==>" + (now - time) / 10.0f + "ms");
+	}
+
+	@Test
+	public void shouldWork6() {
+		SpatialIndex<Item> q = new QuadTree<Item>(Short.MAX_VALUE + 1, 16);
+
+		Box box = new Box(-4184.653317773969,
+		                  3183.6174297948446,
+		                  -4088.3197324911957,
+		                  3222.7770427421046);
+
+		Item it = new Item(box, 1);
+		q.insert(box, it);
+
+		q.search(it.bbox, new SearchCb<Item>() {
+			@Override
+			public boolean call(Item item, Object context) {
+				out.println("==> " + item + " " + (context == item));
+				return true;
+			}
+		}, it);
+		Assert.assertEquals(1, q.size());
+	}
+
+	@Test
+	public void shouldWork7() {
+		SpatialIndex<Item> q = new QuadTree<Item>(Short.MAX_VALUE + 1, 14);
+		//SpatialIndex<Item> q = new RTree<Item>();
+
+		int numItems = 10000;
+
+		List<Item> items = fillRandomTree(q, numItems);
+
+		Assert.assertEquals(numItems, q.size());
+
+		int cnt = numItems;
+		for (Item it : items) {
+			if (!q.remove(it.bbox, it)) {
+				out.println((it.bbox.maxX - it.bbox.minX)
+				        + " x " + (it.bbox.maxY - it.bbox.minY)
+				        + " ==> " + it);
+
+				q.search(it.bbox, new SearchCb<Item>() {
+					@Override
+					public boolean call(Item item, Object context) {
+						if (context == item) {
+							out.println("found...");
+							return false;
+						}
+						return true;
+					}
+				}, it);
+			}
+			Assert.assertEquals(--cnt, q.size());
+		}
+
+		items = fillRandomTree(q, numItems);
+
+		Assert.assertEquals(numItems, q.size());
+
+		cnt = numItems;
+		for (Item it : items) {
+			if (!q.remove(it.bbox, it))
+				out.println((it.bbox.maxX - it.bbox.minX)
+				        + " x " + (it.bbox.maxY - it.bbox.minY)
+				        + " => " + it);
+
+			Assert.assertEquals(--cnt, q.size());
+		}
+		Assert.assertEquals(0, q.size());
+		out.println("");
+	}
+
+	@Test
+	public void shouldWork8() {
+
+		SpatialIndex<Item> q = new QuadTree<Item>(Short.MAX_VALUE + 1, 16);
+		//SpatialIndex<Item> q = new RTree<Item>();
+
+		int numItems = 10000;
+
+		List<Item> items = fillRandomTree(q, numItems);
+
+		final int[] found = { 0 };
+		final int[] matched = { 0 };
+
+		for (Item it : items) {
+			int f = matched[0];
+			int cnt = 0;
+			for (Item it2 : items) {
+				if (it2.bbox.overlap(it.bbox))
+					cnt++;
+			}
+			found[0] = 0;
+			q.search(it.bbox, new SearchCb<Item>() {
+				@Override
+				public boolean call(Item item, Object context) {
+					found[0]++;
+					if (context == item) {
+						matched[0]++;
+						//return false;
+					}
+					return true;
+				}
+			}, it);
+
+			if (found[0] != cnt) {
+				out.println("not found " + (found[0] - cnt));
+			}
+			//Assert.assertEquals(cnt, found[0]);
+			if (f == matched[0])
+				out.println((it.bbox.maxX - it.bbox.minX)
+				        + " x " + (it.bbox.maxY - it.bbox.minY)
+				        + " ==> " + it);
+		}
+
+		//out.println("m:" + matched[0] + "  f:" + found[0]);
+		Assert.assertEquals(numItems, matched[0]);
+		Assert.assertEquals(numItems, q.size());
+	}
+
+	public static void main(String[] args) {
+		QuadTreeTest qt = new QuadTreeTest();
+
+		long time = currentTimeMillis();
+
+		for (int i = 0; i < 100; i++) {
+			qt.shouldWork0();
+			long now = currentTimeMillis();
+
+			out.println("==>" + (now - time));
+			time = now;
+		}
+	}
+}
diff --git a/vtm/src/org/oscim/layers/tile/MapTile.java b/vtm/src/org/oscim/layers/tile/MapTile.java
index b0195bc6..59e763fb 100644
--- a/vtm/src/org/oscim/layers/tile/MapTile.java
+++ b/vtm/src/org/oscim/layers/tile/MapTile.java
@@ -21,7 +21,7 @@ import org.oscim.layers.tile.vector.VectorTileLoader;
 import org.oscim.layers.tile.vector.labeling.LabelTileLoaderHook;
 import org.oscim.renderer.elements.ElementLayers;
 import org.oscim.utils.pool.Inlist;
-import org.oscim.utils.quadtree.Node;
+import org.oscim.utils.quadtree.TreeNode;
 import org.oscim.utils.quadtree.QuadTree;
 
 /**
@@ -32,7 +32,7 @@ import org.oscim.utils.quadtree.QuadTree;
  */
 public class MapTile extends Tile {
 
-	public static class TileNode extends Node<TileNode, MapTile> {
+	public static class TileNode extends TreeNode<TileNode, MapTile> {
 
 	}
 
diff --git a/vtm/src/org/oscim/utils/QuadTree.java b/vtm/src/org/oscim/utils/QuadTree.java
new file mode 100644
index 00000000..1daf206b
--- /dev/null
+++ b/vtm/src/org/oscim/utils/QuadTree.java
@@ -0,0 +1,76 @@
+package org.oscim.utils;
+
+import java.util.List;
+
+import org.oscim.core.Box;
+import org.oscim.utils.pool.Pool;
+import org.oscim.utils.quadtree.BoxTree;
+import org.oscim.utils.quadtree.BoxTree.BoxItem;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class QuadTree<T> extends BoxTree<BoxItem<T>, T> implements SpatialIndex<T> {
+
+	public QuadTree(int extents, int maxDepth) {
+		super(extents, maxDepth);
+	}
+
+	static final Logger log = LoggerFactory.getLogger(QuadTree.class);
+
+	final Pool<BoxItem<T>> boxPool = new Pool<BoxItem<T>>() {
+		@Override
+		protected BoxItem<T> createItem() {
+			return new BoxItem<T>();
+		}
+	};
+
+	private BoxItem<T> getBox(Box box) {
+		BoxItem<T> it = boxPool.get();
+		it.x1 = (int) box.minX;
+		it.y1 = (int) box.minY;
+		it.x2 = (int) box.maxX;
+		it.y2 = (int) box.maxY;
+		return it;
+	}
+
+	@Override
+	public void insert(Box box, T item) {
+		insert(new BoxItem<T>(box, item));
+	}
+
+	@Override
+	public boolean remove(Box box, T item) {
+		BoxItem<T> bbox = getBox(box);
+		boolean ok = remove(bbox, item);
+		boxPool.release(bbox);
+		return ok;
+	}
+
+	static class CollectCb<T> implements SearchCb<T> {
+		@SuppressWarnings("unchecked")
+		@Override
+		public boolean call(T item, Object context) {
+			List<T> l = (List<T>) context;
+			l.add(item);
+			return true;
+		}
+	}
+
+	final CollectCb<T> collectCb = new CollectCb<T>();
+
+	@Override
+	public List<T> search(Box bbox, List<T> results) {
+		BoxItem<T> box = getBox(bbox);
+		search(box, collectCb, results);
+		boxPool.release(box);
+		return results;
+	}
+
+	@Override
+	public int search(Box bbox, SearchCb<T> cb, Object context) {
+		BoxItem<T> box = getBox(bbox);
+		search(box, cb, context);
+		boxPool.release(box);
+		return 0;
+	}
+}
diff --git a/vtm/src/org/oscim/utils/SpatialIndex.java b/vtm/src/org/oscim/utils/SpatialIndex.java
new file mode 100644
index 00000000..b6e74509
--- /dev/null
+++ b/vtm/src/org/oscim/utils/SpatialIndex.java
@@ -0,0 +1,21 @@
+package org.oscim.utils;
+
+import java.util.List;
+
+import org.oscim.core.Box;
+
+public interface SpatialIndex<T> {
+	public interface SearchCb<T> {
+		boolean call(T item, Object context);
+	}
+
+	public void insert(Box box, T item);
+
+	public boolean remove(Box box, T item);
+
+	public List<T> search(Box bbox, List<T> results);
+
+	public int search(Box bbox, SearchCb<T> cb, Object context);
+
+	public int size();
+}
diff --git a/vtm/src/org/oscim/utils/quadtree/BoxTree.java b/vtm/src/org/oscim/utils/quadtree/BoxTree.java
index 998ce43e..df78ed5a 100644
--- a/vtm/src/org/oscim/utils/quadtree/BoxTree.java
+++ b/vtm/src/org/oscim/utils/quadtree/BoxTree.java
@@ -1,6 +1,10 @@
 package org.oscim.utils.quadtree;
 
+import java.util.Arrays;
+
+import org.oscim.utils.SpatialIndex.SearchCb;
 import org.oscim.utils.pool.Inlist;
+import org.oscim.utils.pool.Pool;
 import org.oscim.utils.quadtree.BoxTree.BoxItem;
 import org.oscim.utils.quadtree.BoxTree.BoxNode;
 import org.slf4j.Logger;
@@ -12,28 +16,55 @@ import org.slf4j.LoggerFactory;
  * 
  * ... in case this generic isnt obvious at first sight.
  * */
-public abstract class BoxTree<Box extends BoxItem<E>, E> extends QuadTree<BoxNode<Box>, Box> {
+public class BoxTree<T extends BoxItem<E>, E> extends TileIndex<BoxNode<T>, T> {
 
 	final static Logger log = LoggerFactory.getLogger(BoxTree.class);
 	static boolean dbg = false;
 
 	protected final int extents;
 	protected final int maxDepth;
+	private final static int MAX_STACK = 32;
 
-	public static class BoxNode<T extends BoxItem<?>> extends Node<BoxNode<T>, T> {
-		// for non-recursive traversal
-		BoxNode<T> next;
-		// TODO make final? or update to the actual used extent?
+	static class Stack<E> extends Inlist<Stack<E>> {
+		/** Top of stack index */
+		int tos;
+
+		final E[] nodes;
+
+		@SuppressWarnings("unchecked")
+		Stack() {
+			nodes = (E[]) new BoxNode[MAX_STACK];
+		}
+
+		void push(E node) {
+			nodes[tos] = node;
+			tos++;
+		}
+
+		/** Pop element off iteration stack (For internal use only) */
+		E pop() {
+			// assert (tos > 0);
+			nodes[tos--] = null;
+			return (E) nodes[tos];
+		}
+
+		E node() {
+			return (E) nodes[tos];
+		}
+
+		boolean empty() {
+			return tos <= 0;
+		}
+	}
+
+	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;
 
-		//BoxItem<T> list;
-
-		public boolean overlaps(T it) {
-			return (x1 < it.x2) && (y1 < it.y2) && (it.x1 < x2) && (it.y1 < y2);
-		}
+		// inherits BoxItem<E> item;
 
 		@Override
 		public String toString() {
@@ -44,11 +75,19 @@ public abstract class BoxTree<Box extends BoxItem<E>, E> extends QuadTree<BoxNod
 	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.x2 = x2;
 			this.y2 = y2;
 		}
 
+		public BoxItem(org.oscim.core.Box box, T item) {
+			this.x1 = (int) box.minX;
+			this.y1 = (int) box.minY;
+			this.x2 = (int) box.maxX;
+			this.y2 = (int) box.maxY;
+			this.item = item;
+		}
+
 		@Override
 		public String toString() {
 			return x1 + "," + y1 + "/" + x2 + "," + y2;
@@ -66,7 +105,7 @@ public abstract class BoxTree<Box extends BoxItem<E>, E> extends QuadTree<BoxNod
 		public int y2;
 
 		public boolean overlaps(BoxItem<T> it) {
-			return (x1 < it.x2) && (it.x1 < x2) && (y1 < it.y2) && (it.y1 < y2);
+			return !((x1 > it.x2) || (it.x1 > x2) || (y1 > it.y2) || (it.y1 > y2));
 		}
 	}
 
@@ -74,19 +113,16 @@ public abstract class BoxTree<Box extends BoxItem<E>, E> extends QuadTree<BoxNod
 		boolean process(T item);
 	}
 
-	//	public class NodeVistor<T> implements Visitor<BoxNode<T>> {
-	//
-	//		@Override
-	//		public boolean process(BoxNode<T> item) {
-	//
-	//			return false;
-	//		}
-	//
-	//	}
+	boolean isPowerOfTwo(int x) {
+		return ((x > 0) && (x & (x - 1)) == 0);
+	}
 
 	public BoxTree(int extents, int maxDepth) {
 		super();
-		// size is -extents to +extents
+		if (!isPowerOfTwo(extents))
+			throw new IllegalArgumentException("Extents must be power of two!");
+
+		//size is -extents to +extents
 		this.root.x1 = -extents;
 		this.root.y1 = -extents;
 		this.root.x2 = extents;
@@ -97,169 +133,231 @@ public abstract class BoxTree<Box extends BoxItem<E>, E> extends QuadTree<BoxNod
 	}
 
 	@Override
-	public BoxNode<Box> create() {
-		return new BoxNode<Box>();
+	public BoxNode<T> create() {
+		return new BoxNode<T>();
 	}
 
 	@Override
-	public void removeItem(Box item) {
+	public void removeItem(T item) {
 
 	}
 
-	@SuppressWarnings("unchecked")
-	public int query(Box box) {
-		if (box.x1 > box.x2 || box.y1 > box.y2)
-			throw new IllegalArgumentException();
+	Pool<Stack<BoxNode<T>>> stackPool = new Pool<Stack<BoxNode<T>>>() {
+		@Override
+		protected Stack<BoxNode<T>> createItem() {
+			return new Stack<BoxNode<T>>();
+		}
 
-		int x1 = box.x1;
-		int x2 = box.x2;
-		int y1 = box.y1;
-		int y2 = box.y2;
+		protected boolean clearItem(Stack<BoxNode<T>> item) {
+			if (item.tos != 0) {
+				item.tos = 0;
+				Arrays.fill(item.nodes, null);
+			}
+			return true;
+		};
+	};
 
-		BoxNode<Box> cur, c;
-		BoxNode<Box> stack = root;
-		int result = 0;
+	public boolean search(T box, SearchCb<E> cb, Object ctxt) {
+		BoxNode<T> n;
 
-		boolean drop = false;
+		Stack<BoxNode<T>> stack = stackPool.get();
+		stack.push(root);
 
-		O: while (stack != null) {
+		O: while (!stack.empty()) {
 
-			/** pop cur from stack */
-			cur = stack;
-			stack = stack.next;
+			n = stack.pop();
 
-			/** 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;
+			/* 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;
+				}
+			}
+
+			BoxNode<T> p = n.parent;
+
+			/* push next node on same level onto stack */
+			switch (n.id) {
+				case 0:
+					if (overlaps(p.child01, box)) {
+						stack.push(p.child01);
+						break;
 					}
+				case 1:
+					if (overlaps(p.child10, box)) {
+						stack.push(p.child10);
+						break;
+					}
+				case 2:
+					if (overlaps(p.child11, box)) {
+						stack.push(p.child11);
+						break;
+					}
+				default:
+					break;
+			}
+			/* 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);
+		}
+		stackPool.release(stack);
+		return false;
+	}
 
-					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;
+	public interface SearchBoxCb<T extends BoxItem<?>> {
+		boolean call(T item);
+	}
 
-						continue;
+	public boolean search(T box, SearchBoxCb<T> cb) {
+		BoxNode<T> n;
+		BoxNode<T> start = getNode(box, false);
+		if (start == null)
+			return false;
+
+		Stack<BoxNode<T>> stack = stackPool.get();
+		stack.push(start);
+
+		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)) {
+					@SuppressWarnings("unchecked")
+					T item = (T) it;
+					if (!cb.call(item)) {
+						stackPool.release(stack);
+						return false;
 					}
 				}
-				prev = it;
 			}
 
-			/** put children on stack which overlap with box */
-			if ((c = cur.child00) != null &&
-			        (x1 < c.x2) && (y1 < c.y2) &&
-			        (c.x1 < x2) && (c.y1 < y2)) {
-				c.next = stack;
-				stack = c;
-			}
-			if ((c = cur.child01) != null &&
-			        (x1 < c.x2) && (y1 < c.y2) &&
-			        (c.x1 < x2) && (c.y1 < y2)) {
-				c.next = stack;
-				stack = c;
-			}
-			if ((c = cur.child10) != null &&
-			        (x1 < c.x2) && (y1 < c.y2) &&
-			        (c.x1 < x2) && (c.y1 < y2)) {
-				c.next = stack;
-				stack = c;
-			}
-			if ((c = cur.child11) != null &&
-			        (x1 < c.x2) && (y1 < c.y2) &&
-			        (c.x1 < x2) && (c.y1 < y2)) {
-				c.next = stack;
-				stack = c;
+			BoxNode<T> p = n.parent;
+
+			/* push next node on same level onto stack */
+			switch (n.id) {
+				case 0:
+					if (overlaps(p.child01, box)) {
+						stack.push(p.child01);
+						break;
+					}
+				case 1:
+					if (overlaps(p.child10, box)) {
+						stack.push(p.child10);
+						break;
+					}
+				case 2:
+					if (overlaps(p.child11, box)) {
+						stack.push(p.child11);
+						break;
+					}
+				default:
+					break;
 			}
+
+			/* 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);
 		}
+		stackPool.release(stack);
 
-		/** dont keep dangling references */
-		///* gwt optimizer found this cannot be reached :) */
-		while (stack != null)
-			stack = stack.next;
-
-		return drop ? 1 : 0;
+		return true;
 	}
 
-	public abstract boolean collectAll(BoxNode<Box> node);
-
-	public int all() {
-		return all(root);
+	private static boolean overlaps(BoxNode<?> a, BoxItem<?> b) {
+		return a != null && !((a.x1 > b.x2) || (b.x1 > a.x2) || (a.y1 > b.y2) || (b.y1 > a.y2));
 	}
 
-	public int all(BoxNode<Box> node) {
+	public interface SearchNodeCb<E extends BoxNode<?>> {
+		boolean call(E item);
+	}
 
-		BoxNode<Box> cur, c;
-		BoxNode<Box> stack = node;
+	public boolean collect(SearchNodeCb<BoxNode<T>> cb) {
+		BoxNode<T> n;
 
-		while (stack != null) {
-			cur = stack;
-			stack = stack.next;
+		Stack<BoxNode<T>> stack = stackPool.get();
 
-			if (cur.item != null && !collectAll(cur))
-				break;
+		stack.push(root);
 
-			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;
+		while (!stack.empty()) {
+			n = stack.pop();
+
+			/* process overlapping items from cur node */
+			cb.call(n);
+
+			BoxNode<T> p = n.parent;
+
+			/* push next node on same level onto stack */
+			switch (n.id) {
+				case 0:
+					if (p.child01 != null) {
+						stack.push(p.child01);
+						break;
+					}
+				case 1:
+					if (p.child10 != null) {
+						stack.push(p.child10);
+						break;
+					}
+				case 2:
+					if (p.child11 != null) {
+						stack.push(p.child11);
+						break;
+					}
+				default:
+					break;
 			}
+
+			/* push next level child onto stack */
+			if (n.child00 != null)
+				stack.push(n.child00);
+			else if (n.child01 != null)
+				stack.push(n.child01);
+			else if (n.child10 != null)
+				stack.push(n.child10);
+			else if (n.child11 != null)
+				stack.push(n.child11);
 		}
-
-		// dont keep dangling references
-		while (stack != null)
-			stack = stack.next;
-
-		return 0;
+		stackPool.release(stack);
+		return false;
 	}
 
-	public abstract int process(Box box, Box it);
+	public BoxNode<T> create(BoxNode<T> parent, int i) {
+		BoxNode<T> node;
+		if (pool != null) {
+			node = pool;
+			pool = pool.parent;
+		} else
+			node = new BoxNode<T>();
+
+		node.parent = parent;
 
-	public BoxNode<Box> create(BoxNode<Box> parent, int i) {
-		BoxNode<Box> node = new BoxNode<Box>();
 		int size = (parent.x2 - parent.x1) >> 1;
 		node.x1 = parent.x1;
 		node.y1 = parent.y1;
 
 		if (i == 0) {
-			// top-left
 			parent.child00 = node;
 		} else if (i == 1) {
-			// bottom-left
-			parent.child10 = node;
+			parent.child01 = node;
 			node.y1 += size;
 		} else if (i == 2) {
-			// top-right
-			parent.child01 = node;
+			parent.child10 = node;
 			node.x1 += size;
 		} else {
-			// bottom-right
 			parent.child11 = node;
 			node.x1 += size;
 			node.y1 += size;
@@ -267,93 +365,196 @@ public abstract class BoxTree<Box extends BoxItem<E>, E> extends QuadTree<BoxNod
 
 		node.x2 = node.x1 + size;
 		node.y2 = node.y1 + size;
-
-		node.parent = parent;
+		node.id = (byte) i;
 
 		return node;
 	}
 
-	public void insert(Box box) {
+	public void insert(T box) {
 		if (box.x1 > box.x2 || box.y1 > box.y2)
 			throw new IllegalArgumentException();
 
-		BoxNode<Box> cur = root;
-		BoxNode<Box> child = null;
+		if (box.next != null)
+			throw new IllegalStateException("BoxItem is list");
+
+		BoxNode<T> cur = root;
+		BoxNode<T> 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);
+			cur.refs++;
+
+			/* half size of tile at current level */
 			int hsize = (cur.x2 - cur.x1) >> 1;
 
-			// center of tile (shift by -extents)
-			//int cx = px + hsize - extents;
-			//int cy = py + hsize - extents;
+			/* center of tile */
 			int cx = cur.x1 + hsize;
 			int cy = cur.y1 + 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);
+
+			if (level < maxDepth) {
+				if (x2 < cx) {
+					if (y2 < cy) {
+						if ((child = cur.child00) == null)
+							child = create(cur, 0);
+					} else if (y1 >= cy) {
+						if ((child = cur.child01) == null)
+							child = create(cur, 1);
+					}
 				}
-				// 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.child10) == null)
+							child = create(cur, 2);
+					} else if (y1 >= cy) {
+						if ((child = cur.child11) == null)
+							child = create(cur, 3);
+					}
 				}
 			}
-			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 (cur == minNode && child != null)
-				minNode = cur;
-
-			if (child == null || level == maxDepth) {
-				// push item onto list of this node
+			if (child == null) {
+				/* 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));
+					log.debug("insert: " + level
+					        + " cnt:" + Inlist.size(cur.item) + " " + x1 + ":" + y1
+					        + " /" + (x2) + "x" + (y2) + " " + box.item);
 				break;
 			}
 			cur = child;
 		}
-
 	}
 
-	public void setMinNode(int x1, int y1, int x2, int y2) {
-		/* TODO find lowest node that fully contains the region
-		 * and set it as start for following queries */
+	public boolean remove(T box, E item) {
+		if (box.x1 > box.x2 || box.y1 > box.y2)
+			throw new IllegalArgumentException();
+
+		BoxNode<T> cur = root;
+		BoxNode<T> child = null;
+
+		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 level */
+			int hsize = (cur.x2 - cur.x1) >> 1;
+
+			/* center of tile */
+			int cx = cur.x1 + hsize;
+			int cy = cur.y1 + hsize;
+
+			child = null;
+			if (level < maxDepth) {
+				if (x2 < cx) {
+					if (y2 < cy) {
+						if ((child = cur.child00) == null)
+							return false;
+					} else if (y1 >= cy) {
+						if ((child = cur.child01) == null)
+							return false;
+					}
+				} else if (x1 >= cx) {
+					if (y2 < cy) {
+						if ((child = cur.child10) == null)
+							return false;
+					} else if (y1 >= cy) {
+						if ((child = cur.child11) == null)
+							return false;
+					}
+				}
+			}
+			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) {
+					if (it.item == item) {
+						if (dbg)
+							log.debug("remove: " + level
+							        + " cnt:" + Inlist.size(cur.item) + " " + x1 + ":" + y1
+							        + " /" + (x2) + "x" + (y2) + " " + item);
+
+						if (cur.item == it) {
+							// FUNKY GENERICS...
+							@SuppressWarnings("unchecked")
+							T b = (T) it.next;
+							cur.item = b;
+						} else
+							prev.next = it.next;
+
+						remove(cur);
+						return true;
+					}
+					prev = it;
+				}
+				return false;
+			}
+
+			cur = child;
+		}
+		return false;
 	}
 
-	public abstract boolean process(BoxNode<Box> nodes);
+	public BoxNode<T> getNode(T box, boolean create) {
+		if (box.x1 > box.x2 || box.y1 > box.y2)
+			throw new IllegalArgumentException();
+
+		BoxNode<T> cur = root;
+		BoxNode<T> child = null;
+
+		int x1 = box.x1;
+		int x2 = box.x2;
+		int y1 = box.y1;
+		int y2 = box.y2;
+
+		for (int level = 0; level <= maxDepth; level++) {
+			cur.refs++;
+
+			/* half size of tile at current z */
+			int hsize = (cur.x2 - cur.x1) >> 1;
+
+			/* center of tile (shift by -extents) */
+			int cx = cur.x1 + hsize;
+			int cy = cur.y1 + hsize;
+
+			child = null;
+
+			if (x2 < cx) {
+				if (y2 < cy) {
+					if ((child = cur.child00) == null && create)
+						child = create(cur, 0);
+				} else if (y1 >= cy) {
+					if ((child = cur.child01) == null && create)
+						child = create(cur, 1);
+				}
+			}
+			if (x1 >= cx) {
+				if (y2 < cy) {
+					if ((child = cur.child10) == null && create)
+						child = create(cur, 2);
+				} else if (y1 >= cy) {
+					if ((child = cur.child11) == null && create)
+						child = create(cur, 3);
+				}
+			}
+
+			if (child == null || level == maxDepth)
+				return cur;
+
+			cur = child;
+		}
+		return null;
+	}
 
 	public void clear() {
 		root.child00 = null;
@@ -361,67 +562,10 @@ public abstract class BoxTree<Box extends BoxItem<E>, E> extends QuadTree<BoxNod
 		root.child10 = null;
 		root.child11 = null;
 		root.item = null;
-
-		//root = create();
-		//root.parent = root;
+		root.refs = 0;
 	}
 
-	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
-		}
+	public int size() {
+		return root.refs;
 	}
-
-	//	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();
-	//	}
 }
diff --git a/vtm/src/org/oscim/utils/quadtree/QuadTree.java b/vtm/src/org/oscim/utils/quadtree/QuadTree.java
index 49717b8b..33cc0c77 100644
--- a/vtm/src/org/oscim/utils/quadtree/QuadTree.java
+++ b/vtm/src/org/oscim/utils/quadtree/QuadTree.java
@@ -19,16 +19,17 @@ package org.oscim.utils.quadtree;
 /**
  * A quad tree for the standard map tiling schema.
  */
-public abstract class QuadTree<T extends Node<T, E>, E> {
+public abstract class QuadTree<T extends TreeNode<T, E>, E> {
 
 	protected final T root;
 
-	protected T minNode;
+	//protected T minNode;
 
 	protected T pool;
 
 	public QuadTree() {
 		root = create();
+		root.id = -1;
 		root.parent = root;
 	}
 
@@ -153,15 +154,15 @@ public abstract class QuadTree<T extends Node<T, E>, E> {
 
 		while (cur != root) {
 			if (cur == null)
-				throw new IllegalArgumentException("item not in index");
+				throw new IllegalStateException("Item not in index");
 
-			// keep pointer to parent
+			/* keep pointer to parent */
 			next = cur.parent;
 			cur.refs--;
 
-			// if current node has no children
+			/* if current node has no children */
 			if (cur.refs == 0) {
-				// unhook from parent
+				/* unhook from parent */
 
 				switch (cur.id) {
 					case 0:
@@ -178,7 +179,7 @@ public abstract class QuadTree<T extends Node<T, E>, E> {
 						break;
 				}
 
-				// add item back to pool
+				/* add item back to pool */
 				cur.parent = pool;
 				pool = cur;
 			}
diff --git a/vtm/src/org/oscim/utils/quadtree/Node.java b/vtm/src/org/oscim/utils/quadtree/TreeNode.java
similarity index 75%
rename from vtm/src/org/oscim/utils/quadtree/Node.java
rename to vtm/src/org/oscim/utils/quadtree/TreeNode.java
index 0efcbb19..85f0276c 100644
--- a/vtm/src/org/oscim/utils/quadtree/Node.java
+++ b/vtm/src/org/oscim/utils/quadtree/TreeNode.java
@@ -16,36 +16,31 @@
  */
 package org.oscim.utils.quadtree;
 
-public class Node<T extends Node<T, E>, E> {
+public class TreeNode<T extends TreeNode<T, E>, E> {
+
 	public T parent;
+
+	/** top-left */
 	public T child00;
-	public T child10;
+
+	/** bottom-left */
 	public T child01;
+
+	/** top-right */
+	public T child10;
+
+	/** bottom-right */
 	public T child11;
 
+	/** payload */
 	public E item;
 
-	// id of this child relative to parent
-	byte id;
+	/** id of this child relative to parent */
+	int id;
 
-	// number of children and grandchildren
+	/** number of children and grandchildren */
 	int refs = 0;
 
-	//	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;
 	}