7QuadTree::QuadTree(
float minX,
float minY,
float maxX,
float maxY,
int maxDepth,
int maxPerNode)
8 : rootBounds_(
makeAABB2(minX, minY, maxX, maxY)),
9 maxDepth_(std::max(1, maxDepth)),
10 maxPerNode_(std::max(1, maxPerNode)) {
11 if (!rootBounds_.
valid() || rootBounds_.
width() <= 0.f || rootBounds_.
height() <= 0.f) {
12 throw Exception(
"QuadTree: bounds must have positive area");
17QuadTree::Node *QuadTree::ensureRoot() {
19 root_ = std::make_unique<Node>();
20 root_->bounds = rootBounds_;
37 if (!
b.valid())
return false;
42 if (!insertInto(*ensureRoot(),
id,
b)) {
44 ensureRoot()->itemIds.push_back(
id);
58 return insert(
id, minX, minY, maxX, maxY);
61void QuadTree::rebuild() {
65 for (
const auto &kv : items_) {
66 if (!insertInto(*root_, kv.first, kv.second)) {
67 root_->itemIds.push_back(kv.first);
72bool QuadTree::insertInto(Node &node,
int id,
const AABB2 &bounds) {
73 if (!
node.bounds.containsAABB(bounds) &&
node.depth == 0) {
75 if (!
node.bounds.intersectsAABB(bounds))
return false;
76 }
else if (
node.depth > 0 && !
node.bounds.containsAABB(bounds)) {
81 node.itemIds.push_back(
id);
82 if (
static_cast<int>(
node.itemIds.size()) > maxPerNode_ &&
node.depth < maxDepth_) {
88 for (
int i = 0; i < 4; ++i) {
93 node.itemIds.push_back(
id);
97void QuadTree::split(Node &node) {
98 const float mx =
node.bounds.centerX();
99 const float my =
node.bounds.centerY();
100 const AABB2 quads[4] = {
106 for (
int i = 0; i < 4; ++i) {
112 std::vector<int> remain;
113 remain.reserve(
node.itemIds.size());
114 for (
int id :
node.itemIds) {
115 auto it = items_.find(
id);
116 if (it == items_.end())
continue;
118 for (
int i = 0; i < 4; ++i) {
119 if (
node.
children[i]->bounds.containsAABB(it->second)) {
125 if (!placed) remain.push_back(
id);
127 node.itemIds.swap(remain);
130void QuadTree::collect(Node &node,
const AABB2 *rect,
float cx,
float cy,
float radius,
132 if (rect && !
node.bounds.intersectsAABB(*rect))
return;
133 if (useCircle && !
node.bounds.intersectsCircle(
cx,
cy, radius))
return;
135 for (
int id :
node.itemIds) {
136 auto it = items_.find(
id);
137 if (it == items_.end())
continue;
138 const AABB2 &
b = it->second;
141 hit =
b.intersectsAABB(*rect);
142 }
else if (useCircle) {
143 hit =
b.intersectsCircle(
cx,
cy, radius);
145 hit =
b.containsPoint(
cx,
cy);
150 if (!
node.isLeaf()) {
151 for (
int i = 0; i < 4; ++i) {
159 collect(*ensureRoot(),
nullptr,
x,
y, 0.f,
false);
166 collect(*ensureRoot(), &rect, 0.f, 0.f, 0.f,
false);
172 if (radius < 0.f) radius = 0.f;
173 collect(*ensureRoot(),
nullptr,
cx,
cy, radius,
true);
bool contains(int id) const
bool insert(int id, float minX, float minY, float maxX, float maxY)
bool update(int id, float minX, float minY, float maxX, float maxY)
int queryPoint(float x, float y)
int queryRect(float minX, float minY, float maxX, float maxY)
QuadTree(float minX, float minY, float maxX, float maxY, int maxDepth=8, int maxPerNode=8)
int queryCircle(float cx, float cy, float radius)
NodeDesc node(std::string id, std::vector< NodeDesc > children, std::string name)
AABB2 makeAABB2(float minX, float minY, float maxX, float maxY)
std::vector< NodeDesc > children