Skip to content

Commit c65fd98

Browse files
author
phishman3579
committed
Added a minWidth, minHeight for MX-CIF quadtree
git-svn-id: https://java-algorithms-implementation.googlecode.com/svn/trunk@397 032fbc0f-8cab-eb90-e552-f08422b9a96a
1 parent 6eb5438 commit c65fd98

File tree

2 files changed

+82
-37
lines changed

2 files changed

+82
-37
lines changed

src/com/jwetherell/algorithms/DataStructures.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ private static boolean runTests() {
148148
boolean passed = true;
149149

150150
// MY DYNAMIC DATA STRUCTURES
151-
151+
/*
152152
passed = testAVLTree();
153153
if (!passed) {
154154
System.err.println("AVL Tree failed.");
@@ -331,13 +331,13 @@ private static boolean runTests() {
331331
System.err.println("Matrix failed.");
332332
return false;
333333
}
334-
334+
*/
335335
passed = testQuadTree();
336336
if (!passed) {
337337
System.err.println("QuadTree failed.");
338338
return false;
339339
}
340-
340+
/*
341341
passed = testSegmentTree();
342342
if (!passed) {
343343
System.err.println("Segment Tree failed.");
@@ -355,7 +355,7 @@ private static boolean runTests() {
355355
System.err.println("Suffix Trie failed.");
356356
return false;
357357
}
358-
358+
*/
359359
return true;
360360
}
361361

