RTREE_TEMPLATE void RTREE_QUAL::ChoosePartition(PartitionVars* a_parVars, int a_minFill) { ASSERT(a_parVars); ELEMTYPEREAL biggestDiff; int group, chosen, betterGroup; InitParVars(a_parVars, a_parVars->m_branchCount, a_minFill); PickSeeds(a_parVars); while (((a_parVars->m_count[0] + a_parVars->m_count[1]) < a_parVars->m_total) && (a_parVars->m_count[0] < (a_parVars->m_total - a_parVars->m_minFill)) && (a_parVars->m_count[1] < (a_parVars->m_total - a_parVars->m_minFill))) { biggestDiff = (ELEMTYPEREAL) - 1; for (int index = 0; index < a_parVars->m_total; ++index) { if (PartitionVars::NOT_TAKEN == a_parVars->m_partition[index]) { Rect* curRect = &a_parVars->m_branchBuf[index].m_rect; Rect rect0 = CombineRect(curRect, &a_parVars->m_cover[0]); Rect rect1 = CombineRect(curRect, &a_parVars->m_cover[1]); ELEMTYPEREAL growth0 = CalcRectVolume(&rect0) - a_parVars->m_area[0]; ELEMTYPEREAL growth1 = CalcRectVolume(&rect1) - a_parVars->m_area[1]; ELEMTYPEREAL diff = growth1 - growth0; if (diff >= 0) { group = 0; } else { group = 1; diff = -diff; } if (diff > biggestDiff) { biggestDiff = diff; chosen = index; betterGroup = group; } else if ((diff == biggestDiff) && (a_parVars->m_count[group] < a_parVars->m_count[betterGroup])) { chosen = index; betterGroup = group; } } } Classify(chosen, betterGroup, a_parVars); } // If one group too full, put remaining rects in the other if ((a_parVars->m_count[0] + a_parVars->m_count[1]) < a_parVars->m_total) { if (a_parVars->m_count[0] >= a_parVars->m_total - a_parVars->m_minFill) { group = 1; } else { group = 0; } for (int index = 0; index < a_parVars->m_total; ++index) { if (PartitionVars::NOT_TAKEN == a_parVars->m_partition[index]) { Classify(index, group, a_parVars); } } } ASSERT((a_parVars->m_count[0] + a_parVars->m_count[1]) == a_parVars->m_total); ASSERT((a_parVars->m_count[0] >= a_parVars->m_minFill) && (a_parVars->m_count[1] >= a_parVars->m_minFill)); }
RTREE_TEMPLATE int RTREE_QUAL::PickBranch(const Rect* a_rect, Node* a_node) { ASSERT(a_rect && a_node); bool firstTime = true; ELEMTYPEREAL increase; ELEMTYPEREAL bestIncr = (ELEMTYPEREAL) - 1; ELEMTYPEREAL area; ELEMTYPEREAL bestArea; int best; Rect tempRect; for (int index = 0; index < a_node->m_count; ++index) { Rect* curRect = &a_node->m_branch[index].m_rect; area = CalcRectVolume(curRect); tempRect = CombineRect(a_rect, curRect); increase = CalcRectVolume(&tempRect) - area; if ((increase < bestIncr) || firstTime) { best = index; bestArea = area; bestIncr = increase; firstTime = false; } else if ((increase == bestIncr) && (area < bestArea)) { best = index; bestArea = area; bestIncr = increase; } } return best; }
RTREE_TEMPLATE void RTREE_QUAL::PickSeeds(PartitionVars* a_parVars) { int seed0, seed1; ELEMTYPEREAL worst, waste; ELEMTYPEREAL area[MAXNODES + 1]; for (int index = 0; index < a_parVars->m_total; ++index) { area[index] = CalcRectVolume(&a_parVars->m_branchBuf[index].m_rect); } worst = -a_parVars->m_coverSplitArea - 1; for (int indexA = 0; indexA < a_parVars->m_total - 1; ++indexA) { for (int indexB = indexA + 1; indexB < a_parVars->m_total; ++indexB) { Rect oneRect = CombineRect(&a_parVars->m_branchBuf[indexA].m_rect, &a_parVars->m_branchBuf[indexB].m_rect); waste = CalcRectVolume(&oneRect) - area[indexA] - area[indexB]; if (waste > worst) { worst = waste; seed0 = indexA; seed1 = indexB; } } } Classify(seed0, 0, a_parVars); Classify(seed1, 1, a_parVars); }
RTREE_TEMPLATE typename RTREE_QUAL::Rect RTREE_QUAL::NodeCover(Node* a_node) { ASSERT(a_node); Rect rect = a_node->m_branch[0].m_rect; for (int index = 1; index < a_node->m_count; ++index) { rect = CombineRect(&rect, &(a_node->m_branch[index].m_rect)); } return rect; }
/* Find the smallest rectangle that includes all rectangles in ** branches of a node. */ Rect_t NodeCover(Node_t * n) { register int i, flag; Rect_t r; assert(n); InitRect(&r); flag = 1; for (i = 0; i < NODECARD; i++) if (n->branch[i].child) { if (flag) { r = n->branch[i].rect; flag = 0; } else r = CombineRect(&r, &(n->branch[i].rect)); } return r; }
RTREE_TEMPLATE bool RTREE_QUAL::InsertRectRec(const Branch& a_branch, Node* a_node, Node** a_newNode, int a_level) { ASSERT(a_node && a_newNode); ASSERT(a_level >= 0 && a_level <= a_node->m_level); // recurse until we reach the correct level for the new record. data records // will always be called with a_level == 0 (leaf) if (a_node->m_level > a_level) { // Still above level for insertion, go down tree recursively Node* otherNode; // find the optimal branch for this record int index = PickBranch(&a_branch.m_rect, a_node); // recursively insert this record into the picked branch bool childWasSplit = InsertRectRec(a_branch, a_node->m_branch[index].m_child, &otherNode, a_level); if (!childWasSplit) { // Child was not split. Merge the bounding box of the new record with the // existing bounding box a_node->m_branch[index].m_rect = CombineRect(&a_branch.m_rect, &(a_node->m_branch[index].m_rect)); return false; } else { // Child was split. The old branches are now re-partitioned to two nodes // so we have to re-calculate the bounding boxes of each node a_node->m_branch[index].m_rect = NodeCover(a_node->m_branch[index].m_child); Branch branch; branch.m_child = otherNode; branch.m_rect = NodeCover(otherNode); // The old node is already a child of a_node. Now add the newly-created // node to a_node as well. a_node might be split because of that. return AddBranch(&branch, a_node, a_newNode); } } else if (a_node->m_level == a_level) { // We have reached level for insertion. Add rect, split if necessary return AddBranch(&a_branch, a_node, a_newNode); } else { // Should never occur ASSERT(0); return false; } }
RTREE_TEMPLATE void RTREE_QUAL::Classify(int a_index, int a_group, PartitionVars* a_parVars) { ASSERT(a_parVars); ASSERT(PartitionVars::NOT_TAKEN == a_parVars->m_partition[a_index]); a_parVars->m_partition[a_index] = a_group; // Calculate combined rect if (a_parVars->m_count[a_group] == 0) { a_parVars->m_cover[a_group] = a_parVars->m_branchBuf[a_index].m_rect; } else { a_parVars->m_cover[a_group] = CombineRect(&a_parVars->m_branchBuf[a_index].m_rect, &a_parVars->m_cover[a_group]); } // Calculate volume of combined rect a_parVars->m_area[a_group] = CalcRectVolume(&a_parVars->m_cover[a_group]); ++a_parVars->m_count[a_group]; }
RTREE_TEMPLATE void RTREE_QUAL::GetBranches(Node* a_node, const Branch* a_branch, PartitionVars* a_parVars) { ASSERT(a_node); ASSERT(a_branch); ASSERT(a_node->m_count == MAXNODES); // Load the branch buffer for (int index = 0; index < MAXNODES; ++index) { a_parVars->m_branchBuf[index] = a_node->m_branch[index]; } a_parVars->m_branchBuf[MAXNODES] = *a_branch; a_parVars->m_branchCount = MAXNODES + 1; // Calculate rect containing all in the set a_parVars->m_coverSplit = a_parVars->m_branchBuf[0].m_rect; for (int index = 1; index < MAXNODES + 1; ++index) { a_parVars->m_coverSplit = CombineRect(&a_parVars->m_coverSplit, &a_parVars->m_branchBuf[index].m_rect); } a_parVars->m_coverSplitArea = CalcRectVolume(&a_parVars->m_coverSplit); }
/* 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 PickBranch(Rect_t * r, Node_t * n) { register Rect_t *rr=0; register int i=0, flag=1, increase=0, bestIncr=0, area=0, bestArea=0; int best=0; assert(r && n); for (i = 0; i < NODECARD; i++) { if (n->branch[i].child) { Rect_t rect; rr = &n->branch[i].rect; area = RectArea(rr); /* increase = RectArea(&CombineRect(r, rr)) - area; */ rect = CombineRect(r, rr); increase = RectArea(&rect) - area; if (increase < bestIncr || flag) { best = i; bestArea = area; bestIncr = increase; flag = 0; } else if (increase == bestIncr && area < bestArea) { best = i; bestArea = area; bestIncr = increase; } # ifdef RTDEBUG fprintf(stderr, "i=%d area before=%d area after=%d increase=%d\n", i, area, area + increase, increase); # endif } } # ifdef RTDEBUG fprintf(stderr, "\tpicked %d\n", best); # endif return best; }