v / vlib / datatypes / quadtree.v
205 lines · 181 sloc · 3.85 KB · c51d30bf5309653c6b573ec815268e69a78ea8cc
Raw
1module datatypes
2
3pub struct AABB {
4pub mut:
5 x f64
6 y f64
7 width f64
8 height f64
9}
10
11pub struct Quadtree {
12pub mut:
13 perimeter AABB
14 capacity int
15 depth int
16 level int
17 particles []AABB
18 nodes []Quadtree
19}
20
21// create returns a new configurable root node for the tree.
22pub fn (mut q Quadtree) create(x f64, y f64, width f64, height f64, capacity int, depth int, level int) Quadtree {
23 return Quadtree{
24 perimeter: AABB{
25 x: x
26 y: y
27 width: width
28 height: height
29 }
30 capacity: capacity
31 depth: depth
32 level: level
33 particles: []AABB{}
34 nodes: []Quadtree{len: 0, cap: 4}
35 }
36}
37
38// insert recursively adds a particle in the correct index of the tree.
39pub fn (mut q Quadtree) insert(p AABB) {
40 mut indexes := []int{}
41
42 if q.nodes.len > 0 {
43 indexes = q.get_index(p)
44 for k in 0 .. indexes.len {
45 q.nodes[indexes[k]].insert(p)
46 }
47 return
48 }
49
50 q.particles << p
51
52 if q.particles.len > q.capacity && q.level < q.depth {
53 if q.nodes.len == 0 {
54 q.split()
55 }
56
57 for j in 0 .. q.particles.len {
58 indexes = q.get_index(q.particles[j])
59 for k in 0 .. indexes.len {
60 q.nodes[indexes[k]].insert(q.particles[j])
61 }
62 }
63 q.particles = []
64 }
65}
66
67// retrieve recursively checks if a particle is in a specific index of the tree.
68pub fn (mut q Quadtree) retrieve(p AABB) []AABB {
69 mut indexes := q.get_index(p)
70 mut detected_particles := q.particles.clone()
71
72 if q.nodes.len > 0 {
73 for j in 0 .. indexes.len {
74 detected_particles << q.nodes[indexes[j]].retrieve(p)
75 }
76 }
77 return detected_particles
78}
79
80// clear flushes out nodes and particles from the tree.
81pub fn (mut q Quadtree) clear() {
82 q.particles = []
83 for j in 0 .. q.nodes.len {
84 if q.nodes.len > 0 {
85 q.nodes[j].clear()
86 }
87 }
88 q.nodes = []
89}
90
91// get_nodes recursively returns the subdivisions the tree has.
92pub fn (q Quadtree) get_nodes() []Quadtree {
93 mut nodes := []Quadtree{}
94 if q.nodes.len > 0 {
95 for j in 0 .. q.nodes.len {
96 nodes << q.nodes[j]
97 nodes << q.nodes[j].get_nodes()
98 }
99 }
100 return nodes
101}
102
103fn (mut q Quadtree) split() {
104 if q.nodes.len == 4 {
105 return
106 }
107
108 next_level := q.level + 1
109 child_width := q.perimeter.width / 2
110 child_height := q.perimeter.height / 2
111 x := q.perimeter.x
112 y := q.perimeter.y
113
114 //(0)
115 q.nodes << Quadtree{
116 perimeter: AABB{
117 x: x + child_width
118 y: y
119 width: child_width
120 height: child_height
121 }
122 capacity: q.capacity
123 depth: q.depth
124 level: next_level
125 particles: []AABB{}
126 nodes: []Quadtree{len: 0, cap: 4}
127 }
128
129 //(1)
130 q.nodes << Quadtree{
131 perimeter: AABB{
132 x: x
133 y: y
134 width: child_width
135 height: child_height
136 }
137 capacity: q.capacity
138 depth: q.depth
139 level: next_level
140 particles: []AABB{}
141 nodes: []Quadtree{len: 0, cap: 4}
142 }
143
144 //(2)
145 q.nodes << Quadtree{
146 perimeter: AABB{
147 x: x
148 y: y + child_height
149 width: child_width
150 height: child_height
151 }
152 capacity: q.capacity
153 depth: q.depth
154 level: next_level
155 particles: []AABB{}
156 nodes: []Quadtree{len: 0, cap: 4}
157 }
158
159 //(3)
160 q.nodes << Quadtree{
161 perimeter: AABB{
162 x: x + child_width
163 y: y + child_height
164 width: child_width
165 height: child_height
166 }
167 capacity: q.capacity
168 depth: q.depth
169 level: next_level
170 particles: []AABB{}
171 nodes: []Quadtree{len: 0, cap: 4}
172 }
173}
174
175fn (mut q Quadtree) get_index(p AABB) []int {
176 mut indexes := []int{}
177 mut v_midpoint := q.perimeter.x + (q.perimeter.width / 2)
178 mut h_midpoint := q.perimeter.y + (q.perimeter.height / 2)
179
180 mut north := p.y < h_midpoint
181 mut south := p.y + p.height > h_midpoint
182 mut west := p.x < v_midpoint
183 mut east := p.x + p.width > v_midpoint
184
185 // top-right quad
186 if north && east {
187 indexes << 0
188 }
189
190 // top-left quad
191 if north && west {
192 indexes << 1
193 }
194
195 // bottom-left quad
196 if south && west {
197 indexes << 2
198 }
199
200 // bottom-right quad
201 if south && east {
202 indexes << 3
203 }
204 return indexes
205}
206