37 elt_idx_lft = 0, elt_idx_top = 1, elt_idx_rgt = 2, elt_idx_btm = 3,
60 nd_idx_mx = 0, nd_idx_my = 1, nd_idx_sx = 2, nd_idx_sy = 3,
69static void node_insert(
Quadtree* qt,
int index,
int depth,
int mx,
int my,
int sx,
int sy,
int element);
71static int intersect(
int l1,
int t1,
int r1,
int b1,
int l2,
int t2,
int r2,
int b2 )
73 return l2 <= r1 && r2 >= l1 && t2 <= b1 && b2 >= t1;
76static void leaf_insert(
Quadtree* qt,
int node,
int depth,
int mx,
int my,
int sx,
int sy,
int element )
79 const int nd_fc = il_get(&qt->nodes, node, node_idx_fc);
80 il_set(&qt->nodes, node, node_idx_fc, il_insert(&qt->enodes));
81 il_set(&qt->enodes, il_get(&qt->nodes, node, node_idx_fc), enode_idx_next, nd_fc);
82 il_set(&qt->enodes, il_get(&qt->nodes, node, node_idx_fc), enode_idx_elt, element);
85 if (il_get(&qt->nodes, node, node_idx_num) == qt->max_elements && depth < qt->max_depth) {
91 while (il_get(&qt->nodes, node, node_idx_fc) != -1) {
92 const int index = il_get(&qt->nodes, node, node_idx_fc);
93 const int next_index = il_get(&qt->enodes, index, enode_idx_next);
94 const int elt = il_get(&qt->enodes, index, enode_idx_elt);
97 il_set(&qt->nodes, node, node_idx_fc, next_index);
98 il_erase(&qt->enodes, index);
101 il_set(&elts, il_push_back(&elts), 0, elt);
105 fc = il_insert(&qt->nodes);
106 il_insert(&qt->nodes);
107 il_insert(&qt->nodes);
108 il_insert(&qt->nodes);
109 il_set(&qt->nodes, node, node_idx_fc, fc);
112 for (
int j=0; j < 4; ++j) {
113 il_set(&qt->nodes, fc+j, node_idx_fc, -1);
114 il_set(&qt->nodes, fc+j, node_idx_num, 0);
118 il_set(&qt->nodes, node, node_idx_num, -1);
119 for (
int j=0; j < il_size(&elts); ++j)
120 node_insert(qt, node, depth, mx, my, sx, sy, il_get(&elts, j, 0));
125 il_set(&qt->nodes, node, node_idx_num, il_get(&qt->nodes, node, node_idx_num) + 1);
129static void push_node(
IntList* nodes,
int nd_index,
int nd_depth,
int nd_mx,
int nd_my,
int nd_sx,
int nd_sy )
131 const int back_idx = il_push_back(nodes);
132 il_set(nodes, back_idx, nd_idx_mx, nd_mx);
133 il_set(nodes, back_idx, nd_idx_my, nd_my);
134 il_set(nodes, back_idx, nd_idx_sx, nd_sx);
135 il_set(nodes, back_idx, nd_idx_sy, nd_sy);
136 il_set(nodes, back_idx, nd_idx_index, nd_index);
137 il_set(nodes, back_idx, nd_idx_depth, nd_depth);
140static void find_leaves(
IntList* out,
const Quadtree* qt,
int node,
int depth,
141 int mx,
int my,
int sx,
int sy,
142 int lft,
int top,
int rgt,
int btm )
145 il_create( &to_process, nd_num );
146 push_node( &to_process, node, depth, mx, my, sx, sy );
148 while (il_size(&to_process) > 0) {
149 const int back_idx = il_size(&to_process) - 1;
150 const int nd_mx = il_get(&to_process, back_idx, nd_idx_mx);
151 const int nd_my = il_get(&to_process, back_idx, nd_idx_my);
152 const int nd_sx = il_get(&to_process, back_idx, nd_idx_sx);
153 const int nd_sy = il_get(&to_process, back_idx, nd_idx_sy);
154 const int nd_index = il_get(&to_process, back_idx, nd_idx_index);
155 const int nd_depth = il_get(&to_process, back_idx, nd_idx_depth);
156 il_pop_back(&to_process);
159 if (il_get(&qt->nodes, nd_index, node_idx_num) != -1)
160 push_node(out, nd_index, nd_depth, nd_mx, nd_my, nd_sx, nd_sy);
163 const int fc = il_get(&qt->nodes, nd_index, node_idx_fc);
164 const int hx = nd_sx >> 1, hy = nd_sy >> 1;
165 const int l = nd_mx-hx, t = nd_my-hy, r = nd_mx+hx, b = nd_my+hy;
169 push_node(&to_process, fc+0, nd_depth+1, l,t,hx,hy);
171 push_node(&to_process, fc+1, nd_depth+1, r,t,hx,hy);
175 push_node(&to_process, fc+2, nd_depth+1, l,b,hx,hy);
177 push_node(&to_process, fc+3, nd_depth+1, r,b,hx,hy);
181 il_destroy(&to_process);
184static void node_insert(
Quadtree* qt,
int index,
int depth,
int mx,
int my,
int sx,
int sy,
int element )
189 const int lft = il_get(&qt->elts, element, elt_idx_lft);
190 const int top = il_get(&qt->elts, element, elt_idx_top);
191 const int rgt = il_get(&qt->elts, element, elt_idx_rgt);
192 const int btm = il_get(&qt->elts, element, elt_idx_btm);
194 il_create(&leaves, nd_num);
195 find_leaves(&leaves, qt, index, depth, mx, my, sx, sy, lft, top, rgt, btm);
196 for (
int j=0; j < il_size(&leaves); ++j) {
197 const int nd_mx = il_get(&leaves, j, nd_idx_mx);
198 const int nd_my = il_get(&leaves, j, nd_idx_my);
199 const int nd_sx = il_get(&leaves, j, nd_idx_sx);
200 const int nd_sy = il_get(&leaves, j, nd_idx_sy);
201 const int nd_index = il_get(&leaves, j, nd_idx_index);
202 const int nd_depth = il_get(&leaves, j, nd_idx_depth);
203 leaf_insert(qt, nd_index, nd_depth, nd_mx, nd_my, nd_sx, nd_sy, element);
208void qt_create(
Quadtree* qt,
int x1,
int y1,
int x2,
int y2,
int max_elements,
int max_depth )
210 qt->max_elements = max_elements;
211 qt->max_depth = max_depth;
214 il_create(&qt->nodes, node_num);
215 il_create(&qt->elts, elt_num);
216 il_create(&qt->enodes, enode_num);
219 il_insert(&qt->nodes);
220 il_set(&qt->nodes, 0, node_idx_fc, -1);
221 il_set(&qt->nodes, 0, node_idx_num, 0);
223 int half_width = (x2-x1) >> 1;
224 int half_height = (y2-y1) >> 1;
225 qt->root_sx = half_width;
226 qt->root_sy = half_height;
229 qt->root_mx = x1 + half_width;
230 qt->root_my = y1 + half_height;
235 il_clear( &qt->nodes );
236 il_clear( &qt->elts );
237 il_clear( &qt->enodes );
240 il_insert(&qt->nodes);
241 il_set(&qt->nodes, 0, node_idx_fc, -1);
242 il_set(&qt->nodes, 0, node_idx_num, 0);
247 il_destroy(&qt->nodes);
248 il_destroy(&qt->elts);
249 il_destroy(&qt->enodes);
253int qt_insert (
Quadtree* qt,
int id,
int x1,
int y1,
int x2,
int y2 )
256 const int new_element = il_insert(&qt->elts);
259 il_set(&qt->elts, new_element, elt_idx_lft, x1);
260 il_set(&qt->elts, new_element, elt_idx_top, y1);
261 il_set(&qt->elts, new_element, elt_idx_rgt, x2);
262 il_set(&qt->elts, new_element, elt_idx_btm, y2);
263 il_set(&qt->elts, new_element, elt_idx_id,
id);
266 node_insert(qt, 0, 0, qt->root_mx, qt->root_my, qt->root_sx, qt->root_sy, new_element);
270void qt_remove(
Quadtree* qt,
int element )
275 const int lft = il_get(&qt->elts, element, elt_idx_lft);
276 const int top = il_get(&qt->elts, element, elt_idx_top);
277 const int rgt = il_get(&qt->elts, element, elt_idx_rgt);
278 const int btm = il_get(&qt->elts, element, elt_idx_btm);
280 il_create(&leaves, nd_num);
281 find_leaves(&leaves, qt, 0, 0, qt->root_mx, qt->root_my, qt->root_sx, qt->root_sy, lft, top, rgt, btm);
284 for (
int j=0; j < il_size(&leaves); ++j) {
285 const int nd_index = il_get(&leaves, j, nd_idx_index);
288 int node_index = il_get(&qt->nodes, nd_index, node_idx_fc);
290 while (node_index != -1 && il_get(&qt->enodes, node_index, enode_idx_elt) != element) {
291 prev_index = node_index;
292 node_index = il_get(&qt->enodes, node_index, enode_idx_next);
295 if (node_index != -1) {
297 const int next_index = il_get(&qt->enodes, node_index, enode_idx_next);
298 if (prev_index == -1)
299 il_set(&qt->nodes, nd_index, node_idx_fc, next_index);
301 il_set(&qt->enodes, prev_index, enode_idx_next, next_index);
302 il_erase(&qt->enodes, node_index);
305 il_set(&qt->nodes, nd_index, node_idx_num, il_get(&qt->nodes, nd_index, node_idx_num)-1);
311 il_erase(&qt->elts, element);
314void qt_query(
Quadtree* qt,
IntList* out,
int qlft,
int qtop,
int qrgt,
int qbtm )
318 const int elt_cap = il_size(&qt->elts);
320 if (qt->temp_size < elt_cap) {
321 qt->temp_size = elt_cap;
322 qt->temp = realloc(qt->temp, qt->temp_size *
sizeof(*qt->temp));
323 memset(qt->temp, 0, qt->temp_size *
sizeof(*qt->temp));
327 il_create(&leaves, nd_num);
328 find_leaves(&leaves, qt, 0, 0, qt->root_mx, qt->root_my, qt->root_sx, qt->root_sy, qlft, qtop, qrgt, qbtm);
331 for (
int j=0; j < il_size(&leaves); ++j) {
332 const int nd_index = il_get(&leaves, j, nd_idx_index);
335 int elt_node_index = il_get(&qt->nodes, nd_index, node_idx_fc);
336 while (elt_node_index != -1) {
337 const int element = il_get(&qt->enodes, elt_node_index, enode_idx_elt);
338 const int lft = il_get(&qt->elts, element, elt_idx_lft);
339 const int top = il_get(&qt->elts, element, elt_idx_top);
340 const int rgt = il_get(&qt->elts, element, elt_idx_rgt);
341 const int btm = il_get(&qt->elts, element, elt_idx_btm);
342 if (!qt->temp[element] && intersect(qlft,qtop,qrgt,qbtm, lft,top,rgt,btm)) {
343 il_set(out, il_push_back(out), 0, element);
344 qt->temp[element] = 1;
346 elt_node_index = il_get(&qt->enodes, elt_node_index, enode_idx_next);
352 for (
int j=0; j < il_size(out); ++j) {
353 const int element = il_get(out, j, 0);
354 const int id = il_get(&qt->elts, element, elt_idx_id);
355 qt->temp[element] = 0;
356 il_set(out, j, 0,
id);
363 il_create(&to_process, 1);
366 if (il_get(&qt->nodes, 0, node_idx_num) == -1) {
368 il_set(&to_process, il_push_back(&to_process), 0, 0);
371 while (il_size(&to_process) > 0) {
373 const int node = il_get(&to_process, il_size(&to_process)-1, 0);
374 const int fc = il_get(&qt->nodes, node, node_idx_fc);
375 int num_empty_leaves = 0;
376 il_pop_back(&to_process);
379 for (
int j=0; j < 4; ++j) {
380 const int child = fc + j;
385 if (il_get(&qt->nodes, child, node_idx_num) == 0)
387 else if (il_get(&qt->nodes, child, node_idx_num) == -1)
390 il_set(&to_process, il_push_back(&to_process), 0, child);
396 if (num_empty_leaves == 4) {
400 il_erase(&qt->nodes, fc + 3);
401 il_erase(&qt->nodes, fc + 2);
402 il_erase(&qt->nodes, fc + 1);
403 il_erase(&qt->nodes, fc + 0);
406 il_set(&qt->nodes, node, node_idx_fc, -1);
407 il_set(&qt->nodes, node, node_idx_num, 0);
410 il_destroy(&to_process);
413void qt_traverse(
Quadtree* qt,
void* user_data, QtNodeFunc* branch, QtNodeFunc* leaf )
416 il_create(&to_process, nd_num);
417 push_node(&to_process, 0, 0, qt->root_mx, qt->root_my, qt->root_sx, qt->root_sy);
419 while (il_size(&to_process) > 0) {
420 const int back_idx = il_size(&to_process) - 1;
421 const int nd_mx = il_get(&to_process, back_idx, nd_idx_mx);
422 const int nd_my = il_get(&to_process, back_idx, nd_idx_my);
423 const int nd_sx = il_get(&to_process, back_idx, nd_idx_sx);
424 const int nd_sy = il_get(&to_process, back_idx, nd_idx_sy);
425 const int nd_index = il_get(&to_process, back_idx, nd_idx_index);
426 const int nd_depth = il_get(&to_process, back_idx, nd_idx_depth);
427 const int fc = il_get(&qt->nodes, nd_index, node_idx_fc);
428 il_pop_back(&to_process);
430 if (il_get(&qt->nodes, nd_index, node_idx_num) == -1) {
432 const int hx = nd_sx >> 1, hy = nd_sy >> 1;
433 const int l = nd_mx-hx, t = nd_my-hy, r = nd_mx+hx, b = nd_my+hy;
434 push_node(&to_process, fc+0, nd_depth+1, l,t, hx,hy);
435 push_node(&to_process, fc+1, nd_depth+1, r,t, hx,hy);
436 push_node(&to_process, fc+2, nd_depth+1, l,b, hx,hy);
437 push_node(&to_process, fc+3, nd_depth+1, r,b, hx,hy);
439 branch(qt, user_data, nd_index, nd_depth, nd_mx, nd_my, nd_sx, nd_sy);
442 leaf(qt, user_data, nd_index, nd_depth, nd_mx, nd_my, nd_sx, nd_sy);
444 il_destroy(&to_process);