Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Jotschi committed May 7, 2011
0 parents commit 0b06ee8
Show file tree
Hide file tree
Showing 9 changed files with 1,348 additions and 0 deletions.
674 changes: 674 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions README
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Simple java implementation of a quadtree
31 changes: 31 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>at.jotschi</groupId>
<artifactId>QuadTree</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>QuadTree</name>
<url>http://maven.apache.org</url>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.16</version>
</dependency>

</dependencies>
</project>
278 changes: 278 additions & 0 deletions src/main/java/at/jotschi/quadtree/Node.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,278 @@
package at.jotschi.quadtree;

import java.awt.Dimension;
import java.awt.Point;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;

import org.apache.log4j.Logger;

/**
* Node that represents each 'cell' within the quadtree. The Node will contains
* elements {@link NodeElement} that itself will contain the final data within
* the tree.
*
* @author jotschi
*
* @param <T>
*/
public class Node<T> {

private static Logger log = Logger.getLogger(Node.class);

public static enum Cell {
TOP_LEFT, BOTTOM_RIGHT, BOTTOM_LEFT, TOP_RIGHT
}

private Dimension bounds;
private Point startCoordinates;
private int maxDepth;
private int maxElements;
private int depth;

/**
* Default value for amount of elements
*/
private final int MAX_ELEMENTS = 4;

/**
* Default value for max depth
*/
private final int MAX_DEPTH = 4;

private Map<Cell, Node<T>> nodes = new HashMap<Cell, Node<T>>();

/**
* Holds all elements for this node
*/
private Vector<NodeElement<T>> elements = new Vector<NodeElement<T>>();

public Node(Point startCoordinates, Dimension bounds, int depth) {
log.debug("Creating new Node at depth " + depth);
this.startCoordinates = startCoordinates;
this.bounds = bounds;
this.depth = depth;
this.maxDepth = MAX_DEPTH;
this.maxElements = MAX_ELEMENTS;

}

/**
*
* @param startCoordinates
* @param bounds
* @param depth
* @param maxDepth
* @param maxChildren
*/
public Node(Point startCoordinates, Dimension bounds, int depth,
int maxDepth, int maxChildren) {
log.debug("Creating new Node at depth " + depth);
this.startCoordinates = startCoordinates;
this.bounds = bounds;
this.maxDepth = maxDepth;
this.maxElements = maxChildren;
this.depth = depth;

}

/**
* Returns the subnodes of this node
*
* @return
*/
public Map<Cell, Node<T>> getSubNodes() {
return this.nodes;
}

/**
* Returns the bounds for this Node
*
* @return
*/
public Dimension getBounds() {
return this.bounds;
}

/**
* Returns the startCoordinates for this Node
*
* @return
*/
public Point getStartCoordinates() {
return this.startCoordinates;
}

/**
* Returns the max elements
*
* @return
*/
public int getMaxElements() {
return this.maxElements;
}

/**
* Returns the max depth
*
* @return
*/
public int getMaxDepth() {
return this.maxDepth;
}

/**
* Returns the cell of this element
*
* @param element
* @return
*/
private Cell findIndex(Point coordinates) {
// Compute the sector for the coordinates
boolean left = (coordinates.x > (startCoordinates.x + bounds.width / 2)) ? false
: true;
boolean top = (coordinates.y > (startCoordinates.y + bounds.height / 2)) ? false
: true;

// top left
Cell index = Cell.TOP_LEFT;
if (left) {
// left side
if (!top) {
// bottom left
index = Cell.BOTTOM_LEFT;
}
} else {
// right side
if (top) {
// top right
index = Cell.TOP_RIGHT;
} else {
// bottom right
index = Cell.BOTTOM_RIGHT;

}
}
log.debug("Coordinate [" + coordinates.x + "-" + coordinates.y
+ "] is within " + index.toString() + " at depth " + depth);
return index;
}

/**
* Returns all elements for this node
*
* @return
*/
public Vector<NodeElement<T>> getElements() {
return this.elements;
}

/**
* Returns all elements wihtin the cell that matches the given coordinates
*
* @param coordinates
* @return
*/
public Vector<NodeElement<T>> getElements(Point coordinates) {

// Check if this node has already been subdivided. Therefor this node
// should contain no elements
if (nodes.size() > 0) {
Cell index = findIndex(coordinates);
Node<T> node = this.nodes.get(index);
return node.getElements(coordinates);
} else {
return this.elements;
}
}

/**
* Insert the element into this node. If needed a subdivison will be
* performed
*
* @param element
*/
public void insert(NodeElement<T> element) {
log.debug("Inserting element into Node at depth " + depth);
// If this Node has already been subdivided just add the elements to the
// appropriate cell
if (this.nodes.size() != 0) {
Cell index = findIndex(element);
log.debug("Inserting into existing cell: " + index);
this.nodes.get(index).insert(element);
return;
}

// Add the element to this node
this.elements.add(element);

// Only subdivide the node if it contain more than MAX_CHILDREN and is
// not the deepest node
if (!(this.depth >= MAX_DEPTH) && this.elements.size() > MAX_ELEMENTS) {
this.subdivide();

// Recall insert for each element. This will move all elements of
// this node into the new nodes at the appropriate cell
for (NodeElement<T> current : elements) {
this.insert(current);
}
// Remove all elements from this node since they were moved into
// subnodes
this.elements.clear();

}

}

/**
* Subdivide the current node and add subnodes
*/
public void subdivide() {
log.debug("Subdividing node at depth " + depth);
int depth = this.depth + 1;

int bx = this.startCoordinates.x;
int by = this.startCoordinates.y;

// Create the bounds for the new cell
Dimension newBounds = new Dimension(this.bounds.width / 2,
this.bounds.height / 2);

// Add new bounds to current start coordinates to calculate the new
// start coordinates
int newXStartCoordinate = bx + newBounds.width;
int newYStartCoordinate = by + newBounds.height;

Node<T> cellNode = null;

// top left
cellNode = new Node<T>(new Point(bx, by), newBounds, depth);
this.nodes.put(Cell.TOP_LEFT, cellNode);

// top right
cellNode = new Node<T>(new Point(newXStartCoordinate, by), newBounds,
depth);
this.nodes.put(Cell.TOP_RIGHT, cellNode);

// bottom left
cellNode = new Node<T>(new Point(bx, newYStartCoordinate), newBounds,
depth);
this.nodes.put(Cell.BOTTOM_LEFT, cellNode);

// bottom right
cellNode = new Node<T>(new Point(newXStartCoordinate,
newYStartCoordinate), newBounds, depth);
this.nodes.put(Cell.BOTTOM_RIGHT, cellNode);
}

/**
* Clears this node and all subnodes
*/
public void clear() {
for (Node<T> node : nodes.values()) {
node.clear();
}
elements.clear();
}
}
39 changes: 39 additions & 0 deletions src/main/java/at/jotschi/quadtree/NodeElement.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package at.jotschi.quadtree;

import java.awt.Point;

/**
* Container class that holds the object within the quadtree
*
* @author jotschi
*
*/
public class NodeElement<T> extends Point {

private static final long serialVersionUID = -6818452324965717494L;

private T element;

/**
* Create a new NodeElement that holds the element at the given coordinates.
*
* @param x
* @param y
* @param element
*/
public NodeElement(Point coordinates, T element) {
super(coordinates);
this.element = element;

}

/**
* Returns the element that is contained within this NodeElement
*
* @return
*/
public T getElement() {
return element;
}

}
Loading

0 comments on commit 0b06ee8

Please sign in to comment.