// Add a branch to a node. Split the node if necessary. // Returns 0 if node not split. Old node updated. // Returns 1 if node split, sets *new_node to address of new node. // Old node updated, becomes one of two. // int Xastir_RTreeAddBranch(struct Branch *B, struct Node *N, struct Node **New_node) { register struct Branch *b = B; register struct Node *n = N; register struct Node **new_node = New_node; register int i; assert(b); assert(n); if (n->count < MAXKIDS(n)) /* split won't be necessary */ { for (i = 0; i < MAXKIDS(n); i++) /* find empty branch */ { if (n->branch[i].child == NULL) { n->branch[i] = *b; n->count++; break; } } return 0; } else { assert(new_node); Xastir_RTreeSplitNode(n, b, new_node); return 1; } }
/*----------------------------------------------------------------------------- | Load branch buffer with branches from full node plus the extra branch. -----------------------------------------------------------------------------*/ static void RTreeGetBranches(struct Node *n, struct Branch *b) { register int i; assert(n); assert(b); /* load the branch buffer */ for (i=0; i<MAXKIDS(n); i++) { assert(n->branch[i].child); /* n should have every entry full */ BranchBuf[i] = n->branch[i]; } BranchBuf[MAXKIDS(n)] = *b; BranchCount = MAXKIDS(n) + 1; /* calculate rect containing all in the set */ CoverSplit = BranchBuf[0].rect; for (i=1; i<MAXKIDS(n)+1; i++) { CoverSplit = RTreeCombineRect(&CoverSplit, &BranchBuf[i].rect); } CoverSplitArea = RTreeRectSphericalVolume(&CoverSplit); RTreeInitNode(n); }
/* * Delete a data rectangle from an index structure. * Pass in a pointer to a Rect, the tid of the record, ptr to ptr to root node. * Returns 1 if record not found, 0 if success. * RTreeDeleteRect provides for eliminating the root. */ int RTreeDeleteRect(struct Rect *R, long Tid, struct Node**Nn) { register struct Rect *r = R; register long tid = Tid; register struct Node **nn = Nn; register int i; struct Node *tmp_nptr = NULL; struct ListNode *reInsertList = NULL; register struct ListNode *e; assert(r && nn); assert(*nn); assert(tid >= 0); if (!RTreeDeleteRect2(r, tid, *nn, &reInsertList)) { /* found and deleted a data item */ /* reinsert any branches from eliminated nodes */ while (reInsertList) { tmp_nptr = reInsertList->node; for (i = 0; i < MAXKIDS(tmp_nptr); i++) { if (tmp_nptr->branch[i].child) { RTreeInsertRect( &(tmp_nptr->branch[i].rect), (long)(tmp_nptr->branch[i].child), nn, tmp_nptr->level); } } e = reInsertList; reInsertList = reInsertList->next; RTreeFreeNode(e->node); RTreeFreeListNode(e); } /* check for redundant root (not leaf, 1 child) and eliminate */ if ((*nn)->count == 1 && (*nn)->level > 0) { for (i = 0; i < NODECARD; i++) { tmp_nptr = (*nn)->branch[i].child; if(tmp_nptr) break; } assert(tmp_nptr); RTreeFreeNode(*nn); *nn = tmp_nptr; } return 0; } else { return 1; } }
// Disconnect a dependent node. // void Xastir_RTreeDisconnectBranch(struct Node *n, int i) { assert(n && i>=0 && i<MAXKIDS(n)); assert(n->branch[i].child); Xastir_RTreeInitBranch(&(n->branch[i])); n->count--; }
/* * Add a branch to a node. Split the node if necessary. * Returns 0 if node not split. Old node updated. * Returns 1 if node split, sets *new_node to address of new node. * Old node updated, becomes one of two. * Returns 2 if branches were removed for forced reinsertion */ int RTreeAddBranch(struct RTree_Branch *b, struct RTree_Node *n, struct RTree_Node **newnode, struct RTree_ListBranch **ee, struct RTree_Rect *cover, int *overflow, struct RTree *t) { int i, maxkids; maxkids = MAXKIDS((n)->level, t); if (n->count < maxkids) { /* split won't be necessary */ if ((n)->level > 0) { /* internal node */ for (i = 0; i < maxkids; i++) { /* find empty branch */ if (!t->valid_child(&(n->branch[i].child))) { n->branch[i] = *b; n->count++; break; } } return 0; } else if ((n)->level == 0) { /* leaf */ for (i = 0; i < maxkids; i++) { /* find empty branch */ if (n->branch[i].child.id == 0) { n->branch[i] = *b; n->count++; break; } } return 0; } } else { if (n->level < t->rootlevel && overflow[n->level]) { /* R*-tree forced reinsert */ RTreeRemoveBranches(n, b, ee, cover, t); overflow[n->level] = 0; return 2; } else { if (t->fd > -1) RTreeInitNode(*newnode, NODETYPE(n->level, t->fd)); else *newnode = RTreeNewNode(t, (n)->level); RTreeSplitNode(n, b, *newnode, t); return 1; } } /* should not be reached */ assert(0); return -1; }
// Find the smallest rectangle that includes all rectangles in // branches of a node. // struct Rect Xastir_RTreeNodeCover(struct Node *N) { register struct Node *n = N; register int i, first_time=1; struct Rect r; assert(n); Xastir_RTreeInitRect(&r); for (i = 0; i < MAXKIDS(n); i++) if (n->branch[i].child) { if (first_time) { r = n->branch[i].rect; first_time = 0; } else r = Xastir_RTreeCombineRect(&r, &(n->branch[i].rect)); } return r; }
// Pick a branch. Pick the one that will need the smallest increase // in area to accomodate the new rectangle. This will result in the // least total area for the covering rectangles in the current node. // In case of a tie, pick the one which was smaller before, to get // the best resolution when searching. // int Xastir_RTreePickBranch(struct Rect *R, struct Node *N) { register struct Rect *r = R; register struct Node *n = N; register struct Rect *rr; register int i, first_time=1; // Although it is impossible for bestArea and best to be used // unininitialized the way the code is structured, gcc complains // about possible uninitialized usage. Let's keep it happy. // Original superliminal.com had no initializers here. RectReal increase, bestIncr=(RectReal)-1, area, bestArea=0.0; int best=0; struct Rect tmp_rect; assert(r && n); for (i=0; i<MAXKIDS(n); i++) { if (n->branch[i].child) { rr = &n->branch[i].rect; area = Xastir_RTreeRectSphericalVolume(rr); tmp_rect = Xastir_RTreeCombineRect(r, rr); increase = Xastir_RTreeRectSphericalVolume(&tmp_rect) - area; if (increase < bestIncr || first_time) { best = i; bestArea = area; bestIncr = increase; first_time = 0; } else if (increase == bestIncr && area < bestArea) { best = i; bestArea = area; bestIncr = increase; } } } return best; }
/* * Remove branches from a node. Select the 2 branches whose rectangle * center is farthest away from node cover center. * Old node updated. */ static void RTreeRemoveBranches(struct RTree_Node *n, struct RTree_Branch *b, struct RTree_ListBranch **ee, struct RTree_Rect *cover, struct RTree *t) { int i, j, maxkids, type; RectReal center_n[NUMDIMS], center_r, delta; struct RTree_Branch branchbuf[MAXCARD + 1]; struct dist rdist[MAXCARD + 1]; struct RTree_Rect new_cover; assert(cover); maxkids = MAXKIDS((n)->level, t); type = NODETYPE((n)->level, t->fd); assert(n->count == maxkids); /* must be full */ new_cover = RTreeCombineRect(cover, &(b->rect), t); /* center coords of node cover */ for (j = 0; j < t->ndims; j++) { center_n[j] = (new_cover.boundary[j + NUMDIMS] + new_cover.boundary[j]) / 2; } /* compute distances of child rectangle centers to node cover center */ for (i = 0; i < maxkids; i++) { branchbuf[i] = n->branch[i]; rdist[i].distance = 0; rdist[i].id = i; for (j = 0; j < t->ndims; j++) { center_r = (branchbuf[i].rect.boundary[j + NUMDIMS] + branchbuf[i].rect.boundary[j]) / 2; delta = center_n[j] - center_r; rdist[i].distance += delta * delta; } RTreeInitBranch[type](&(n->branch[i])); } /* new branch */ branchbuf[maxkids] = *b; rdist[maxkids].distance = 0; for (j = 0; j < t->ndims; j++) { center_r = (b->rect.boundary[j + NUMDIMS] + b->rect.boundary[j]) / 2; delta = center_n[j] - center_r; rdist[maxkids].distance += delta * delta; } rdist[maxkids].id = maxkids; /* quicksort dist */ RTreeQuicksortDist(rdist, maxkids); /* put largest three in branch list, farthest from center first */ for (i = 0; i < FORCECARD; i++) { RTreeReInsertBranch(branchbuf[rdist[maxkids - i].id], n->level, ee); } /* put remaining in node, closest to center first */ for (i = 0; i < maxkids - FORCECARD + 1; i++) { n->branch[i] = branchbuf[rdist[i].id]; } n->count = maxkids - FORCECARD + 1; }
// Delete a data rectangle from an index structure. // Pass in a pointer to a Rect, the tid of the record, ptr to ptr to root node. // Returns 1 if record not found, 0 if success. // Xastir_RTreeDeleteRect provides for eliminating the root. // int Xastir_RTreeDeleteRect(struct Rect *R, void *Tid, struct Node**Nn) { register struct Rect *r = R; register void *tid = Tid; register struct Node **nn = Nn; register int i; register struct Node *tmp_nptr=NULL; // Original superliminal.com // source did not initialize. // Code analysis says shouldn't // matter, but let's initialize // to shut up GCC struct ListNode *reInsertList = NULL; register struct ListNode *e; assert(r && nn); assert(*nn); assert(tid >= (void *)0); if (!Xastir_RTreeDeleteRect2(r, tid, *nn, &reInsertList)) { /* found and deleted a data item */ /* reinsert any branches from eliminated nodes */ while (reInsertList) { tmp_nptr = reInsertList->node; for (i = 0; i < MAXKIDS(tmp_nptr); i++) { if (tmp_nptr->branch[i].child) { Xastir_RTreeInsertRect( &(tmp_nptr->branch[i].rect), tmp_nptr->branch[i].child, nn, tmp_nptr->level); } } e = reInsertList; reInsertList = reInsertList->next; Xastir_RTreeFreeNode(e->node); Xastir_RTreeFreeListNode(e); } /* check for redundant root (not leaf, 1 child) and eliminate */ if ((*nn)->count == 1 && (*nn)->level > 0) { for (i = 0; i < Xastir_NODECARD; i++) { tmp_nptr = (*nn)->branch[i].child; if(tmp_nptr) break; } assert(tmp_nptr); Xastir_RTreeFreeNode(*nn); *nn = tmp_nptr; } return 0; } else { return 1; } }