/* * Find the smallest rectangle that includes all rectangles in * branches of a node. */ struct RTree_Rect RTreeNodeCover(struct RTree_Node *n, struct RTree *t) { int i, first_time = 1; struct RTree_Rect r; RTreeInitRect(&r); if ((n)->level > 0) { /* internal node */ for (i = 0; i < t->nodecard; i++) { if (t->valid_child(&(n->branch[i].child))) { if (first_time) { r = n->branch[i].rect; first_time = 0; } else r = RTreeCombineRect(&r, &(n->branch[i].rect), t); } } } else { /* leaf */ for (i = 0; i < t->leafcard; i++) { if (n->branch[i].child.id) { if (first_time) { r = n->branch[i].rect; first_time = 0; } else r = RTreeCombineRect(&r, &(n->branch[i].rect), t); } } } return r; }
/*----------------------------------------------------------------------------- | Pick two rects from set to be the first elements of the two groups. | Pick the two that waste the most area if covered by a single rectangle. -----------------------------------------------------------------------------*/ static void RTreePickSeeds(struct PartitionVars *p) { int i, j, seed0=0, seed1=0; RectReal worst, waste, area[MAXCARD+1]; for (i=0; i<p->total; i++) area[i] = RTreeRectSphericalVolume(&BranchBuf[i].rect); worst = -CoverSplitArea - 1; for (i=0; i<p->total-1; i++) { for (j=i+1; j<p->total; j++) { struct Rect one_rect; one_rect = RTreeCombineRect( &BranchBuf[i].rect, &BranchBuf[j].rect); waste = RTreeRectSphericalVolume(&one_rect) - area[i] - area[j]; if (waste > worst) { worst = waste; seed0 = i; seed1 = j; } } } RTreeClassify(seed0, 0, p); RTreeClassify(seed1, 1, p); }
/* * 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 RTreePickBranch(struct RTree_Rect *r, struct RTree_Node *n, struct RTree *t) { struct RTree_Rect *rr; int i, first_time = 1; RectReal increase, bestIncr = (RectReal) -1, area, bestArea = 0; int best = 0; struct RTree_Rect tmp_rect; assert((n)->level > 0); /* must not be called on leaf node */ if ((n)->level == 1) return RTreePickLeafBranch(r, n, t); for (i = 0; i < t->nodecard; i++) { if (t->valid_child(&(n->branch[i].child))) { rr = &n->branch[i].rect; area = RTreeRectSphericalVolume(rr, t); tmp_rect = RTreeCombineRect(r, rr, t); increase = RTreeRectSphericalVolume(&tmp_rect, t) - 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; } } } return best; }
/*----------------------------------------------------------------------------- | 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); }
/* * Inserts a new data rectangle into the index structure. * Recursively descends tree, propagates splits back up. * Returns 0 if node was not split. Old node updated. * If node was split, returns 1 and sets the pointer pointed to by * new_node to point to the new node. Old node updated to become one of two. * The level argument specifies the number of steps up from the leaf * level to insert; e.g. a data rectangle goes in at level = 0. */ static int RTreeInsertRect2(struct Rect *r, long tid, struct Node *n, struct Node **new_node, int level) { /* register struct Rect *r = R; register long tid = Tid; register struct Node *n = N, **new_node = New_node; register int level = Level; */ register int i; struct Branch b; struct Node *n2; assert(r && n && new_node); assert(level >= 0 && level <= n->level); /* Still above level for insertion, go down tree recursively */ if (n->level > level) { i = RTreePickBranch(r, n); if (!RTreeInsertRect2(r, tid, n->branch[i].child, &n2, level)) { /* child was not split */ n->branch[i].rect = RTreeCombineRect(r,&(n->branch[i].rect)); return 0; } else /* child was split */ { n->branch[i].rect = RTreeNodeCover(n->branch[i].child); b.child = n2; b.rect = RTreeNodeCover(n2); return RTreeAddBranch(&b, n, new_node); } } /* Have reached level for insertion. Add rect, split if necessary */ else if (n->level == level) { b.rect = *r; b.child = (struct Node *) (tid); /* child field of leaves contains tid of data record */ return RTreeAddBranch(&b, n, new_node); } else { /* Not supposed to happen */ assert (FALSE); return 0; } }
static int RTreePickLeafBranch(struct RTree_Rect *r, struct RTree_Node *n, struct RTree *t) { struct RTree_Rect *rr; int i, j; RectReal increase, bestIncr = -1, area, bestArea = 0; int best = 0, bestoverlap; struct RTree_Rect tmp_rect; int overlap; bestoverlap = t->nodecard + 1; /* get the branch that will overlap with the smallest number of * sibling branches when including the new rectangle */ for (i = 0; i < t->nodecard; i++) { if (t->valid_child(&(n->branch[i].child))) { rr = &n->branch[i].rect; tmp_rect = RTreeCombineRect(r, rr, t); area = RTreeRectSphericalVolume(rr, t); increase = RTreeRectSphericalVolume(&tmp_rect, t) - area; overlap = 0; for (j = 0; j < t->leafcard; j++) { if (j != i) { rr = &n->branch[j].rect; overlap += RTreeOverlap(&tmp_rect, rr, t); } } if (overlap < bestoverlap) { best = i; bestoverlap = overlap; bestArea = area; bestIncr = increase; } else if (overlap == bestoverlap) { /* resolve ties */ if (increase < bestIncr) { best = i; bestArea = area; bestIncr = increase; } else if (increase == bestIncr && area < bestArea) { best = i; bestArea = area; } } } } return best; }
/*----------------------------------------------------------------------------- | Put a branch in one of the groups. -----------------------------------------------------------------------------*/ static void RTreeClassify(int i, int group, struct PartitionVars *p) { assert(p); assert(!p->taken[i]); p->partition[i] = group; p->taken[i] = TRUE; if (p->count[group] == 0) p->cover[group] = BranchBuf[i].rect; else p->cover[group] = RTreeCombineRect(&BranchBuf[i].rect, &p->cover[group]); p->area[group] = RTreeRectSphericalVolume(&p->cover[group]); p->count[group]++; }
/* * 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; }
/*----------------------------------------------------------------------------- | Method #0 for choosing a partition: | As the seeds for the two groups, pick the two rects that would waste the | most area if covered by a single rectangle, i.e. evidently the worst pair | to have in the same group. | Of the remaining, one at a time is chosen to be put in one of the two groups. | The one chosen is the one with the greatest difference in area expansion | depending on which group - the rect most strongly attracted to one group | and repelled from the other. | If one group gets too full (more would force other group to violate min | fill requirement) then other group gets the rest. | These last are the ones that can go in either group most easily. -----------------------------------------------------------------------------*/ static void RTreeMethodZero(struct PartitionVars *p, int minfill) { register int i; RectReal biggestDiff; int group, chosen=0, betterGroup=0; assert(p); RTreeInitPVars(p, BranchCount, minfill); RTreePickSeeds(p); while (p->count[0] + p->count[1] < p->total && p->count[0] < p->total - p->minfill && p->count[1] < p->total - p->minfill) { biggestDiff = (RectReal)-1.; for (i=0; i<p->total; i++) { if (!p->taken[i]) { struct Rect *r, rect_0, rect_1; RectReal growth0, growth1, diff; r = &BranchBuf[i].rect; rect_0 = RTreeCombineRect(r, &p->cover[0]); rect_1 = RTreeCombineRect(r, &p->cover[1]); growth0 = RTreeRectSphericalVolume( &rect_0)-p->area[0]; growth1 = RTreeRectSphericalVolume( &rect_1)-p->area[1]; diff = growth1 - growth0; if (diff >= 0) group = 0; else { group = 1; diff = -diff; } if (diff > biggestDiff) { biggestDiff = diff; chosen = i; betterGroup = group; } else if (diff==biggestDiff && p->count[group]<p->count[betterGroup]) { chosen = i; betterGroup = group; } } } RTreeClassify(chosen, betterGroup, p); } /* if one group too full, put remaining rects in the other */ if (p->count[0] + p->count[1] < p->total) { if (p->count[0] >= p->total - p->minfill) group = 1; else group = 0; for (i=0; i<p->total; i++) { if (!p->taken[i]) RTreeClassify(i, group, p); } } assert(p->count[0] + p->count[1] == p->total); assert(p->count[0] >= p->minfill && p->count[1] >= p->minfill); }