QuadtreeNode.cpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. #include "QuadtreeNode.h"
  2. #include "Quadtree.h"
  3. #include <cassert>
  4. using namespace ltbl;
  5. QuadtreeNode::QuadtreeNode(const sf::FloatRect &region, int level, QuadtreeNode* pParent, Quadtree* pQuadtree)
  6. : _pParent(pParent)
  7. , _pQuadtree(pQuadtree)
  8. , _region(region)
  9. , _level(level)
  10. {}
  11. void QuadtreeNode::create(const sf::FloatRect &region, int level, QuadtreeNode* pParent, Quadtree* pQuadtree) {
  12. _hasChildren = false;
  13. _region = region;
  14. _level = level;
  15. _pParent = pParent;
  16. _pQuadtree = pQuadtree;
  17. }
  18. void QuadtreeNode::getPossibleOccupantPosition(QuadtreeOccupant* oc, sf::Vector2i &point) {
  19. // Compare the center of the AABB of the occupant to that of this node to determine
  20. // which child it may (possibly, not certainly) fit in
  21. const sf::Vector2f &occupantCenter = rectCenter(oc->getAABB());
  22. const sf::Vector2f &nodeRegionCenter = rectCenter(_region);
  23. point.x = occupantCenter.x > nodeRegionCenter.x ? 1 : 0;
  24. point.y = occupantCenter.y > nodeRegionCenter.y ? 1 : 0;
  25. }
  26. void QuadtreeNode::addToThisLevel(QuadtreeOccupant* oc) {
  27. oc->_pQuadtreeNode = this;
  28. if (_occupants.find(oc) != _occupants.end())
  29. return;
  30. _occupants.insert(oc);
  31. }
  32. bool QuadtreeNode::addToChildren(QuadtreeOccupant* oc) {
  33. assert(_hasChildren);
  34. sf::Vector2i position;
  35. getPossibleOccupantPosition(oc, position);
  36. QuadtreeNode* pChild = _children[position.x + position.y * 2].get();
  37. // See if the occupant fits in the child at the selected position
  38. if (rectContains(pChild->_region, oc->getAABB())) {
  39. // Fits, so can add to the child and finish
  40. pChild->add(oc);
  41. return true;
  42. }
  43. return false;
  44. }
  45. void QuadtreeNode::partition() {
  46. assert(!_hasChildren);
  47. sf::Vector2f halfRegionDims = rectHalfDims(_region);
  48. sf::Vector2f regionLowerBound = rectLowerBound(_region);
  49. sf::Vector2f regionCenter = rectCenter(_region);
  50. int nextLowerLevel = _level - 1;
  51. for (int x = 0; x < 2; x++)
  52. for (int y = 0; y < 2; y++) {
  53. sf::Vector2f offset(x * halfRegionDims.x, y * halfRegionDims.y);
  54. sf::FloatRect childAABB = rectFromBounds(regionLowerBound + offset, regionCenter + offset);
  55. // Scale up AABB by the oversize multiplier
  56. sf::Vector2f newHalfDims = rectHalfDims(childAABB);
  57. sf::Vector2f center = rectCenter(childAABB);
  58. childAABB = rectFromBounds(center - newHalfDims, center + newHalfDims);
  59. _children[x + y * 2].reset(new QuadtreeNode(childAABB, nextLowerLevel, this, _pQuadtree));
  60. }
  61. _hasChildren = true;
  62. }
  63. void QuadtreeNode::merge() {
  64. if (_hasChildren) {
  65. // Place all occupants at lower levels into this node
  66. getOccupants(_occupants);
  67. destroyChildren();
  68. }
  69. }
  70. void QuadtreeNode::getOccupants(std::unordered_set<QuadtreeOccupant*> &occupants) {
  71. // Iteratively parse subnodes in order to collect all occupants below this node
  72. std::list<QuadtreeNode*> open;
  73. open.push_back(this);
  74. while (!open.empty()) {
  75. // Depth-first (results in less memory usage), remove objects from open list
  76. QuadtreeNode* pCurrent = open.back();
  77. open.pop_back();
  78. // Get occupants
  79. for (std::unordered_set<QuadtreeOccupant*>::iterator it = pCurrent->_occupants.begin(); it != pCurrent->_occupants.end(); it++)
  80. if ((*it) != nullptr) {
  81. // Assign new node
  82. (*it)->_pQuadtreeNode = this;
  83. // Add to this node
  84. occupants.insert(*it);
  85. }
  86. // If the node has children, add them to the open list
  87. if (pCurrent->_hasChildren)
  88. for (int i = 0; i < 4; i++)
  89. open.push_back(pCurrent->_children[i].get());
  90. }
  91. }
  92. void QuadtreeNode::removeForDeletion(std::unordered_set<QuadtreeOccupant*> &occupants) {
  93. // Iteratively parse subnodes in order to collect all occupants below this node
  94. std::list<QuadtreeNode*> open;
  95. open.push_back(this);
  96. while (!open.empty()) {
  97. // Depth-first (results in less memory usage), remove objects from open list
  98. QuadtreeNode* pCurrent = open.back();
  99. open.pop_back();
  100. // Get occupants
  101. for (std::unordered_set<QuadtreeOccupant*>::iterator it = pCurrent->_occupants.begin(); it != pCurrent->_occupants.end(); it++)
  102. if ((*it) != nullptr) {
  103. // Since will be deleted, remove the reference
  104. (*it)->_pQuadtreeNode = nullptr;
  105. // Add to this node
  106. occupants.insert(*it);
  107. }
  108. // If the node has children, add them to the open list
  109. if (pCurrent->_hasChildren)
  110. for (int i = 0; i < 4; i++)
  111. open.push_back(pCurrent->_children[i].get());
  112. }
  113. }
  114. void QuadtreeNode::getAllOccupantsBelow(std::vector<QuadtreeOccupant*> &occupants) {
  115. // Iteratively parse subnodes in order to collect all occupants below this node
  116. std::list<QuadtreeNode*> open;
  117. open.push_back(this);
  118. while (!open.empty()) {
  119. // Depth-first (results in less memory usage), remove objects from open list
  120. QuadtreeNode* pCurrent = open.back();
  121. open.pop_back();
  122. // Get occupants
  123. for (std::unordered_set<QuadtreeOccupant*>::iterator it = pCurrent->_occupants.begin(); it != pCurrent->_occupants.end(); it++)
  124. if ((*it) != nullptr)
  125. // Add to this node
  126. occupants.push_back(*it);
  127. // If the node has children, add them to the open list
  128. if (pCurrent->_hasChildren)
  129. for (int i = 0; i < 4; i++)
  130. open.push_back(pCurrent->_children[i].get());
  131. }
  132. }
  133. void QuadtreeNode::getAllOccupantsBelow(std::unordered_set<QuadtreeOccupant*> &occupants) {
  134. // Iteratively parse subnodes in order to collect all occupants below this node
  135. std::list<QuadtreeNode*> open;
  136. open.push_back(this);
  137. while (!open.empty()) {
  138. // Depth-first (results in less memory usage), remove objects from open list
  139. QuadtreeNode* pCurrent = open.back();
  140. open.pop_back();
  141. // Get occupants
  142. for (std::unordered_set<QuadtreeOccupant*>::iterator it = pCurrent->_occupants.begin(); it != pCurrent->_occupants.end(); it++)
  143. if ((*it) == nullptr)
  144. // Add to this node
  145. occupants.insert(*it);
  146. // If the node has children, add them to the open list
  147. if (pCurrent->_hasChildren)
  148. for (int i = 0; i < 4; i++)
  149. open.push_back(pCurrent->_children[i].get());
  150. }
  151. }
  152. void QuadtreeNode::update(QuadtreeOccupant* oc) {
  153. if (oc == nullptr)
  154. return;
  155. if (!_occupants.empty())
  156. // Remove, may be re-added to this node later
  157. _occupants.erase(oc);
  158. // Propogate upwards, looking for a node that has room (the current one may still have room)
  159. QuadtreeNode* pNode = this;
  160. while (pNode != nullptr) {
  161. pNode->_numOccupantsBelow--;
  162. // If has room for 1 more, found a spot
  163. if (rectContains(pNode->_region, oc->getAABB()))
  164. break;
  165. pNode = pNode->_pParent;
  166. }
  167. // If no node that could contain the occupant was found, add to outside root set
  168. if (pNode == nullptr) {
  169. assert(_pQuadtree != nullptr);
  170. if (_pQuadtree->_outsideRoot.find(oc) != _pQuadtree->_outsideRoot.end())
  171. return;
  172. _pQuadtree->_outsideRoot.insert(oc);
  173. oc->_pQuadtreeNode = nullptr;
  174. }
  175. else // Add to the selected node
  176. pNode->add(oc);
  177. }
  178. void QuadtreeNode::remove(QuadtreeOccupant* oc) {
  179. assert(!_occupants.empty());
  180. // Remove from node
  181. _occupants.erase(oc);
  182. if (oc == nullptr)
  183. return;
  184. // Propogate upwards, merging if there are enough occupants in the node
  185. QuadtreeNode* pNode = this;
  186. while (pNode != nullptr) {
  187. pNode->_numOccupantsBelow--;
  188. if (pNode->_numOccupantsBelow > 0 && static_cast<size_t>(pNode->_numOccupantsBelow) >= _pQuadtree->_minNumNodeOccupants) {
  189. pNode->merge();
  190. break;
  191. }
  192. pNode = pNode->_pParent;
  193. }
  194. }
  195. void QuadtreeNode::add(QuadtreeOccupant* oc) {
  196. assert(oc != nullptr);
  197. _numOccupantsBelow++;
  198. // See if the occupant fits into any children (if there are any)
  199. if (_hasChildren) {
  200. if (addToChildren(oc))
  201. return; // Fit, can stop
  202. }
  203. else {
  204. // Check if we need a new partition
  205. if (_occupants.size() >= _pQuadtree->_maxNumNodeOccupants && static_cast<size_t>(_level) < _pQuadtree->_maxLevels) {
  206. partition();
  207. if (addToChildren(oc))
  208. return;
  209. }
  210. }
  211. // Did not fit in anywhere, add to this level, even if it goes over the maximum size
  212. addToThisLevel(oc);
  213. }