123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649 |
- /****************************************************************************
- * MODULE: R-Tree library
- *
- * AUTHOR(S): Antonin Guttman - original code
- * Daniel Green (green@superliminal.com) - major clean-up
- * and implementation of bounding spheres
- * Markus Metz - file-based and memory-based R*-tree
- *
- * PURPOSE: Multidimensional index
- *
- * COPYRIGHT: (C) 2010 by the GRASS Development Team
- *
- * This program is free software under the GNU General Public
- * License (>=v2). Read the file COPYING that comes with GRASS
- * for details.
- *****************************************************************************/
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <assert.h>
- #include <grass/gis.h>
- #include "index.h"
- #include "split.h"
- #include "card.h"
- /* rectangle distances for forced removal */
- struct dist
- {
- int id; /* branch id */
- RectReal distance; /* distance to node center */
- };
- /* Initialize one branch cell in an internal node. */
- static void RTreeInitNodeBranchM(struct RTree_Branch *b, struct RTree *t)
- {
- RTreeInitRect(&(b->rect), t);
- memset(&(b->child), 0, sizeof(union RTree_Child));
- b->child.ptr = NULL;
- }
- /* Initialize one branch cell in an internal node. */
- static void RTreeInitNodeBranchF(struct RTree_Branch *b, struct RTree *t)
- {
- RTreeInitRect(&(b->rect), t);
- memset(&(b->child), 0, sizeof(union RTree_Child));
- b->child.pos = -1;
- }
- /* Initialize one branch cell in a leaf node. */
- static void RTreeInitLeafBranch(struct RTree_Branch *b, struct RTree *t)
- {
- RTreeInitRect(&(b->rect), t);
- memset(&(b->child), 0, sizeof(union RTree_Child));
- b->child.id = 0;
- }
- static void (*RTreeInitBranch[3]) (struct RTree_Branch *b, struct RTree *t) = {
- RTreeInitLeafBranch, RTreeInitNodeBranchM, RTreeInitNodeBranchF
- };
- /* Initialize a Node structure. */
- /* type = 1: leaf, type = 2: internal, memory, type = 3: internal, file */
- void RTreeInitNode(struct RTree *t, struct RTree_Node *n, int type)
- {
- int i;
- n->count = 0;
- n->level = -1;
- for (i = 0; i < MAXCARD; i++)
- RTreeInitBranch[type](&(n->branch[i]), t);
- }
- /* Make a new node and initialize to have all branch cells empty. */
- struct RTree_Node *RTreeAllocNode(struct RTree *t, int level)
- {
- int i;
- struct RTree_Node *n;
- n = (struct RTree_Node *)malloc(sizeof(struct RTree_Node));
- assert(n);
- n->count = 0;
- n->level = level;
-
- n->branch = malloc(MAXCARD * sizeof(struct RTree_Branch));
- for (i = 0; i < MAXCARD; i++) {
- n->branch[i].rect.boundary = RTreeAllocBoundary(t);
- RTreeInitBranch[NODETYPE(level, t->fd)](&(n->branch[i]), t);
- }
- return n;
- }
- void RTreeFreeNode(struct RTree_Node *n)
- {
- int i;
- assert(n);
- for (i = 0; i < MAXCARD; i++)
- RTreeFreeBoundary(&(n->branch[i].rect));
- free(n->branch);
- free(n);
- }
- /* copy node 2 to node 1 */
- void RTreeCopyNode(struct RTree_Node *n1, struct RTree_Node *n2, struct RTree *t)
- {
- int i;
- assert(n1 && n2);
- n1->count = n2->count;
- n1->level = n2->level;
- for (i = 0; i < MAXCARD; i++) {
- RTreeCopyBranch(&(n1->branch[i]), &(n2->branch[i]), t);
- }
- }
- /* copy branch 2 to branch 1 */
- void RTreeCopyBranch(struct RTree_Branch *b1, struct RTree_Branch *b2, struct RTree *t)
- {
- b1->child = b2->child;
- RTreeCopyRect(&(b1->rect), &(b2->rect), t);
- }
- /*
- * Find the smallest rectangle that includes all rectangles in
- * branches of a node.
- */
- void RTreeNodeCover(struct RTree_Node *n, struct RTree_Rect *r, struct RTree *t)
- {
- int i, first_time = 1;
- if ((n)->level > 0) { /* internal node */
- for (i = 0; i < t->nodecard; i++) {
- if (t->valid_child(&(n->branch[i].child))) {
- if (first_time) {
- RTreeCopyRect(r, &(n->branch[i].rect), t);
- first_time = 0;
- }
- else
- RTreeExpandRect(r, &(n->branch[i].rect), t);
- }
- }
- }
- else { /* leaf */
- for (i = 0; i < t->leafcard; i++) {
- if (n->branch[i].child.id) {
- if (first_time) {
- RTreeCopyRect(r, &(n->branch[i].rect), t);
- first_time = 0;
- }
- else
- RTreeExpandRect(r, &(n->branch[i].rect), t);
- }
- }
- }
- }
- /*
- * Idea from R*-tree, modified: not overlap size but overlap number
- *
- * Pick a branch from leaf nodes (current node has level 1). Pick the
- * one that will result in the smallest number of overlapping siblings.
- * This will result in the least ambiguous node covering the new
- * rectangle, improving search speed.
- * In case of a tie, pick the one which needs the smallest increase in
- * area to accommodate the new rectangle, then the smallest area before,
- * to get the best resolution when searching.
- */
- 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;
- 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;
- RTreeCombineRect(r, rr, &(t->orect), t);
- area = RTreeRectSphericalVolume(rr, t);
- increase = RTreeRectSphericalVolume(&(t->orect), t) - area;
- overlap = 0;
- for (j = 0; j < t->leafcard; j++) {
- if (j != i) {
- rr = &n->branch[j].rect;
- overlap += RTreeOverlap(&(t->orect), 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;
- }
- /*
- * Pick a branch. Pick the one that will need the smallest increase
- * in area to accommodate 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;
- 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);
- RTreeCombineRect(r, rr, &(t->orect), t);
- increase = RTreeRectSphericalVolume(&(t->orect), 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;
- }
- /* Disconnect a dependent node. */
- void RTreeDisconnectBranch(struct RTree_Node *n, int i, struct RTree *t)
- {
- if ((n)->level > 0) {
- assert(n && i >= 0 && i < t->nodecard);
- assert(t->valid_child(&(n->branch[i].child)));
- if (t->fd < 0)
- RTreeInitNodeBranchM(&(n->branch[i]), t);
- else
- RTreeInitNodeBranchF(&(n->branch[i]), t);
- }
- else {
- assert(n && i >= 0 && i < t->leafcard);
- assert(n->branch[i].child.id);
- RTreeInitLeafBranch(&(n->branch[i]), t);
- }
- n->count--;
- }
- /* Destroy (free) node recursively. */
- /* NOTE: only needed for memory based index */
- void RTreeDestroyNode(struct RTree_Node *n, int nodes)
- {
- int i;
- if (n->level > 0) { /* it is not leaf -> destroy childs */
- for (i = 0; i < nodes; i++) {
- if (n->branch[i].child.ptr) {
- RTreeDestroyNode(n->branch[i].child.ptr, nodes);
- }
- }
- }
- /* Free this node */
- RTreeFreeNode(n);
-
- return;
- }
- /****************************************************************
- * *
- * R*-tree: force remove FORCECARD branches for reinsertion *
- * *
- ****************************************************************/
- /*
- * swap dist structs
- */
- static void RTreeSwapDist(struct dist *a, struct dist *b)
- {
- struct dist c;
- c = *a;
- *a = *b;
- *b = c;
- }
- /*
- * check if dist is sorted ascending to distance
- */
- static int RTreeDistIsSorted(struct dist *d, int first, int last)
- {
- int i;
- for (i = first; i < last; i++) {
- if (d[i].distance > d[i + 1].distance)
- return 0;
- }
- return 1;
- }
- /*
- * partition dist for quicksort on distance
- */
- static int RTreePartitionDist(struct dist *d, int first, int last)
- {
- int pivot, mid = ((first + last) >> 1);
- int larger, smaller;
- if (last - first == 1) { /* only two items in list */
- if (d[first].distance > d[last].distance) {
- RTreeSwapDist(&(d[first]), &(d[last]));
- }
- return last;
- }
- /* Larger of two */
- larger = pivot = mid;
- smaller = first;
- if (d[first].distance > d[mid].distance) {
- larger = pivot = first;
- smaller = mid;
- }
- if (d[larger].distance > d[last].distance) {
- /* larger is largest, get the larger of smaller and last */
- pivot = last;
- if (d[smaller].distance > d[last].distance) {
- pivot = smaller;
- }
- }
- if (pivot != last) {
- RTreeSwapDist(&(d[pivot]), &(d[last]));
- }
- pivot = first;
- while (first < last) {
- if (d[first].distance <= d[last].distance) {
- if (pivot != first) {
- RTreeSwapDist(&(d[pivot]), &(d[first]));
- }
- pivot++;
- }
- ++first;
- }
- if (pivot != last) {
- RTreeSwapDist(&(d[pivot]), &(d[last]));
- }
- return pivot;
- }
- /*
- * quicksort dist struct ascending by distance
- * n is last valid index
- */
- static void RTreeQuicksortDist(struct dist *d, int n)
- {
- int pivot, first, last;
- int s_first[MAXCARD + 1], s_last[MAXCARD + 1], stacksize;
- s_first[0] = 0;
- s_last[0] = n;
- stacksize = 1;
- /* use stack */
- while (stacksize) {
- stacksize--;
- first = s_first[stacksize];
- last = s_last[stacksize];
- if (first < last) {
- if (!RTreeDistIsSorted(d, first, last)) {
- pivot = RTreePartitionDist(d, first, last);
- s_first[stacksize] = first;
- s_last[stacksize] = pivot - 1;
- stacksize++;
- s_first[stacksize] = pivot + 1;
- s_last[stacksize] = last;
- stacksize++;
- }
- }
- }
- }
- /*
- * Allocate space for a branch in the list used in InsertRect to
- * store branches of nodes that are too full.
- */
- static struct RTree_ListBranch *RTreeNewListBranch(struct RTree *t)
- {
- struct RTree_ListBranch *p =
- (struct RTree_ListBranch *)malloc(sizeof(struct RTree_ListBranch));
- assert(p);
- p->b.rect.boundary = RTreeAllocBoundary(t);
- return p;
- }
- /*
- * Add a branch to the reinsertion list. It will later
- * be reinserted into the index structure.
- */
- static void RTreeReInsertBranch(struct RTree_Branch b, int level,
- struct RTree_ListBranch **ee, struct RTree *t)
- {
- register struct RTree_ListBranch *l;
- l = RTreeNewListBranch(t);
- RTreeCopyBranch(&(l->b), &b, t);
- l->level = level;
- l->next = *ee;
- *ee = l;
- }
- /*
- * 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_r, delta;
- struct dist rdist[MAXCARD + 1];
- struct RTree_Rect *new_cover = &(t->orect);
- RectReal *center_n = t->center_n;
- assert(cover);
- maxkids = MAXKIDS((n)->level, t);
- type = NODETYPE((n)->level, t->fd);
-
- assert(n->count == maxkids); /* must be full */
- RTreeCombineRect(cover, &(b->rect), new_cover, t);
- /* center coords of node cover */
- for (j = 0; j < t->ndims; j++) {
- center_n[j] = (new_cover->boundary[j + t->ndims_alloc] + new_cover->boundary[j]) / 2;
- }
- /* compute distances of child rectangle centers to node cover center */
- for (i = 0; i < maxkids; i++) {
- RTreeCopyBranch(&(t->BranchBuf[i]), &(n->branch[i]), t);
- rdist[i].distance = 0;
- rdist[i].id = i;
- for (j = 0; j < t->ndims; j++) {
- center_r =
- (t->BranchBuf[i].rect.boundary[j + t->ndims_alloc] +
- t->BranchBuf[i].rect.boundary[j]) / 2;
- delta = center_n[j] - center_r;
- rdist[i].distance += delta * delta;
- }
- RTreeInitBranch[type](&(n->branch[i]), t);
- }
- /* new branch */
- RTreeCopyBranch(&(t->BranchBuf[maxkids]), b, t);
- rdist[maxkids].distance = 0;
- for (j = 0; j < t->ndims; j++) {
- center_r =
- (b->rect.boundary[j + t->ndims_alloc] +
- 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(t->BranchBuf[rdist[maxkids - i].id], n->level, ee, t);
- }
- /* put remaining in node, closest to center first */
- for (i = 0; i < maxkids - FORCECARD + 1; i++) {
- RTreeCopyBranch(&(n->branch[i]), &(t->BranchBuf[rdist[i].id]), t);
- }
- n->count = maxkids - FORCECARD + 1;
- }
- /*
- * 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, char *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))) {
- /* copy branch */
- n->branch[i].child = b->child;
- RTreeCopyRect(&(n->branch[i].rect), &(b->rect), t);
- 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) {
- /* copy branch */
- n->branch[i].child = b->child;
- RTreeCopyRect(&(n->branch[i].rect), &(b->rect), t);
- 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(t, *newnode, NODETYPE(n->level, t->fd));
- else
- *newnode = RTreeAllocNode(t, (n)->level);
- RTreeSplitNode(n, b, *newnode, t);
- return 1;
- }
- }
- /* should not be reached */
- assert(0);
- return -1;
- }
- /*
- * for debugging only: print items to stdout
- */
- void RTreeTabIn(int depth)
- {
- int i;
- for (i = 0; i < depth; i++)
- putchar('\t');
- }
- static void RTreePrintBranch(struct RTree_Branch *b, int depth, struct RTree *t)
- {
- RTreePrintRect(&(b->rect), depth, t);
- RTreePrintNode(b->child.ptr, depth, t);
- }
- /* Print out the data in a node. */
- void RTreePrintNode(struct RTree_Node *n, int depth, struct RTree *t)
- {
- int i, maxkids;
- RTreeTabIn(depth);
- maxkids = (n->level > 0 ? t->nodecard : t->leafcard);
- fprintf(stdout, "node");
- if (n->level == 0)
- fprintf(stdout, " LEAF");
- else if (n->level > 0)
- fprintf(stdout, " NONLEAF");
- else
- fprintf(stdout, " TYPE=?");
- fprintf(stdout, " level=%d count=%d", n->level, n->count);
- for (i = 0; i < maxkids; i++) {
- if (n->level == 0) {
- RTreeTabIn(depth);
- RTreePrintRect(&(n->branch[i].rect), depth, t);
- fprintf(stdout, "\t%d: data id = %d\n", i,
- n->branch[i].child.id);
- }
- else {
- RTreeTabIn(depth);
- fprintf(stdout, "branch %d\n", i);
- RTreePrintBranch(&(n->branch[i]), depth + 1, t);
- }
- }
- }
|