package stray.util; import java.util.ArrayList; import java.util.List; import com.badlogic.gdx.math.Rectangle; public class QuadTree { private int MAX_OBJECTS = 10; private int MAX_LEVELS = 12; private int level; private List<Sizeable> objects; private Rectangle bounds; private QuadTree[] nodes; /* * Constructor */ public QuadTree(int pLevel, Rectangle pBounds) { level = pLevel; objects = new ArrayList(); bounds = pBounds; nodes = new QuadTree[4]; } public QuadTree setMaxObjects(int o) { MAX_OBJECTS = o; return this; } public QuadTree setMaxLevels(int l) { MAX_LEVELS = l; return this; } public int getChecks() { int num = 0; num += (objects.size() * objects.size()); for (int i = 0; i < nodes.length; i++) { if (nodes[i] != null) { num += nodes[i].getChecks(); } } return num; } /* * Clears the quadtree */ public void clear() { objects.clear(); for (int i = 0; i < nodes.length; i++) { if (nodes[i] != null) { nodes[i].clear(); nodes[i] = null; } } } /* * Splits the node into 4 subnodes */ private void split() { int subWidth = (int) (bounds.getWidth() / 2); int subHeight = (int) (bounds.getHeight() / 2); int x = (int) bounds.getX(); int y = (int) bounds.getY(); nodes[0] = new QuadTree(level + 1, new Rectangle(x + subWidth, y, subWidth, subHeight)); nodes[1] = new QuadTree(level + 1, new Rectangle(x, y, subWidth, subHeight)); nodes[2] = new QuadTree(level + 1, new Rectangle(x, y + subHeight, subWidth, subHeight)); nodes[3] = new QuadTree(level + 1, new Rectangle(x + subWidth, y + subHeight, subWidth, subHeight)); } /* * Determine which node the object belongs to. -1 means object cannot * completely fit within a child node and is part of the parent node */ private int getIndex(Sizeable pRect) { int index = -1; double verticalMidpoint = bounds.getX() + (bounds.getWidth() / 2); double horizontalMidpoint = bounds.getY() + (bounds.getHeight() / 2); // Object can completely fit within the top quadrants boolean topQuadrant = (pRect.getY() < horizontalMidpoint && pRect.getY() + pRect.getHeight() < horizontalMidpoint); // Object can completely fit within the bottom quadrants boolean bottomQuadrant = (pRect.getY() > horizontalMidpoint); // Object can completely fit within the left quadrants if (pRect.getX() < verticalMidpoint && pRect.getX() + pRect.getWidth() < verticalMidpoint) { if (topQuadrant) { index = 1; } else if (bottomQuadrant) { index = 2; } } // Object can completely fit within the right quadrants else if (pRect.getX() > verticalMidpoint) { if (topQuadrant) { index = 0; } else if (bottomQuadrant) { index = 3; } } return index; } /* * Insert the object into the quadtree. If the node exceeds the capacity, it * will split and add all objects to their corresponding nodes. */ public void insert(Sizeable pRect) { if (nodes[0] != null) { int index = getIndex(pRect); if (index != -1) { nodes[index].insert(pRect); return; } } objects.add(pRect); if (objects.size() > MAX_OBJECTS && level < MAX_LEVELS) { if (nodes[0] == null) { split(); } int i = 0; while (i < objects.size()) { int index = getIndex(objects.get(i)); if (index != -1) { nodes[index].insert(objects.remove(i)); } else { i++; } } } } /* * Return all objects that could collide with the given object */ public List retrieve(List returnObjects, Sizeable pRect) { int index = getIndex(pRect); if (index != -1 && nodes[0] != null) { nodes[index].retrieve(returnObjects, pRect); } returnObjects.addAll(objects); return returnObjects; } }