[GRASS-SVN] r63543 - grass/trunk/lib/btree2
svn_grass at osgeo.org
svn_grass at osgeo.org
Sun Dec 14 14:19:53 PST 2014
Author: mmetz
Date: 2014-12-14 14:19:53 -0800 (Sun, 14 Dec 2014)
New Revision: 63543
Added:
grass/trunk/lib/btree2/kdtree.c
grass/trunk/lib/btree2/kdtree.h
Modified:
grass/trunk/lib/btree2/Makefile
Log:
libbtree2: add kdtree for nearest neighbor search
Modified: grass/trunk/lib/btree2/Makefile
===================================================================
--- grass/trunk/lib/btree2/Makefile 2014-12-14 20:17:29 UTC (rev 63542)
+++ grass/trunk/lib/btree2/Makefile 2014-12-14 22:19:53 UTC (rev 63543)
@@ -8,4 +8,12 @@
include $(MODULE_TOPDIR)/include/Make/Lib.make
-default: lib
+HEADERS := $(ARCH_INCDIR)/kdtree.h
+
+default: headers
+ $(MAKE) lib
+
+headers: $(HEADERS)
+
+$(ARCH_INCDIR)/kdtree.h: kdtree.h
+ $(INSTALL_DATA) $< $@
Added: grass/trunk/lib/btree2/kdtree.c
===================================================================
--- grass/trunk/lib/btree2/kdtree.c (rev 0)
+++ grass/trunk/lib/btree2/kdtree.c 2014-12-14 22:19:53 UTC (rev 63543)
@@ -0,0 +1,875 @@
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <grass/gis.h>
+#include <grass/glocale.h>
+#include "kdtree.h"
+
+#ifdef MAX
+#undef MAX
+#endif
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+
+#define KD_BTOL 6
+
+#ifdef KD_DEBUG
+#undef KD_DEBUG
+#endif
+
+static struct kdnode *kdtree_insert2(struct kdtree *, struct kdnode *,
+ struct kdnode *, int, int);
+static int kdtree_replace(struct kdtree *, struct kdnode *);
+static struct kdnode *kdtree_balance(struct kdtree *, struct kdnode *);
+
+static int cmp(struct kdnode *a, struct kdnode *b, int p)
+{
+ if (a->c[p] < b->c[p])
+ return -1;
+ if (a->c[p] > b->c[p])
+ return 1;
+
+ return (a->uid < b->uid ? -1 : a->uid > b->uid);
+}
+
+static int cmpc(struct kdnode *a, struct kdnode *b, struct kdtree *t)
+{
+ int i;
+ for (i = 0; i < t->ndims; i++) {
+ if (a->c[i] != b->c[i]) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static struct kdnode *kdtree_newnode(struct kdtree *t)
+{
+ struct kdnode *n = G_malloc(sizeof(struct kdnode));
+
+ n->c = G_malloc(t->ndims * sizeof(double));
+ n->dim = 0;
+ n->depth = 0;
+ n->uid = 0;
+ n->child[0] = NULL;
+ n->child[1] = NULL;
+
+ return n;
+}
+
+static void kdtree_free_node(struct kdnode *n)
+{
+ G_free(n->c);
+ G_free(n);
+}
+
+/* create a new kd tree with ndims dimensions,
+ * optionally set balancing tolerance */
+struct kdtree *kdtree_create(char ndims, int *btol)
+{
+ int i;
+ struct kdtree *t;
+
+ t = G_malloc(sizeof(struct kdtree));
+
+ t->ndims = ndims;
+ t->csize = ndims * sizeof(double);
+ t->btol = KD_BTOL;
+ if (btol) {
+ t->btol = *btol;
+ if (t->btol < 2)
+ t->btol = 2;
+ }
+
+ t->nextdim = G_malloc(ndims * sizeof(char));
+ for (i = 0; i < ndims - 1; i++)
+ t->nextdim[i] = i + 1;
+ t->nextdim[ndims - 1] = 0;
+
+ t->count = 0;
+ t->root = NULL;
+
+ return t;
+}
+
+/* clear the tree, removing all entries */
+void kdtree_clear(struct kdtree *t)
+{
+ struct kdnode *it;
+ struct kdnode *save = t->root;
+
+ /*
+ Rotate away the left links so that
+ we can treat this like the destruction
+ of a linked list
+ */
+ while((it = save) != NULL) {
+ if (it->child[0] == NULL) {
+ /* No left links, just kill the node and move on */
+ save = it->child[1];
+ kdtree_free_node(it);
+ it = NULL;
+ }
+ else {
+ /* Rotate away the left link and check again */
+ save = it->child[0];
+ it->child[0] = save->child[1];
+ save->child[1] = it;
+ }
+ }
+ t->root = NULL;
+}
+
+/* destroy the tree */
+void kdtree_destroy(struct kdtree *t)
+{
+ /* remove all entries */
+ kdtree_clear(t);
+ G_free(t->nextdim);
+
+ G_free(t);
+ t = NULL;
+}
+
+/* insert an item (coordinates c and uid) into the kd tree
+ * dc == 1: allow duplicate coordinates */
+int kdtree_insert(struct kdtree *t, double *c, int uid, int dc)
+{
+ struct kdnode *nnew;
+ size_t count = t->count;
+
+ nnew = kdtree_newnode(t);
+ memcpy(nnew->c, c, t->csize);
+ nnew->uid = uid;
+
+ t->root = kdtree_insert2(t, t->root, nnew, 1, dc);
+
+ return count < t->count;
+}
+
+/* remove an item from the kd tree
+ * coordinates c and uid must match */
+int kdtree_remove(struct kdtree *t, double *c, int uid)
+{
+ struct kdnode sn, *n;
+ struct kdstack {
+ struct kdnode *n;
+ int dir;
+ } s[256];
+ int top;
+ int dir, found;
+ int ld, rd;
+
+ sn.c = c;
+ sn.uid = uid;
+
+ /* find sn node */
+ top = 0;
+ s[top].n = t->root;
+ dir = 1;
+ found = 0;
+ while (found) {
+ n = s[top].n;
+ found = (!cmpc(&sn, n, t) && sn.uid == n->uid);
+ if (!found) {
+ dir = cmp(&sn, n, n->dim) > 0;
+ s[top].dir = dir;
+ top++;
+ s[top].n = n->child[dir];
+
+ if (!s[top].n) {
+ G_warning("Node does not exist");
+
+ return 0;
+ }
+ }
+ }
+ if (!kdtree_replace(t, s[top].n)) {
+ t->root = NULL;
+
+ return 1;
+ }
+ if (top) {
+ top--;
+ dir = s[top].dir;
+ n = s[top].n;
+ n->child[dir] = kdtree_balance(t, n->child[dir]);
+
+ /* update node depth */
+ ld = rd = -1;
+ if (n->child[0])
+ ld = n->child[0]->depth;
+ if (n->child[1])
+ rd = n->child[1]->depth;
+ n->depth = MAX(ld, rd) + 1;
+ }
+ while (top) {
+ top--;
+ n = s[top].n;
+
+ /* update node depth */
+ ld = rd = -1;
+ if (n->child[0])
+ ld = n->child[0]->depth;
+ if (n->child[1])
+ rd = n->child[1]->depth;
+ n->depth = MAX(ld, rd) + 1;
+ }
+
+ t->root = kdtree_balance(t, t->root);
+
+ return 1;
+}
+
+/* find k nearest neighbors
+ * results are stored in uid and d (distances)
+ * optionally an uid to be skipped can be given
+ * useful when searching for the nearest neighbor of an item
+ * that is also in the tree */
+int kdtree_knn(struct kdtree *t, double *c, int *uid, double *d, int k, int *skip)
+{
+ int i, found;
+ double diff, dist, maxdist;
+ struct kdnode sn, *n, *r;
+ struct kdstack {
+ struct kdnode *n;
+ int dir;
+ char v;
+ } s[256];
+ int dir;
+ int top;
+
+ r = t->root;
+ sn.c = c;
+ sn.uid = (int)0x80000000;
+ if (skip)
+ sn.uid = *skip;
+
+ top = 0;
+ s[top].n = r;
+ if (!s[top].n)
+ return 0;
+
+ maxdist = 1.0 / 0.0;
+ found = 0;
+
+ n = s[top].n;
+ if (n->uid != sn.uid) {
+ maxdist = 0;
+ for (i = 0; i < t->ndims; i++) {
+ diff = sn.c[i] - n->c[i];
+ maxdist += diff * diff;
+ }
+ d[0] = maxdist;
+ uid[0] = n->uid;
+ found = 1;
+ }
+
+ /* go down */
+ while (s[top].n) {
+ n = s[top].n;
+ dir = cmp(&sn, n, n->dim) > 0;
+ s[top].dir = dir;
+ s[top].v = 0;
+ top++;
+ s[top].n = n->child[dir];
+ }
+
+ /* go back up */
+ while (top) {
+ top--;
+ n = s[top].n;
+
+ if (!s[top].v) {
+ s[top].v = 1;
+
+ 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) {
+ i = found;
+ 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[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--;
+ }
+ 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;
+ }
+
+ /* look on the other side ? */
+ dir = s[top].dir;
+ diff = sn.c[(int)n->dim] - n->c[(int)n->dim];
+ dist = diff * diff;
+
+ if (dist <= maxdist) {
+ /* go down the other side */
+ top++;
+ s[top].n = n->child[!dir];
+ while (s[top].n) {
+ n = s[top].n;
+ dir = cmp(&sn, n, n->dim) > 0;
+ s[top].dir = dir;
+ s[top].v = 0;
+ top++;
+ s[top].n = n->child[dir];
+ }
+ }
+ }
+ }
+
+ for (i = 0; i < found; i++)
+ d[i] = sqrt(d[i]);
+
+ return found;
+}
+
+/* find all nearest neighbors within distance
+ * results are stored in puid and pd (distances)
+ * memory is allocated as needed, the calling fn must free the memory
+ * optionally an uid to be skipped can be given */
+int kdtree_dnn(struct kdtree *t, double *c, int **puid, double **pd, double maxdist, int *skip)
+{
+ int i, k, found;
+ double diff, dist;
+ struct kdnode sn, *n, *r;
+ struct kdstack {
+ struct kdnode *n;
+ int dir;
+ char v;
+ } s[256];
+ int dir;
+ int top;
+ int *uid;
+ double *d;
+
+ r = t->root;
+ sn.c = c;
+ sn.uid = (int)0x80000000;
+ if (skip)
+ sn.uid = *skip;
+
+ *pd = NULL;
+ *puid = NULL;
+
+ top = 0;
+ s[top].n = r;
+ if (!s[top].n)
+ return 0;
+
+ k = 0;
+ uid = NULL;
+ d = NULL;
+
+ found = 0;
+ maxdist = maxdist * maxdist;
+
+ /* go down */
+ while (s[top].n) {
+ n = s[top].n;
+ dir = cmp(&sn, n, n->dim) > 0;
+ s[top].dir = dir;
+ s[top].v = 0;
+ top++;
+ s[top].n = n->child[dir];
+ }
+
+ /* go back up */
+ while (top) {
+ top--;
+ n = s[top].n;
+
+ if (!s[top].v && 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 (dist <= maxdist) {
+ if (found + 1 >= k) {
+ k += 10;
+ uid = G_realloc(uid, k * sizeof(int));
+ d = G_realloc(d, k * sizeof(double));
+ }
+ i = found;
+ 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;
+ found++;
+ }
+ }
+
+ /* look on the other side ? */
+ if (!s[top].v) {
+ s[top].v = 1;
+ dir = s[top].dir;
+
+ diff = sn.c[(int)n->dim] - n->c[(int)n->dim];
+ dist = diff * diff;
+ if (dist <= maxdist) {
+ /* go down the other side */
+ top++;
+ s[top].n = n->child[!dir];
+ while (s[top].n) {
+ n = s[top].n;
+ dir = cmp(&sn, n, n->dim) > 0;
+ s[top].dir = dir;
+ s[top].v = 0;
+ top++;
+ s[top].n = n->child[dir];
+ }
+ }
+ }
+ }
+
+ for (i = 0; i < found; i++)
+ d[i] = sqrt(d[i]);
+
+ *pd = d;
+ *puid = uid;
+
+ return found;
+}
+
+
+/**********************************************/
+/* internal functions */
+/**********************************************/
+
+static int kdtree_replace(struct kdtree *t, struct kdnode *r)
+{
+ double mindist;
+ int rdir, ordir, dir;
+ int ld, rd;
+ struct kdnode *n, *rn, *or;
+ struct kdstack {
+ struct kdnode *n;
+ int dir;
+ char v;
+ } s[256];
+ int top, top2;
+ int is_leaf;
+ int nr;
+
+ /* find replacement for r
+ * overwrite r, delete replacement */
+ nr = 0;
+
+ /* pick a subtree */
+ rdir = 1;
+
+ or = r;
+ ld = (!or->child[0] ? -1 : or->child[0]->depth);
+ rd = (!or->child[1] ? -1 : or->child[1]->depth);
+
+ if (ld > rd) {
+ rdir = 0;
+ }
+
+ if (!or->child[rdir]) {
+ /* no replacement, delete */
+ kdtree_free_node(r);
+
+ return nr;
+ }
+
+ /* replace old root, make replacement the new root
+ * repeat until replacement is leaf */
+ ordir = rdir;
+ is_leaf = 0;
+ top2 = 0;
+ mindist = -1;
+ while (!is_leaf) {
+ rn = NULL;
+
+ /* find replacement for old root */
+ top = top2;
+ s[top].n = or->child[ordir];
+ if (!s[top].n)
+ break;
+
+ n = s[top].n;
+ rn = n;
+ mindist = fabs(or->c[(int)or->dim] - n->c[(int)or->dim]);
+
+ /* go down */
+ while (s[top].n) {
+ n = s[top].n;
+ dir = !ordir;
+ if (n->dim != or->dim)
+ dir = cmp(or, n, n->dim) > 0;
+ s[top].dir = dir;
+ s[top].v = 0;
+ top++;
+ s[top].n = n->child[dir];
+ }
+
+ /* go back up */
+ while (top > top2) {
+ top--;
+
+ if (!s[top].v) {
+ s[top].v = 1;
+ n = s[top].n;
+ if ((cmp(rn, n, or->dim) > 0) == ordir) {
+ rn = n;
+ mindist = fabs(or->c[(int)or->dim] - n->c[(int)or->dim]);
+ }
+
+ /* look on the other side ? */
+ dir = s[top].dir;
+ if (n->dim != or->dim &&
+ mindist >= fabs(n->c[(int)n->dim] - n->c[(int)n->dim])) {
+ /* go down the other side */
+ top++;
+ s[top].n = n->child[!dir];
+ while (s[top].n) {
+ n = s[top].n;
+ dir = !ordir;
+ if (n->dim != or->dim)
+ dir = cmp(or, n, n->dim) > 0;
+ s[top].dir = dir;
+ s[top].v = 0;
+ top++;
+ s[top].n = n->child[dir];
+ }
+ }
+ }
+ }
+
+#ifdef KD_DEBUG
+ if (!rn)
+ G_fatal_error("No replacement");
+ if (ordir && or->c[(int)or->dim] > rn->c[(int)or->dim])
+ G_fatal_error("rn is smaller");
+
+ if (!ordir && or->c[(int)or->dim] < rn->c[(int)or->dim])
+ G_fatal_error("rn is larger");
+
+ if (or->child[1]) {
+ dir = cmp(or->child[1], rn, or->dim);
+ if (dir < 0) {
+ int i;
+ for (i = 0; i < t->ndims; i++)
+ G_debug(0, "rn c %g, or child c %g",
+ rn->c[i], or->child[1]->c[i]);
+ G_fatal_error("Right or child is smaller than rn, dir is %d", ordir);
+ }
+ }
+ if (or->child[0]) {
+ dir = cmp(or->child[0], rn, or->dim);
+ if (dir > 0) {
+ int i;
+ for (i = 0; i < t->ndims; i++)
+ G_debug(0, "rn c %g, or child c %g",
+ rn->c[i], or->child[0]->c[i]);
+ G_fatal_error("Left or child is larger than rn, dir is %d", ordir);
+ }
+ }
+#endif
+
+ is_leaf = (rn->child[0] == NULL && rn->child[1] == NULL);
+
+#ifdef KD_DEBUG
+ if (is_leaf && rn->depth != 0)
+ G_fatal_error("rn is leaf but depth is %d", (int)rn->depth);
+ if (!is_leaf && rn->depth <= 0)
+ G_fatal_error("rn is not leaf but depth is %d", (int)rn->depth);
+#endif
+
+ nr++;
+
+ /* go to replacement from or->child[ordir] */
+ top = top2;
+ dir = 1;
+ while (dir) {
+ n = s[top].n;
+ dir = cmp(rn, n, n->dim);
+ if (dir) {
+ s[top].dir = dir > 0;
+ top++;
+ s[top].n = n->child[dir > 0];
+
+ if (!s[top].n) {
+ G_fatal_error("(Last) replacement disappeared %d", nr);
+ }
+ }
+ }
+ if (s[top].n != rn)
+ G_fatal_error("rn is unreachable from or");
+
+ top2 = top;
+ s[top2 + 1].n = NULL;
+
+ /* copy replacement to old root */
+ memcpy(or->c, rn->c, t->csize);
+ or->uid = rn->uid;
+
+ if (!is_leaf) {
+ /* make replacement the old root */
+ or = rn;
+
+ /* pick a subtree */
+ ordir = 1;
+ ld = (!or->child[0] ? -1 : or->child[0]->depth);
+ rd = (!or->child[1] ? -1 : or->child[1]->depth);
+ if (ld > rd) {
+ ordir = 0;
+ }
+ s[top2].dir = ordir;
+ top2++;
+ }
+ }
+
+ if (!rn)
+ G_fatal_error("No replacement at all");
+
+ /* delete replacement */
+ top = top2;
+ if (top) {
+ int old_depth;
+
+ n = s[top - 1].n;
+ dir = 0;
+ if (n->child[dir] != rn) {
+ dir = !dir;
+ }
+ if (n->child[dir] != rn) {
+ G_fatal_error("Last replacement disappeared");
+ }
+ n->child[dir] = NULL;
+
+#ifndef KD_DEBUG
+ old_depth = n->depth;
+ n->depth = (!n->child[!dir] ? 0 : n->child[!dir]->depth + 1);
+ top--;
+ if (n->depth == old_depth)
+ top = 0;
+#endif
+
+ /* go back up */
+ while (top) {
+ top--;
+ n = s[top].n;
+
+#ifdef KD_DEBUG
+ /* debug directions */
+ if (n->child[0]) {
+ if (cmp(n->child[0], n, n->dim) > 0)
+ G_warning("Left child is larger");
+ }
+ if (n->child[1]) {
+ if (cmp(n->child[1], n, n->dim) < 1)
+ G_warning("Right child is not larger");
+ }
+#endif
+
+ /* update depth */
+ ld = (!n->child[0] ? -1 : n->child[0]->depth);
+ rd = (!n->child[1] ? -1 : n->child[1]->depth);
+ n->depth = MAX(ld, rd) + 1;
+ }
+ }
+ else {
+ r->child[rdir] = NULL;
+ }
+ kdtree_free_node(rn);
+ t->count--;
+
+ /* update depth */
+ ld = (!r->child[0] ? -1 : r->child[0]->depth);
+ rd = (!r->child[1] ? -1 : r->child[1]->depth);
+ r->depth = MAX(ld, rd) + 1;
+
+ return nr;
+}
+
+static struct kdnode *kdtree_balance(struct kdtree *t, struct kdnode *r)
+{
+ struct kdnode *or;
+ int dir;
+ int rd, ld;
+
+ if (!r)
+ return NULL;
+
+ /* subtree difference */
+ dir = -1;
+ ld = (!r->child[0] ? -1 : r->child[0]->depth);
+ rd = (!r->child[1] ? -1 : r->child[1]->depth);
+ if (ld > rd + t->btol) {
+ dir = 0;
+ }
+ else if (rd > ld + t->btol) {
+ dir = 1;
+ }
+ else
+ return r;
+
+ or = kdtree_newnode(t);
+ memcpy(or->c, r->c, t->csize);
+ or->uid = r->uid;
+ or->dim = t->nextdim[r->dim];
+
+ if (!kdtree_replace(t, r))
+ G_fatal_error("kdtree_balance: nothing replaced");
+
+#ifdef KD_DEBUG
+ if (!cmp(r, or, r->dim)) {
+ G_warning("kdtree_balance: replacement failed");
+ kdtree_free_node(or);
+
+ return r;
+ }
+#endif
+
+ r->child[!dir] = kdtree_insert2(t, r->child[!dir], or, 0, 1);
+
+ /* update node depth */
+ ld = r->child[0]->depth;
+ rd = r->child[1]->depth;
+ r->depth = MAX(ld, rd) + 1;
+
+ return r;
+}
+
+static struct kdnode *kdtree_insert2(struct kdtree *t, struct kdnode *r,
+ struct kdnode *nnew, int balance, int dc)
+{
+ struct kdnode *n;
+ struct kdstack {
+ struct kdnode *n;
+ int dir;
+ } s[256];
+ int top;
+ int dir;
+ int ld, rd;
+ int old_depth;
+ int go_back;
+
+ if (!r) {
+ r = nnew;
+ t->count++;
+
+ return r;
+ }
+
+ if (balance) {
+ /* balance root */
+ r = kdtree_balance(t, r);
+ }
+
+ /* find node with free child */
+ top = 0;
+ go_back = 0;
+ s[top].n = r;
+ while (s[top].n) {
+ n = s[top].n;
+ if (!cmpc(nnew, n, t) && (!dc || nnew->uid == n->uid)) {
+
+ G_debug(1, "KD node exists already, nothing to do");
+ kdtree_free_node(nnew);
+
+ return r;
+ }
+ dir = cmp(nnew, n, n->dim) > 0;
+ s[top].dir = dir;
+
+ if (balance) {
+ /* balance left subtree */
+ n->child[0] = kdtree_balance(t, n->child[0]);
+ /* balance right subtree */
+ n->child[1] = kdtree_balance(t, n->child[1]);
+ }
+ old_depth = n->depth;
+ /* update node depth */
+ ld = (!n->child[0] ? -1 : n->child[0]->depth);
+ rd = (!n->child[1] ? -1 : n->child[1]->depth);
+ n->depth = MAX(ld, rd) + 1;
+ if (old_depth != n->depth)
+ go_back = top;
+
+ top++;
+ if (top > 255)
+ G_fatal_error("depth too large: %d", top);
+ s[top].n = n->child[dir];
+ }
+
+ /* insert, update child pointer of parent */
+ s[top].n = nnew;
+ top--;
+ dir = s[top].dir;
+ s[top].n->child[dir] = nnew;
+ nnew->dim = t->nextdim[s[top].n->dim];
+
+ old_depth = s[top].n->depth;
+ s[top].n->depth = (!s[top].n->child[!dir] ? 1 : s[top].n->child[!dir]->depth + 1);
+
+ if (old_depth != s[top].n->depth)
+ go_back = top;
+
+ t->count++;
+
+ /* go back up */
+#ifndef KD_DEBUG
+ top = go_back;
+#endif
+
+ while (top) {
+ top--;
+ n = s[top].n;
+
+#ifdef KD_DEBUG
+ /* debug directions */
+ if (n->child[0]) {
+ if (cmp(n->child[0], n, n->dim) > 0)
+ G_warning("Insert before balance: Left child is larger");
+ }
+ if (n->child[1]) {
+ if (cmp(n->child[1], n, n->dim) < 1)
+ G_warning("Insert before balance: Right child is not larger");
+ }
+#endif
+
+ /* update node depth */
+ ld = (!n->child[0] ? -1 : n->child[0]->depth);
+ rd = (!n->child[1] ? -1 : n->child[1]->depth);
+ n->depth = MAX(ld, rd) + 1;
+ }
+
+ return r;
+}
Property changes on: grass/trunk/lib/btree2/kdtree.c
___________________________________________________________________
Added: svn:mime-type
+ text/x-csrc
Added: svn:eol-style
+ native
Added: grass/trunk/lib/btree2/kdtree.h
===================================================================
--- grass/trunk/lib/btree2/kdtree.h (rev 0)
+++ grass/trunk/lib/btree2/kdtree.h 2014-12-14 22:19:53 UTC (rev 63543)
@@ -0,0 +1,27 @@
+
+struct kdnode
+{
+ unsigned char dim; /* split dimension of this node */
+ unsigned char depth; /* depth at this node */
+ double *c; /* coordinates */
+ int uid; /* unique id of this node */
+ struct kdnode *child[2]; /* link to children: link[0] for smaller, link[1] for larger */
+};
+
+struct kdtree
+{
+ unsigned char ndims; /* number of dimensions */
+ unsigned char *nextdim; /* split dimension of child nodes */
+ int csize; /* size of coordinates in bytes */
+ int btol; /* balancing tolerance */
+ size_t count; /* number of items in the tree */
+ struct kdnode *root; /* tree root */
+};
+
+struct kdtree *kdtree_create(char, int *);
+void kdtree_destroy(struct kdtree *);
+void kdtree_clear(struct kdtree *);
+int kdtree_insert(struct kdtree *, double *, int, int);
+int kdtree_remove(struct kdtree *, double *, int);
+int kdtree_knn(struct kdtree *, double *, int *, double *, int, int *);
+int kdtree_dnn(struct kdtree *, double *, int **, double **, double, int *);
Property changes on: grass/trunk/lib/btree2/kdtree.h
___________________________________________________________________
Added: svn:mime-type
+ text/x-chdr
Added: svn:eol-style
+ native
More information about the grass-commit
mailing list