Skip to content

Commit f2410bc

Browse files
author
phishman3579
committed
Added leafCapacity and maxHeight to QuadTree
git-svn-id: https://java-algorithms-implementation.googlecode.com/svn/trunk@389 032fbc0f-8cab-eb90-e552-f08422b9a96a
1 parent cb25164 commit f2410bc

File tree

1 file changed

+71
-31
lines changed

1 file changed

+71
-31
lines changed

src/com/jwetherell/algorithms/data_structures/QuadTree.java

Lines changed: 71 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,8 @@
22

33
import java.util.ArrayList;
44
import java.util.Comparator;
5-
import java.util.HashSet;
65
import java.util.LinkedList;
76
import java.util.List;
8-
import java.util.Set;
97

108
/**
119
* A quadtree is a tree data structure in which each internal node has exactly four children. Quadtrees
@@ -18,19 +16,39 @@
1816
*/
1917
public class QuadTree<T extends QuadTree.XYPoint> {
2018

21-
private static int capacity = 0;
22-
2319
private QuadNode root = null;
2420

21+
/**
22+
* Create a quadtree who's upper left coordinate is located at x,y and it's bounding box is described
23+
* by the height and width. This uses a default leafCapacity of 4 and a maxTreeHeight of 20.
24+
*
25+
* @param x Upper left X coordinate
26+
* @param y Upper left Y coordinate
27+
* @param height Height of the bounding box containing all points
28+
* @param width Width of the bounding box containing all points
29+
*/
2530
public QuadTree(double x, double y, double height, double width) {
26-
this(x,y,height,width,4);
31+
this(x,y,height,width,4,20);
2732
}
2833

29-
public QuadTree(double x, double y, double height, double width, int capacity) {
34+
/**
35+
* Create a quadtree who's upper left coordinate is located at x,y and it's bounding box is described
36+
* by the height and width.
37+
*
38+
* @param x Upper left X coordinate
39+
* @param y Upper left Y coordinate
40+
* @param height Height of the bounding box containing all points
41+
* @param width Width of the bounding box containing all points
42+
* @param leafCapacity Max capacity of leaf nodes. (Note: All data is stored in leaf nodes)
43+
* @param maxTreeHeight Max height of the quadtree. (Note: If this is defined, the tree will ignore the
44+
* max capacity defined by leafCapacity)
45+
*/
46+
public QuadTree(double x, double y, double height, double width, int leafCapacity, int maxTreeHeight) {
3047
XYPoint xyPoint = new XYPoint(x,y);
3148
AxisAlignedBoundingBox aabb = new AxisAlignedBoundingBox(xyPoint,height,width);
3249
this.root = new QuadNode(aabb);
33-
QuadTree.capacity = capacity;
50+
QuadNode.maxCapacity = leafCapacity;
51+
QuadNode.maxHeight = maxTreeHeight;
3452
}
3553

3654
// insert point into tree
@@ -59,7 +77,11 @@ public String toString() {
5977

6078
private static class QuadNode implements Comparable<QuadNode> {
6179

62-
private Set<XYPoint> points = new HashSet<XYPoint>(capacity);
80+
private static int maxCapacity = 0;
81+
private static int maxHeight = 0;
82+
83+
private List<XYPoint> points = new LinkedList<XYPoint>();
84+
private int height = 1;
6385
private AxisAlignedBoundingBox aabb = null;
6486
private QuadNode northWest = null;
6587
private QuadNode northEast = null;
@@ -72,59 +94,77 @@ private QuadNode(AxisAlignedBoundingBox aabb) {
7294

7395
private boolean insert(XYPoint p) {
7496
// Ignore objects which do not belong in this quad tree
75-
if (!aabb.containsPoint(p) || points.contains(p)) return false; // object cannot be added
97+
if (!aabb.containsPoint(p) || (isLeaf() && points.contains(p))) return false; // object cannot be added
7698

7799
// If there is space in this quad tree, add the object here
78-
if (points.size() < capacity) {
100+
if ((height==maxHeight) || (isLeaf() && points.size() < maxCapacity)) {
79101
points.add(p);
80102
return true;
81103
}
82104

83105
// Otherwise, we need to subdivide then add the point to whichever node will accept it
84-
if (northWest == null) subdivide();
85-
86-
if (northWest.insert(p)) return true;
87-
if (northEast.insert(p)) return true;
88-
if (southWest.insert(p)) return true;
89-
if (southEast.insert(p)) return true;
106+
if (isLeaf() && height<maxHeight) subdivide();
107+
insertIntoChildren(p);
90108

91109
// Otherwise, the point cannot be inserted for some unknown reason (which should never happen)
92110
return false;
93111
}
94112

113+
private boolean isLeaf() {
114+
return (northWest==null);
115+
}
116+
95117
private void subdivide() {
96-
double height = aabb.width/2;
97-
double width = aabb.width/2;
118+
double h = aabb.height/2;
119+
double w = aabb.width/2;
98120

99-
AxisAlignedBoundingBox aabbNW = new AxisAlignedBoundingBox(aabb.upperLeft,height,width);
121+
AxisAlignedBoundingBox aabbNW = new AxisAlignedBoundingBox(aabb.upperLeft,h,w);
100122
northWest = new QuadNode(aabbNW);
123+
northWest.height = height+1;
101124

102-
XYPoint xyNE = new XYPoint(aabb.upperLeft.x+width,aabb.upperLeft.y);
103-
AxisAlignedBoundingBox aabbNE = new AxisAlignedBoundingBox(xyNE,height,width);
125+
XYPoint xyNE = new XYPoint(aabb.upperLeft.x+w,aabb.upperLeft.y);
126+
AxisAlignedBoundingBox aabbNE = new AxisAlignedBoundingBox(xyNE,h,w);
104127
northEast = new QuadNode(aabbNE);
128+
northEast.height = height+1;
105129

106-
XYPoint xySW = new XYPoint(aabb.upperLeft.x,aabb.upperLeft.y+height);
107-
AxisAlignedBoundingBox aabbSW = new AxisAlignedBoundingBox(xySW,height,width);
130+
XYPoint xySW = new XYPoint(aabb.upperLeft.x,aabb.upperLeft.y+h);
131+
AxisAlignedBoundingBox aabbSW = new AxisAlignedBoundingBox(xySW,h,w);
108132
southWest = new QuadNode(aabbSW);
133+
southWest.height = height+1;
109134

110-
XYPoint xySE = new XYPoint(aabb.upperLeft.x+width,aabb.upperLeft.y+height);
111-
AxisAlignedBoundingBox aabbSE = new AxisAlignedBoundingBox(xySE,height,width);
135+
XYPoint xySE = new XYPoint(aabb.upperLeft.x+w,aabb.upperLeft.y+h);
136+
AxisAlignedBoundingBox aabbSE = new AxisAlignedBoundingBox(xySE,h,w);
112137
southEast = new QuadNode(aabbSE);
138+
southEast.height = height+1;
139+
140+
// points live in leaf nodes, so distribute
141+
for (XYPoint p : points) {
142+
insertIntoChildren(p);
143+
}
144+
points.clear();
145+
}
146+
147+
private boolean insertIntoChildren(XYPoint p) {
148+
if (northWest.insert(p)) return true;
149+
if (northEast.insert(p)) return true;
150+
if (southWest.insert(p)) return true;
151+
if (southEast.insert(p)) return true;
152+
return false; // should never happen
113153
}
114154

115155
// Find all points which appear within a range
116156
private void queryRange(AxisAlignedBoundingBox range, List<XYPoint> pointsInRange) {
117157
// Automatically abort if the range does not collide with this quad
118158
if (!aabb.intersectsBox(range)) return;
119159

120-
// Check objects at this quad level
121-
for (XYPoint xyPoint : points) {
122-
if (range.containsPoint(xyPoint)) pointsInRange.add(xyPoint);
160+
// If leaf, check objects at this level
161+
if (isLeaf()) {
162+
for (XYPoint xyPoint : points) {
163+
if (range.containsPoint(xyPoint)) pointsInRange.add(xyPoint);
164+
}
165+
return;
123166
}
124167

125-
// Terminate here, if there are no children
126-
if (northWest == null) return;
127-
128168
// Otherwise, add the points from the children
129169
northWest.queryRange(range,pointsInRange);
130170
northEast.queryRange(range,pointsInRange);

0 commit comments

Comments
 (0)