[GRASS-SVN] r63951 - grass/trunk/lib/btree2
svn_grass at osgeo.org
svn_grass at osgeo.org
Sun Jan 4 11:32:25 PST 2015
Author: mmetz
Date: 2015-01-04 11:32:25 -0800 (Sun, 04 Jan 2015)
New Revision: 63951
Modified:
grass/trunk/lib/btree2/kdtree.c
grass/trunk/lib/btree2/kdtree.h
Log:
btree2lib: add kdtree traversal
Modified: grass/trunk/lib/btree2/kdtree.c
===================================================================
--- grass/trunk/lib/btree2/kdtree.c 2015-01-03 22:50:11 UTC (rev 63950)
+++ grass/trunk/lib/btree2/kdtree.c 2015-01-04 19:32:25 UTC (rev 63951)
@@ -35,6 +35,8 @@
struct kdnode *, int, int);
static int kdtree_replace(struct kdtree *, struct kdnode *);
static int kdtree_balance(struct kdtree *, struct kdnode *);
+static int kdtree_first(struct kdtrav *, double *, int *);
+static int kdtree_next(struct kdtrav *, double *, int *);
static int cmp(struct kdnode *a, struct kdnode *b, int p)
{
@@ -417,14 +419,15 @@
n = s[top].n;
if (n->uid != sn.uid) {
- dist = 0;
- for (i = 0; i < t->ndims; i++) {
- diff = sn.c[i] - n->c[i];
- dist += diff * diff;
- if (found == k && dist > maxdist)
- break;
- }
if (found < k) {
+ dist = 0.0;
+ i = t->ndims - 1;
+ do {
+ diff = sn.c[i] - n->c[i];
+ dist += diff * diff;
+
+ } while (i--);
+
i = found;
while (i > 0 && d[i - 1] > dist) {
d[i] = d[i - 1];
@@ -438,19 +441,29 @@
maxdist = d[found];
found++;
}
- else if (dist < maxdist) {
- i = k - 1;
- while (i > 0 && d[i - 1] > dist) {
- d[i] = d[i - 1];
- uid[i] = uid[i - 1];
- i--;
+ else {
+ dist = 0.0;
+ i = t->ndims - 1;
+ do {
+ diff = sn.c[i] - n->c[i];
+ dist += diff * diff;
+
+ } while (i-- && dist <= maxdist);
+
+ if (dist < maxdist) {
+ i = k - 1;
+ while (i > 0 && d[i - 1] > dist) {
+ d[i] = d[i - 1];
+ uid[i] = uid[i - 1];
+ i--;
+ }
+ if (d[i] == dist && uid[i] == n->uid)
+ G_fatal_error("knn: inserting duplicate");
+ d[i] = dist;
+ uid[i] = n->uid;
+
+ maxdist = d[k - 1];
}
- if (d[i] == dist && uid[i] == n->uid)
- G_fatal_error("knn: inserting duplicate");
- d[i] = dist;
- uid[i] = n->uid;
-
- maxdist = d[k - 1];
}
if (found == k && maxdist == 0.0)
break;
@@ -540,15 +553,16 @@
if (n->uid != sn.uid) {
dist = 0;
- for (i = 0; i < t->ndims; i++) {
+ i = t->ndims - 1;
+ do {
diff = sn.c[i] - n->c[i];
dist += diff * diff;
- if (dist > maxdistsq)
- break;
- }
+
+ } while (i-- && dist <= maxdistsq);
+
if (dist <= maxdistsq) {
if (found + 1 >= k) {
- k += 10;
+ k = found + 10;
uid = G_realloc(uid, k * sizeof(int));
d = G_realloc(d, k * sizeof(double));
}
@@ -592,7 +606,45 @@
return found;
}
+/* initialize tree traversal
+ * (re-)sets trav structure
+ * returns 0
+ */
+int kdtree_init_trav(struct kdtrav *trav, struct kdtree *tree)
+{
+ trav->tree = tree;
+ trav->curr_node = tree->root;
+ trav->first = 1;
+ trav->top = 0;
+ return 0;
+}
+
+/* traverse the tree
+ * useful to get all items in the tree non-recursively
+ * struct kdtrav *trav needs to be initialized first
+ * returns 1, 0 when finished
+ */
+int kdtree_traverse(struct kdtrav *trav, double *c, int *uid)
+{
+ if (trav->curr_node == NULL) {
+ if (trav->first)
+ G_debug(1, "k-d tree: empty tree");
+ else
+ G_debug(1, "k-d tree: finished traversing");
+
+ return 0;
+ }
+
+ if (trav->first) {
+ trav->first = 0;
+ return kdtree_first(trav, c, uid);
+ }
+
+ return kdtree_next(trav, c, uid);
+}
+
+
/**********************************************/
/* internal functions */
/**********************************************/
@@ -1038,3 +1090,60 @@
return r;
}
+
+/* start traversing the tree
+ * returns pointer to first item
+ */
+static int kdtree_first(struct kdtrav *trav, double *c, int *uid)
+{
+ /* get smallest item */
+ while (trav->curr_node->child[0] != NULL) {
+ trav->up[trav->top++] = trav->curr_node;
+ trav->curr_node = trav->curr_node->child[0];
+ }
+
+ memcpy(c, trav->curr_node->c, trav->tree->csize);
+ *uid = trav->curr_node->uid;
+
+ return 1;
+}
+
+/* continue traversing the tree in ascending order
+ * returns pointer to data item, NULL when finished
+ */
+static int kdtree_next(struct kdtrav *trav, double *c, int *uid)
+{
+ if (trav->curr_node->child[1] != NULL) {
+ /* something on the right side: larger item */
+ trav->up[trav->top++] = trav->curr_node;
+ trav->curr_node = trav->curr_node->child[1];
+
+ /* go down, find smallest item in this branch */
+ while (trav->curr_node->child[0] != NULL) {
+ trav->up[trav->top++] = trav->curr_node;
+ trav->curr_node = trav->curr_node->child[0];
+ }
+ }
+ else {
+ /* at smallest item in this branch, go back up */
+ struct kdnode *last;
+
+ do {
+ if (trav->top == 0) {
+ trav->curr_node = NULL;
+ break;
+ }
+ last = trav->curr_node;
+ trav->curr_node = trav->up[--trav->top];
+ } while (last == trav->curr_node->child[1]);
+ }
+
+ if (trav->curr_node != NULL) {
+ memcpy(c, trav->curr_node->c, trav->tree->csize);
+ *uid = trav->curr_node->uid;
+
+ return 1;
+ }
+
+ return 0; /* finished traversing */
+}
Modified: grass/trunk/lib/btree2/kdtree.h
===================================================================
--- grass/trunk/lib/btree2/kdtree.h 2015-01-03 22:50:11 UTC (rev 63950)
+++ grass/trunk/lib/btree2/kdtree.h 2015-01-04 19:32:25 UTC (rev 63951)
@@ -68,6 +68,15 @@
struct kdnode *root; /* tree root */
};
+struct kdtrav
+{
+ struct kdtree *tree; /* tree being traversed */
+ struct kdnode *curr_node; /* current node */
+ struct kdnode *up[256]; /* stack of parent nodes */
+ int top; /* index for stack */
+ int first; /* little helper flag */
+};
+
/* creae a new k-d tree */
struct kdtree *kdtree_create(char ndims, /* number of dimensions */
int *btol); /* optional balancing tolerance */
@@ -119,3 +128,16 @@
* level 0 = a bit, 1 = more, 2 = a lot */
void kdtree_optimize(struct kdtree *t, /* k-d tree */
int level); /* optimization level */
+
+/* initialize tree traversal
+ * (re-)sets trav structure
+ * returns 0
+ */
+int kdtree_init_trav(struct kdtrav *trav, struct kdtree *tree);
+
+/* traverse the tree
+ * useful to get all items in the tree non-recursively
+ * struct kdtrav *trav needs to be initialized first
+ * returns 1, 0 when finished
+ */
+int kdtree_traverse(struct kdtrav *trav, double *c, int *uid);
More information about the grass-commit
mailing list