|
Blender
V2.59
|
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 }