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; }
/* * Delete a rectangle from non-root part of an index structure. * Called by RTreeDeleteRect. Descends tree recursively, * merges branches on the way back up. * Returns 1 if record not found, 0 if success. */ static int RTreeDeleteRect2(struct Rect *R, long Tid, struct Node *N, struct ListNode **Ee) { register struct Rect *r = R; register long tid = Tid; register struct Node *n = N; register struct ListNode **ee = Ee; register int i; assert(r && n && ee); assert(tid >= 0); assert(n->level >= 0); if (n->level > 0) /* not a leaf node */ { for (i = 0; i < NODECARD; i++) { if (n->branch[i].child && RTreeOverlap(r, &(n->branch[i].rect))) { if (!RTreeDeleteRect2(r, tid, n->branch[i].child, ee)) { if (n->branch[i].child->count >= MinNodeFill) { n->branch[i].rect = RTreeNodeCover( n->branch[i].child); } else { /* not enough entries in child, eliminate child node */ RTreeReInsert(n->branch[i].child, ee); RTreeDisconnectBranch(n, i); } return 0; } } } return 1; } else /* a leaf node */ { for (i = 0; i < LEAFCARD; i++) { if (n->branch[i].child && (struct Node *)(n->branch[i].child) == (struct Node *) tid) { RTreeDisconnectBranch(n, i); return 0; } } return 1; } }
/* * Search in an index tree for all data retangles that * overlap the argument rectangle. * Return the number of qualifying data rects. */ int RTreeSearchF(struct RTree *t, struct RTree_Rect *r, SearchHitCallback *shcb, void *cbarg) { struct RTree_Node *n; int hitCount = 0, notfound, currlevel; int i; int top = 0; struct nstack *s = t->ns; /* stack size of t->rootlevel + 1 is enough because of depth first search */ /* only one node per level on stack at any given time */ /* add root node position to stack */ currlevel = t->rootlevel; s[top].pos = t->rootpos; s[top].sn = RTreeGetNode(s[top].pos, currlevel, t); s[top].branch_id = i = 0; while (top >= 0) { n = s[top].sn; if (s[top].sn->level > 0) { /* this is an internal node in the tree */ notfound = 1; currlevel = s[top].sn->level - 1; for (i = s[top].branch_id; i < t->nodecard; i++) { if (s[top].sn->branch[i].child.pos > -1 && RTreeOverlap(r, &(s[top].sn->branch[i].rect), t)) { s[top++].branch_id = i + 1; /* add next node to stack */ s[top].pos = n->branch[i].child.pos; s[top].sn = RTreeGetNode(s[top].pos, currlevel, t); s[top].branch_id = 0; notfound = 0; break; } } if (notfound) { /* nothing else found, go back up */ s[top].branch_id = t->nodecard; top--; } } else { /* this is a leaf node */ for (i = 0; i < t->leafcard; i++) { if (s[top].sn->branch[i].child.id && RTreeOverlap(r, &(s[top].sn->branch[i].rect), t)) { hitCount++; if (shcb) { /* call the user-provided callback */ if (!shcb(s[top].sn->branch[i].child.id, &(s[top].sn->branch[i].rect), cbarg)) { /* callback wants to terminate search early */ return hitCount; } } } } top--; } } return hitCount; }
/* * Delete a rectangle from non-root part of an index structure. * Called by RTreeDeleteRect. Descends tree non-recursively, * merges branches on the way back up. * Returns 1 if record not found, 0 if success. */ static int RTreeDeleteRect2F(struct RTree_Rect *r, union RTree_Child child, struct RTree *t, struct RTree_ListNode **ee) { int i, notfound = 1, currlevel; struct RTree_Node *n; int top = 0, down = 0; int minfill; struct nstack *s = t->ns; struct RTree_Rect *nr = &(t->orect); /* add root node position to stack */ currlevel = t->rootlevel; s[top].pos = t->rootpos; s[top].sn = RTreeGetNode(s[top].pos, currlevel, t); s[top].branch_id = 0; while (notfound && top >= 0) { /* go down to level 0, remember path */ if (s[top].sn->level > 0) { n = s[top].sn; currlevel = s[top].sn->level - 1; for (i = s[top].branch_id; i < t->nodecard; i++) { if (n->branch[i].child.pos > -1 && RTreeOverlap(r, &(n->branch[i].rect), t)) { s[top++].branch_id = i + 1; /* add next node to stack */ s[top].pos = n->branch[i].child.pos; s[top].sn = RTreeGetNode(s[top].pos, currlevel, t); s[top].branch_id = 0; notfound = 0; break; } } if (notfound) { /* nothing else found, go back up */ s[top].branch_id = t->nodecard; top--; } else /* found a way down but not yet the item */ notfound = 1; } else { for (i = 0; i < t->leafcard; i++) { if (s[top].sn->branch[i].child.id && s[top].sn->branch[i].child.id == child.id) { /* found item */ RTreeDisconnectBranch(s[top].sn, i, t); RTreeNodeChanged(s[top].sn, s[top].pos, t); t->n_leafs--; notfound = 0; break; } } if (notfound) /* continue searching */ top--; } } if (notfound) { return notfound; } /* go back up */ while (top) { down = top; top--; i = s[top].branch_id - 1; minfill = (s[down].sn->level ? t->min_node_fill : t->min_leaf_fill); if (s[down].sn->count >= minfill) { /* just update node cover */ RTreeNodeCover(s[down].sn, nr, t); /* rewrite rect */ if (!RTreeCompareRect(nr, &(s[top].sn->branch[i].rect), t)) { RTreeCopyRect(&(s[top].sn->branch[i].rect), nr, t); RTreeNodeChanged(s[top].sn, s[top].pos, t); } } else { /* not enough entries in child, eliminate child node */ n = RTreeAllocNode(t, s[down].sn->level); /* copy node */ RTreeCopyNode(n, s[down].sn, t); RTreeAddNodePos(s[down].pos, s[down].sn->level, t); RTreeReInsertNode(n, ee); RTreeDisconnectBranch(s[top].sn, i, t); RTreeNodeChanged(s[top].sn, s[top].pos, t); } } return notfound; }
/*! \brief Search spatial index file Can't use regular RTreeSearch() here because sidx must be read with dig__fread_port_*() functions \param t pointer to RTree \param r search rectangle \param shcb user-provided callback \param cbarg argument for shcb \param Plus pointer to Plus_head structure \return number of qualifying rectangles */ int rtree_search(struct RTree *t, struct RTree_Rect *r, SearchHitCallback shcb, void *cbarg, struct Plus_head *Plus) { int hitCount = 0, found; /* int j, maxcard; */ int i; struct spidxpstack s[MAXLEVEL]; int top = 0, level; off_t lastpos; assert(r); assert(t); /* stack size of t->rootlevel + 1 is enough because of depth first search */ /* only one node per level on stack at any given time */ dig_set_cur_port(&(Plus->spidx_port)); /* add root node position to stack */ s[top].sn = rtree_get_node(t->rootpos, t->rootlevel, t, Plus); #if 0 dig_fseek(&(Plus->spidx_fp), t->rootpos, SEEK_SET); /* read with dig__fread_port_* fns */ dig__fread_port_I(&(s[top].sn.count), 1, &(Plus->spidx_fp)); dig__fread_port_I(&(s[top].sn.level), 1, &(Plus->spidx_fp)); maxcard = t->rootlevel ? t->nodecard : t->leafcard; for (j = 0; j < maxcard; j++) { dig__fread_port_D(s[top].sn.branch[j].rect.boundary, NUMSIDES, &(Plus->spidx_fp)); dig__fread_port_O(&(s[top].pos[j]), 1, &(Plus->spidx_fp), Plus->spidx_port.off_t_size); /* leaf node: vector object IDs are stored in child.id */ if (s[top].sn.level == 0) { s[top].sn.branch[j].child.id = (int)s[top].pos[j]; } else { s[top].sn.branch[j].child.pos = s[top].pos[j]; } } #endif s[top].branch_id = i = 0; while (top >= 0) { level = s[top].sn->level; if (level > 0) { /* this is an internal node in the tree */ found = 1; for (i = s[top].branch_id; i < t->nodecard; i++) { lastpos = s[top].sn->branch[i].child.pos; if (lastpos > 0 && RTreeOverlap(r, &(s[top].sn->branch[i].rect), t)) { s[top++].branch_id = i + 1; s[top].sn = rtree_get_node(lastpos, level - 1, t, Plus); #if 0 dig_fseek(&(Plus->spidx_fp), lastpos, SEEK_SET); /* read with dig__fread_port_* fns */ dig__fread_port_I(&(s[top].sn.count), 1, &(Plus->spidx_fp)); dig__fread_port_I(&(s[top].sn.level), 1, &(Plus->spidx_fp)); maxcard = s[top].sn.level ? t->nodecard : t->leafcard; for (j = 0; j < maxcard; j++) { dig__fread_port_D(s[top].sn.branch[j].rect.boundary, NUMSIDES, &(Plus->spidx_fp)); dig__fread_port_O(&(s[top].pos[j]), 1, &(Plus->spidx_fp), Plus->spidx_port.off_t_size); if (s[top].sn.level == 0) { s[top].sn.branch[j].child.id = (int)s[top].pos[j]; } else { s[top].sn.branch[j].child.pos = s[top].pos[j]; } } #endif s[top].branch_id = 0; found = 0; break; } } if (found) { /* nothing else found, go back up */ s[top].branch_id = t->nodecard; top--; } } else { /* this is a leaf node */ for (i = 0; i < t->leafcard; i++) { if (s[top].sn->branch[i].child.id && RTreeOverlap(r, &(s[top].sn->branch[i].rect), t)) { hitCount++; if (shcb) { /* call the user-provided callback */ if (!shcb((int)s[top].sn->branch[i].child.id, &s[top].sn->branch[i].rect, cbarg)) { /* callback wants to terminate search early */ return hitCount; } } } } top--; } } return hitCount; }
/* * Search in an index tree or subtree for all data rectangles that * overlap the argument rectangle. * Return the number of qualifying data rects. */ int RTreeSearch(struct Node *N, struct Rect *R, SearchHitCallback shcb, void* cbarg, int mode) { register struct Node *n = N; register struct Rect *r = R; /* NOTE: Suspected bug was R sent in as Node* and cast to Rect* here.*/ /* Fix not yet tested. */ register int hitCount = 0; register int i; long index; int sdebug = 0; if(mode == ID) { index = (long)N; n = &nodes[index]; } if(sdebug) { if (n->level > 0) printf("\nChecking internal node %ld\n", index); else printf("\nChecking leaf node %ld\n", index); } assert(n); assert(n->level >= 0); assert(r); if (n->level > 0) /* this is an internal node in the tree */ { for (i=0; i<NODECARD; i++) { if (sdebug && n->branch[i].child) { printf("\nNODECARD %ld\n", (long)n->branch[i].child); fflush(stdout); } if (n->branch[i].child && RTreeOverlap(r,&n->branch[i].rect)) { if(RTreeContained(&n->branch[i].rect, r)) hitCount += RTreeSearch(n->branch[i].child, R, shcb, cbarg, mode); else hitCount += RTreeSearch(n->branch[i].child, R, shcb, cbarg, mode); } } } else /* this is a leaf node */ { for (i=0; i<LEAFCARD; i++) { if (sdebug && n->branch[i].child) { printf("\nLEAFCARD %ld\n", (long)n->branch[i].child); fflush(stdout); } if (n->branch[i].child && RTreeOverlap(r,&n->branch[i].rect)) { hitCount++; if(sdebug) printf("---> Found\n"); if(shcb) /* call the user-provided callback */ if( ! shcb((long)n->branch[i].child, cbarg)) return hitCount; /* callback wants to terminate search early */ } } } return hitCount; }