-
Notifications
You must be signed in to change notification settings - Fork 3
/
quadTree.lua
154 lines (128 loc) · 3.62 KB
/
quadTree.lua
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
-- todo: rewrite this broken piece of code :|
MAX_OBJECTS_PER_QUAD = 40
QuadTree = {
name = "QuadTree",
__index = QuadTree
}
local insert = table.insert
local floor = math.floor
function QuadTree:new(_left, _top, _width, _height)
_left = _left or -1048575
_top = _top or -1048575
_width = _width or 2*1048575
_height = _height or 2*1048575
local options = {
x = _left,
y = _top,
w = _width,
h = _height,
children = nil,
count = 0,
objects = {}
}
setmetatable(options, self)
self.__index = self
return options
end
function QuadTree:subdivide()
local x = self.x
local y = self.y
local w = floor(self.w / 2)
local h = floor(self.h / 2)
self.children = {
["NW"] = QuadTree:new(x , y , w, h),
["NE"] = QuadTree:new(x + w, y , w, h),
["SE"] = QuadTree:new(x , y + h, w, h),
["SW"] = QuadTree:new(x + w, y + h, w, h)
}
for _, o in pairs(self.objects) do
for c in pairs(self.children) do
self.children[c]:addObject(o)
end
end
self.objects = {}
self.count = 0
end
function QuadTree:check(object, func, x, y)
local oleft = x or object.x
local otop = y or object.y
local oright = object.w and (oleft + object.w - 1) or oleft
local obottom = object.h and (otop + object.h - 1) or otop
local left = self.x
local top = self.y
local right = left + self.w - 1
local bottom = top + self.h - 1
if oright < left or obottom < top or oleft > right or otop > bottom then
return false
else
if not self.children then
func(self)
else
for c in pairs(self.children) do
self.children[c]:check(object, func, x, y)
end
end
end
end
function QuadTree:addObject(object)
local function add(tree)
if tree.count == MAX_OBJECTS_PER_QUAD then
tree:subdivide()
end
if tree.children then
for i,child in pairs(tree.children) do
child:addObject(object)
end
else
insert(tree.objects, object)
tree.count = tree.count + 1
end
end
self:check(object, add)
end
function QuadTree:removeObject(object)
local function remove(tree)
for _, o in pairs(tree.objects) do
if o['x'] == object['x'] and o['y'] == object['y'] then
tree.objects[_] = nil
tree.count = self.count - 1
break
end
end
end
self:check(object, remove)
end
function QuadTree:getObjectsInRange(range)
-- if true then
-- return self.objects
-- end
local near = {}
if not self.children then
for i,o in pairs(self.objects) do
if o.x >= range.x and o.x <= range.x+range.w and o.y >= range.y and o.y <= range.y+range.h then
near[#near+1] = o
end
end
else
local quads = {}
local function add (child) insert(quads, child) end
self:check(range, add)
for _,q in pairs(quads) do
for i,o in pairs(q.objects) do
if o.x >= range.x and o.x <= range.x+range.w and o.y >= range.y and o.y <= range.y+range.h then
near[#near+1] = o
end
end
end
end
return near
end
function QuadTree:remeta()
if self.children then
for _, sq in pairs(self.children) do
setmetatable(self.children[_], QuadTree)
self.children[_]:remeta()
end
end
end
QuadTree:new()