76static void node_insert(
Quadtree *qt,
int index,
int depth,
int mx,
int my,
77 int sx,
int sy,
int element );
79static int intersect(
int l1,
int t1,
int r1,
int b1,
int l2,
int t2,
int r2,
82 return l2 <= r1 && r2 >= l1 && t2 <= b1 && b2 >= t1;
85static void leaf_insert(
Quadtree *qt,
int node,
int depth,
int mx,
int my,
86 int sx,
int sy,
int element )
89 const int nd_fc = il_get( &qt->nodes, node, node_idx_fc );
90 il_set( &qt->nodes, node, node_idx_fc, il_insert( &qt->enodes ) );
91 il_set( &qt->enodes, il_get( &qt->nodes, node, node_idx_fc ), enode_idx_next,
93 il_set( &qt->enodes, il_get( &qt->nodes, node, node_idx_fc ), enode_idx_elt,
97 if ( il_get( &qt->nodes, node, node_idx_num ) == qt->max_elements &&
98 depth < qt->max_depth ) {
101 il_create( &elts, 1 );
104 while ( il_get( &qt->nodes, node, node_idx_fc ) != -1 ) {
105 const int index = il_get( &qt->nodes, node, node_idx_fc );
106 const int next_index = il_get( &qt->enodes, index, enode_idx_next );
107 const int elt = il_get( &qt->enodes, index, enode_idx_elt );
110 il_set( &qt->nodes, node, node_idx_fc, next_index );
111 il_erase( &qt->enodes, index );
114 il_set( &elts, il_push_back( &elts ), 0, elt );
118 fc = il_insert( &qt->nodes );
119 il_insert( &qt->nodes );
120 il_insert( &qt->nodes );
121 il_insert( &qt->nodes );
122 il_set( &qt->nodes, node, node_idx_fc, fc );
125 for (
int j = 0; j < 4; ++j ) {
126 il_set( &qt->nodes, fc + j, node_idx_fc, -1 );
127 il_set( &qt->nodes, fc + j, node_idx_num, 0 );
131 il_set( &qt->nodes, node, node_idx_num, -1 );
132 for (
int j = 0; j < il_size( &elts ); ++j )
133 node_insert( qt, node, depth, mx, my, sx, sy, il_get( &elts, j, 0 ) );
137 il_set( &qt->nodes, node, node_idx_num,
138 il_get( &qt->nodes, node, node_idx_num ) + 1 );
142static void push_node(
IntList *nodes,
int nd_index,
int nd_depth,
int nd_mx,
143 int nd_my,
int nd_sx,
int nd_sy )
145 const int back_idx = il_push_back( nodes );
146 il_set( nodes, back_idx, nd_idx_mx, nd_mx );
147 il_set( nodes, back_idx, nd_idx_my, nd_my );
148 il_set( nodes, back_idx, nd_idx_sx, nd_sx );
149 il_set( nodes, back_idx, nd_idx_sy, nd_sy );
150 il_set( nodes, back_idx, nd_idx_index, nd_index );
151 il_set( nodes, back_idx, nd_idx_depth, nd_depth );
154static void find_leaves(
IntList *out,
const Quadtree *qt,
int node,
int depth,
155 int mx,
int my,
int sx,
int sy,
int lft,
int top,
159 il_create( &to_process, nd_num );
160 push_node( &to_process, node, depth, mx, my, sx, sy );
162 while ( il_size( &to_process ) > 0 ) {
163 const int back_idx = il_size( &to_process ) - 1;
164 const int nd_mx = il_get( &to_process, back_idx, nd_idx_mx );
165 const int nd_my = il_get( &to_process, back_idx, nd_idx_my );
166 const int nd_sx = il_get( &to_process, back_idx, nd_idx_sx );
167 const int nd_sy = il_get( &to_process, back_idx, nd_idx_sy );
168 const int nd_index = il_get( &to_process, back_idx, nd_idx_index );
169 const int nd_depth = il_get( &to_process, back_idx, nd_idx_depth );
170 il_pop_back( &to_process );
173 if ( il_get( &qt->nodes, nd_index, node_idx_num ) != -1 )
174 push_node( out, nd_index, nd_depth, nd_mx, nd_my, nd_sx, nd_sy );
177 const int fc = il_get( &qt->nodes, nd_index, node_idx_fc );
178 const int hx = nd_sx >> 1, hy = nd_sy >> 1;
179 const int l = nd_mx - hx, t = nd_my - hy, r = nd_mx + hx,
182 if ( top <= nd_my ) {
184 push_node( &to_process, fc + 0, nd_depth + 1, l, t, hx, hy );
186 push_node( &to_process, fc + 1, nd_depth + 1, r, t, hx, hy );
190 push_node( &to_process, fc + 2, nd_depth + 1, l, b, hx, hy );
192 push_node( &to_process, fc + 3, nd_depth + 1, r, b, hx, hy );
196 il_destroy( &to_process );
199static void node_insert(
Quadtree *qt,
int index,
int depth,
int mx,
int my,
200 int sx,
int sy,
int element )
205 const int lft = il_get( &qt->elts, element, elt_idx_lft );
206 const int top = il_get( &qt->elts, element, elt_idx_top );
207 const int rgt = il_get( &qt->elts, element, elt_idx_rgt );
208 const int btm = il_get( &qt->elts, element, elt_idx_btm );
210 il_create( &leaves, nd_num );
211 find_leaves( &leaves, qt, index, depth, mx, my, sx, sy, lft, top, rgt, btm );
212 for (
int j = 0; j < il_size( &leaves ); ++j ) {
213 const int nd_mx = il_get( &leaves, j, nd_idx_mx );
214 const int nd_my = il_get( &leaves, j, nd_idx_my );
215 const int nd_sx = il_get( &leaves, j, nd_idx_sx );
216 const int nd_sy = il_get( &leaves, j, nd_idx_sy );
217 const int nd_index = il_get( &leaves, j, nd_idx_index );
218 const int nd_depth = il_get( &leaves, j, nd_idx_depth );
219 leaf_insert( qt, nd_index, nd_depth, nd_mx, nd_my, nd_sx, nd_sy,
222 il_destroy( &leaves );
225void qt_create(
Quadtree *qt,
int x1,
int y1,
int x2,
int y2,
int max_elements,
228 qt->max_elements = max_elements;
229 qt->max_depth = max_depth;
232 il_create( &qt->nodes, node_num );
233 il_create( &qt->elts, elt_num );
234 il_create( &qt->enodes, enode_num );
237 il_insert( &qt->nodes );
238 il_set( &qt->nodes, 0, node_idx_fc, -1 );
239 il_set( &qt->nodes, 0, node_idx_num, 0 );
241 int half_width = ( x2 - x1 ) >> 1;
242 int half_height = ( y2 - y1 ) >> 1;
243 qt->root_sx = half_width;
244 qt->root_sy = half_height;
247 qt->root_mx = x1 + half_width;
248 qt->root_my = y1 + half_height;
253 il_clear( &qt->nodes );
254 il_clear( &qt->elts );
255 il_clear( &qt->enodes );
258 il_insert( &qt->nodes );
259 il_set( &qt->nodes, 0, node_idx_fc, -1 );
260 il_set( &qt->nodes, 0, node_idx_num, 0 );
265 il_destroy( &qt->nodes );
266 il_destroy( &qt->elts );
267 il_destroy( &qt->enodes );
271int qt_insert(
Quadtree *qt,
int id,
int x1,
int y1,
int x2,
int y2 )
274 const int new_element = il_insert( &qt->elts );
277 il_set( &qt->elts, new_element, elt_idx_lft, x1 );
278 il_set( &qt->elts, new_element, elt_idx_top, y1 );
279 il_set( &qt->elts, new_element, elt_idx_rgt, x2 );
280 il_set( &qt->elts, new_element, elt_idx_btm, y2 );
281 il_set( &qt->elts, new_element, elt_idx_id,
id );
284 node_insert( qt, 0, 0, qt->root_mx, qt->root_my, qt->root_sx, qt->root_sy,
289void qt_remove(
Quadtree *qt,
int element )
294 const int lft = il_get( &qt->elts, element, elt_idx_lft );
295 const int top = il_get( &qt->elts, element, elt_idx_top );
296 const int rgt = il_get( &qt->elts, element, elt_idx_rgt );
297 const int btm = il_get( &qt->elts, element, elt_idx_btm );
299 il_create( &leaves, nd_num );
300 find_leaves( &leaves, qt, 0, 0, qt->root_mx, qt->root_my, qt->root_sx,
301 qt->root_sy, lft, top, rgt, btm );
304 for (
int j = 0; j < il_size( &leaves ); ++j ) {
305 const int nd_index = il_get( &leaves, j, nd_idx_index );
308 int node_index = il_get( &qt->nodes, nd_index, node_idx_fc );
310 while ( node_index != -1 &&
311 il_get( &qt->enodes, node_index, enode_idx_elt ) != element ) {
312 prev_index = node_index;
313 node_index = il_get( &qt->enodes, node_index, enode_idx_next );
316 if ( node_index != -1 ) {
318 const int next_index =
319 il_get( &qt->enodes, node_index, enode_idx_next );
320 if ( prev_index == -1 )
321 il_set( &qt->nodes, nd_index, node_idx_fc, next_index );
323 il_set( &qt->enodes, prev_index, enode_idx_next, next_index );
324 il_erase( &qt->enodes, node_index );
327 il_set( &qt->nodes, nd_index, node_idx_num,
328 il_get( &qt->nodes, nd_index, node_idx_num ) - 1 );
331 il_destroy( &leaves );
334 il_erase( &qt->elts, element );
337void qt_query(
Quadtree *qt,
IntList *out,
int qlft,
int qtop,
int qrgt,
342 const int elt_cap = il_size( &qt->elts );
344 if ( qt->temp_size < elt_cap ) {
345 qt->temp_size = elt_cap;
346 qt->temp = realloc( qt->temp, qt->temp_size *
sizeof( *qt->temp ) );
347 memset( qt->temp, 0, qt->temp_size *
sizeof( *qt->temp ) );
351 il_create( &leaves, nd_num );
352 find_leaves( &leaves, qt, 0, 0, qt->root_mx, qt->root_my, qt->root_sx,
353 qt->root_sy, qlft, qtop, qrgt, qbtm );
356 for (
int j = 0; j < il_size( &leaves ); ++j ) {
357 const int nd_index = il_get( &leaves, j, nd_idx_index );
360 int elt_node_index = il_get( &qt->nodes, nd_index, node_idx_fc );
361 while ( elt_node_index != -1 ) {
363 il_get( &qt->enodes, elt_node_index, enode_idx_elt );
364 const int lft = il_get( &qt->elts, element, elt_idx_lft );
365 const int top = il_get( &qt->elts, element, elt_idx_top );
366 const int rgt = il_get( &qt->elts, element, elt_idx_rgt );
367 const int btm = il_get( &qt->elts, element, elt_idx_btm );
368 if ( !qt->temp[element] &&
369 intersect( qlft, qtop, qrgt, qbtm, lft, top, rgt, btm ) ) {
370 il_set( out, il_push_back( out ), 0, element );
371 qt->temp[element] = 1;
373 elt_node_index = il_get( &qt->enodes, elt_node_index, enode_idx_next );
376 il_destroy( &leaves );
379 for (
int j = 0; j < il_size( out ); ++j ) {
380 const int element = il_get( out, j, 0 );
381 const int id = il_get( &qt->elts, element, elt_idx_id );
382 qt->temp[element] = 0;
383 il_set( out, j, 0,
id );
390 il_create( &to_process, 1 );
393 if ( il_get( &qt->nodes, 0, node_idx_num ) == -1 ) {
395 il_set( &to_process, il_push_back( &to_process ), 0, 0 );
398 while ( il_size( &to_process ) > 0 ) {
400 const int node = il_get( &to_process, il_size( &to_process ) - 1, 0 );
401 const int fc = il_get( &qt->nodes, node, node_idx_fc );
402 int num_empty_leaves = 0;
403 il_pop_back( &to_process );
406 for (
int j = 0; j < 4; ++j ) {
407 const int child = fc + j;
412 if ( il_get( &qt->nodes, child, node_idx_num ) == 0 )
414 else if ( il_get( &qt->nodes, child, node_idx_num ) == -1 ) {
416 il_set( &to_process, il_push_back( &to_process ), 0, child );
422 if ( num_empty_leaves == 4 ) {
426 il_erase( &qt->nodes, fc + 3 );
427 il_erase( &qt->nodes, fc + 2 );
428 il_erase( &qt->nodes, fc + 1 );
429 il_erase( &qt->nodes, fc + 0 );
432 il_set( &qt->nodes, node, node_idx_fc, -1 );
433 il_set( &qt->nodes, node, node_idx_num, 0 );
436 il_destroy( &to_process );
439void qt_traverse(
Quadtree *qt,
void *user_data, QtNodeFunc *branch,
443 il_create( &to_process, nd_num );
444 push_node( &to_process, 0, 0, qt->root_mx, qt->root_my, qt->root_sx,
447 while ( il_size( &to_process ) > 0 ) {
448 const int back_idx = il_size( &to_process ) - 1;
449 const int nd_mx = il_get( &to_process, back_idx, nd_idx_mx );
450 const int nd_my = il_get( &to_process, back_idx, nd_idx_my );
451 const int nd_sx = il_get( &to_process, back_idx, nd_idx_sx );
452 const int nd_sy = il_get( &to_process, back_idx, nd_idx_sy );
453 const int nd_index = il_get( &to_process, back_idx, nd_idx_index );
454 const int nd_depth = il_get( &to_process, back_idx, nd_idx_depth );
455 const int fc = il_get( &qt->nodes, nd_index, node_idx_fc );
456 il_pop_back( &to_process );
458 if ( il_get( &qt->nodes, nd_index, node_idx_num ) == -1 ) {
460 const int hx = nd_sx >> 1, hy = nd_sy >> 1;
461 const int l = nd_mx - hx, t = nd_my - hy, r = nd_mx + hx,
463 push_node( &to_process, fc + 0, nd_depth + 1, l, t, hx, hy );
464 push_node( &to_process, fc + 1, nd_depth + 1, r, t, hx, hy );
465 push_node( &to_process, fc + 2, nd_depth + 1, l, b, hx, hy );
466 push_node( &to_process, fc + 3, nd_depth + 1, r, b, hx, hy );
468 branch( qt, user_data, nd_index, nd_depth, nd_mx, nd_my, nd_sx,
471 leaf( qt, user_data, nd_index, nd_depth, nd_mx, nd_my, nd_sx, nd_sy );
473 il_destroy( &to_process );