⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rtree.h

📁 最近点对问题
💻 H
📖 第 1 页 / 共 3 页
字号:
    }  }  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 + -