The following source code is working Quad Tree Implementation in C++11. How can I simplify the source code but also allow the user to bring his own Point Class Implementation?
#pragma once
#include <algorithm>
#include <array>
#include <cstddef>
#include <functional>
#include <vector>
namespace forest {
template <typename T, std::size_t Capacity>
class QuadTree {
public:
using Point = std::array<T, 2>;
using Points = std::vector<Point>;
using PointsIt = typename std::vector<Point>::iterator;
using Callback = std::function<void(const Point &)>;
public:
class Range {
template <typename U, std::size_t K>
friend class QuadTree;
private:
Point mOrigin;
Point mTransform;
public:
Range() = default;
Range(const Point &origin, const Point &transform)
: mOrigin(origin), mTransform(transform) {}
~Range() = default;
public:
void setOrigin(const Point &origin) { mOrigin = origin; }
void setTransform(const Point &transform) { mTransform = transform; }
public:
Point getOrigin() const { return mOrigin; }
Point getTransform() const { return mTransform; }
public:
bool Contains(const Point &point) const {
return point[0] >= mOrigin[0] - mTransform[0] &&
point[0] <= mOrigin[0] + mTransform[0] &&
point[1] >= mOrigin[1] - mTransform[1] &&
point[1] <= mOrigin[1] + mTransform[1];
}
bool Intersects(const Range &other) const {
return mOrigin[0] - mTransform[0] <=
other.mOrigin[0] + other.mTransform[0] &&
mOrigin[0] + mTransform[0] >=
other.mOrigin[0] - other.mTransform[0] &&
mOrigin[1] - mTransform[1] <=
other.mOrigin[1] + other.mTransform[1] &&
mOrigin[1] + mTransform[1] >=
other.mOrigin[1] - other.mTransform[1];
}
};
private:
Points mBucket;
private:
Range mBoundary;
private:
bool mDivided{false};
private:
QuadTree *NW{nullptr};
QuadTree *NE{nullptr};
QuadTree *SW{nullptr};
QuadTree *SE{nullptr};
private:
void Divide() {
NW = new QuadTree<T, Capacity>(
{{mBoundary.mOrigin[0] - mBoundary.mTransform[0] / 2,
mBoundary.mOrigin[1] + mBoundary.mTransform[1] / 2},
{mBoundary.mTransform[0] / 2, mBoundary.mTransform[1] / 2}});
NE = new QuadTree<T, Capacity>(
{{mBoundary.mOrigin[0] + mBoundary.mTransform[0] / 2,
mBoundary.mOrigin[1] + mBoundary.mTransform[1] / 2},
{mBoundary.mTransform[0] / 2, mBoundary.mTransform[1] / 2}});
SW = new QuadTree<T, Capacity>(
{{mBoundary.mOrigin[0] - mBoundary.mTransform[0] / 2,
mBoundary.mOrigin[1] - mBoundary.mTransform[1] / 2},
{mBoundary.mTransform[0] / 2, mBoundary.mTransform[1] / 2}});
SE = new QuadTree<T, Capacity>(
{{mBoundary.mOrigin[0] + mBoundary.mTransform[0] / 2,
mBoundary.mOrigin[1] - mBoundary.mTransform[1] / 2},
{mBoundary.mTransform[0] / 2, mBoundary.mTransform[1] / 2}});
mDivided = true;
}
void Merge() {
delete NW;
delete NE;
delete SW;
delete SE;
NW = nullptr;
NE = nullptr;
SW = nullptr;
SE = nullptr;
mDivided = false;
}
public:
QuadTree() = delete;
QuadTree(const Range &BOUNDARY) : mBoundary(BOUNDARY) {}
~QuadTree() { Clear(); }
public:
bool Insert(const Point &point) {
if (!mBoundary.Contains(point)) return false;
if (!mDivided) {
if (std::find(mBucket.begin(), mBucket.end(), point) != mBucket.end())
return false;
mBucket.push_back(point);
if (mBucket.size() > Capacity) {
Divide();
PointsIt it = mBucket.begin();
while (it != mBucket.end()) {
if (NW->mBoundary.Contains(*it))
NW->Insert(*it);
else if (NE->mBoundary.Contains(*it))
NE->Insert(*it);
else if (SW->mBoundary.Contains(*it))
SW->Insert(*it);
else if (SE->mBoundary.Contains(*it))
SE->Insert(*it);
it = mBucket.erase(it);
}
}
return true;
}
return NW->Insert(point) || NE->Insert(point) || SW->Insert(point) ||
SE->Insert(point);
}
bool Remove(const Point &point) {
if (!mBoundary.Contains(point)) return false;
if (!mDivided) {
PointsIt begin = mBucket.begin();
PointsIt end = mBucket.end();
mBucket.erase(std::remove(begin, end, point), end);
return true;
}
if (NW->Remove(point) || NE->Remove(point) || SW->Remove(point) ||
SE->Remove(point)) {
if (!NW->mDivided && !NE->mDivided && !SW->mDivided && !SE->mDivided) {
if (NW->mBucket.empty() && NE->mBucket.empty() && SW->mBucket.empty() &&
SE->mBucket.empty()) {
Merge();
}
}
return true;
}
return false;
}
bool Search(const Point &point) {
if (!mBoundary.Contains(point)) return false;
if (mDivided) {
return NW->Search(point) || NE->Search(point) || SW->Search(point) ||
SE->Search(point);
}
return std::find(mBucket.begin(), mBucket.end(), point) != mBucket.end();
}
void Query(const Range &range, const Callback callback) {
if (!range.Intersects(mBoundary)) return;
if (mDivided) {
NW->Query(range, callback);
NE->Query(range, callback);
SW->Query(range, callback);
SE->Query(range, callback);
} else {
for (auto child : mBucket) {
if (range.Contains(child)) {
callback(child);
}
}
}
}
public:
void Clear() {
if (mDivided) {
NW->Clear();
NE->Clear();
SW->Clear();
SE->Clear();
}
mBucket.clear();
Merge();
}
};
} // namespace forest