Blender  V2.59
BLI_kdtree.c
Go to the documentation of this file.
00001 /*
00002  * $Id: BLI_kdtree.c 35246 2011-02-27 20:37:56Z jesterking $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00021  * All rights reserved.
00022  *
00023  * The Original Code is: none of this file.
00024  *
00025  * Contributor(s): Janne Karhu
00026  *                 Brecht Van Lommel
00027  *
00028  * ***** END GPL LICENSE BLOCK *****
00029  */
00030 
00037 #include "MEM_guardedalloc.h"
00038 
00039 #include "BLI_math.h"
00040 #include "BLI_kdtree.h"
00041 
00042 #ifndef SWAP
00043 #define SWAP(type, a, b) { type sw_ap; sw_ap=(a); (a)=(b); (b)=sw_ap; }
00044 #endif
00045 
00046 typedef struct KDTreeNode {
00047         struct KDTreeNode *left, *right;
00048         float co[3], nor[3];
00049         int index;
00050         short d;
00051 } KDTreeNode;
00052 
00053 struct KDTree {
00054         KDTreeNode *nodes;
00055         int totnode;
00056         KDTreeNode *root;
00057 };
00058 
00059 KDTree *BLI_kdtree_new(int maxsize)
00060 {
00061         KDTree *tree;
00062 
00063         tree= MEM_callocN(sizeof(KDTree), "KDTree");
00064         tree->nodes= MEM_callocN(sizeof(KDTreeNode)*maxsize, "KDTreeNode");
00065         tree->totnode= 0;
00066 
00067         return tree;
00068 }
00069 
00070 void BLI_kdtree_free(KDTree *tree)
00071 {
00072         if(tree) {
00073                 MEM_freeN(tree->nodes);
00074                 MEM_freeN(tree);
00075         }
00076 }
00077 
00078 void BLI_kdtree_insert(KDTree *tree, int index, float *co, float *nor)
00079 {
00080         KDTreeNode *node= &tree->nodes[tree->totnode++];
00081 
00082         node->index= index;
00083         copy_v3_v3(node->co, co);
00084         if(nor) copy_v3_v3(node->nor, nor);
00085 }
00086 
00087 static KDTreeNode *kdtree_balance(KDTreeNode *nodes, int totnode, int axis)
00088 {
00089         KDTreeNode *node;
00090         float co;
00091         int left, right, median, i, j;
00092 
00093         if(totnode <= 0)
00094                 return NULL;
00095         else if(totnode == 1)
00096                 return nodes;
00097         
00098         /* quicksort style sorting around median */
00099         left= 0;
00100         right= totnode-1;
00101         median= totnode/2;
00102 
00103         while(right > left) {
00104                 co= nodes[right].co[axis];
00105                 i= left-1;
00106                 j= right;
00107 
00108                 while(1) {
00109                         while(nodes[++i].co[axis] < co);
00110                         while(nodes[--j].co[axis] > co && j>left);
00111 
00112                         if(i >= j) break;
00113                         SWAP(KDTreeNode, nodes[i], nodes[j]);
00114                 }
00115 
00116                 SWAP(KDTreeNode, nodes[i], nodes[right]);
00117                 if(i >= median)
00118                         right= i-1;
00119                 if(i <= median)
00120                         left= i+1;
00121         }
00122 
00123         /* set node and sort subnodes */
00124         node= &nodes[median];
00125         node->d= axis;
00126         node->left= kdtree_balance(nodes, median, (axis+1)%3);
00127         node->right= kdtree_balance(nodes+median+1, (totnode-(median+1)), (axis+1)%3);
00128 
00129         return node;
00130 }
00131 
00132 void BLI_kdtree_balance(KDTree *tree)
00133 {
00134         tree->root= kdtree_balance(tree->nodes, tree->totnode, 0);
00135 }
00136 
00137 static float squared_distance(float *v2, float *v1, float *n1, float *n2)
00138 {
00139         float d[3], dist;
00140         (void)n1; /* unused */
00141 
00142         d[0]= v2[0]-v1[0];
00143         d[1]= v2[1]-v1[1];
00144         d[2]= v2[2]-v1[2];
00145 
00146         dist= d[0]*d[0] + d[1]*d[1] + d[2]*d[2];
00147 
00148         //if(n1 && n2 && n1[0]*n2[0] + n1[1]*n2[1] + n1[2]*n2[2] < 0.0f)
00149         if(n2 && d[0]*n2[0] + d[1]*n2[1] + d[2]*n2[2] < 0.0f)
00150                 dist *= 10.0f;
00151 
00152         return dist;
00153 }
00154 
00155 int     BLI_kdtree_find_nearest(KDTree *tree, float *co, float *nor, KDTreeNearest *nearest)
00156 {
00157         KDTreeNode *root, *node, *min_node;
00158         KDTreeNode **stack, *defaultstack[100];
00159         float min_dist, cur_dist;
00160         int totstack, cur=0;
00161 
00162         if(!tree->root)
00163                 return -1;
00164 
00165         stack= defaultstack;
00166         totstack= 100;
00167 
00168         root= tree->root;
00169         min_node= root;
00170         min_dist= squared_distance(root->co,co,root->nor,nor);
00171 
00172         if(co[root->d] < root->co[root->d]) {
00173                 if(root->right)
00174                         stack[cur++]=root->right;
00175                 if(root->left)
00176                         stack[cur++]=root->left;
00177         }
00178         else {
00179                 if(root->left)
00180                         stack[cur++]=root->left;
00181                 if(root->right)
00182                         stack[cur++]=root->right;
00183         }
00184         
00185         while(cur--){
00186                 node=stack[cur];
00187 
00188                 cur_dist = node->co[node->d] - co[node->d];
00189 
00190                 if(cur_dist<0.0){
00191                         cur_dist= -cur_dist*cur_dist;
00192 
00193                         if(-cur_dist<min_dist){
00194                                 cur_dist=squared_distance(node->co,co,node->nor,nor);
00195                                 if(cur_dist<min_dist){
00196                                         min_dist=cur_dist;
00197                                         min_node=node;
00198                                 }
00199                                 if(node->left)
00200                                         stack[cur++]=node->left;
00201                         }
00202                         if(node->right)
00203                                 stack[cur++]=node->right;
00204                 }
00205                 else{
00206                         cur_dist= cur_dist*cur_dist;
00207 
00208                         if(cur_dist<min_dist){
00209                                 cur_dist=squared_distance(node->co,co,node->nor,nor);
00210                                 if(cur_dist<min_dist){
00211                                         min_dist=cur_dist;
00212                                         min_node=node;
00213                                 }
00214                                 if(node->right)
00215                                         stack[cur++]=node->right;
00216                         }
00217                         if(node->left)
00218                                 stack[cur++]=node->left;
00219                 }
00220                 if(cur+3 > totstack){
00221                         KDTreeNode **temp=MEM_callocN((totstack+100)*sizeof(KDTreeNode*), "psys_treestack");
00222                         memcpy(temp,stack,totstack*sizeof(KDTreeNode*));
00223                         if(stack != defaultstack)
00224                                 MEM_freeN(stack);
00225                         stack=temp;
00226                         totstack+=100;
00227                 }
00228         }
00229 
00230         if(nearest) {
00231                 nearest->index= min_node->index;
00232                 nearest->dist= sqrt(min_dist);
00233                 copy_v3_v3(nearest->co, min_node->co);
00234         }
00235 
00236         if(stack != defaultstack)
00237                 MEM_freeN(stack);
00238 
00239         return min_node->index;
00240 }
00241 
00242 static void add_nearest(KDTreeNearest *ptn, int *found, int n, int index, float dist, float *co)
00243 {
00244         int i;
00245 
00246         if(*found<n) (*found)++;
00247 
00248         for(i=*found-1; i>0; i--) {
00249                 if(dist >= ptn[i-1].dist)
00250                         break;
00251                 else
00252                         ptn[i]= ptn[i-1];
00253         }
00254 
00255         ptn[i].index= index;
00256         ptn[i].dist= dist;
00257         copy_v3_v3(ptn[i].co, co);
00258 }
00259 
00260 /* finds the nearest n entries in tree to specified coordinates */
00261 int     BLI_kdtree_find_n_nearest(KDTree *tree, int n, float *co, float *nor, KDTreeNearest *nearest)
00262 {
00263         KDTreeNode *root, *node= NULL;
00264         KDTreeNode **stack, *defaultstack[100];
00265         float cur_dist;
00266         int i, totstack, cur=0, found=0;
00267 
00268         if(!tree->root)
00269                 return 0;
00270 
00271         stack= defaultstack;
00272         totstack= 100;
00273 
00274         root= tree->root;
00275 
00276         cur_dist= squared_distance(root->co,co,root->nor,nor);
00277         add_nearest(nearest,&found,n,root->index,cur_dist,root->co);
00278         
00279         if(co[root->d] < root->co[root->d]) {
00280                 if(root->right)
00281                         stack[cur++]=root->right;
00282                 if(root->left)
00283                         stack[cur++]=root->left;
00284         }
00285         else {
00286                 if(root->left)
00287                         stack[cur++]=root->left;
00288                 if(root->right)
00289                         stack[cur++]=root->right;
00290         }
00291 
00292         while(cur--){
00293                 node=stack[cur];
00294 
00295                 cur_dist = node->co[node->d] - co[node->d];
00296 
00297                 if(cur_dist<0.0){
00298                         cur_dist= -cur_dist*cur_dist;
00299 
00300                         if(found<n || -cur_dist<nearest[found-1].dist){
00301                                 cur_dist=squared_distance(node->co,co,node->nor,nor);
00302 
00303                                 if(found<n || cur_dist<nearest[found-1].dist)
00304                                         add_nearest(nearest,&found,n,node->index,cur_dist,node->co);
00305 
00306                                 if(node->left)
00307                                         stack[cur++]=node->left;
00308                         }
00309                         if(node->right)
00310                                 stack[cur++]=node->right;
00311                 }
00312                 else{
00313                         cur_dist= cur_dist*cur_dist;
00314 
00315                         if(found<n || cur_dist<nearest[found-1].dist){
00316                                 cur_dist=squared_distance(node->co,co,node->nor,nor);
00317                                 if(found<n || cur_dist<nearest[found-1].dist)
00318                                         add_nearest(nearest,&found,n,node->index,cur_dist,node->co);
00319 
00320                                 if(node->right)
00321                                         stack[cur++]=node->right;
00322                         }
00323                         if(node->left)
00324                                 stack[cur++]=node->left;
00325                 }
00326                 if(cur+3 > totstack){
00327                         KDTreeNode **temp=MEM_callocN((totstack+100)*sizeof(KDTreeNode*), "psys_treestack");
00328                         memcpy(temp,stack,totstack*sizeof(KDTreeNode*));
00329                         if(stack != defaultstack)
00330                                 MEM_freeN(stack);
00331                         stack=temp;
00332                         totstack+=100;
00333                 }
00334         }
00335 
00336         for(i=0; i<found; i++)
00337                 nearest[i].dist= sqrt(nearest[i].dist);
00338 
00339         if(stack != defaultstack)
00340                 MEM_freeN(stack);
00341 
00342         return found;
00343 }
00344 
00345 static int range_compare(const void * a, const void * b)
00346 {
00347         const KDTreeNearest *kda = a;
00348         const KDTreeNearest *kdb = b;
00349 
00350         if(kda->dist < kdb->dist)
00351                 return -1;
00352         else if(kda->dist > kdb->dist)
00353                 return 1;
00354         else
00355                 return 0;
00356 }
00357 static void add_in_range(KDTreeNearest **ptn, int found, int *totfoundstack, int index, float dist, float *co)
00358 {
00359         KDTreeNearest *to;
00360 
00361         if(found+1 > *totfoundstack) {
00362                 KDTreeNearest *temp=MEM_callocN((*totfoundstack+50)*sizeof(KDTreeNode), "psys_treefoundstack");
00363                 memcpy(temp, *ptn, *totfoundstack * sizeof(KDTreeNearest));
00364                 if(*ptn)
00365                         MEM_freeN(*ptn);
00366                 *ptn = temp;
00367                 *totfoundstack+=50;
00368         }
00369 
00370         to = (*ptn) + found;
00371 
00372         to->index = index;
00373         to->dist = sqrt(dist);
00374         copy_v3_v3(to->co, co);
00375 }
00376 int BLI_kdtree_range_search(KDTree *tree, float range, float *co, float *nor, KDTreeNearest **nearest)
00377 {
00378         KDTreeNode *root, *node= NULL;
00379         KDTreeNode **stack, *defaultstack[100];
00380         KDTreeNearest *foundstack=NULL;
00381         float range2 = range*range, dist2;
00382         int totstack, cur=0, found=0, totfoundstack=0;
00383 
00384         if(!tree || !tree->root)
00385                 return 0;
00386 
00387         stack= defaultstack;
00388         totstack= 100;
00389 
00390         root= tree->root;
00391 
00392         if(co[root->d] + range < root->co[root->d]) {
00393                 if(root->left)
00394                         stack[cur++]=root->left;
00395         }
00396         else if(co[root->d] - range > root->co[root->d]) {
00397                 if(root->right)
00398                         stack[cur++]=root->right;
00399         }
00400         else {
00401                 dist2 = squared_distance(root->co, co, root->nor, nor);
00402                 if(dist2  <= range2)
00403                         add_in_range(&foundstack, found++, &totfoundstack, root->index, dist2, root->co);
00404 
00405                 if(root->left)
00406                         stack[cur++]=root->left;
00407                 if(root->right)
00408                         stack[cur++]=root->right;
00409         }
00410 
00411         while(cur--) {
00412                 node=stack[cur];
00413 
00414                 if(co[node->d] + range < node->co[node->d]) {
00415                         if(node->left)
00416                                 stack[cur++]=node->left;
00417                 }
00418                 else if(co[node->d] - range > node->co[node->d]) {
00419                         if(node->right)
00420                                 stack[cur++]=node->right;
00421                 }
00422                 else {
00423                         dist2 = squared_distance(node->co, co, node->nor, nor);
00424                         if(dist2 <= range2)
00425                                 add_in_range(&foundstack, found++, &totfoundstack, node->index, dist2, node->co);
00426 
00427                         if(node->left)
00428                                 stack[cur++]=node->left;
00429                         if(node->right)
00430                                 stack[cur++]=node->right;
00431                 }
00432 
00433                 if(cur+3 > totstack){
00434                         KDTreeNode **temp=MEM_callocN((totstack+100)*sizeof(KDTreeNode*), "psys_treestack");
00435                         memcpy(temp,stack,totstack*sizeof(KDTreeNode*));
00436                         if(stack != defaultstack)
00437                                 MEM_freeN(stack);
00438                         stack=temp;
00439                         totstack+=100;
00440                 }
00441         }
00442 
00443         if(stack != defaultstack)
00444                 MEM_freeN(stack);
00445 
00446         if(found)
00447                 qsort(foundstack, found, sizeof(KDTreeNearest), range_compare);
00448 
00449         *nearest = foundstack;
00450 
00451         return found;
00452 }