| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284 | #include "QuadtreeNode.h"#include "Quadtree.h"#include <cassert>using namespace ltbl;QuadtreeNode::QuadtreeNode(const sf::FloatRect ®ion, int level, QuadtreeNode* pParent, Quadtree* pQuadtree)    : _pParent(pParent)    , _pQuadtree(pQuadtree)    , _region(region)    , _level(level){}void QuadtreeNode::create(const sf::FloatRect ®ion, int level, QuadtreeNode* pParent, Quadtree* pQuadtree) {    _hasChildren = false;    _region = region;    _level = level;    _pParent = pParent;    _pQuadtree = pQuadtree;}void QuadtreeNode::getPossibleOccupantPosition(QuadtreeOccupant* oc, sf::Vector2i &point) {    // Compare the center of the AABB of the occupant to that of this node to determine    // which child it may (possibly, not certainly) fit in    const sf::Vector2f &occupantCenter = rectCenter(oc->getAABB());    const sf::Vector2f &nodeRegionCenter = rectCenter(_region);    point.x = occupantCenter.x > nodeRegionCenter.x ? 1 : 0;    point.y = occupantCenter.y > nodeRegionCenter.y ? 1 : 0;}void QuadtreeNode::addToThisLevel(QuadtreeOccupant* oc) {    oc->_pQuadtreeNode = this;    if (_occupants.find(oc) != _occupants.end())        return;    _occupants.insert(oc);}bool QuadtreeNode::addToChildren(QuadtreeOccupant* oc) {    assert(_hasChildren);    sf::Vector2i position;    getPossibleOccupantPosition(oc, position);    QuadtreeNode* pChild = _children[position.x + position.y * 2].get();    // See if the occupant fits in the child at the selected position    if (rectContains(pChild->_region, oc->getAABB())) {        // Fits, so can add to the child and finish        pChild->add(oc);        return true;    }    return false;}void QuadtreeNode::partition() {    assert(!_hasChildren);    sf::Vector2f halfRegionDims = rectHalfDims(_region);    sf::Vector2f regionLowerBound = rectLowerBound(_region);    sf::Vector2f regionCenter = rectCenter(_region);    int nextLowerLevel = _level - 1;    for (int x = 0; x < 2; x++)        for (int y = 0; y < 2; y++) {            sf::Vector2f offset(x * halfRegionDims.x, y * halfRegionDims.y);            sf::FloatRect childAABB = rectFromBounds(regionLowerBound + offset, regionCenter + offset);            // Scale up AABB by the oversize multiplier            sf::Vector2f newHalfDims = rectHalfDims(childAABB);            sf::Vector2f center = rectCenter(childAABB);            childAABB = rectFromBounds(center - newHalfDims, center + newHalfDims);            _children[x + y * 2].reset(new QuadtreeNode(childAABB, nextLowerLevel, this, _pQuadtree));        }    _hasChildren = true;}void QuadtreeNode::merge() {    if (_hasChildren) {        // Place all occupants at lower levels into this node        getOccupants(_occupants);        destroyChildren();    }}void QuadtreeNode::getOccupants(std::unordered_set<QuadtreeOccupant*> &occupants) {    // Iteratively parse subnodes in order to collect all occupants below this node    std::list<QuadtreeNode*> open;    open.push_back(this);    while (!open.empty()) {        // Depth-first (results in less memory usage), remove objects from open list        QuadtreeNode* pCurrent = open.back();        open.pop_back();        // Get occupants        for (std::unordered_set<QuadtreeOccupant*>::iterator it = pCurrent->_occupants.begin(); it != pCurrent->_occupants.end(); it++)            if ((*it) != nullptr) {                // Assign new node                (*it)->_pQuadtreeNode = this;                // Add to this node                occupants.insert(*it);            }        // If the node has children, add them to the open list        if (pCurrent->_hasChildren)            for (int i = 0; i < 4; i++)                open.push_back(pCurrent->_children[i].get());    }}void QuadtreeNode::removeForDeletion(std::unordered_set<QuadtreeOccupant*> &occupants) {    // Iteratively parse subnodes in order to collect all occupants below this node    std::list<QuadtreeNode*> open;    open.push_back(this);    while (!open.empty()) {        // Depth-first (results in less memory usage), remove objects from open list        QuadtreeNode* pCurrent = open.back();        open.pop_back();        // Get occupants        for (std::unordered_set<QuadtreeOccupant*>::iterator it = pCurrent->_occupants.begin(); it != pCurrent->_occupants.end(); it++)            if ((*it) != nullptr) {                // Since will be deleted, remove the reference                (*it)->_pQuadtreeNode = nullptr;                // Add to this node                occupants.insert(*it);            }        // If the node has children, add them to the open list        if (pCurrent->_hasChildren)            for (int i = 0; i < 4; i++)                open.push_back(pCurrent->_children[i].get());    }}void QuadtreeNode::getAllOccupantsBelow(std::vector<QuadtreeOccupant*> &occupants) {    // Iteratively parse subnodes in order to collect all occupants below this node    std::list<QuadtreeNode*> open;    open.push_back(this);    while (!open.empty()) {        // Depth-first (results in less memory usage), remove objects from open list        QuadtreeNode* pCurrent = open.back();        open.pop_back();        // Get occupants        for (std::unordered_set<QuadtreeOccupant*>::iterator it = pCurrent->_occupants.begin(); it != pCurrent->_occupants.end(); it++)            if ((*it) != nullptr)                // Add to this node                occupants.push_back(*it);        // If the node has children, add them to the open list        if (pCurrent->_hasChildren)            for (int i = 0; i < 4; i++)                open.push_back(pCurrent->_children[i].get());    }}void QuadtreeNode::getAllOccupantsBelow(std::unordered_set<QuadtreeOccupant*> &occupants) {    // Iteratively parse subnodes in order to collect all occupants below this node    std::list<QuadtreeNode*> open;    open.push_back(this);    while (!open.empty()) {        // Depth-first (results in less memory usage), remove objects from open list        QuadtreeNode* pCurrent = open.back();        open.pop_back();        // Get occupants        for (std::unordered_set<QuadtreeOccupant*>::iterator it = pCurrent->_occupants.begin(); it != pCurrent->_occupants.end(); it++)            if ((*it) == nullptr)                // Add to this node                occupants.insert(*it);        // If the node has children, add them to the open list        if (pCurrent->_hasChildren)            for (int i = 0; i < 4; i++)                open.push_back(pCurrent->_children[i].get());    }}void QuadtreeNode::update(QuadtreeOccupant* oc) {    if (oc == nullptr)        return;    if (!_occupants.empty())        // Remove, may be re-added to this node later        _occupants.erase(oc);    // Propogate upwards, looking for a node that has room (the current one may still have room)    QuadtreeNode* pNode = this;    while (pNode != nullptr) {        pNode->_numOccupantsBelow--;        // If has room for 1 more, found a spot        if (rectContains(pNode->_region, oc->getAABB()))            break;        pNode = pNode->_pParent;    }    // If no node that could contain the occupant was found, add to outside root set    if (pNode == nullptr) {        assert(_pQuadtree != nullptr);        if (_pQuadtree->_outsideRoot.find(oc) != _pQuadtree->_outsideRoot.end())            return;        _pQuadtree->_outsideRoot.insert(oc);        oc->_pQuadtreeNode = nullptr;    }    else // Add to the selected node        pNode->add(oc);}void QuadtreeNode::remove(QuadtreeOccupant* oc) {    assert(!_occupants.empty());    // Remove from node    _occupants.erase(oc);    if (oc == nullptr)        return;    // Propogate upwards, merging if there are enough occupants in the node    QuadtreeNode* pNode = this;    while (pNode != nullptr) {        pNode->_numOccupantsBelow--;        if (pNode->_numOccupantsBelow > 0 && static_cast<size_t>(pNode->_numOccupantsBelow) >= _pQuadtree->_minNumNodeOccupants) {            pNode->merge();            break;        }        pNode = pNode->_pParent;    }}void QuadtreeNode::add(QuadtreeOccupant* oc) {    assert(oc != nullptr);    _numOccupantsBelow++;    // See if the occupant fits into any children (if there are any)    if (_hasChildren) {        if (addToChildren(oc))            return; // Fit, can stop    }    else {        // Check if we need a new partition        if (_occupants.size() >= _pQuadtree->_maxNumNodeOccupants && static_cast<size_t>(_level) < _pQuadtree->_maxLevels) {            partition();            if (addToChildren(oc))                return;        }    }    // Did not fit in anywhere, add to this level, even if it goes over the maximum size    addToThisLevel(oc);}
 |