Revision: 15970
          
http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=15970
Author:   unclezeiv
Date:     2008-08-05 14:41:53 +0200 (Tue, 05 Aug 2008)

Log Message:
-----------
Added a number of features to BLI_kdtree:
- BLI_kdtree_find_in_sphere, returns all elements within distance "dist" from 
"co"
- BLI_kdtree_weak_delete, marks an element as deleted: this means it won't be 
returned by subsequent queries

In order to have a O(1) BLI_kdtree_weak_delete, we need a conversion table from 
user defined indices to internal node indices:
- BLI_kdtree_build_correspondence is the function to create such table

Finally, a very specific need:
- BLI_kdtree_change_index, to replace a user defined index with another one 
(updating the correspondence table as well)

All these features, if unused, shouldn't have a significant impact on existing 
usage of kd-trees. Still, tests to confirm this are very welcome.

If module maintainers feel that these changes are not appropriate here, I'm 
ready to move them somewhere else.

Modified Paths:
--------------
    branches/soc-2008-unclezeiv/source/blender/blenlib/BLI_kdtree.h
    branches/soc-2008-unclezeiv/source/blender/blenlib/intern/BLI_kdtree.c

Modified: branches/soc-2008-unclezeiv/source/blender/blenlib/BLI_kdtree.h
===================================================================
--- branches/soc-2008-unclezeiv/source/blender/blenlib/BLI_kdtree.h     
2008-08-05 10:48:17 UTC (rev 15969)
+++ branches/soc-2008-unclezeiv/source/blender/blenlib/BLI_kdtree.h     
2008-08-05 12:41:53 UTC (rev 15970)
@@ -52,9 +52,28 @@
 
 /* Find nearest returns index, and -1 if no node is found.
  * Find n nearest returns number of points found, with results in nearest.
+ * Find all points within a certain distance; returns number of points found, 
with results in nearest.
  * Normal is optional. */
 int    BLI_kdtree_find_nearest(KDTree *tree, float *co, float *nor, 
KDTreeNearest *nearest);
 int    BLI_kdtree_find_n_nearest(KDTree *tree, int n, float *co, float *nor, 
KDTreeNearest *nearest);
+int    BLI_kdtree_find_in_sphere(KDTree *tree, float dist, float *co, float 
*nor, KDTreeNearest *nearest);
 
+/* Builds a correspondence table to convert from user provided indices to 
internal ones
+ * Factor multiplies the amount of space allocated for the table; should 
normally be "1"
+ * Optional; only useful if specifically required by a method */
+void BLI_kdtree_build_correspondence(KDTree *tree, int factor);
+
+/* Marks a node as deleted: it won't be returned in subsequent queries.
+ * Returns 1 if successful, 0 otherwise
+ * Please note: a correspondence table must be built (once) before using this 
feature
+ * TODO: balance() should remove nodes marked as deleted */
+int BLI_kdtree_weak_delete(KDTree *tree, int index);
+
+/* changes a user provided index into another one, and updates the 
correspondance table accordingly
+ * Note: it's a O(1) operation, as it doesn't perform a search
+ * Returns 1 if successful, 0 otherwise
+ * Please note: a correspondence table must be built (once) before using this 
feature */
+int BLI_kdtree_change_index(KDTree *tree, int old_index, int new_index);
+
 #endif
 

Modified: branches/soc-2008-unclezeiv/source/blender/blenlib/intern/BLI_kdtree.c
===================================================================
--- branches/soc-2008-unclezeiv/source/blender/blenlib/intern/BLI_kdtree.c      
2008-08-05 10:48:17 UTC (rev 15969)
+++ branches/soc-2008-unclezeiv/source/blender/blenlib/intern/BLI_kdtree.c      
2008-08-05 12:41:53 UTC (rev 15970)
@@ -36,20 +36,21 @@
 
 #include "BLI_arithb.h"
 #include "BLI_kdtree.h"
+#include "BKE_utildefines.h"
 
-#define SWAP(type, a, b) { type sw_ap; sw_ap=(a); (a)=(b); (b)=sw_ap; }
-
 typedef struct KDTreeNode {
        struct KDTreeNode *left, *right;
        float co[3], nor[3];
        int index;
-       short d;
+       short d, invalid;
 } KDTreeNode;
 
 struct KDTree {
        KDTreeNode *nodes;
        int totnode;
        KDTreeNode *root;
+       int totdeleted;
+       int *correspondence;
 };
 
 KDTree *BLI_kdtree_new(int maxsize)
@@ -67,6 +68,8 @@
 {
        if(tree) {
                MEM_freeN(tree->nodes);
+               if (tree->correspondence)
+                       MEM_freeN(tree->correspondence);
                MEM_freeN(tree);
        }
 }
@@ -80,6 +83,7 @@
        if(nor) VecCopyf(node->nor, nor);
 }
 
+/* TODO: would be useful if it removed "weakly deleted" nodes */
 static KDTreeNode *kdtree_balance(KDTreeNode *nodes, int totnode, int axis)
 {
        KDTreeNode *node;
@@ -133,14 +137,12 @@
 static float squared_distance(float *v1, float *v2, float *n1, float *n2)
 {
        float d[3], dist;
+       
+       VECSUB(d,v2,v1);
 
-       d[0]= v2[0]-v1[0];
-       d[1]= v2[1]-v1[1];
-       d[2]= v2[2]-v1[2];
+       dist= INPR(d, d);
 
-       dist= d[0]*d[0] + d[1]*d[1] + d[2]*d[2];
-
-       if(n1 && n2 && n1[0]*n2[0] + n1[1]*n2[1] + n1[2]*n2[2] < 0.0f)
+       if(n1 && n2 && INPR(n1, n2) < 0.0f)
                dist *= 10.0f;
 
        return dist;
@@ -233,9 +235,12 @@
        return min_node->index;
 }
 
-static void add_nearest(KDTreeNearest *ptn, int *found, int n, int index, 
float dist, float *co)
+static void add_nearest(KDTreeNearest *ptn, KDTreeNode *node, int *found, int 
n, float dist)
 {
        int i;
+       
+       if (node->invalid)
+               return;
 
        if(*found<n) (*found)++;
 
@@ -246,9 +251,9 @@
                        ptn[i]= ptn[i-1];
        }
 
-       ptn[i].index= index;
+       ptn[i].index= node->index;
        ptn[i].dist= dist;
-       VecCopyf(ptn[i].co, co);
+       VecCopyf(ptn[i].co, node->co);
 }
 
 /* finds the nearest n entries in tree to specified coordinates */
@@ -268,7 +273,7 @@
        root= tree->root;
 
        cur_dist= squared_distance(root->co,co,root->nor,nor);
-       add_nearest(nearest,&found,n,root->index,cur_dist,root->co);
+       add_nearest(nearest,root,&found,n,cur_dist);
        
        if(co[root->d] < root->co[root->d]) {
                if(root->right)
@@ -295,7 +300,7 @@
                                
cur_dist=squared_distance(node->co,co,node->nor,nor);
 
                                if(found<n || cur_dist<nearest[found-1].dist)
-                                       
add_nearest(nearest,&found,n,node->index,cur_dist,node->co);
+                                       
add_nearest(nearest,node,&found,n,cur_dist);
 
                                if(node->left)
                                        stack[cur++]=node->left;
@@ -308,8 +313,9 @@
 
                        if(found<n || cur_dist<nearest[found-1].dist){
                                
cur_dist=squared_distance(node->co,co,node->nor,nor);
+                               
                                if(found<n || cur_dist<nearest[found-1].dist)
-                                       
add_nearest(nearest,&found,n,node->index,cur_dist,node->co);
+                                       
add_nearest(nearest,node,&found,n,cur_dist);
 
                                if(node->right)
                                        stack[cur++]=node->right;
@@ -336,3 +342,126 @@
        return found;
 }
 
+/* finds all the entries within distance (dist) from (co) */
+int    BLI_kdtree_find_in_sphere(KDTree *tree, float dist, float *co, float 
*nor, KDTreeNearest *nearest)
+{
+       KDTreeNode *root, *node=0;
+       KDTreeNode **stack, *defaultstack[100];
+       float cur_dist;
+       int i, totstack, cur=0, found=0, n;
+
+       if(!tree->root)
+               return 0;
+
+       stack= defaultstack;
+       totstack= 100;
+
+       root= tree->root;
+       n= tree->totnode;
+       dist*= dist;
+
+       cur_dist= squared_distance(root->co,co,root->nor,nor);
+       if (cur_dist <= dist)
+               add_nearest(nearest,root,&found,n,cur_dist);
+       
+       if(co[root->d] < root->co[root->d]) {
+               if(root->right)
+                       stack[cur++]=root->right;
+               if(root->left)
+                       stack[cur++]=root->left;
+       }
+       else {
+               if(root->left)
+                       stack[cur++]=root->left;
+               if(root->right)
+                       stack[cur++]=root->right;
+       }
+
+       while(cur--){
+               node=stack[cur];
+
+               cur_dist = node->co[node->d] - co[node->d];
+
+               if(cur_dist<0.0){
+                       cur_dist= -cur_dist*cur_dist;
+
+                       if(-cur_dist<dist){
+                               
cur_dist=squared_distance(node->co,co,node->nor,nor);
+                               if(cur_dist<=dist)
+                                       
add_nearest(nearest,node,&found,n,cur_dist);
+
+                               if(node->left)
+                                       stack[cur++]=node->left;
+                       }
+                       if(node->right)
+                               stack[cur++]=node->right;
+               }
+               else{
+                       cur_dist= cur_dist*cur_dist;
+
+                       if(cur_dist<dist){
+                               
cur_dist=squared_distance(node->co,co,node->nor,nor);
+                               if(cur_dist<=dist)
+                                       
add_nearest(nearest,node,&found,n,cur_dist);
+
+                               if(node->right)
+                                       stack[cur++]=node->right;
+                       }
+                       if(node->left)
+                               stack[cur++]=node->left;
+               }
+               if(cur+3 > totstack){
+                       KDTreeNode 
**temp=MEM_callocN((totstack+100)*sizeof(KDTreeNode*), "psys_treestack");
+                       memcpy(temp,stack,totstack*sizeof(KDTreeNode*));
+                       if(stack != defaultstack)
+                               MEM_freeN(stack);
+                       stack=temp;
+                       totstack+=100;
+               }
+       }
+
+       for(i=0; i<found; i++)
+               nearest[i].dist= sqrt(nearest[i].dist);
+
+       if(stack != defaultstack)
+               MEM_freeN(stack);
+
+       return found;
+}
+
+void BLI_kdtree_build_correspondence(KDTree *tree, int factor)
+{
+       int i;
+       
+       if (tree->correspondence)
+               MEM_freeN(tree->correspondence);
+       
+       tree->correspondence= MEM_callocN(sizeof(int) * tree->totnode * factor, 
"KDTree correspondence");
+       
+       for (i=0; i< tree->totnode; i++) {
+               int idx= tree->nodes[i].index;
+               /* NOTE: this should always be true */
+               if (idx >= 0 && idx < tree->totnode)
+                       tree->correspondence[idx]= i;
+       }
+}
+
+int BLI_kdtree_weak_delete(KDTree *tree, int index)
+{
+       if (!tree->correspondence)
+               return 0;
+
+       tree->nodes[tree->correspondence[index]].invalid= 1;
+       tree->totdeleted++;
+       return 1;
+}
+
+int BLI_kdtree_change_index(KDTree *tree, int old_index, int new_index)
+{
+       if (!tree->correspondence)
+               return 0;
+       
+       tree->nodes[tree->correspondence[old_index]].index= new_index;
+       tree->correspondence[new_index]= tree->correspondence[old_index];
+       return 1;
+}


_______________________________________________
Bf-blender-cvs mailing list
[email protected]
http://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to