我目前正在C++中实现自己的C++。它运行良好的100项,但一旦你开始增加更多,它减慢。remove、getAll和insert都被描述为需要一段时间。如有任何建议,敬请谅解!
class QuadTree {
private:
const static int MAX_OBJECTS = 20;
AABB bounds;
std::vector<QuadTree> children;
std::set<Locatable*> entities;
std::set<Locatable*> allEntities;
// Internal methods
void split() {
children.clear();
double width = (bounds.getWidth() / 2);
double height = (bounds.getHeight() / 2);
double x = bounds.getX();
double y = bounds.getY();
children.push_back(QuadTree(AABB(x + width, y, width, height)));
children.push_back(QuadTree(AABB(x, y, width, height)));
children.push_back(QuadTree(AABB(x, y + height, width, height)));
children.push_back(QuadTree(AABB(x + width, y + height, width, height)));
}
int getIndex(AABB& aabb) {
double vertMid = bounds.getVertMid();
double horzMid = bounds.getHorzMid();
// Fits in top
bool topQuadrant = aabb.getY() + aabb.getHeight() < horzMid;
// Fits in botom
bool bottomQuadrant = aabb.getY() > horzMid;
// Fits in left
if (aabb.getX() + aabb.getWidth() < vertMid) {
if (topQuadrant) {
return 1;
} else if (bottomQuadrant) {
return 2;
}
}
// Fits in right
else if (aabb.getX() > vertMid) {
if (topQuadrant) {
return 0;
} else if (bottomQuadrant) {
return 3;
}
}
return -1;
}
void merge(std::set<Locatable*>& one, std::set<Locatable*> two) {
one.insert(two.begin(), two.end());
}
// End Internal methods
public:
QuadTree(AABB bounds) : bounds(bounds) {
children.reserve(4);
}
// Base
void clear() {
entities.clear();
allEntities.clear();
for (auto it = children.begin(); it != children.end(); it++) {
it->clear();
}
children.clear();
}
void insert(Locatable* object) {
AABB aabb = object->getAABB();
allEntities.insert(object);
if (entities.size() > MAX_OBJECTS) {
if (children.empty()) {
split();
auto it = entities.begin();
while (it != entities.end()) {
int index = getIndex((*it)->getAABB());
if (index != -1) {
children.at(index).insert(*it);
it = entities.erase(it);
}
else {
it++;
}
}
}
int index = getIndex(aabb);
if (index != -1) {
children.at(index).insert(object);
}
else {
entities.insert(object);
}
}
else {
entities.insert(object);
}
}
void remove(Locatable* object, AABB aabb) {
auto it = allEntities.find(object);
if (it == allEntities.end()) {
return;
}
allEntities.erase(it);
it = entities.find(object);
if (it == entities.end()) {
if (!children.empty()) {
int index = getIndex(aabb);
if (index != -1) {
children.at(index).remove(object, aabb);
}
}
}
else {
entities.erase(it);
}
}
QuadTree* getLowestRoot(AABB aabb) {
int index = getIndex(aabb);
if (index == -1 || children.empty()) {
return this;
}
return children.at(index).getLowestRoot(aabb);
}
std::set<Locatable*> getAll() {
std::set<Locatable*> result;
if (children.empty()) {
return entities;
}
result = entities;
for (auto it = children.begin(); it != children.end(); it++) {
merge(result, it->getAll());
}
return result;
}
// End Base
};发布于 2014-03-24 09:43:56
。
class AABB
{
public:
AABB(double minX,double minY,double maxX,double maxY);
double getMinX() const;
double getMinY() const;
double getMaxX() const;
double getMaxY() const;
double getMidX() const;
double getMidY() const;
int getQuad(const AABB& aabb) const;
private:
int getQuad(double x,double y) const;
private:
double minX;
double minY;
double maxX;
double maxY;
double midX;
double midY;
};
AABB::AABB(double minX_,double minY_,double maxX_,double maxY_)
:minX(minX_),
minY(minY_),
maxX(maxX_),
maxY(maxY_),
midX((minX_+maxX_)/2.0),
midY((minY_+maxY_)/2.0)
{}
double AABB::getMinX() const
{
return minX;
}
double AABB::getMinY() const
{
return minY;
}
double AABB::getMaxX() const
{
return maxX;
}
double AABB::getMaxY() const
{
return maxY;
}
double AABB::getMidX() const
{
return midX;
}
double AABB::getMidY() const
{
return midY;
}
int AABB::getQuad(const AABB& aabb) const
{
int tl = getQuad(aabb.getMinX(),aabb.getMinY());
int br = getQuad(aabb.getMaxX(),aabb.getMaxY());
if(tl==br)
return tl;
return -1;
}
int AABB::getQuad(double x,double y) const
{
if(y<getMidY())
{
if(x<getMidX())
return 1;
else
return 0;
}
else
{
if(x<getMidX())
return 2;
else
return 3;
}
}const AABB& getAABB() const;这些变量是多余的,维护它们都需要太多的开销。与getAll()相比,您应该消除的调用频率取决于调用insert()getAll()的频率。这两个版本都在下面。我对正确性所做的测试很少,所以您可能希望确保这些测试具有与当前版本相同的输出。
class QuadTree
{
private:
static const int MAX_OBJECTS = 20;
public:
QuadTree(const AABB& bounds);
void clear();
void insert(Locatable* object);
void remove(Locatable* object);
void remove(Locatable* object,const AABB& aabb);
QuadTree* getLowestRoot(const AABB& aabb);
const std::unordered_set<Locatable*>& getAll() const;
const std::unordered_set<Locatable*>& getAllIn(const AABB& aabb) const;
private:
void split();
private:
AABB bounds;
std::vector<QuadTree> children;
std::unordered_set<Locatable*> allEntities;
};
QuadTree::QuadTree(const AABB& bounds)
:bounds(bounds)
{
children.reserve(4);
}
void QuadTree::clear()
{
allEntities.clear();
children.clear();
}
void QuadTree::insert(Locatable* object)
{
allEntities.emplace(object);
if(children.empty())
{
if(allEntities.size() > MAX_OBJECTS)
split();
}
else
{
int index = bounds.getQuad(object->getAABB());
if(index!=-1)
children.at(index).insert(object);
}
}
void QuadTree::remove(Locatable* object)
{
if(allEntities.erase(object)!=0 && !children.empty())
{
int index = bounds.getQuad(object->getAABB());
if (index != -1)
children.at(index).remove(object);
}
}
void QuadTree::remove(Locatable* object,const AABB& aabb)
{
if(allEntities.erase(object)!=0 && !children.empty())
{
int index = bounds.getQuad(aabb);
if (index != -1)
children.at(index).remove(object),aabb;
}
}
QuadTree* QuadTree::getLowestRoot(const AABB& aabb)
{
if(children.empty())
return this;
int index = bounds.getQuad(aabb);
if(index == -1)
return this;
return children.at(index).getLowestRoot(aabb);
}
const std::unordered_set<Locatable*>& QuadTree::getAll() const
{
return allEntities;
}
const std::unordered_set<Locatable*>& QuadTree::getAllIn(const AABB& aabb) const
{
if(children.empty())
return allEntities;
int index = bounds.getQuad(aabb);
if(index == -1)
return allEntities;
return children.at(index).getAllIn(aabb);
}
void QuadTree::split()
{
children.emplace_back(AABB(bounds.getMidX(),bounds.getMinY(),bounds.getMaxX(),bounds.getMidY()));
children.emplace_back(AABB(bounds.getMinX(),bounds.getMinY(),bounds.getMidX(),bounds.getMidY()));
children.emplace_back(AABB(bounds.getMinX(),bounds.getMidY(),bounds.getMidX(),bounds.getMaxY()));
children.emplace_back(AABB(bounds.getMidX(),bounds.getMidY(),bounds.getMaxX(),bounds.getMaxY()));
for(Locatable* l : allEntities)
{
int index = bounds.getQuad(l->getAABB());
if(index!=-1)
children.at(index).insert(l);
}
}。
class QuadTree
{
private:
static const int MAX_OBJECTS = 20;
public:
QuadTree(const AABB& bounds);
void clear();
void insert(Locatable* object);
void remove(Locatable* object);
void remove(Locatable* object,const AABB& aabb);
QuadTree* getLowestRoot(const AABB& aabb);
void getAll(std::unordered_set<Locatable*>& all) const;
void getAllIn(std::unordered_set<Locatable*>& all,const AABB& aabb) const;
private:
void split();
private:
AABB bounds;
std::vector<QuadTree> children;
std::unordered_set<Locatable*> entities;
};
QuadTree::QuadTree(const AABB& bounds)
:bounds(bounds)
{
children.reserve(4);
}
void QuadTree::clear()
{
entities.clear();
children.clear();
}
void QuadTree::insert(Locatable* object)
{
if(children.empty())
{
entities.emplace(object);
if(entities.size() > MAX_OBJECTS)
split();
}
else
{
int index = bounds.getQuad(object->getAABB());
if(index==-1)
entities.emplace(object);
else
children.at(index).insert(object);
}
}
void QuadTree::remove(Locatable* object)
{
if(entities.erase(object)==0 && !children.empty())
{
int index = bounds.getQuad(object->getAABB());
if(index!=-1)
children.at(index).remove(object);
}
}
void QuadTree::remove(Locatable* object,const AABB& aabb)
{
if(entities.erase(object)==0 && !children.empty())
{
int index = bounds.getQuad(aabb);
if(index!=-1)
children.at(index).remove(object,aabb);
}
}
QuadTree* QuadTree::getLowestRoot(const AABB& aabb)
{
if(children.empty())
return this;
int index = bounds.getQuad(aabb);
if(index == -1)
return this;
return children.at(index).getLowestRoot(aabb);
}
void QuadTree::getAll(std::unordered_set<Locatable*>& all) const
{
for(Locatable* l : entities)
all.emplace(l);
if(!children.empty())
{
children.at(0).getAll(all);
children.at(1).getAll(all);
children.at(2).getAll(all);
children.at(3).getAll(all);
}
}
void QuadTree::getAllIn(std::unordered_set<Locatable*>& all,const AABB& aabb) const
{
if(children.empty())
{
getAll(all);
return;
}
int index = bounds.getQuad(aabb);
if(index == -1)
{
getAll(all);
return;
}
return children.at(index).getAllIn(all,aabb);
}
void QuadTree::split()
{
children.emplace_back(AABB(bounds.getMidX(),bounds.getMinY(),bounds.getMaxX(),bounds.getMidY()));
children.emplace_back(AABB(bounds.getMinX(),bounds.getMinY(),bounds.getMidX(),bounds.getMidY()));
children.emplace_back(AABB(bounds.getMinX(),bounds.getMidY(),bounds.getMidX(),bounds.getMaxY()));
children.emplace_back(AABB(bounds.getMidX(),bounds.getMidY(),bounds.getMaxX(),bounds.getMaxY()));
auto cit = entities.cbegin();
while(cit!=entities.cend())
{
int index = bounds.getQuad((*cit)->getAABB());
if(index!=-1)
{
children.at(index).insert(*cit);
cit = entities.erase(cit);
}
else
++cit;
}
}https://codereview.stackexchange.com/questions/45178
复制相似问题