package utils.scene.quadtree;
import java.util.AbstractCollection;
import java.util.ArrayList;
import java.util.Iterator;
public class QuadTree<T> {
protected QuadNode<T> root = null;
private volatile int size = 0;
private AbstractCollection<T> values = null;
/**
* Creates an empty QuadTree with the bounds
*/
public QuadTree(float minX, float minY, float maxX, float maxY, int maxElementsPerNode) {
this.root = new QuadNode<T>(minX, minY, maxX, maxY, maxElementsPerNode, this);
}
/**
* Associates the specified value with the specified coords in this
* QuadTree.
*/
public boolean put(float x, float y, T value) {
if (this.root.put(x, y, value)) {
increaseSize();
return true;
}
return false;
}
public boolean remove(float x, float y, T value) {
boolean found = false;
if (this.root.remove(x, y, value)) {
decreaseSize();
return true;
// fail safe: iterate through all leafs and find our value if x and y
} /*else {
QuadLeaf<T> leaf = firstLeaf();
do {
if(leaf.values.contains(value)) {
leaf.values.remove(value);
found = true;
QuadNode<T> currentNode = leaf.node;
if(currentNode.getLeaf() == leaf)
currentNode.clearLeaf();
else
System.out.println("Wrong node reference in quad tree leaf");
decreaseSize();
}
leaf = nextLeaf(leaf);
} while(leaf != null && !found);
}*/
if(!found)
return !contains(value);
return found;
}
public boolean update(float x, float y, T value) {
boolean success = false;
success = root.update(x, y, value);
if(!success)
return !contains(value);
return success;
}
public boolean contains(T value) {
return root.contains(value);
}
public void clear() {
this.root.clear();
this.size = 0;
}
private void increaseSize() {
this.size++; this.values = null;
}
private void decreaseSize() {
this.size--; this.values = null;
}
/**
* Gets the object closest to (x,y)
*/
public T get(float x, float y) {
return this.root.get(x, y, new AbstractFloat(Float.POSITIVE_INFINITY));
}
/**
* Gets all objects within a certain distance
*/
public ArrayList<T> get(float x, float y, float distance) {
return this.root.get(x, y, distance, new ArrayList<T>());
}
/**
* Gets all objects inside the specified boundary.
*/
/*public ArrayList<T> get(Box bounds, ArrayList<T> values) {
return this.root.get(bounds, values);
}*/
/**
* Gets all objects inside the specified area.
*/
/*public ArrayList<T> get(float minX, float minY, float maxX, float maxY, ArrayList<T> values) {
return get(new Box(minX, minY, maxX, maxY), values);
}
public int execute(Box bounds, Executor<T> executor) {
if (bounds == null) {
return this.root.execute(this.root.getBounds(), executor);
}
return this.root.execute(bounds, executor);
}
public int execute(float minX, float minY, float maxX, float maxY, Executor<T> executor) {
return execute(new Box(minX, minY, maxX, maxY), executor);
}*/
public int size() {
return this.size;
}
public float getMinX() {
return this.root.getBounds().minX;
}
public float getMaxX() {
return this.root.getBounds().maxX;
}
public float getMinY() {
return this.root.getBounds().minY;
}
public float getMaxY() {
return this.root.getBounds().maxY;
}
/*public AbstractCollection<T> values() {
if (this.values == null) {
this.values = new AbstractCollection<T>() {
@Override
public Iterator<T> iterator() {
Iterator<T> iterator = new Iterator<T>() {
private QuadLeaf<T> currentLeaf = firstLeaf();
private int nextIndex = 0;
private T next = first();
private T first() {
if (this.currentLeaf == null) {
return null;
}
this.nextIndex = 0;
loadNext();
return this.next;
}
@Override
public boolean hasNext() {
return this.next != null;
}
@Override
public T next() {
if (this.next == null) {
return null;
}
T current = this.next;
loadNext();
return current;
}
private void loadNext() {
boolean searching = true;
while (searching) {
if (this.nextIndex < this.currentLeaf.values.size()) {
this.nextIndex++;
this.next = this.currentLeaf.values.get(this.nextIndex - 1);
searching = false;
} else {
this.currentLeaf = nextLeaf(this.currentLeaf);
if (this.currentLeaf == null) {
this.next = null;
searching = false;
} else {
this.nextIndex = 0;
}
}
}
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
return iterator;
}
@Override
public int size() {
return QuadTree.this.size;
}
};
}
return this.values;
}*/
private QuadLeaf<T> firstLeaf() {
return this.root.firstLeaf();
}
private QuadLeaf<T> nextLeaf(QuadLeaf<T> currentLeaf) {
return this.root.nextLeaf(currentLeaf);
}
interface Executor<T>{
public void execute(float x, float y, T object);
}
}