#include #include #include #include #include #include "rtree.h" static node_t RTreeNewNode (void); static void RTreeDestroyNode (node_t); static void RTreeNodeInit (node_t); static int RTreeSearchNode (node_t, rect_t, SearchHitCallback, void *); static int RTreeInsertNode (node_t, int, rect_t,void *,node_t *); static int RTreePickBranch (rect_t, node_t); static int RTreeAddBranch(node_t, branch_t, node_t *); static void RTreeSplitNode (node_t, branch_t, node_t *); static void RTreePickSeeds(partition_t *, node_t, node_t); static void RTreeNodeAddBranch(rect_t *, node_t, branch_t); static void RTreePickNext(partition_t *, node_t, node_t); static rect_t RTreeNodeCover(node_t); static double RectArea (rect_t); static rect_t RectCombine (rect_t, rect_t); static int RectOverlap (rect_t, rect_t); static void RectPrint (rect_t); static partition_t PartitionNew (void); static void PartitionPush (partition_t *, branch_t); static branch_t PartitionPop (partition_t *); static branch_t PartitionGet (partition_t *, int); rtree_t RTreeNew (void) { rtree_t t; t = RTreeNewNode(); t->level = 0; /*leaf*/ return t; } void RTreeDestroy (rtree_t t) { if (t) RTreeDestroyNode (t); } static node_t RTreeNewNode (void) { node_t n; n = (node_t) malloc (sizeof(*n)); assert(n); RTreeNodeInit(n); return n; } static void RTreeDestroyNode (node_t node) { int i; if (node->level == 0) /* leaf level*/ { for (i = 0; i < MAXCARD; i++) if (node->branch[i].child) ;/* allow user free data*/ else break; } else { for (i = 0; i < MAXCARD; i++) if (node->branch[i].child) RTreeDestroyNode (node->branch[i].child); else break; } free (node); } static void RTreeNodeInit (node_t n) { memset((void *) n,0, sizeof(*n)); n->level = -1; } int RTreeSearch (rtree_t t, rect_t s, SearchHitCallback f, void *arg) { assert(t); return RTreeSearchNode(t,s,f,arg); } static int RTreeSearchNode (node_t n, rect_t s, SearchHitCallback f, void *arg) { int i; int c = 0; if (n->level > 0) { for (i = 0; i < MAXCARD; i++) if (n->branch[i].child && RectOverlap (s,n->branch[i].mbr)) c += RTreeSearchNode ((node_t) n->branch[i].child, s, f, arg); } else { for (i = 0; i < MAXCARD; i++) if (n->branch[i].child && RectOverlap (s,n->branch[i].mbr)) { c ++; if (f) if ( !f(n->branch[i].mbr,n->branch[i].child,arg)) return c; } } return c; } void RTreeInsert (rtree_t *t, rect_t r, void *data) { node_t n2; node_t new_root; branch_t b; assert(t && *t); if (RTreeInsertNode(*t, 0, r, data, &n2)) /* deal with root split */ { new_root = RTreeNewNode(); new_root->level = (*t)->level + 1; b.mbr = RTreeNodeCover(*t); b.child = (void *) *t; RTreeAddBranch(new_root, b, NULL); b.mbr = RTreeNodeCover(n2); b.child = (void *) n2; RTreeAddBranch(new_root, b, NULL); *t = new_root; } } static int RTreeInsertNode (node_t n, int level, rect_t r, void *data, node_t *new_node) { int i; node_t n2; branch_t b; assert(n && new_node); assert(level >= 0 && level <= n->level); if (n->level > level) { i = RTreePickBranch(r,n); if (!RTreeInsertNode((node_t) n->branch[i].child, level, r, data,&n2)) /* not split */ { n->branch[i].mbr = RectCombine(r,n->branch[i].mbr); return FALSE; } else /* node split */ { n->branch[i].mbr = RTreeNodeCover(n->branch[i].child); b.child = n2; b.mbr = RTreeNodeCover(n2); return RTreeAddBranch(n, b, new_node); } } else /*insert level*/ { b.mbr = r; b.child = data; return RTreeAddBranch(n, b, new_node); } } static int RTreeAddBranch(node_t n, branch_t b, node_t *new_node) { int i; assert(n); if (n->count < MAXCARD) /*split not necessary*/ { for (i = 0; i < MAXCARD; i++) if (n->branch[i].child == NULL) { n->branch[i] = b; n->count ++; break; } return FALSE; } else /*needs to split*/ { assert(new_node); RTreeSplitNode (n, b, new_node); return TRUE; } } static int RTreePickBranch (rect_t r, node_t n) { int i; double area; double inc_area; rect_t tmp; int best_i; double best_inc; double best_i_area; best_i = 0; best_inc = DBL_MAX; /* double Max value */ best_i_area = DBL_MAX; for (i = 0; i < MAXCARD; i++) if (n->branch[i].child) { area = RectArea (n->branch[i].mbr); tmp = RectCombine (r, n->branch[i].mbr); inc_area = RectArea (tmp) - area; if (inc_area < best_inc) { best_inc = inc_area; best_i = i; best_i_area = area; } else if (inc_area == best_inc && best_i_area > area) { best_inc = inc_area; best_i = i; best_i_area = area; } } else break; return best_i; } static void RTreeSplitNode (node_t n, branch_t b, node_t *new_node) { partition_t p; int level; int i; assert(n); assert(new_node); p = PartitionNew(); for (i = 0; i < MAXCARD; i ++) PartitionPush(&p,n->branch[i]); PartitionPush(&p,b); level = n->level; RTreeNodeInit(n); n->level = level; *new_node = RTreeNewNode(); (*new_node)->level = level; RTreePickSeeds(&p, n, *new_node); while (p.n) if (n->count + p.n <= MINCARD) /* first group (n) needs all entries */ RTreeNodeAddBranch(&(p.cover[0]), n, PartitionPop(&p)); else if ((*new_node)->count + p.n <= MINCARD) /* second group (new_node) needs all entries */ RTreeNodeAddBranch(&(p.cover[1]), *new_node, PartitionPop(&p)); else RTreePickNext(&p, n, *new_node); } static void RTreePickNext(partition_t *p, node_t n1, node_t n2) /* linear version */ { branch_t b; double area[2], inc_area[2]; rect_t tmp; b = PartitionPop(p); area[0] = RectArea (p->cover[0]); tmp = RectCombine (p->cover[0], b.mbr); inc_area[0] = RectArea (tmp) - area[0]; area[1] = RectArea (p->cover[1]); tmp = RectCombine (p->cover[1], b.mbr); inc_area[1] = RectArea (tmp) - area[1]; if (inc_area[0] < inc_area[1] || (inc_area[0] == inc_area[1] && area[0] < area[1])) RTreeNodeAddBranch(&(p->cover[0]),n1,b); else RTreeNodeAddBranch(&(p->cover[1]),n2,b); } static void RTreePickSeeds(partition_t *p, node_t n1, node_t n2) /* puts in index 0 of each node the resulting entry, forming the two groups This is the linear version */ { int dim,high, i; int highestLow[NUMDIMS], lowestHigh[NUMDIMS]; double width[NUMDIMS]; int seed0, seed1; double sep, best_sep; assert(p->n == MAXCARD + 1); for (dim = 0; dim < NUMDIMS; dim++) { high = dim + NUMDIMS; highestLow[dim] = lowestHigh[dim] = 0; for (i = 1; i < MAXCARD +1; i++) { if (p->buffer[i].mbr.coords[dim] > p->buffer[highestLow[dim]].mbr.coords[dim]) highestLow[dim] = i; if (p->buffer[i].mbr.coords[high] < p->buffer[lowestHigh[dim]].mbr.coords[high]) lowestHigh[dim] = i; } width[dim] = p->cover_all.coords[high] - p->cover_all.coords[dim]; assert(width[dim] >= 0); } seed0 = lowestHigh[0]; seed1 = highestLow[0]; best_sep = 0; for (dim = 0; dim < NUMDIMS; dim ++) { high = dim + NUMDIMS; sep = (p->buffer[highestLow[dim]].mbr.coords[dim] - p->buffer[lowestHigh[dim]].mbr.coords[high]) / width[dim]; if (sep > best_sep) { seed0 = lowestHigh[dim]; seed1 = highestLow[dim]; best_sep = sep; } } /* assert (seed0 != seed1); */ if (seed0 > seed1) { RTreeNodeAddBranch(&(p->cover[0]),n1,PartitionGet(p,seed0)); RTreeNodeAddBranch(&(p->cover[1]),n2,PartitionGet(p,seed1)); } else if (seed0 < seed1) { RTreeNodeAddBranch(&(p->cover[0]),n1,PartitionGet(p,seed1)); RTreeNodeAddBranch(&(p->cover[1]),n2,PartitionGet(p,seed0)); } } static void RTreeNodeAddBranch(rect_t *r, node_t n, branch_t b) { int i; assert(n); assert(n->count < MAXCARD); for (i = 0; i < MAXCARD; i++) if (n->branch[i].child == NULL) { n->branch[i] = b; n->count ++; break; } *r = RectCombine(*r,b.mbr); } void RTreePrint(node_t t) { int i; /* printf("rtree([_,_,_,_,_]).\n"); */ printf("rtree(%p,%d,[",t,t->level); for (i = 0; i < MAXCARD; i++) { if (t->branch[i].child != NULL) { printf("(%p,",t->branch[i].child); RectPrint(t->branch[i].mbr); printf(")"); } else { printf("nil"); } if (i < MAXCARD-1) printf(","); } printf("]).\n"); if (t->level != 0) for (i = 0; i < MAXCARD; i++) if (t->branch[i].child != NULL) RTreePrint((node_t) t->branch[i].child); else break; } /* * Partition related */ static partition_t PartitionNew (void) { partition_t p; memset((void *) &p,0, sizeof(p)); p.cover[0] = p.cover[1] = p.cover_all = RectInit(); return p; } static void PartitionPush (partition_t *p, branch_t b) { assert(p->n < MAXCARD + 1); p->buffer[p->n] = b; p->n ++; p->cover_all = RectCombine(p->cover_all,b.mbr); } static branch_t PartitionPop (partition_t *p) { assert(p->n > 0); p->n --; return p->buffer[p->n]; } static branch_t PartitionGet (partition_t *p, int n) { branch_t b; assert (p->n > n); b = p->buffer[n]; p->buffer[n] = PartitionPop(p); return b; } /* * Rect related */ rect_t RectInit (void) { rect_t r = {{DBL_MAX, DBL_MAX, DBL_MIN, DBL_MIN}}; return (r); } static double RectArea (rect_t r) { int i; double area; for (i = 0,area = 1; i < NUMDIMS; i++) area *= r.coords[i+NUMDIMS] - r.coords[i]; /* area = (r.coords[1] - r.coords[0]) * */ /* (r.coords[3] - r.coords[2]); */ return area; } static rect_t RectCombine (rect_t r, rect_t s) { int i; rect_t new_rect; for (i = 0; i < NUMDIMS; i++) { new_rect.coords[i] = MIN(r.coords[i],s.coords[i]); new_rect.coords[i+NUMDIMS] = MAX(r.coords[i+NUMDIMS],s.coords[i+NUMDIMS]); } return new_rect; } static int RectOverlap (rect_t r, rect_t s) { int i; for (i = 0; i < NUMDIMS; i++) if (r.coords[i] > s.coords[i + NUMDIMS] || s.coords[i] > r.coords[i + NUMDIMS]) return FALSE; return TRUE; } static rect_t RTreeNodeCover(node_t n) { int i; rect_t r = RectInit(); for (i = 0; i < MAXCARD; i++) if (n->branch[i].child) { r = RectCombine (r, n->branch[i].mbr); } else break; return r; } static void RectPrint (rect_t r) { int i; printf("["); for (i = 0; i < 2*NUMDIMS; i++) { printf("%f",r.coords[i]); if ( i < 2*NUMDIMS - 1) printf(","); } printf("]"); }