/* * Copyright (c) 2008-2009 Bill Whitacre http://rampancy.g0dsoft.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "quad_tree.h" rat_quad_tree_matrix *rat_quad_tree_matrix_create(vector2 origin,vector2 cellsize,unsigned int numcells_x,unsigned int numcells_y) { register unsigned int i,j,numcells=numcells_x*numcells_y; rat_quad_tree_matrix *matrix=(rat_quad_tree_matrix *)rat_alloc(sizeof(rat_quad_tree_matrix)); memset(matrix,0,sizeof(rat_quad_tree_matrix)); matrix->origin=origin; matrix->cellsize=cellsize; matrix->matrix_width=numcells_x; matrix->matrix_height=numcells_y; matrix->numcells=numcells; matrix->quadtrees=(rat_quad_tree **)rat_alloc(sizeof(rat_quad_tree)*numcells); for (i=0; iquadtrees[i+j*numcells_x]=rat_quad_tree_create(quad); } } return matrix; } void rat_quad_tree_matrix_destroy(rat_quad_tree_matrix *matrix) { register unsigned int i; for (i=0; inumcells; i++) rat_quad_tree_destroy(matrix->quadtrees[i]); rat_dealloc((void *)matrix->quadtrees); rat_dealloc((void *)matrix); } static void add_entity_to_node(rat_quad_tree_node *node,rat_body *entity) { register unsigned int i; rat_quad_tree_node *parent; if (node->numentities==0) { node->thisnode_entities=(rat_body **)rat_alloc(sizeof(rat_body *)); node->thisnode_entities[0]=entity; node->numentities=1; } else { node->thisnode_entities=(rat_body **) rat_realloc(node->thisnode_entities,(node->numentities+1)*sizeof(rat_body *)); node->thisnode_entities[node->numentities]=entity; node->numentities++; } for (parent=node->parent; parent; parent=parent->parent) { if (parent->numchildents==0) { parent->numchildents=1; parent->childnode_entities=(rat_body **)rat_alloc(sizeof(rat_body *)); parent->childnode_entities[0]=entity; } else { register int is_already=0; for (i=0; inumchildents; i++) { if (parent->childnode_entities[i]==entity) { is_already=1; break; } } if (!is_already) { parent->childnode_entities= (rat_body **)rat_realloc (parent->childnode_entities,sizeof(rat_body *)* (parent->numchildents+1)); parent->childnode_entities[parent->numchildents]=entity; parent->numchildents++; } } } } void rat_quad_tree_matrix_build(rat_quad_tree_matrix *matrix,rat_body **entities,unsigned int numentities) { // this function just uses bounding box indexing to // speed up queries, meaning of course that we will go // over the head of rat_quad_tree_build a little bit. // that's okay though... register int i,j,k; for (i=0; i<(int)numentities; i++) { register int cell_l=(int)((entities[i]->hull->cached_bb.a.x-matrix->origin.x)/matrix->cellsize.x); register int cell_r=(int)((entities[i]->hull->cached_bb.b.x-matrix->origin.x)/matrix->cellsize.x); register int cell_t=(int)((entities[i]->hull->cached_bb.a.y-matrix->origin.y)/matrix->cellsize.y); register int cell_b=(int)((entities[i]->hull->cached_bb.b.y-matrix->origin.y)/matrix->cellsize.y); cell_l=cell_l<0?0:cell_l; cell_r=cell_r<(int)matrix->matrix_width?cell_r:(int)matrix->matrix_width-1; cell_t=cell_t<0?0:cell_t; cell_b=cell_b<(int)matrix->matrix_height?cell_b:(int)matrix->matrix_height-1; if (cell_l==cell_r&&cell_t==cell_b) rat_quad_tree_build(matrix->quadtrees[cell_l+cell_t*(int)matrix->matrix_width],entities+i,1); else if (cell_r>cell_l&&cell_t==cell_b) { for (j=cell_l; j<=cell_r; j++) { matrix->quadtrees[j+cell_t*matrix->matrix_width]->is_built=1; add_entity_to_node(matrix->quadtrees[j+cell_t*matrix->matrix_width]->root,entities[i]); } } else if (cell_b>cell_t&&cell_l==cell_r) { for (j=cell_t; j<=cell_b; j++) { matrix->quadtrees[cell_l+j*matrix->matrix_width]->is_built=1; add_entity_to_node(matrix->quadtrees[cell_l+j*matrix->matrix_width]->root,entities[i]); } } else { for (j=cell_l; j<=cell_r; j++) { for (k=cell_t; k<=cell_b; k++) { matrix->quadtrees[j+k*matrix->matrix_width]->is_built=1; add_entity_to_node(matrix->quadtrees[j+k*matrix->matrix_width]->root,entities[i]); } } } } } void rat_quad_tree_matrix_eachin(rat_quad_tree_matrix *matrix,rat_quad_tree_each_method each_method,void *data) { register unsigned int i; for (i=0; inumcells; i++) { if (matrix->quadtrees[i]->is_built) rat_quad_tree_eachin(matrix->quadtrees[i],each_method,data); } } void rat_quad_tree_matrix_clear(rat_quad_tree_matrix *matrix) { register unsigned int i; for (i=0; inumcells; i++) rat_quad_tree_clear(matrix->quadtrees[i]); } rat_quad_tree_node *rat_quad_tree_node_create(aabb quad,unsigned int depth,rat_quad_tree *tree,rat_quad_tree_node *parent) { rat_quad_tree_node *node=(rat_quad_tree_node *)rat_alloc(sizeof(rat_quad_tree_node)); memset(node,0,sizeof(rat_quad_tree_node)); node->tree=tree; node->parent=parent; node->quad=quad; node->depth=depth; node->tree->numnodes++; node->tree->maxdepth=depth>node->tree->maxdepth?depth:node->tree->maxdepth; return node; } rat_quad_tree *rat_quad_tree_create(aabb quad) { rat_quad_tree *tree=(rat_quad_tree *)rat_alloc(sizeof(rat_quad_tree)); memset(tree,0,sizeof(rat_quad_tree)); tree->is_built=0; tree->root=rat_quad_tree_node_create(quad,0,tree,NULL); return tree; } void rat_quad_tree_node_destroy(rat_quad_tree_node *node) { register unsigned int i; if (node->are_children) { for (i=0; i<4; i++) rat_quad_tree_node_destroy(node->children[i]); rat_dealloc((void *)node->children); } if (node->numentities) rat_dealloc((void *)node->thisnode_entities); if (node->numchildents) rat_dealloc((void *)node->childnode_entities); node->tree->numnodes--; rat_dealloc((void *)node); } void rat_quad_tree_destroy(rat_quad_tree *tree) { rat_quad_tree_node_destroy(tree->root); rat_dealloc((void *)tree); } int rat_quad_tree_node_query_entity(rat_quad_tree_node *node,rat_body *entity) { if (node->are_children) { if (aabb_is_aabb_inside(entity->hull->cached_bb,node->quad)) { register int result1=rat_quad_tree_node_query_entity(node->children[0],entity); register int result2=rat_quad_tree_node_query_entity(node->children[1],entity); register int result3=rat_quad_tree_node_query_entity(node->children[2],entity); register int result4=rat_quad_tree_node_query_entity(node->children[3],entity); if (!result1&&!result2&&!result3&&!result4) add_entity_to_node(node,entity); return 1; } else if (node->depth==0) { if (aabb_is_aabb_overlapping(entity->hull->cached_bb,node->quad)) { add_entity_to_node(node,entity); return 1; } } } else if (aabb_is_aabb_inside(entity->hull->cached_bb,node->quad)) { register unsigned int i; add_entity_to_node(node,entity); if (node->numentities>2) { register unsigned int i; register unsigned int numents=node->numentities; rat_body **theseentities=(rat_body **)rat_alloc(sizeof(rat_body *)*numents); for (i=0; ithisnode_entities[i]; //memcpy(theseentities,node->thisnode_entities,sizeof(rat_body *)*numents); rat_quad_tree_node_split(node); rat_quad_tree_node_clear(node); for (i=0; idepth==0) { if (aabb_is_aabb_overlapping(entity->hull->cached_bb,node->quad)) { add_entity_to_node(node,entity); return 1; } } return 0; } void rat_quad_tree_node_split(rat_quad_tree_node *node) { register unsigned int i; register vector2 avg,tl,br; register aabb ul,ur,ll,lr; if (node->are_children) return; tl=node->quad.a; br=node->quad.b; avg=vector2_multf(vector2_add(node->quad.a,node->quad.b),0.5); ul.a=tl; ul.b=avg; lr.a=avg; lr.b=br; ur.a.x=avg.x; ur.a.y=tl.y; ur.b.x=br.x; ur.b.y=avg.y; ll.a.x=tl.x; ll.a.y=avg.y; ll.b.x=avg.x; ll.b.y=br.y; node->are_children=1; node->children=(rat_quad_tree_node **)rat_alloc(sizeof(rat_quad_tree_node *)*4); node->children[0]=rat_quad_tree_node_create(ul,node->depth+1,node->tree,node); node->children[1]=rat_quad_tree_node_create(ur,node->depth+1,node->tree,node); node->children[2]=rat_quad_tree_node_create(ll,node->depth+1,node->tree,node); node->children[3]=rat_quad_tree_node_create(lr,node->depth+1,node->tree,node); } void rat_quad_tree_build(rat_quad_tree *tree,rat_body **entities,unsigned int numentities) { register unsigned int i; tree->is_built=1; for (i=0; iroot,entities[i]); } /* static void quad_node_draw(rat_quad_tree_node *node) { drawutil_draw_rect(node->quad.a.x,node->quad.a.y,node->quad.b.x,node->quad.b.y); if (node->are_children) { quad_node_draw(node->children[0]); quad_node_draw(node->children[1]); quad_node_draw(node->children[2]); quad_node_draw(node->children[3]); } } void rat_quad_tree_draw(rat_quad_tree *tree) { drawutil_set_color(0,0,0,1.0); quad_node_draw(tree->root); } */ void rat_quad_tree_node_eachin(rat_quad_tree_node *node,rat_quad_tree_each_method each_method,void *data) { register unsigned int i,j; if (node->numentities>0) { if (node->numentities>1) { for (i=0; inumentities; i++) { for (j=i+1; jnumentities; j++) each_method(node->thisnode_entities[i],node->thisnode_entities[j],data); for (j=0; jnumchildents; j++) each_method(node->thisnode_entities[i],node->childnode_entities[j],data); } } else { for (j=0; jnumchildents; j++) each_method(node->thisnode_entities[0],node->childnode_entities[j],data); } } if (node->are_children&&node->numchildents>0) { rat_quad_tree_node_eachin(node->children[0],each_method,data); rat_quad_tree_node_eachin(node->children[1],each_method,data); rat_quad_tree_node_eachin(node->children[2],each_method,data); rat_quad_tree_node_eachin(node->children[3],each_method,data); } } void rat_quad_tree_eachin(rat_quad_tree *tree,rat_quad_tree_each_method each_method,void *data) { rat_quad_tree_node_eachin(tree->root,each_method,data); } void rat_quad_tree_node_clear(rat_quad_tree_node *node) { if (node->numentities) rat_dealloc((void *)node->thisnode_entities); if (node->numchildents) rat_dealloc((void *)node->childnode_entities); node->numentities=0; node->numchildents=0; } void rat_quad_tree_clear(rat_quad_tree *tree) { aabb quad=tree->root->quad; rat_quad_tree_node_destroy(tree->root); tree->root=rat_quad_tree_node_create(quad,0,tree,NULL); tree->is_built=0; tree->maxdepth=0; }