载入中...
搜索中...
未找到
QuadTree.cpp
浏览该文件的文档.
1#include "spatial/QuadTree.h"
2
3#include "common/Exception.h"
4
5namespace eve::spatial {
6
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");
13 }
14 ensureRoot();
15}
16
17QuadTree::Node *QuadTree::ensureRoot() {
18 if (!root_) {
19 root_ = std::make_unique<Node>();
20 root_->bounds = rootBounds_;
21 root_->depth = 0;
22 }
23 return root_.get();
24}
25
27 items_.clear();
28 results_.clear();
29 root_.reset();
30 ensureRoot();
31}
32
33bool QuadTree::contains(int id) const { return items_.find(id) != items_.end(); }
34
35bool QuadTree::insert(int id, float minX, float minY, float maxX, float maxY) {
36 AABB2 b = makeAABB2(minX, minY, maxX, maxY);
37 if (!b.valid()) return false;
38 if (contains(id)) {
39 remove(id);
40 }
41 items_[id] = b;
42 if (!insertInto(*ensureRoot(), id, b)) {
43 // Outside root or failed fit: keep in map but force root storage.
44 ensureRoot()->itemIds.push_back(id);
45 }
46 return true;
47}
48
49bool QuadTree::remove(int id) {
50 if (!contains(id)) return false;
51 items_.erase(id);
52 rebuild();
53 return true;
54}
55
56bool QuadTree::update(int id, float minX, float minY, float maxX, float maxY) {
57 if (!contains(id)) return false;
58 return insert(id, minX, minY, maxX, maxY);
59}
60
61void QuadTree::rebuild() {
62 results_.clear();
63 root_.reset();
64 ensureRoot();
65 for (const auto &kv : items_) {
66 if (!insertInto(*root_, kv.first, kv.second)) {
67 root_->itemIds.push_back(kv.first);
68 }
69 }
70}
71
72bool QuadTree::insertInto(Node &node, int id, const AABB2 &bounds) {
73 if (!node.bounds.containsAABB(bounds) && node.depth == 0) {
74 // Allow root to hold items that extend slightly outside.
75 if (!node.bounds.intersectsAABB(bounds)) return false;
76 } else if (node.depth > 0 && !node.bounds.containsAABB(bounds)) {
77 return false;
78 }
79
80 if (node.isLeaf()) {
81 node.itemIds.push_back(id);
82 if (static_cast<int>(node.itemIds.size()) > maxPerNode_ && node.depth < maxDepth_) {
83 split(node);
84 }
85 return true;
86 }
87
88 for (int i = 0; i < 4; ++i) {
89 if (node.children[i] && node.children[i]->bounds.containsAABB(bounds)) {
90 return insertInto(*node.children[i], id, bounds);
91 }
92 }
93 node.itemIds.push_back(id);
94 return true;
95}
96
97void QuadTree::split(Node &node) {
98 const float mx = node.bounds.centerX();
99 const float my = node.bounds.centerY();
100 const AABB2 quads[4] = {
101 makeAABB2(node.bounds.minX, node.bounds.minY, mx, my),
102 makeAABB2(mx, node.bounds.minY, node.bounds.maxX, my),
103 makeAABB2(node.bounds.minX, my, mx, node.bounds.maxY),
104 makeAABB2(mx, my, node.bounds.maxX, node.bounds.maxY),
105 };
106 for (int i = 0; i < 4; ++i) {
107 node.children[i] = std::make_unique<Node>();
108 node.children[i]->bounds = quads[i];
109 node.children[i]->depth = node.depth + 1;
110 }
111
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;
117 bool placed = false;
118 for (int i = 0; i < 4; ++i) {
119 if (node.children[i]->bounds.containsAABB(it->second)) {
120 node.children[i]->itemIds.push_back(id);
121 placed = true;
122 break;
123 }
124 }
125 if (!placed) remain.push_back(id);
126 }
127 node.itemIds.swap(remain);
128}
129
130void QuadTree::collect(Node &node, const AABB2 *rect, float cx, float cy, float radius,
131 bool useCircle) {
132 if (rect && !node.bounds.intersectsAABB(*rect)) return;
133 if (useCircle && !node.bounds.intersectsCircle(cx, cy, radius)) return;
134
135 for (int id : node.itemIds) {
136 auto it = items_.find(id);
137 if (it == items_.end()) continue;
138 const AABB2 &b = it->second;
139 bool hit = false;
140 if (rect) {
141 hit = b.intersectsAABB(*rect);
142 } else if (useCircle) {
143 hit = b.intersectsCircle(cx, cy, radius);
144 } else {
145 hit = b.containsPoint(cx, cy);
146 }
147 if (hit) results_.addUnique(id);
148 }
149
150 if (!node.isLeaf()) {
151 for (int i = 0; i < 4; ++i) {
152 if (node.children[i]) collect(*node.children[i], rect, cx, cy, radius, useCircle);
153 }
154 }
155}
156
157int QuadTree::queryPoint(float x, float y) {
158 results_.clear();
159 collect(*ensureRoot(), nullptr, x, y, 0.f, false);
160 return results_.getCount();
161}
162
163int QuadTree::queryRect(float minX, float minY, float maxX, float maxY) {
164 results_.clear();
165 AABB2 rect = makeAABB2(minX, minY, maxX, maxY);
166 collect(*ensureRoot(), &rect, 0.f, 0.f, 0.f, false);
167 return results_.getCount();
168}
169
170int QuadTree::queryCircle(float cx, float cy, float radius) {
171 results_.clear();
172 if (radius < 0.f) radius = 0.f;
173 collect(*ensureRoot(), nullptr, cx, cy, radius, true);
174 return results_.getCount();
175}
176
177} // namespace eve::spatial
float cx
Definition CardTypes.cpp:31
float cy
Definition CardTypes.cpp:32
std::string id
int y
Definition Grass.cpp:135
int x
Definition Grass.cpp:135
uint32_t b
bool contains(int id) const
Definition QuadTree.cpp:33
bool insert(int id, float minX, float minY, float maxX, float maxY)
Definition QuadTree.cpp:35
bool update(int id, float minX, float minY, float maxX, float maxY)
Definition QuadTree.cpp:56
int queryPoint(float x, float y)
Definition QuadTree.cpp:157
int queryRect(float minX, float minY, float maxX, float maxY)
Definition QuadTree.cpp:163
QuadTree(float minX, float minY, float maxX, float maxY, int maxDepth=8, int maxPerNode=8)
Definition QuadTree.cpp:7
int queryCircle(float cx, float cy, float radius)
Definition QuadTree.cpp:170
bool remove(int id)
Definition QuadTree.cpp:49
int getCount() const
Definition QueryIds.h:24
void addUnique(int id)
Definition QueryIds.h:15
NodeDesc node(std::string id, std::vector< NodeDesc > children, std::string name)
Definition NodeDesc.cpp:214
AABB2 makeAABB2(float minX, float minY, float maxX, float maxY)
Definition Bounds.h:85
std::vector< NodeDesc > children
Definition NodeDesc.h:33
bool valid() const
Definition Bounds.h:20
float width() const
Definition Bounds.h:15
float height() const
Definition Bounds.h:16