-
Notifications
You must be signed in to change notification settings - Fork 19.9k
/
Copy pathQuadTree.java
176 lines (149 loc) · 5.71 KB
/
QuadTree.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
package com.thealgorithms.datastructures.trees;
import java.util.ArrayList;
import java.util.List;
/**
* Point is a simple class that represents a point in 2D space.
*
* @see <a href="https://en.wikipedia.org/wiki/Point_(geometry)">Point</a>
* @author <a href="https://github.com/sailok">Sailok Chinta</a>
*/
class Point {
public double x;
public double y;
Point(double x, double y) {
this.x = x;
this.y = y;
}
}
/**
* BoundingBox is a simple class that represents a bounding box in 2D space.
*
* @see <a href="https://en.wikipedia.org/wiki/Bounding_box">Bounding Box</a>
* @author <a href="https://github.com/sailok">Sailok Chinta</a>
*/
class BoundingBox {
public Point center;
public double halfWidth;
BoundingBox(Point center, double halfWidth) {
this.center = center;
this.halfWidth = halfWidth;
}
/**
* Checks if the point is inside the bounding box
*
* @param point The point to check
* @return true if the point is inside the bounding box, false otherwise
*/
public boolean containsPoint(Point point) {
return point.x >= center.x - halfWidth && point.x <= center.x + halfWidth && point.y >= center.y - halfWidth && point.y <= center.y + halfWidth;
}
/**
* Checks if the bounding box intersects with the other bounding box
*
* @param otherBoundingBox The other bounding box
* @return true if the bounding box intersects with the other bounding box, false otherwise
*/
public boolean intersectsBoundingBox(BoundingBox otherBoundingBox) {
return otherBoundingBox.center.x - otherBoundingBox.halfWidth <= center.x + halfWidth && otherBoundingBox.center.x + otherBoundingBox.halfWidth >= center.x - halfWidth && otherBoundingBox.center.y - otherBoundingBox.halfWidth <= center.y + halfWidth
&& otherBoundingBox.center.y + otherBoundingBox.halfWidth >= center.y - halfWidth;
}
}
/**
* QuadTree is a tree data structure that is used to store spatial information
* in an efficient way.
*
* This implementation is specific to Point QuadTrees
*
* @see <a href="https://en.wikipedia.org/wiki/Quadtree">Quad Tree</a>
* @author <a href="https://github.com/sailok">Sailok Chinta</a>
*/
public class QuadTree {
private final BoundingBox boundary;
private final int capacity;
private List<Point> pointList;
private boolean divided;
private QuadTree northWest;
private QuadTree northEast;
private QuadTree southWest;
private QuadTree southEast;
public QuadTree(BoundingBox boundary, int capacity) {
this.boundary = boundary;
this.capacity = capacity;
this.pointList = new ArrayList<>();
this.divided = false;
this.northWest = null;
this.northEast = null;
this.southWest = null;
this.southEast = null;
}
/**
* Inserts a point into the tree
*
* @param point The point to insert
* @return true if the point is successfully inserted, false otherwise
*/
public boolean insert(Point point) {
if (point == null) {
return false;
}
// Ignore points that don't belong to this quad tree
if (!boundary.containsPoint(point)) {
return false;
}
// if the space is not already occupied, add it to the list
if (pointList.size() < capacity) {
pointList.add(point);
return true;
}
// if subdivision hasn't happened, divide the tree
if (!divided) {
subDivide();
}
// try to add the point in one of the four quadrants
if (northWest.insert(point)) {
return true;
}
if (northEast.insert(point)) {
return true;
}
if (southWest.insert(point)) {
return true;
}
if (southEast.insert(point)) {
return true;
}
return false;
}
/**
* Create four children that fully divide this quad into four quads of equal area
*/
private void subDivide() {
double quadrantHalfWidth = boundary.halfWidth / 2;
northWest = new QuadTree(new BoundingBox(new Point(boundary.center.x - quadrantHalfWidth, boundary.center.y + quadrantHalfWidth), quadrantHalfWidth), this.capacity);
northEast = new QuadTree(new BoundingBox(new Point(boundary.center.x + quadrantHalfWidth, boundary.center.y + quadrantHalfWidth), quadrantHalfWidth), this.capacity);
southWest = new QuadTree(new BoundingBox(new Point(boundary.center.x - quadrantHalfWidth, boundary.center.y - quadrantHalfWidth), quadrantHalfWidth), this.capacity);
southEast = new QuadTree(new BoundingBox(new Point(boundary.center.x + quadrantHalfWidth, boundary.center.y - quadrantHalfWidth), quadrantHalfWidth), this.capacity);
divided = true;
}
/**
* Queries all the points that intersect with the other bounding box
*
* @param otherBoundingBox The other bounding box
* @return List of points that intersect with the other bounding box
*/
public List<Point> query(BoundingBox otherBoundingBox) {
List<Point> points = new ArrayList<>();
if (!boundary.intersectsBoundingBox(otherBoundingBox)) {
return points;
}
// filter the points that intersect with the other bounding box
points.addAll(pointList.stream().filter(otherBoundingBox::containsPoint).toList());
if (divided) {
points.addAll(northWest.query(otherBoundingBox));
points.addAll(northEast.query(otherBoundingBox));
points.addAll(southWest.query(otherBoundingBox));
points.addAll(southEast.query(otherBoundingBox));
}
return points;
}
}