@@ -7365,7 +7365,7 @@ private static boolean testQuadTree() {
73657365
long avgQueryTime;
73667366
long treeMemory;
73677367
long treeQuery;
7368-
7368+
/*
73697369
// Point based quad tree
73707370
{
73717371
QuadTree.PointRegionQuadTree<QuadTree.XYPoint> tree = new QuadTree.PointRegionQuadTree<QuadTree.XYPoint>(0,0,size,size);
@@ -7428,10 +7428,10 @@ private static boolean testQuadTree() {
74287428
prev = p;
74297429
}
74307430
}
7431-
7431+
*/
74327432
// Rectangle base quadtree
74337433
{
7434-
QuadTree.MxCifQuadTree<QuadTree.AxisAlignedBoundingBox> tree = new QuadTree.MxCifQuadTree<QuadTree.AxisAlignedBoundingBox>(0,0,size,size);
7434+
QuadTree.MxCifQuadTree<QuadTree.AxisAlignedBoundingBox> tree = new QuadTree.MxCifQuadTree<QuadTree.AxisAlignedBoundingBox>(0,0,size,size,20,20);
74357435
beforeMemory = DataStructures.getMemoryUse();
74367436
avgInsertTime = 0;
74377437
for (int i=0; i<listSize; i++) {

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

Lines changed: 75 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public abstract class QuadTree<G extends QuadTree.GeometricObject> {
2626
/**
2727
* Range query of the quadtree.
2828
*/
29-
public abstract List<G> queryRange(float x, float y, float height, float width);
29+
public abstract List<G> queryRange(float x, float y, float width, float height);
3030

3131
/**
3232
* A PR (Point Region) Quadtree is a four-way search trie. This means that each node has either
@@ -45,11 +45,11 @@ public static class PointRegionQuadTree<P extends QuadTree.XYPoint> extends Quad
4545
*
4646
* @param x Upper left X coordinate
4747
* @param y Upper left Y coordinate
48-
* @param height Height of the bounding box containing all points
4948
* @param width Width of the bounding box containing all points
49+
* @param height Height of the bounding box containing all points
5050
*/
51-
public PointRegionQuadTree(float x, float y, float height, float width) {
52-
this(x,y,height,width,4,20);
51+
public PointRegionQuadTree(float x, float y, float width, float height) {
52+
this(x,y,width,height,4,20);
5353
}
5454

5555
/**
@@ -58,18 +58,32 @@ public PointRegionQuadTree(float x, float y, float height, float width) {
5858
*
5959
* @param x Upper left X coordinate
6060
* @param y Upper left Y coordinate
61+
* @param width Width of the bounding box containing all points
6162
* @param height Height of the bounding box containing all points
63+
* @param leafCapacity Max capacity of leaf nodes. (Note: All data is stored in leaf nodes)
64+
*/
65+
public PointRegionQuadTree(float x, float y, float width, float height, int leafCapacity) {
66+
this(x,y,width,height,leafCapacity,20);
67+
}
68+
69+
/**
70+
* Create a quadtree who's upper left coordinate is located at x,y and it's bounding box is described
71+
* by the height and width.
72+
*
73+
* @param x Upper left X coordinate
74+
* @param y Upper left Y coordinate
6275
* @param width Width of the bounding box containing all points
76+
* @param height Height of the bounding box containing all points
6377
* @param leafCapacity Max capacity of leaf nodes. (Note: All data is stored in leaf nodes)
6478
* @param maxTreeHeight Max height of the quadtree. (Note: If this is defined, the tree will ignore the
6579
* max capacity defined by leafCapacity)
6680
*/
67-
public PointRegionQuadTree(float x, float y, float height, float width, int leafCapacity, int maxTreeHeight) {
81+
public PointRegionQuadTree(float x, float y, float width, float height, int leafCapacity, int maxTreeHeight) {
6882
XYPoint xyPoint = new XYPoint(x,y);
69-
AxisAlignedBoundingBox aabb = new AxisAlignedBoundingBox(xyPoint,height,width);
70-
root = new PointRegionQuadNode<P>(aabb);
83+
AxisAlignedBoundingBox aabb = new AxisAlignedBoundingBox(xyPoint,width,height);
7184
PointRegionQuadNode.maxCapacity = leafCapacity;
7285
PointRegionQuadNode.maxHeight = maxTreeHeight;
86+
root = new PointRegionQuadNode<P>(aabb);
7387
}
7488

7589
/**
@@ -96,11 +110,11 @@ public void insert(float x, float y) {
96110
* {@inheritDoc}
97111
*/
98112
@Override
99-
public List<P> queryRange(float x, float y, float height, float width) {
113+
public List<P> queryRange(float x, float y, float width, float height) {
100114
List<P> pointsInRange = new LinkedList<P>();
101115
if (root==null) return (List<P>)pointsInRange;
102116
XYPoint xyPoint = new XYPoint(x,y);
103-
AxisAlignedBoundingBox range = new AxisAlignedBoundingBox(xyPoint,height,width);
117+
AxisAlignedBoundingBox range = new AxisAlignedBoundingBox(xyPoint,width,height);
104118
root.queryRange(range,pointsInRange);
105119
return (List<P>)pointsInRange;
106120
}
@@ -156,22 +170,22 @@ private void subdivide() {
156170
float h = aabb.height/2;
157171
float w = aabb.width/2;
158172

159-
AxisAlignedBoundingBox aabbNW = new AxisAlignedBoundingBox(aabb.upperLeft,h,w);
173+
AxisAlignedBoundingBox aabbNW = new AxisAlignedBoundingBox(aabb.upperLeft,w,h);
160174
northWest = new PointRegionQuadNode<XY>(aabbNW);
161175
((PointRegionQuadNode<XY>)northWest).height = height+1;
162176

163177
XYPoint xyNE = new XYPoint(aabb.upperLeft.x+w,aabb.upperLeft.y);
164-
AxisAlignedBoundingBox aabbNE = new AxisAlignedBoundingBox(xyNE,h,w);
178+
AxisAlignedBoundingBox aabbNE = new AxisAlignedBoundingBox(xyNE,w,h);
165179
northEast = new PointRegionQuadNode<XY>(aabbNE);
166180
((PointRegionQuadNode<XY>)northEast).height = height+1;
167181

168182
XYPoint xySW = new XYPoint(aabb.upperLeft.x,aabb.upperLeft.y+h);
169-
AxisAlignedBoundingBox aabbSW = new AxisAlignedBoundingBox(xySW,h,w);
183+
AxisAlignedBoundingBox aabbSW = new AxisAlignedBoundingBox(xySW,w,h);
170184
southWest = new PointRegionQuadNode<XY>(aabbSW);
171185
((PointRegionQuadNode<XY>)southWest).height = height+1;
172186

173187
XYPoint xySE = new XYPoint(aabb.upperLeft.x+w,aabb.upperLeft.y+h);
174-
AxisAlignedBoundingBox aabbSE = new AxisAlignedBoundingBox(xySE,h,w);
188+
AxisAlignedBoundingBox aabbSE = new AxisAlignedBoundingBox(xySE,w,h);
175189
southEast = new PointRegionQuadNode<XY>(aabbSE);
176190
((PointRegionQuadNode<XY>)southEast).height = height+1;
177191

@@ -245,12 +259,29 @@ public static class MxCifQuadTree<B extends QuadTree.AxisAlignedBoundingBox> ext
245259
*
246260
* @param x Upper left X coordinate
247261
* @param y Upper left Y coordinate
262+
* @param width Width of the bounding box containing all points
248263
* @param height Height of the bounding box containing all points
264+
*/
265+
public MxCifQuadTree(float x, float y, float width, float height) {
266+
this(x,y,width,height,0,0);
267+
}
268+
269+
/**
270+
* Create a quadtree who's upper left coordinate is located at x,y and it's bounding box is described
271+
* by the height and width. This uses a default leafCapacity of 4 and a maxTreeHeight of 20.
272+
*
273+
* @param x Upper left X coordinate
274+
* @param y Upper left Y coordinate
249275
* @param width Width of the bounding box containing all points
276+
* @param height Height of the bounding box containing all points
277+
* @param minWidth The tree will stop splitting when leaf node's width <= minWidth
278+
* @param minHeight The tree will stop splitting when leaf node's height <= minHeight
250279
*/
251-
public MxCifQuadTree(float x, float y, float height, float width) {
280+
public MxCifQuadTree(float x, float y, float width, float height, float minWidth, float minHeight) {
252281
XYPoint xyPoint = new XYPoint(x,y);
253-
AxisAlignedBoundingBox aabb = new AxisAlignedBoundingBox(xyPoint,height,width);
282+
AxisAlignedBoundingBox aabb = new AxisAlignedBoundingBox(xyPoint,width,height);
283+
MxCifQuadNode.minWidth = minWidth;
284+
MxCifQuadNode.minHeight = minHeight;
254285
root = new MxCifQuadNode<B>(aabb);
255286
}
256287

@@ -267,25 +298,25 @@ public QuadTree.QuadNode<B> getRoot() {
267298
*
268299
* @param x X position of upper-left hand corner.
269300
* @param y Y position of upper-left hand corner.
270-
* @param height Height of the rectangle.
271301
* @param width Width of the rectangle.
302+
* @param height Height of the rectangle.
272303
*/
273304
@SuppressWarnings("unchecked")
274-
public void insert(float x, float y, float height, float width) {
305+
public void insert(float x, float y, float width, float height) {
275306
XYPoint xyPoint = new XYPoint(x,y);
276-
AxisAlignedBoundingBox range = new AxisAlignedBoundingBox(xyPoint,height,width);
307+
AxisAlignedBoundingBox range = new AxisAlignedBoundingBox(xyPoint,width,height);
277308
root.insert((B)range);
278309
}
279310

280311
/**
281312
* {@inheritDoc}
282313
*/
283314
@Override
284-
public List<B> queryRange(float x, float y, float height, float width) {
315+
public List<B> queryRange(float x, float y, float width, float height) {
285316
List<B> geometricObjectsInRange = new LinkedList<B>();
286317
if (root==null) return (List<B>)geometricObjectsInRange;
287318
XYPoint xyPoint = new XYPoint(x,y);
288-
AxisAlignedBoundingBox range = new AxisAlignedBoundingBox(xyPoint,height,width);
319+
AxisAlignedBoundingBox range = new AxisAlignedBoundingBox(xyPoint,width,height);
289320
root.queryRange(range,geometricObjectsInRange);
290321
return (List<B>)geometricObjectsInRange;
291322
}
@@ -300,6 +331,9 @@ public String toString() {
300331

301332
protected static class MxCifQuadNode<AABB extends QuadTree.AxisAlignedBoundingBox> extends QuadNode<AABB> {
302333

334+
protected static float minWidth = 1;
335+
protected static float minHeight = 1;
336+
303337
protected List<AABB> aabbs = new LinkedList<AABB>();
304338

305339
protected MxCifQuadNode(AxisAlignedBoundingBox aabb) {
@@ -319,7 +353,15 @@ protected boolean insert(AABB b) {
319353

320354
// Subdivide then add the objects to whichever node will accept it
321355
if (isLeaf()) subdivide(b);
322-
boolean inserted = insertIntoChildren(b);
356+
357+
boolean inserted = false;
358+
if (isLeaf()) {
359+
aabbs.add(b);
360+
inserted = true;
361+
} else {
362+
inserted = insertIntoChildren(b);
363+
}
364+
323365
if (!inserted) {
324366
// Couldn't insert into children (it could strattle the bounds of the box)
325367
aabbs.add(b);
@@ -329,24 +371,27 @@ protected boolean insert(AABB b) {
329371
}
330372
}
331373

332-
private void subdivide(AABB b) {
333-
float h = aabb.height/2;
374+
private boolean subdivide(AABB b) {
334375
float w = aabb.width/2;
376+
float h = aabb.height/2;
377+
if (w<minWidth || h<minHeight) return false;
335378

336-
AxisAlignedBoundingBox aabbNW = new AxisAlignedBoundingBox(aabb.upperLeft,h,w);
379+
AxisAlignedBoundingBox aabbNW = new AxisAlignedBoundingBox(aabb.upperLeft,w,h);
337380
northWest = new MxCifQuadNode<AABB>(aabbNW);
338381

339382
XYPoint xyNE = new XYPoint(aabb.upperLeft.x+w,aabb.upperLeft.y);
340-
AxisAlignedBoundingBox aabbNE = new AxisAlignedBoundingBox(xyNE,h,w);
383+
AxisAlignedBoundingBox aabbNE = new AxisAlignedBoundingBox(xyNE,w,h);
341384
northEast = new MxCifQuadNode<AABB>(aabbNE);
342385

343386
XYPoint xySW = new XYPoint(aabb.upperLeft.x,aabb.upperLeft.y+h);
344-
AxisAlignedBoundingBox aabbSW = new AxisAlignedBoundingBox(xySW,h,w);
387+
AxisAlignedBoundingBox aabbSW = new AxisAlignedBoundingBox(xySW,w,h);
345388
southWest = new MxCifQuadNode<AABB>(aabbSW);
346389

347390
XYPoint xySE = new XYPoint(aabb.upperLeft.x+w,aabb.upperLeft.y+h);
348-
AxisAlignedBoundingBox aabbSE = new AxisAlignedBoundingBox(xySE,h,w);
391+
AxisAlignedBoundingBox aabbSE = new AxisAlignedBoundingBox(xySE,w,h);
349392
southEast = new MxCifQuadNode<AABB>(aabbSE);
393+
394+
return true;
350395
}
351396

352397
private boolean insertIntoChildren(AABB b) {
@@ -421,7 +466,7 @@ protected QuadNode(AxisAlignedBoundingBox aabb) {
421466
/**
422467
* Find all objects which appear within a range.
423468
*
424-
* @param range Upper-left and height,width of a axis-aligned bounding box.
469+
* @param range Upper-left and width,height of a axis-aligned bounding box.
425470
* @param geometricObjectsInRange Geometric objects inside the bounding box.
426471
*/
427472
protected abstract void queryRange(AxisAlignedBoundingBox range, List<G> geometricObjectsInRange);
@@ -567,10 +612,10 @@ public static class AxisAlignedBoundingBox extends GeometricObject implements Co
567612
private float maxX = 0;
568613
private float maxY = 0;
569614

570-
public AxisAlignedBoundingBox(XYPoint upperLeft, float height, float width) {
615+
public AxisAlignedBoundingBox(XYPoint upperLeft, float width, float height) {
571616
this.upperLeft = upperLeft;
572-
this.height = height;
573617
this.width = width;
618+
this.height = height;
574619

575620
minX = upperLeft.x;
576621
minY = upperLeft.y;

0 commit comments

Comments
 (0)