#include #include #include "KDTree.h" #define INF 1000000 struct DataPoint; struct Node; struct Region; struct Radius; struct KDTree { struct DataPoint* _data_point_list; int _data_point_list_size; struct Radius* _radius_list; struct Neighbor* _neighbor_list; struct Node *_root; struct Region *_query_region; long int _count; long int _neighbor_count; float _radius; float _radius_sq; float _neighbor_radius; float _neighbor_radius_sq; float *_center_coord; float *_coords; int _bucket_size; int dim; }; /* DataPoint */ static int DataPoint_current_dim=0; struct DataPoint { long int _index; float *_coord; }; static int compare(const void* self, const void* other) { float a, b; const struct DataPoint* p = (const struct DataPoint*)self; const struct DataPoint* q = (const struct DataPoint*)other; a=p->_coord[DataPoint_current_dim]; b=q->_coord[DataPoint_current_dim]; if (a < b) return -1; if (a > b) return +1; return 0; } static void DataPoint_sort(struct DataPoint* list, int n, int i) { /* set sort dimension */ DataPoint_current_dim=i; qsort(list, n, sizeof(struct DataPoint), compare); } /* Node */ struct Node { struct Node *_left; struct Node *_right; float _cut_value; int _cut_dim; long int _start, _end; }; static struct Node* Node_create(float cut_value, int cut_dim, long int start, long int end) { struct Node* node = malloc(sizeof(struct Node)); if (node==NULL) return NULL; node->_left=NULL; node->_right=NULL; node->_cut_value=cut_value; node->_cut_dim=cut_dim; /* start and end index in _data_point_list */ node->_start=start; node->_end=end; return node; } static void Node_destroy(struct Node* node) { if(node==NULL) return; Node_destroy(node->_left); Node_destroy(node->_right); free(node); } static int Node_is_leaf(struct Node* node) { if (node->_left==NULL && node->_right==NULL) return 1; else return 0; } /* Region */ static int Region_dim=3; struct Region { float *_left; float *_right; }; static struct Region* Region_create(const float *left, const float *right) { struct Region* region = malloc(sizeof(struct Region)); if(!region) return NULL; region->_left= malloc(Region_dim*sizeof(float)); region->_right= malloc(Region_dim*sizeof(float)); if (region->_left==NULL || region->_right==NULL) { if (region->_left) free(region->_left); if (region->_right) free(region->_right); free(region); return NULL; } if (left==NULL || right==NULL) { /* [-INF, INF] */ int i; for (i=0; i_left[i]=-INF; region->_right[i]=INF; } } else { int i; for (i=0; i_left[i]=left[i]; region->_right[i]=right[i]; } } return region; } static void Region_destroy(struct Region* region) { if(region==NULL) return; if(region->_left) free(region->_left); if(region->_right) free(region->_right); free(region); } static struct Region* Region_create_intersect_left(struct Region* region, float split_coord, int current_dim) { struct Region* p; const float value = region->_right[current_dim]; region->_right[current_dim]=split_coord; p = Region_create(region->_left, region->_right); region->_right[current_dim] = value; return p; } static struct Region* Region_create_intersect_right(struct Region* region, float split_coord, int current_dim) { struct Region* p; const float value = region->_left[current_dim]; region->_left[current_dim]=split_coord; p = Region_create(region->_left, region->_right); region->_left[current_dim]=value; return p; } static int Region_test_intersect_left(struct Region* region, float split_coord, int current_dim) { float l, r; r=region->_right[current_dim]; l=region->_left[current_dim]; if (split_coord_right[current_dim]; l=region->_left[current_dim]; if (split_coord<=l) return -1; else if (split_coord<=r) return 0; /* split point in interval */ else return +1; } static int Region_encloses(struct Region* region, float *coord) { int i; for (i=0; i=region->_left[i] && coord[i]<=region->_right[i])) { return 0; } } return 1; } static int Region_test_intersection(struct Region* this_region, struct Region *query_region, float radius) { int status=2; int i; for (i=0; i_right[i]; ls=this_region->_left[i]; rq=query_region->_right[i]; lq=query_region->_left[i]; if (ls-rq>radius) { /* outside */ return 0; } else if (lq-rs>radius) { /* outside */ return 0; } else if (rs<=rq && ls>=lq) { /* inside (at least in dim i) */ if (status > 2) status=2; } else { /* overlap (at least in dim i) */ status=1; } } return status; } /* Radius */ struct Radius { long int index; float value; }; /* KDTree */ struct KDTree* KDTree_init(int dim, int bucket_size) { struct KDTree* tree; tree = malloc(sizeof(struct KDTree)); if (!tree) return NULL; tree->_center_coord= malloc(dim*sizeof(float)); if (tree->_center_coord==NULL) { free(tree); return NULL; } tree->dim=dim; Region_dim=tree->dim; tree->_query_region=NULL; tree->_root=NULL; tree->_coords=NULL; tree->_radius_list = NULL; tree->_count=0; tree->_neighbor_count=0; tree->_neighbor_list = NULL; tree->_bucket_size=bucket_size; tree->_data_point_list = NULL; tree->_data_point_list_size = 0; return tree; } void KDTree_destroy(struct KDTree* tree) { /* clean up KD tree */ if (!tree) return; Node_destroy(tree->_root); Region_destroy(tree->_query_region); if (tree->_center_coord) free(tree->_center_coord); if (tree->_coords) free(tree->_coords); free(tree); } static struct Node *KDTree_build_tree(struct KDTree* tree, long int offset_begin, long int offset_end, int depth) { int localdim; if (depth==0) { /* start with [begin, end+1] */ offset_begin=0; offset_end=tree->_data_point_list_size; localdim=0; } else { localdim=depth%tree->dim; } if ((offset_end-offset_begin)<=tree->_bucket_size) { /* leaf node */ return Node_create(-1, localdim, offset_begin, offset_end); } else { long int offset_split; long int left_offset_begin, left_offset_end; long int right_offset_begin, right_offset_end; long int d; float cut_value; struct DataPoint data_point; struct Node *left_node, *right_node, *new_node; DataPoint_sort(tree->_data_point_list+offset_begin, offset_end-offset_begin, localdim); /* calculate index of split point */ d=offset_end-offset_begin; offset_split=d/2+d%2; data_point=tree->_data_point_list[offset_begin+offset_split-1]; cut_value = data_point._coord[localdim]; /* create new node and bind to left & right nodes */ new_node=Node_create(cut_value, localdim, offset_begin, offset_end); if (new_node==NULL) return NULL; /* left */ left_offset_begin=offset_begin; left_offset_end=offset_begin+offset_split; left_node=KDTree_build_tree(tree, left_offset_begin, left_offset_end, depth+1); /* right */ right_offset_begin=left_offset_end; right_offset_end=offset_end; right_node=KDTree_build_tree(tree, right_offset_begin, right_offset_end, depth+1); new_node->_left = left_node; new_node->_right = right_node; if (left_node==NULL || right_node==NULL) { Node_destroy(new_node); return NULL; } return new_node; } } static int KDTree_add_point(struct KDTree* tree, long int index, float *coord) { int n; struct DataPoint* p; n = tree->_data_point_list_size; p = realloc(tree->_data_point_list, (n+1)*sizeof(struct DataPoint)); if (p==NULL) return 0; p[n]._index = index; p[n]._coord = coord; tree->_data_point_list_size = n+1; tree->_data_point_list = p; return 1; } static float KDTree_dist(float *coord1, float *coord2, int dim) { /* returns the SQUARE of the distance between two points */ int i; float sum=0, dif=0; for (i=0; i_center_coord, coord, tree->dim); if (r<=tree->_radius_sq) { int n = tree->_count; struct Radius* p; p = realloc(tree->_radius_list, (n+1)*sizeof(struct Radius)); if (p==NULL) { return 0; } /* note use of sqrt - only calculated if necessary */ p[n].index = index; p[n].value = sqrt(r); tree->_radius_list = p; tree->_count++; } return 1; } static int KDTree_report_subtree(struct KDTree* tree, struct Node *node) { int ok; if (Node_is_leaf(node)) { /* report point(s) */ long int i; for (i=node->_start; i_end; i++) { struct DataPoint data_point; data_point=tree->_data_point_list[i]; ok = KDTree_report_point(tree, data_point._index, data_point._coord); if (!ok) return 0; } } else { /* find points in subtrees via recursion */ ok = KDTree_report_subtree(tree, node->_left); if (!ok) return 0; ok = KDTree_report_subtree(tree, node->_right); if (!ok) return 0; } return 1; } long int KDTree_get_count(struct KDTree* tree) { return tree->_count; } long int KDTree_neighbor_get_count(struct KDTree* tree) { return tree->_neighbor_count; } static int KDTree_search(struct KDTree* tree, struct Region *region, struct Node *node, int depth); static int KDTree_test_region(struct KDTree* tree, struct Node *node, struct Region *region, int depth) { int ok; int intersect_flag; /* is node region inside, outside or overlapping * with query region? */ intersect_flag=Region_test_intersection(region, tree->_query_region, 0); if (intersect_flag==2) { /* inside - extract points */ ok = KDTree_report_subtree(tree, node); /* end of recursion -- get rid of region */ Region_destroy(region); if (!ok) return 0; } else if (intersect_flag==1) { /* overlap - recursion */ ok = KDTree_search(tree, region, node, depth+1); /* search does cleanup of region */ if (!ok) return 0; } else { /* outside - stop */ /* end of recursion -- get rid of region */ Region_destroy(region); } return 1; } static int KDTree_search(struct KDTree* tree, struct Region *region, struct Node *node, int depth) { int current_dim; int ok = 1; if(depth==0) { /* start with [-INF, INF] region */ region = Region_create(NULL, NULL); if (region==NULL) return 0; /* start with root node */ node=tree->_root; } current_dim=depth%tree->dim; if(Node_is_leaf(node)) { long int i; for (i=node->_start; i_end; i++) { struct DataPoint data_point; data_point=tree->_data_point_list[i]; if (Region_encloses(tree->_query_region, data_point._coord)) { /* point is enclosed in query region - report & stop */ ok = KDTree_report_point(tree, data_point._index, data_point._coord); } } } else { struct Node *left_node, *right_node; struct Region *left_region, *right_region; int intersect_left, intersect_right; left_node=node->_left; /* LEFT HALF PLANE */ /* new region */ intersect_left=Region_test_intersect_left(region, node->_cut_value, current_dim); if(intersect_left==1) { left_region = Region_create(region->_left, region->_right); if (left_region) ok = KDTree_test_region(tree, left_node, left_region, depth); else ok = 0; } else if (intersect_left==0) { left_region = Region_create_intersect_left(region, node->_cut_value, current_dim); if (left_region) ok = KDTree_test_region(tree, left_node, left_region, depth); else ok = 0; } /* intersect_left is -1 if no overlap */ /* RIGHT HALF PLANE */ right_node=node->_right; /* new region */ intersect_right=Region_test_intersect_right(region, node->_cut_value, current_dim); if (intersect_right==-1) { right_region = Region_create(region->_left, region->_right); /* test for overlap/inside/outside & do recursion/report/stop */ if (right_region) ok = KDTree_test_region(tree, right_node, right_region, depth); else ok = 0; } else if (intersect_right==0) { right_region = Region_create_intersect_right(region, node->_cut_value, current_dim); /* test for overlap/inside/outside & do recursion/report/stop */ if (right_region) ok = KDTree_test_region(tree, right_node, right_region, depth); else ok = 0; } /* intersect_right is +1 if no overlap */ } Region_destroy(region); return ok; } int KDTree_set_data(struct KDTree* tree, float *coords, long int nr_points) { long int i; int ok; Region_dim=tree->dim; /* clean up stuff from previous use */ Node_destroy(tree->_root); if (tree->_coords) free(tree->_coords); if (tree->_radius_list) { free(tree->_radius_list); tree->_radius_list = NULL; } tree->_count=0; /* keep pointer to coords to delete it */ tree->_coords=coords; for (i=0; idim); if (!ok) { free(tree->_data_point_list); tree->_data_point_list = NULL; tree->_data_point_list_size = 0; return 0; } } /* build KD tree */ tree->_root=KDTree_build_tree(tree, 0, 0, 0); if(!tree->_root) return 0; return 1; } int KDTree_search_center_radius(struct KDTree* tree, float *coord, float radius) { int i; int dim = tree->dim; float* left = malloc(dim*sizeof(float)); float* right = malloc(dim*sizeof(float)); if (left==NULL || right==NULL) { if (left) free(left); if (right) free(right); return 0; } Region_dim=tree->dim; if (tree->_radius_list) { free(tree->_radius_list); tree->_radius_list = NULL; } tree->_count=0; tree->_radius=radius; /* use of r^2 to avoid sqrt use */ tree->_radius_sq=radius*radius; for (i=0; idim; i++) { left[i]=coord[i]-radius; right[i]=coord[i]+radius; /* set center of query */ tree->_center_coord[i]=coord[i]; } /* clean up! */ if (coord) free(coord); Region_destroy(tree->_query_region); tree->_query_region= Region_create(left, right); free(left); free(right); if (!tree->_query_region) return 0; return KDTree_search(tree, NULL, NULL, 0); } void KDTree_copy_indices(struct KDTree* tree, long *indices) { long int i; if (tree->_count==0) return; for(i=0; i_count; i++) { indices[i]=tree->_radius_list[i].index; } } void KDTree_copy_radii(struct KDTree* tree, float *radii) { long int i; if (tree->_count==0) return; for(i=0; i_count; i++) { radii[i]=tree->_radius_list[i].value; } } static int KDTree_test_neighbors(struct KDTree* tree, struct DataPoint* p1, struct DataPoint* p2) { float r; r=KDTree_dist(p1->_coord, p2->_coord, tree->dim); if(r<=tree->_neighbor_radius_sq) { /* we found a neighbor pair! */ struct Neighbor* p; int n; n = tree->_neighbor_count; p = realloc(tree->_neighbor_list, (n+1)*sizeof(struct Neighbor)); if (p==NULL) return 0; p[n].index1 = p1->_index; p[n].index2 = p2->_index; /* note sqrt */ p[n].radius = sqrt(r); tree->_neighbor_list = p; tree->_neighbor_count++; } return 1; } static int KDTree_search_neighbors_between_buckets(struct KDTree* tree, struct Node *node1, struct Node *node2) { long int i; int ok; for(i=node1->_start; i_end; i++) { struct DataPoint p1; long int j; p1=tree->_data_point_list[i]; for (j=node2->_start; j_end; j++) { struct DataPoint p2; p2=tree->_data_point_list[j]; ok = KDTree_test_neighbors(tree, &p1, &p2); if (!ok) return 0; } } return 1; } static int KDTree_neighbor_search_pairs(struct KDTree* tree, struct Node *down, struct Region *down_region, struct Node *up, struct Region *up_region, int depth) { int down_is_leaf, up_is_leaf; int localdim; int ok = 1; /* if regions do not overlap - STOP */ if (!down || !up || !down_region || !up_region) { /* STOP */ return ok; } if (Region_test_intersection(down_region, up_region, tree->_neighbor_radius)==0) { /* regions cannot contain neighbors */ return ok; } /* dim */ localdim=depth%tree->dim; /* are they leaves? */ up_is_leaf=Node_is_leaf(up); down_is_leaf=Node_is_leaf(down); if (up_is_leaf && down_is_leaf) { /* two leaf nodes */ ok = KDTree_search_neighbors_between_buckets(tree, down, up); } else { /* one or no leaf nodes */ struct Node *up_right, *up_left, *down_left, *down_right; struct Region *up_left_region = NULL; struct Region *up_right_region = NULL; struct Region *down_left_region = NULL; struct Region *down_right_region = NULL; if (down_is_leaf) { down_left=down; /* make a copy of down_region */ down_left_region= Region_create(down_region->_left, down_region->_right); if (down_left_region==NULL) ok = 0; down_right=NULL; down_right_region=NULL; } else { float cut_value; int intersect; cut_value=down->_cut_value; down_left=down->_left; down_right=down->_right; intersect=Region_test_intersect_left(down_region, cut_value, localdim); if(intersect==1) { down_left_region = Region_create(down_region->_left, down_region->_right); if (down_left_region==NULL) ok = 0; } else if(intersect==0) { down_left_region = Region_create_intersect_left(down_region, cut_value, localdim); if (down_left_region==NULL) ok = 0; } else if(intersect==-1) /* intersect is -1 if no overlap */ { down_left_region = NULL; } intersect=Region_test_intersect_right(down_region, cut_value, localdim); if(intersect==-1) { down_right_region = Region_create(down_region->_left, down_region->_right); if (down_right_region==NULL) ok = 0; } else if(intersect==0) { down_right_region = Region_create_intersect_right(down_region, cut_value, localdim); if (down_right_region==NULL) ok = 0; } else if(intersect==+1) { down_right_region = NULL; } } if (up_is_leaf) { up_left=up; /* make a copy of up_region */ up_left_region= Region_create(up_region->_left, up_region->_right); if (up_left_region==NULL) ok = 0; up_right=NULL; up_right_region=NULL; } else { float cut_value; int intersect; cut_value=up->_cut_value; up_left=up->_left; up_right=up->_right; intersect=Region_test_intersect_left(up_region, cut_value, localdim); if(intersect==1) { up_left_region = Region_create(up_region->_left, up_region->_right); if (up_left_region==NULL) ok = 0; } else if(intersect==0) { up_left_region = Region_create_intersect_left(up_region, cut_value, localdim); if (up_left_region==NULL) ok = 0; } else if(intersect==-1) /* intersect is -1 if no overlap */ { up_left_region = NULL; } intersect=Region_test_intersect_right(up_region, cut_value, localdim); if(intersect==-1) { up_right_region = Region_create(up_region->_left, up_region->_right); if (up_right_region==NULL) ok = 0; } else if(intersect==0) { up_right_region = Region_create_intersect_right(up_region, cut_value, localdim); if (up_right_region==NULL) ok = 0; } else if(intersect==+1) /* intersect is +1 if no overlap */ { up_right_region = NULL; } } if (ok) ok = KDTree_neighbor_search_pairs(tree, up_left, up_left_region, down_left, down_left_region, depth+1); if (ok) ok = KDTree_neighbor_search_pairs(tree, up_left, up_left_region, down_right, down_right_region, depth+1); if (ok) ok = KDTree_neighbor_search_pairs(tree, up_right, up_right_region, down_left, down_left_region, depth+1); if (ok) ok = KDTree_neighbor_search_pairs(tree, up_right, up_right_region, down_right, down_right_region, depth+1); Region_destroy(down_left_region); Region_destroy(down_right_region); Region_destroy(up_left_region); Region_destroy(up_right_region); } return ok; } static int KDTree_search_neighbors_in_bucket(struct KDTree* tree, struct Node *node) { long int i; int ok; for(i=node->_start; i_end; i++) { struct DataPoint p1; long int j; p1=tree->_data_point_list[i]; for (j=i+1; j_end; j++) { struct DataPoint p2; p2=tree->_data_point_list[j]; ok = KDTree_test_neighbors(tree, &p1, &p2); if (!ok) return 0; } } return 1; } static int KDTree__neighbor_search(struct KDTree* tree, struct Node *node, struct Region *region, int depth) { struct Node *left, *right; struct Region *left_region = NULL; struct Region *right_region = NULL; int localdim; int intersect; float cut_value; int ok = 1; localdim=depth%tree->dim; left=node->_left; right=node->_right; cut_value = node->_cut_value; /* planes of left and right nodes */ intersect=Region_test_intersect_left(region, cut_value, localdim); if(intersect==1) { left_region = Region_create(region->_left, region->_right); if (!left_region) ok = 0; } else if(intersect==0) { left_region = Region_create_intersect_left(region, cut_value, localdim); if (!left_region) ok = 0; } else if(intersect==-1) /* intersect is -1 if no overlap */ { left_region = NULL; } intersect=Region_test_intersect_right(region, cut_value, localdim); if(intersect==-1) { right_region = Region_create(region->_left, region->_right); if (!right_region) ok = 0; } else if(intersect==0) { right_region = Region_create_intersect_right(region, cut_value, localdim); if (!right_region) ok = 0; } else if(intersect==+1) /* intersect is +1 if no overlap */ { right_region = NULL; } if (ok) { if (!Node_is_leaf(left)) { /* search for pairs in this half plane */ ok = KDTree__neighbor_search(tree, left, left_region, depth+1); } else { ok = KDTree_search_neighbors_in_bucket(tree, left); } } if (ok) { if (!Node_is_leaf(right)) { /* search for pairs in this half plane */ ok = KDTree__neighbor_search(tree, right, right_region, depth+1); } else { ok = KDTree_search_neighbors_in_bucket(tree, right); } } /* search for pairs between the half planes */ if (ok) { ok = KDTree_neighbor_search_pairs(tree, left, left_region, right, right_region, depth+1); } /* cleanup */ Region_destroy(left_region); Region_destroy(right_region); return ok; } int KDTree_neighbor_search(struct KDTree* tree, float neighbor_radius, struct Neighbor** neighbors) { long int i; int ok; Region_dim=tree->dim; if(tree->_neighbor_list) { free(tree->_neighbor_list); tree->_neighbor_list = NULL; } tree->_neighbor_count=0; /* note the use of r^2 to avoid use of sqrt */ tree->_neighbor_radius=neighbor_radius; tree->_neighbor_radius_sq=neighbor_radius*neighbor_radius; if (Node_is_leaf(tree->_root)) { /* this is a boundary condition */ /* bucket_size>nr of points */ ok = KDTree_search_neighbors_in_bucket(tree, tree->_root); } else { /* "normal" situation */ struct Region *region; /* start with [-INF, INF] */ region= Region_create(NULL, NULL); if (!region) return 0; ok = KDTree__neighbor_search(tree, tree->_root, region, 0); Region_destroy(region); } if (!ok) return 0; *neighbors = NULL; for (i = 0; i < tree->_neighbor_count; i++) { struct Neighbor* neighbor = malloc(sizeof(struct Neighbor)); if (!neighbor) { while(1) { neighbor = *neighbors; if (!neighbor) return 0; *neighbors = neighbor->next; free(neighbor); } } *neighbor = tree->_neighbor_list[i]; neighbor->next = *neighbors; *neighbors = neighbor; } return 1; } int KDTree_neighbor_simple_search(struct KDTree* tree, float radius, struct Neighbor** neighbors) { long int i; int ok = 1; Region_dim=tree->dim; tree->_neighbor_radius=radius; tree->_neighbor_radius_sq=radius*radius; tree->_neighbor_count=0; if (tree->_neighbor_list) { free(tree->_neighbor_list); tree->_neighbor_list = NULL; } DataPoint_sort(tree->_data_point_list, tree->_data_point_list_size, 0); for (i=0; i_data_point_list_size; i++) { float x1; long int j; struct DataPoint p1; p1=tree->_data_point_list[i]; x1=p1._coord[0]; for (j=i+1; j_data_point_list_size; j++) { struct DataPoint p2; float x2; p2=tree->_data_point_list[j]; x2=p2._coord[0]; if (fabs(x2-x1)<=radius) { ok = KDTree_test_neighbors(tree, &p1, &p2); if (!ok) break; } else { break; } } } if (!ok) return 0; *neighbors = NULL; for (i = 0; i < tree->_neighbor_count; i++) { struct Neighbor* neighbor = malloc(sizeof(struct Neighbor)); if (!neighbor) { while(1) { neighbor = *neighbors; if (!neighbor) return 0; *neighbors = neighbor->next; free(neighbor); } } *neighbor = tree->_neighbor_list[i]; neighbor->next = *neighbors; *neighbors = neighbor; } return 1; }