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

📄 rtree.h

📁 最近点对问题
💻 H
📖 第 1 页 / 共 3 页
字号:
#ifndef RTREE_H#define RTREE_H// NOTE This file compiles under MSVC 6 SP5 and MSVC .Net 2003 it may not work on other compilers without modification.// NOTE These next few lines may be win32 specific, you may need to modify them to compile on other platform#include <stdio.h>#include <math.h>#include <assert.h>#include <stdlib.h>#define ASSERT assert // RTree uses ASSERT( condition )#ifndef Min  #define Min __min #endif //Min#ifndef Max  #define Max __max #endif //Max//// RTree.h//#define RTREE_TEMPLATE template<class DATATYPE, class ELEMTYPE, int NUMDIMS, class ELEMTYPEREAL, int TMAXNODES, int TMINNODES>#define RTREE_QUAL RTree<DATATYPE, ELEMTYPE, NUMDIMS, ELEMTYPEREAL, TMAXNODES, TMINNODES>#define RTREE_DONT_USE_MEMPOOLS // This version does not contain a fixed memory allocator, fill in lines with EXAMPLE to implement one.#define RTREE_USE_SPHERICAL_VOLUME // Better split classification, may be slower on some systems// Fwd declclass RTFileStream;  // File I/O helper class, look below for implementation and notes./// \class RTree/// Implementation of RTree, a multidimensional bounding rectangle tree./// Example usage: For a 3-dimensional tree use RTree<Object*, float, 3> myTree;////// This modified, templated C++ version by Greg Douglas at Auran (http://www.auran.com)////// DATATYPE Referenced data, should be int, void*, obj* etc. no larger than sizeof<void*> and simple type/// ELEMTYPE Type of element such as int or float/// NUMDIMS Number of dimensions such as 2 or 3/// ELEMTYPEREAL Type of element that allows fractional and large values such as float or double, for use in volume calcs////// NOTES: Inserting and removing data requires the knowledge of its constant Minimal Bounding Rectangle.///        This version uses new/delete for nodes, I recommend using a fixed size allocator for efficiency.///        Instead of using a callback function for returned results, I recommend and efficient pre-sized, grow-only memory///        array similar to MFC CArray or STL Vector for returning search query result.///template<class DATATYPE, class ELEMTYPE, int NUMDIMS,          class ELEMTYPEREAL = ELEMTYPE, int TMAXNODES = 8, int TMINNODES = TMAXNODES / 2>class RTree{protected:   struct Node;  // Fwd decl.  Used by other internal structs and iteratorpublic:  // These constant must be declared after Branch and before Node struct  // Stuck up here for MSVC 6 compiler.  NSVC .NET 2003 is much happier.  enum  {    MAXNODES = TMAXNODES,                         ///< Max elements in node    MINNODES = TMINNODES,                         ///< Min elements in node  };public:  RTree();  virtual ~RTree();    /// Insert entry  /// \param a_min Min of bounding rect  /// \param a_max Max of bounding rect  /// \param a_dataId Positive Id of data.  Maybe zero, but negative numbers not allowed.  void Insert(const ELEMTYPE a_min[NUMDIMS], const ELEMTYPE a_max[NUMDIMS], const DATATYPE& a_dataId);    /// Remove entry  /// \param a_min Min of bounding rect  /// \param a_max Max of bounding rect  /// \param a_dataId Positive Id of data.  Maybe zero, but negative numbers not allowed.  void Remove(const ELEMTYPE a_min[NUMDIMS], const ELEMTYPE a_max[NUMDIMS], const DATATYPE& a_dataId);    /// Find all within search rectangle  /// \param a_min Min of search bounding rect  /// \param a_max Max of search bounding rect  /// \param a_searchResult Search result array.  Caller should set grow size. Function will reset, not append to array.  /// \param a_resultCallback Callback function to return result.  Callback should return 'true' to continue searching  /// \param a_context User context to pass as parameter to a_resultCallback  /// \return Returns the number of entries found  int Search(const ELEMTYPE a_min[NUMDIMS], const ELEMTYPE a_max[NUMDIMS], bool __cdecl a_resultCallback(DATATYPE a_data, void* a_context), void* a_context);    /// Remove all entries from tree  void RemoveAll();  /// Count the data elements in this container.  This is slow as no internal counter is maintained.  int Count();  /// Load tree contents from file  bool Load(const char* a_fileName);  /// Load tree contents from stream  bool Load(RTFileStream& a_stream);    /// Save tree contents to file  bool Save(const char* a_fileName);  /// Save tree contents to stream  bool Save(RTFileStream& a_stream);  /// Iterator is not remove safe.  class Iterator  {  private:      enum { MAX_STACK = 32 }; //  Max stack size. Allows almost n^32 where n is number of branches in node        struct StackElement    {      Node* m_node;      int m_branchIndex;    };      public:      Iterator()                                    { Init(); }    ~Iterator()                                   { }        /// Is iterator invalid    bool IsNull()                                 { return (m_tos <= 0); }    /// Is iterator pointing to valid data    bool IsNotNull()                              { return (m_tos > 0); }    /// Access the current data element. Caller must be sure iterator is not NULL first.    DATATYPE& operator*()    {      ASSERT(IsNotNull());      StackElement& curTos = m_stack[m_tos - 1];      return curTos.m_node->m_branch[curTos.m_branchIndex].m_data;    }     /// Access the current data element. Caller must be sure iterator is not NULL first.    const DATATYPE& operator*() const    {      ASSERT(IsNotNull());      StackElement& curTos = m_stack[m_tos - 1];      return curTos.m_node->m_branch[curTos.m_branchIndex].m_data;    }     /// Find the next data element    bool operator++()                             { return FindNextData(); }  private:      /// Reset iterator    void Init()                                   { m_tos = 0; }    /// Find the next data element in the tree (For internal use only)    bool FindNextData()    {      for(;;)      {        if(m_tos <= 0)        {          return false;        }        StackElement curTos = Pop(); // Copy stack top cause it may change as we use it        if(curTos.m_node->IsLeaf())        {          // Keep walking through data while we can          if(curTos.m_branchIndex+1 < curTos.m_node->m_count)          {            // There is more data, just point to the next one            Push(curTos.m_node, curTos.m_branchIndex + 1);            return true;          }          // No more data, so it will fall back to previous level        }        else        {          if(curTos.m_branchIndex+1 < curTos.m_node->m_count)          {            // Push sibling on for future tree walk            // This is the 'fall back' node when we finish with the current level            Push(curTos.m_node, curTos.m_branchIndex + 1);          }          // Since cur node is not a leaf, push first of next level to get deeper into the tree          Node* nextLevelnode = curTos.m_node->m_branch[curTos.m_branchIndex].m_child;          Push(nextLevelnode, 0);                    // If we pushed on a new leaf, exit as the data is ready at TOS          if(nextLevelnode->IsLeaf())          {            return true;          }        }      }    }    /// Push node and branch onto iteration stack (For internal use only)    void Push(Node* a_node, int a_branchIndex)    {      m_stack[m_tos].m_node = a_node;      m_stack[m_tos].m_branchIndex = a_branchIndex;      ++m_tos;      ASSERT(m_tos <= MAX_STACK);    }        /// Pop element off iteration stack (For internal use only)    StackElement& Pop()    {      ASSERT(m_tos > 0);      --m_tos;      return m_stack[m_tos];    }    StackElement m_stack[MAX_STACK];              ///< Stack as we are doing iteration instead of recursion    int m_tos;                                    ///< Top Of Stack index      friend RTree; // Allow hiding of non-public functions while allowing manipulation by logical owner  };  /// Get 'first' for iteration  void GetFirst(Iterator& a_it)  {    a_it.Init();    if(m_root && (m_root->m_count > 0))    {      a_it.Push(m_root, 0);      a_it.FindNextData();    }  }  /// Get Next for iteration  void GetNext(Iterator& a_it)                    { ++a_it; }  /// Is iterator NULL, or at end?  bool IsNull(Iterator& a_it)                     { return a_it.IsNull(); }  /// Get object at iterator position  DATATYPE& GetAt(Iterator& a_it)                 { return *a_it; }protected:  /// Minimal bounding rectangle (n-dimensional)  struct Rect  {    ELEMTYPE m_min[NUMDIMS];                      ///< Min dimensions of bounding box     ELEMTYPE m_max[NUMDIMS];                      ///< Max dimensions of bounding box   };  /// May be data or may be another subtree  /// The parents level determines this.  /// If the parents level is 0, then this is data  struct Branch  {    Rect m_rect;                                  ///< Bounds    union    {      Node* m_child;                              ///< Child node      DATATYPE m_data;                            ///< Data Id or Ptr    };  };  /// Node for each branch level  struct Node  {    bool IsInternalNode()                         { return (m_level > 0); } // Not a leaf, but a internal node    bool IsLeaf()                                 { return (m_level == 0); } // A leaf, contains data        int m_count;                                  ///< Count    int m_level;                                  ///< Leaf is zero, others positive    Branch m_branch[MAXNODES];                    ///< Branch  };    /// A link list of nodes for reinsertion after a delete operation  struct ListNode  {    ListNode* m_next;                             ///< Next in list    Node* m_node;                                 ///< Node  };  /// Variables for finding a split partition  struct PartitionVars  {    int m_partition[MAXNODES+1];    int m_total;    int m_minFill;    int m_taken[MAXNODES+1];    int m_count[2];    Rect m_cover[2];    ELEMTYPEREAL m_area[2];    Branch m_branchBuf[MAXNODES+1];    int m_branchCount;    Rect m_coverSplit;    ELEMTYPEREAL m_coverSplitArea;  };    Node* AllocNode();  void FreeNode(Node* a_node);  void InitNode(Node* a_node);  void InitRect(Rect* a_rect);  bool InsertRectRec(Rect* a_rect, const DATATYPE& a_id, Node* a_node, Node** a_newNode, int a_level);  bool InsertRect(Rect* a_rect, const DATATYPE& a_id, Node** a_root, int a_level);  Rect NodeCover(Node* a_node);  bool AddBranch(Branch* a_branch, Node* a_node, Node** a_newNode);  void DisconnectBranch(Node* a_node, int a_index);  int PickBranch(Rect* a_rect, Node* a_node);  Rect CombineRect(Rect* a_rectA, Rect* a_rectB);  void SplitNode(Node* a_node, Branch* a_branch, Node** a_newNode);  ELEMTYPEREAL RectSphericalVolume(Rect* a_rect);  ELEMTYPEREAL RectVolume(Rect* a_rect);  ELEMTYPEREAL CalcRectVolume(Rect* a_rect);  void GetBranches(Node* a_node, Branch* a_branch, PartitionVars* a_parVars);  void ChoosePartition(PartitionVars* a_parVars, int a_minFill);  void LoadNodes(Node* a_nodeA, Node* a_nodeB, PartitionVars* a_parVars);  void InitParVars(PartitionVars* a_parVars, int a_maxRects, int a_minFill);  void PickSeeds(PartitionVars* a_parVars);  void Classify(int a_index, int a_group, PartitionVars* a_parVars);  bool RemoveRect(Rect* a_rect, const DATATYPE& a_id, Node** a_root);  bool RemoveRectRec(Rect* a_rect, const DATATYPE& a_id, Node* a_node, ListNode** a_listNode);  ListNode* AllocListNode();  void FreeListNode(ListNode* a_listNode);  bool Overlap(Rect* a_rectA, Rect* a_rectB);  void ReInsert(Node* a_node, ListNode** a_listNode);  bool Search(Node* a_node, Rect* a_rect, int& a_foundCount, bool __cdecl a_resultCallback(DATATYPE a_data, void* a_context), void* a_context);  void RemoveAllRec(Node* a_node);  void Reset();  void CountRec(Node* a_node, int& a_count);  bool SaveRec(Node* a_node, RTFileStream& a_stream);  bool LoadRec(Node* a_node, RTFileStream& a_stream);    Node* m_root;                                    ///< Root of tree  ELEMTYPEREAL m_unitSphereVolume;                 ///< Unit sphere constant for required number of dimensions};// Because there is not stream support, this is a quick and dirty file I/O helper.// Users will likely replace its usage with a Stream implementation from their favorite API.class RTFileStream{  FILE* m_file;public:    RTFileStream()  {    m_file = NULL;  }  ~RTFileStream()  {    Close();  }  bool OpenRead(const char* a_fileName)  {    m_file = fopen(a_fileName, "rb");    if(!m_file)    {      return false;    }    return true;  }  bool OpenWrite(const char* a_fileName)  {    m_file = fopen(a_fileName, "wb");    if(!m_file)    {      return false;    }    return true;  }  void Close()  {    if(m_file)    {      fclose(m_file);      m_file = NULL;    }  }  template< typename TYPE >  size_t Write(const TYPE& a_value)  {    ASSERT(m_file);    return fwrite((void*)&a_value, sizeof(a_value), 1, m_file);  }  template< typename TYPE >  size_t WriteArray(const TYPE* a_array, int a_count)  {    ASSERT(m_file);    return fwrite((void*)a_array, sizeof(TYPE) * a_count, 1, m_file);  }  template< typename TYPE >  size_t Read(TYPE& a_value)  {    ASSERT(m_file);    return fread((void*)&a_value, sizeof(a_value), 1, m_file);  }  template< typename TYPE >  size_t ReadArray(TYPE* a_array, int a_count)  {    ASSERT(m_file);    return fread((void*)a_array, sizeof(TYPE) * a_count, 1, m_file);  }};RTREE_TEMPLATERTREE_QUAL::RTree(){  ASSERT(MAXNODES > MINNODES);  ASSERT(MINNODES > 0);  // We only support machine word size simple data type eg. integer index or object pointer.  // Since we are storing as union with non data branch  ASSERT(sizeof(DATATYPE) == sizeof(void*) || sizeof(DATATYPE) == sizeof(int));  // Precomputed volumes of the unit spheres for the first few dimensions  const float UNIT_SPHERE_VOLUMES[] = {    0.000000f, 2.000000f, 3.141593f, // Dimension  0,1,2    4.188790f, 4.934802f, 5.263789f, // Dimension  3,4,5    5.167713f, 4.724766f, 4.058712f, // Dimension  6,7,8    3.298509f, 2.550164f, 1.884104f, // Dimension  9,10,11    1.335263f, 0.910629f, 0.599265f, // Dimension  12,13,14    0.381443f, 0.235331f, 0.140981f, // Dimension  15,16,17    0.082146f, 0.046622f, 0.025807f, // Dimension  18,19,20   };  m_root = AllocNode();  m_root->m_level = 0;  m_unitSphereVolume = (ELEMTYPEREAL)UNIT_SPHERE_VOLUMES[NUMDIMS];}RTREE_TEMPLATERTREE_QUAL::~RTree(){  Reset(); // Free, or reset node memory}RTREE_TEMPLATEvoid RTREE_QUAL::Insert(const ELEMTYPE a_min[NUMDIMS], const ELEMTYPE a_max[NUMDIMS], const DATATYPE& a_dataId){#ifdef _DEBUG  for(int index=0; index<NUMDIMS; ++index)  {    ASSERT(a_min[index] <= a_max[index]);  }#endif //_DEBUG  Rect rect;    for(int axis=0; axis<NUMDIMS; ++axis)  {    rect.m_min[axis] = a_min[axis];    rect.m_max[axis] = a_max[axis];  }    InsertRect(&rect, a_dataId, &m_root, 0);}RTREE_TEMPLATEvoid RTREE_QUAL::Remove(const ELEMTYPE a_min[NUMDIMS], const ELEMTYPE a_max[NUMDIMS], const DATATYPE& a_dataId){#ifdef _DEBUG  for(int index=0; index<NUMDIMS; ++index)  {    ASSERT(a_min[index] <= a_max[index]);  }#endif //_DEBUG  Rect rect;    for(int axis=0; axis<NUMDIMS; ++axis)  {    rect.m_min[axis] = a_min[axis];    rect.m_max[axis] = a_max[axis];  }  RemoveRect(&rect, a_dataId, &m_root);}RTREE_TEMPLATEint RTREE_QUAL::Search(const ELEMTYPE a_min[NUMDIMS], const ELEMTYPE a_max[NUMDIMS], bool __cdecl a_resultCallback(DATATYPE a_data, void* a_context), void* a_context){#ifdef _DEBUG  for(int index=0; index<NUMDIMS; ++index)  {    ASSERT(a_min[index] <= a_max[index]);  }#endif //_DEBUG  Rect rect;    for(int axis=0; axis<NUMDIMS; ++axis)  {    rect.m_min[axis] = a_min[axis];    rect.m_max[axis] = a_max[axis];  }  // NOTE: May want to return search result another way, perhaps returning the number of found elements here.  int foundCount = 0;  Search(m_root, &rect, foundCount, a_resultCallback, a_context);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -