📄 rtree.h
字号:
} } return best;}// Combine two rectangles into larger one containing bothRTREE_TEMPLATEtypename RTREE_QUAL::Rect RTREE_QUAL::CombineRect(Rect* a_rectA, Rect* a_rectB){ ASSERT(a_rectA && a_rectB); Rect newRect; for(int index = 0; index < NUMDIMS; ++index) { newRect.m_min[index] = Min(a_rectA->m_min[index], a_rectB->m_min[index]); newRect.m_max[index] = Max(a_rectA->m_max[index], a_rectB->m_max[index]); } return newRect;}// 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.RTREE_TEMPLATEvoid RTREE_QUAL::SplitNode(Node* a_node, Branch* a_branch, Node** a_newNode){ ASSERT(a_node); ASSERT(a_branch); // Could just use local here, but member or external is faster since it is reused PartitionVars localVars; PartitionVars* parVars = &localVars; int level; // Load all the branches into a buffer, initialize old node level = a_node->m_level; GetBranches(a_node, a_branch, parVars); // Find partition ChoosePartition(parVars, MINNODES); // Put branches from buffer into 2 nodes according to chosen partition *a_newNode = AllocNode(); (*a_newNode)->m_level = a_node->m_level = level; LoadNodes(a_node, *a_newNode, parVars); ASSERT((a_node->m_count + (*a_newNode)->m_count) == parVars->m_total);}// Calculate the n-dimensional volume of a rectangleRTREE_TEMPLATEELEMTYPEREAL RTREE_QUAL::RectVolume(Rect* a_rect){ ASSERT(a_rect); ELEMTYPEREAL volume = (ELEMTYPEREAL)1; for(int index=0; index<NUMDIMS; ++index) { volume *= a_rect->m_max[index] - a_rect->m_min[index]; } ASSERT(volume >= (ELEMTYPEREAL)0); return volume;}// The exact volume of the bounding sphere for the given RectRTREE_TEMPLATEELEMTYPEREAL RTREE_QUAL::RectSphericalVolume(Rect* a_rect){ ASSERT(a_rect); ELEMTYPEREAL sumOfSquares = (ELEMTYPEREAL)0; ELEMTYPEREAL radius; for(int index=0; index < NUMDIMS; ++index) { ELEMTYPEREAL halfExtent = ((ELEMTYPEREAL)a_rect->m_max[index] - (ELEMTYPEREAL)a_rect->m_min[index]) * 0.5f; sumOfSquares += halfExtent * halfExtent; } radius = (ELEMTYPEREAL)sqrt(sumOfSquares); // Pow maybe slow, so test for common dims like 2,3 and just use x*x, x*x*x. if(NUMDIMS == 3) { return (radius * radius * radius * m_unitSphereVolume); } else if(NUMDIMS == 2) { return (radius * radius * m_unitSphereVolume); } else { return (ELEMTYPEREAL)(pow(radius, NUMDIMS) * m_unitSphereVolume); }}// Use one of the methods to calculate retangle volumeRTREE_TEMPLATEELEMTYPEREAL RTREE_QUAL::CalcRectVolume(Rect* a_rect){#ifdef RTREE_USE_SPHERICAL_VOLUME return RectSphericalVolume(a_rect); // Slower but helps certain merge cases#else // RTREE_USE_SPHERICAL_VOLUME return RectVolume(a_rect); // Faster but can cause poor merges#endif // RTREE_USE_SPHERICAL_VOLUME }// Load branch buffer with branches from full node plus the extra branch.RTREE_TEMPLATEvoid RTREE_QUAL::GetBranches(Node* a_node, 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(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); InitNode(a_node);}// 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.RTREE_TEMPLATEvoid 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(!a_parVars->m_taken[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(!a_parVars->m_taken[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));}// Copy branches from the buffer into two nodes according to the partition.RTREE_TEMPLATEvoid RTREE_QUAL::LoadNodes(Node* a_nodeA, Node* a_nodeB, PartitionVars* a_parVars){ ASSERT(a_nodeA); ASSERT(a_nodeB); ASSERT(a_parVars); for(int index=0; index < a_parVars->m_total; ++index) { ASSERT(a_parVars->m_partition[index] == 0 || a_parVars->m_partition[index] == 1); if(a_parVars->m_partition[index] == 0) { AddBranch(&a_parVars->m_branchBuf[index], a_nodeA, NULL); } else if(a_parVars->m_partition[index] == 1) { AddBranch(&a_parVars->m_branchBuf[index], a_nodeB, NULL); } }}// Initialize a PartitionVars structure.RTREE_TEMPLATEvoid RTREE_QUAL::InitParVars(PartitionVars* a_parVars, int a_maxRects, int a_minFill){ ASSERT(a_parVars); a_parVars->m_count[0] = a_parVars->m_count[1] = 0; a_parVars->m_area[0] = a_parVars->m_area[1] = (ELEMTYPEREAL)0; a_parVars->m_total = a_maxRects; a_parVars->m_minFill = a_minFill; for(int index=0; index < a_maxRects; ++index) { a_parVars->m_taken[index] = false; a_parVars->m_partition[index] = -1; }}RTREE_TEMPLATEvoid 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);}// Put a branch in one of the groups.RTREE_TEMPLATEvoid RTREE_QUAL::Classify(int a_index, int a_group, PartitionVars* a_parVars){ ASSERT(a_parVars); ASSERT(!a_parVars->m_taken[a_index]); a_parVars->m_partition[a_index] = a_group; a_parVars->m_taken[a_index] = true; 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]); } a_parVars->m_area[a_group] = CalcRectVolume(&a_parVars->m_cover[a_group]); ++a_parVars->m_count[a_group];}// Delete a data rectangle from an index structure.// Pass in a pointer to a Rect, the tid of the record, ptr to ptr to root node.// Returns 1 if record not found, 0 if success.// RemoveRect provides for eliminating the root.RTREE_TEMPLATEbool RTREE_QUAL::RemoveRect(Rect* a_rect, const DATATYPE& a_id, Node** a_root){ ASSERT(a_rect && a_root); ASSERT(*a_root); Node* tempNode; ListNode* reInsertList = NULL; if(!RemoveRectRec(a_rect, a_id, *a_root, &reInsertList)) { // Found and deleted a data item // Reinsert any branches from eliminated nodes while(reInsertList) { tempNode = reInsertList->m_node; for(int index = 0; index < tempNode->m_count; ++index) { InsertRect(&(tempNode->m_branch[index].m_rect), tempNode->m_branch[index].m_data, a_root, tempNode->m_level); } ListNode* remLNode = reInsertList; reInsertList = reInsertList->m_next; FreeNode(remLNode->m_node); FreeListNode(remLNode); } // Check for redundant root (not leaf, 1 child) and eliminate if((*a_root)->m_count == 1 && (*a_root)->IsInternalNode()) { tempNode = (*a_root)->m_branch[0].m_child; ASSERT(tempNode); FreeNode(*a_root); *a_root = tempNode; } return false; } else { return true; }}// Delete a rectangle from non-root part of an index structure.// Called by RemoveRect. Descends tree recursively,// merges branches on the way back up.// Returns 1 if record not found, 0 if success.RTREE_TEMPLATEbool RTREE_QUAL::RemoveRectRec(Rect* a_rect, const DATATYPE& a_id, Node* a_node, ListNode** a_listNode){ ASSERT(a_rect && a_node && a_listNode); ASSERT(a_node->m_level >= 0); if(a_node->IsInternalNode()) // not a leaf node { for(int index = 0; index < a_node->m_count; ++index) { if(Overlap(a_rect, &(a_node->m_branch[index].m_rect))) { if(!RemoveRectRec(a_rect, a_id, a_node->m_branch[index].m_child, a_listNode)) { if(a_node->m_branch[index].m_child->m_count >= MINNODES) { // child removed, just resize parent rect a_node->m_branch[index].m_rect = NodeCover(a_node->m_branch[index].m_child); } else { // child removed, not enough entries in node, eliminate node ReInsert(a_node->m_branch[index].m_child, a_listNode); DisconnectBranch(a_node, index); // Must return after this call as count has changed } return false; } } } return true; } else // A leaf node { for(int index = 0; index < a_node->m_count; ++index) { if(a_node->m_branch[index].m_child == (Node*)a_id) { DisconnectBranch(a_node, index); // Must return after this call as count has changed return false; } } return true; }}// Decide whether two rectangles overlap.RTREE_TEMPLATEbool RTREE_QUAL::Overlap(Rect* a_rectA, Rect* a_rectB){ ASSERT(a_rectA && a_rectB); for(int index=0; index < NUMDIMS; ++index) { if (a_rectA->m_min[index] > a_rectB->m_max[index] || a_rectB->m_min[index] > a_rectA->m_max[index]) { return false; } } return true;}// Add a node to the reinsertion list. All its branches will later// be reinserted into the index structure.RTREE_TEMPLATEvoid RTREE_QUAL::ReInsert(Node* a_node, ListNode** a_listNode){ ListNode* newListNode; newListNode = AllocListNode(); newListNode->m_node = a_node; newListNode->m_next = *a_listNode; *a_listNode = newListNode;}// Search in an index tree or subtree for all data retangles that overlap the argument rectangle.RTREE_TEMPLATEbool RTREE_QUAL::Search(Node* a_node, Rect* a_rect, int& a_foundCount, bool __cdecl a_resultCallback(DATATYPE a_data, void* a_context), void* a_context){ ASSERT(a_node); ASSERT(a_node->m_level >= 0); ASSERT(a_rect); if(a_node->IsInternalNode()) // This is an internal node in the tree { for(int index=0; index < a_node->m_count; ++index) { if(Overlap(a_rect, &a_node->m_branch[index].m_rect)) { if(!Search(a_node->m_branch[index].m_child, a_rect, a_foundCount, a_resultCallback, a_context)) { return false; // Don't continue searching } } } } else // This is a leaf node { for(int index=0; index < a_node->m_count; ++index) { if(Overlap(a_rect, &a_node->m_branch[index].m_rect)) { DATATYPE& id = a_node->m_branch[index].m_data; // NOTE: There are different ways to return results. Here's where to modify if(&a_resultCallback) { ++a_foundCount; if(!a_resultCallback(id, a_context)) { return false; // Don't continue searching } } } } } return true; // Continue searching}#undef RTREE_TEMPLATE#undef RTREE_QUAL#endif //RTREE_H
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -