// // $Id: split_l.cpp 5027 2010-02-18 19:41:48Z rares $ // // split_l.cpp // // Copyright (C) 2003 - 2007 by The Regents of the University of // California // // Redistribution of this file is permitted under the terms of the // BSD license // // Date: March 2002 // // Authors: Michael Ortega-Binderberger // Liang Jin // Chen Li // #include #include "assert.h" #include "index.h" //#include "card.h" #include "split_l.h" /*----------------------------------------------------------------------------- | Load branch buffer with branches from full node plus the extra branch. -----------------------------------------------------------------------------*/ static void RTreeGetBranches(struct Node *N, struct Branch *B) { register struct Node *n = N; register struct Branch *b = B; register int i; assert(n); assert(b); /* load the branch buffer */ for (i=0; ibranch[i].child); /* every entry should be full */ BranchBuf[i] = n->branch[i]; } BranchBuf[NODECARD] = *b; BranchCount = NODECARD + 1; /* calculate rect containing all in the set */ CoverSplit = BranchBuf[0].rect; for (i=1; icount[0] = p->count[1] = 0; p->total = maxrects; p->minfill = minfill; for (i=0; itaken[i] = FALSE; p->partition[i] = -1; } } /*----------------------------------------------------------------------------- | 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]++; } /*----------------------------------------------------------------------------- | Pick two rects from set to be the first elements of the two groups. | Pick the two that are separated most along any dimension, or overlap least. | Distance for separation or overlap is measured modulo the width of the | space covered by the entire set along that dimension. -----------------------------------------------------------------------------*/ static void RTreePickSeeds(struct PartitionVars *P) { register struct PartitionVars *p = P; register int i, dim, high; register struct Rect *r, *rlow, *rhigh; register float w, separation, bestSep; RectReal width[NUMDIMS]; int leastUpper[NUMDIMS], greatestLower[NUMDIMS]; int seed0, seed1; assert(p); for (dim=0; dimboundary[dim] > BranchBuf[greatestLower[dim]].rect.boundary[dim]) { greatestLower[dim] = i; } if (r->boundary[high] < BranchBuf[leastUpper[dim]].rect.boundary[high]) { leastUpper[dim] = i; } } /* find width of the whole collection along this dimension */ width[dim] = CoverSplit.boundary[high] - CoverSplit.boundary[dim]; } /* pick the best separation dimension and the two seed rects */ for (dim=0; dim= 0); if (width[dim] == 0) w = (RectReal)1; else w = width[dim]; rlow = &BranchBuf[leastUpper[dim]].rect; rhigh = &BranchBuf[greatestLower[dim]].rect; if (dim == 0) { seed0 = leastUpper[0]; seed1 = greatestLower[0]; separation = bestSep = (rhigh->boundary[0] - rlow->boundary[NUMDIMS]) / w; } else { separation = (rhigh->boundary[dim] - rlow->boundary[dim+NUMDIMS]) / w; if (separation > bestSep) { seed0 = leastUpper[dim]; seed1 = greatestLower[dim]; bestSep = separation; } } } if (seed0 != seed1) { RTreeClassify(seed0, 0, p); RTreeClassify(seed1, 1, p); } } /*----------------------------------------------------------------------------- | Put each rect that is not already in a group into a group. | Process one rect at a time, using the following hierarchy of criteria. | In case of a tie, go to the next test. | 1) If one group already has the max number of elements that will allow | the minimum fill for the other group, put r in the other. | 2) Put r in the group whose cover will expand less. This automatically | takes care of the case where one group cover contains r. | 3) Put r in the group whose cover will be smaller. This takes care of the | case where r is contained in both covers. | 4) Put r in the group with fewer elements. | 5) Put in group 1 (arbitrary). | | Also update the covers for both groups. -----------------------------------------------------------------------------*/ static void RTreePigeonhole(struct PartitionVars *P) { register struct PartitionVars *p = P; struct Rect newCover[2]; register int i, group; RectReal newArea[2], increase[2]; for (i=0; itaken[i]) { /* if one group too full, put rect in the other */ if (p->count[0] >= p->total - p->minfill) { RTreeClassify(i, 1, p); continue; } else if (p->count[1] >= p->total - p->minfill) { RTreeClassify(i, 0, p); continue; } /* find areas of the two groups' old and new covers */ for (group=0; group<2; group++) { if (p->count[group]>0) newCover[group] = RTreeCombineRect( &BranchBuf[i].rect, &p->cover[group]); else newCover[group] = BranchBuf[i].rect; newArea[group] = RTreeRectSphericalVolume( &newCover[group]); increase[group] = newArea[group]-p->area[group]; } /* put rect in group whose cover will expand less */ if (increase[0] < increase[1]) RTreeClassify(i, 0, p); else if (increase[1] < increase[0]) RTreeClassify(i, 1, p); /* put rect in group that will have a smaller cover */ else if (p->area[0] < p->area[1]) RTreeClassify(i, 0, p); else if (p->area[1] < p->area[0]) RTreeClassify(i, 1, p); /* put rect in group with fewer elements */ else if (p->count[0] < p->count[1]) RTreeClassify(i, 0, p); else RTreeClassify(i, 1, p); } } assert(p->count[0] + p->count[1] == NODECARD + 1); } /*----------------------------------------------------------------------------- | Method 0 for finding a partition: | First find two seeds, one for each group, well separated. | Then put other rects in whichever group will be smallest after addition. -----------------------------------------------------------------------------*/ static void RTreeMethodZero(struct PartitionVars *p, int minfill) { RTreeInitPVars(p, BranchCount, minfill); RTreePickSeeds(p); RTreePigeonhole(p); } /*----------------------------------------------------------------------------- | Copy branches from the buffer into two nodes according to the partition. -----------------------------------------------------------------------------*/ static void RTreeLoadNodes(struct Node *N, struct Node *Q, struct PartitionVars *P) { register struct Node *n = N, *q = Q; register struct PartitionVars *p = P; register int i; assert(n); assert(q); assert(p); for (i=0; ipartition[i] == 0) RTreeAddBranch(&BranchBuf[i], n, NULL); else if (p->partition[i] == 1) RTreeAddBranch(&BranchBuf[i], q, NULL); else assert(FALSE); } } /*----------------------------------------------------------------------------- | Split a node. | Divides the nodes branches and the extra one between two nodes. | Old node is one of the new ones, and one really new one is created. -----------------------------------------------------------------------------*/ void RTreeSplitNode(struct Node *n, struct Branch *b, struct Node **nn) { register struct PartitionVars *p; register int level; RectReal area; assert(n); assert(b); /* load all the branches into a buffer, initialize old node */ level = n->level; RTreeGetBranches(n, b); /* find partition */ p = &Partitions[0]; /* Note: can't use MINFILL(n) below since n was cleared by GetBranches() */ RTreeMethodZero(p, level>0 ? MinNodeFill : MinLeafFill); /* record how good the split was for statistics */ area = p->area[0] + p->area[1]; /* put branches from buffer in 2 nodes according to chosen partition */ *nn = RTreeNewNode(); (*nn)->level = n->level = level; RTreeLoadNodes(n, *nn, p); assert(n->count + (*nn)->count == NODECARD+1); } /*----------------------------------------------------------------------------- | Print out data for a partition from PartitionVars struct. -----------------------------------------------------------------------------*/ static void RTreePrintPVars(struct PartitionVars *p) { int i; assert(p); printf("\npartition:\n"); for (i=0; itaken[i]) printf(" t\t"); else printf("\t"); } printf("\n"); for (i=0; ipartition[i]); } printf("\n"); printf("count[0] = %d area = %f\n", p->count[0], p->area[0]); printf("count[1] = %d area = %f\n", p->count[1], p->area[1]); printf("total area = %f effectiveness = %3.2f\n", p->area[0] + p->area[1], RTreeRectSphericalVolume(&CoverSplit)/(p->area[0]+p->area[1])); printf("cover[0]:\n"); RTreePrintRect(&p->cover[0], 0); printf("cover[1]:\n"); RTreePrintRect(&p->cover[1], 0); }