This is my first Quadtree implementation and I’m not too impressed with it 
I started out because I wanted to speed up my Boids application (http://www.red3d.com/cwr/boids/).
- Boids move around
 - Boids adapt their movement based on their closest neigbours
 
Without any form of spatial organisation I had a O(n^2) complexity for each update
Enter the StaticQuadtree…
My StaticQuadtree generates all lower levels of the tree on instantiation.
A StaticQuadtree with 1 level is basically the same as my original Vector.
After some performance tests I noticed that generating more than 5 levels starts to decrease performance. Especially when removing Boids from the Quadtree when they move and when searching in an area that contains several sub levels.
Is that a normal number of levels for a Quadtree, or can this code be improved by multitudes after a few simple optimizations? 
Also, am I correct in asuming that I have to remove and re-add all boids during update?
Wouldn’t it be easier (quicker even) to regenerate the Quadtree before each update?
My first implementation:
import java.util.Collection;
import java.util.Vector;
public class StaticQuadtree implements Quadtree {
	private final static int DEFAULT_LEVELS = 5;
	private final Collection<Entity> entities = new Vector<Entity>();
	private final Node head;
	public StaticQuadtree() {
		this(DEFAULT_LEVELS);
	}
	public StaticQuadtree(int levels) {
		if (levels < 0) throw new IllegalArgumentException();
		head = new Node(levels, new BoundingBox(-256, -256, 256, 256));
	}
	@Override
	public synchronized int size() {
		return entities.size();
	}
	@Override
	public synchronized Collection<Entity> get() {
		return new Vector<Entity>(entities);
	}
	@Override
	public synchronized void get(BoundingBox bb, Collection<Entity> result) {
		head.get(bb, result);
	}
	@Override
	public synchronized void add(Entity entity) {
		if (entities.contains(entity)) throw new RuntimeException();
		entities.add(entity);
		head.add(entity);
	}
	@Override
	public synchronized void remove(Entity entity) {
		if (!entities.contains(entity)) throw new RuntimeException();
		entities.remove(entity);
		head.remove(entity);
	}
	@Override
	public String toString() {
		return "[QT "+ head +"]";
	}
	private final class Node {
		private final int level;
		private final BoundingBox bb;
		private final Collection<Entity> entities;
		private final Node minmin, minmax, maxmin, maxmax;
		public Node(final int level, BoundingBox bb) {
			if (level < 0) throw new IllegalArgumentException();
			this.level = level;
			this.bb = bb;
			if (level > 0) {
				entities = null;
				final double dx = (bb.maxX - bb.minX)/2;
				final double dy = (bb.maxY - bb.minY)/2;
				minmin = new Node(level-1, new BoundingBox(bb.minX,    bb.minY,    bb.maxX-dx, bb.maxY-dy));
				minmax = new Node(level-1, new BoundingBox(bb.minX,    bb.minY+dy, bb.maxX-dx, bb.maxY));
				maxmin = new Node(level-1, new BoundingBox(bb.minX+dx, bb.minY,    bb.maxX,    bb.maxY-dy));
				maxmax = new Node(level-1, new BoundingBox(bb.minX+dx, bb.minY+dy, bb.maxX,    bb.maxY));
			} else {
				entities = new Vector<Entity>();
				minmin = null;
				minmax = null;
				maxmin = null;
				maxmax = null;
			}
		}
		public synchronized int size() {
			if (level == 0) {
				return entities.size();
			}
			int sum = 0;
			sum += minmin.size();
			sum += minmax.size();
			sum += maxmin.size();
			sum += maxmax.size();
			return sum;
		}
		public synchronized void get(Collection<Entity> result) {
			if (level == 0) {
				result.addAll(entities);
			} else {
				minmin.get(result);
				minmax.get(result);
				maxmin.get(result);
				maxmax.get(result);
			}
		}
		public synchronized void get(BoundingBox bb, Collection<Entity> result) {
			if (!this.bb.intersects(bb)) throw new RuntimeException();
			if (level == 0) {
				for (Entity entity : entities) {
					if (bb.contains(entity.pos)) {
						result.add(entity);
					}
				}
			} else {
				if (minmin.bb.intersects(bb)) minmin.get(bb, result);
				if (minmax.bb.intersects(bb)) minmax.get(bb, result);
				if (maxmin.bb.intersects(bb)) maxmin.get(bb, result);
				if (maxmax.bb.intersects(bb)) maxmax.get(bb, result);
			}
		}
		public synchronized void add(Entity entity) {
			if (!this.bb.contains(entity.pos)) throw new RuntimeException();
			if (level == 0) {
				entities.add(entity);
			} else {
				if (minmin.bb.contains(entity.pos)) minmin.add(entity);
				if (minmax.bb.contains(entity.pos)) minmax.add(entity);
				if (maxmin.bb.contains(entity.pos)) maxmin.add(entity);
				if (maxmax.bb.contains(entity.pos)) maxmax.add(entity);
			}
		}
		public synchronized void remove(Entity entity) {
			if (!this.bb.contains(entity.pos)) throw new RuntimeException();
			if (level == 0) {
				entities.remove(entity);
			} else {
				if (minmin.bb.contains(entity.pos)) minmin.remove(entity);
				if (minmax.bb.contains(entity.pos)) minmax.remove(entity);
				if (maxmin.bb.contains(entity.pos)) maxmin.remove(entity);
				if (maxmax.bb.contains(entity.pos)) maxmax.remove(entity);
			}
		}
		@Override
		public String toString() {
			StringBuffer sb = new StringBuffer();
			if (entities != null) sb.append(entities);
			if (minmin != null) sb.append(minmin);
			if (minmax != null) sb.append(minmax);
			if (maxmin != null) sb.append(maxmin);
			if (maxmax != null) sb.append(maxmax);
			return "[Node "+ sb.toString() +"]";
		}
	}
}
final class Entity {
	public Point pos;
	public Point vel;
	public Entity(double x, double y) {
		this.pos = new Point(x, y);
		this.vel = new Point(0, 0);
	}
	@Override
	public String toString() {
		return "[Entity "+ pos.x +":"+ pos.y +"]";
	}
}
final class Point {
	public final double x, y;
	public Point(double x, double y) {
		this.x = x;
		this.y = y;
	}
}
final class BoundingBox {
	public final double minX, minY;
	public final double maxX, maxY;
	public BoundingBox(double minX, double minY, double maxX, double maxY) {
		if (minX >= maxX) throw new IllegalArgumentException();
		if (minY >= maxY) throw new IllegalArgumentException();
		this.minX = minX;
		this.minY = minY;
		this.maxX = maxX;
		this.maxY = maxY;
	}
	public boolean contains(double x, double y) {
		return (minX < x && x <= maxX &&
				minY < y && y <= maxY);
	}
	public boolean contains(Point that) {
		return contains(that.x, that.y);
	}
	public boolean intersects(BoundingBox that) {
		return (minX < that.maxX && that.minX <= maxX &&
				minY < that.maxY && that.minY <= maxY);
	}
}
Stay tuned for my DynamicQuadtree update… 