// // $Id: split_q.cpp 4034 2008-10-03 01:17:40Z rares $ // // split_q.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 (miki@ics.uci.edu) // Liang Jin (liangj@ics.uci.edu) // Chen Li (chenli@ics.uci.edu) // // #include #include "assert.h" #include "index.h" #include "split_q.h" /*----------------------------------------------------------------------------- | 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; ibranch[i].child); /* n should have every entry full */ BranchBuf[i] = n->branch[i]; } BranchBuf[NODECARD] = *b; /* calculate rect containing all in the set */ CoverSplit = BranchBuf[0].rect; for (i=1; itaken[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 waste the most area if covered by a single rectangle. -----------------------------------------------------------------------------*/ static void RTreePickSeeds(struct PartitionVars *p) { register int i, j, seed0, seed1; RectReal worst, waste, area[NODECARD+1]; for (i=0; i worst) { worst = waste; seed0 = i; seed1 = j; } } } RTreeClassify(seed0, 0, p); RTreeClassify(seed1, 1, 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 int i; assert(n); assert(q); assert(p); for (i=0; ipartition[i] == 0 || p->partition[i] == 1); if (p->partition[i] == 0) RTreeAddBranch(&BranchBuf[i], n, NULL); else if (p->partition[i] == 1) RTreeAddBranch(&BranchBuf[i], q, NULL); } } /*----------------------------------------------------------------------------- | Initialize a PartitionVars structure. -----------------------------------------------------------------------------*/ static void RTreeInitPVars(struct PartitionVars *p) { register int i; assert(p); p->count[0] = p->count[1] = 0; p->cover[0] = p->cover[1] = RTreeNullRect(); p->area[0] = p->area[1] = (RectReal)0; for (i=0; itaken[i] = FALSE; p->partition[i] = -1; } } /*----------------------------------------------------------------------------- | Print out data for a partition from PartitionVars struct. -----------------------------------------------------------------------------*/ static void RTreePrintPVars(struct PartitionVars *p) { register 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]); if (p->area[0] + p->area[1] > 0) { printf("total area = %f effectiveness = %3.2f\n", p->area[0] + p->area[1], (float)CoverSplitArea / (p->area[0] + p->area[1])); } printf("cover[0]:\n"); RTreePrintRect(&p->cover[0], 0); printf("cover[1]:\n"); RTreePrintRect(&p->cover[1], 0); } /*----------------------------------------------------------------------------- | 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) { register int i; RectReal biggestDiff; register int group, chosen, betterGroup; assert(p); RTreeInitPVars(p); RTreePickSeeds(p); while (p->count[0] + p->count[1] < NODECARD + 1 && p->count[0] < NODECARD + 1 - MinFill && p->count[1] < NODECARD + 1 - MinFill) { biggestDiff = (RectReal)-1.; for (i=0; itaken[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]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] < NODECARD + 1) { if (p->count[0] >= NODECARD + 1 - MinFill) group = 1; else group = 0; for (i=0; itaken[i]) RTreeClassify(i, group, p); } } assert(p->count[0] + p->count[1] == NODECARD+1); assert(p->count[0] >= MinFill && p->count[1] >= MinFill); } /*----------------------------------------------------------------------------- | 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. | Tries more than one method for choosing a partition, uses best result. -----------------------------------------------------------------------------*/ extern void RTreeSplitNode(struct Node *n, struct Branch *b, struct Node **nn) { register struct PartitionVars *p; register int level; 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]; RTreeMethodZero(p); /* * put branches from buffer into 2 nodes * according to chosen partition */ *nn = RTreeNewNode(); (*nn)->level = n->level = level; RTreeLoadNodes(n, *nn, p); assert(n->count+(*nn)->count == NODECARD+1); }