载入中...
搜索中...
未找到
Octree.cpp
浏览该文件的文档.
1#include "spatial/Octree.h"
2
3#include "common/Exception.h"
4
5namespace eve::spatial {
6
7Octree::Octree(float minX, float minY, float minZ, float maxX, float maxY, float maxZ,
8 int maxDepth, int maxPerNode)
9 : rootBounds_(makeAABB3(minX, minY, minZ, maxX, maxY, maxZ)),
10 maxDepth_(std::max(1, maxDepth)),
11 maxPerNode_(std::max(1, maxPerNode)) {
12 if (!rootBounds_.valid() || rootBounds_.width() <= 0.f || rootBounds_.height() <= 0.f ||
13 rootBounds_.depth() <= 0.f) {
14 throw Exception("Octree: bounds must have positive volume");
15 }
16 ensureRoot();
17}
18
19Octree::Node *Octree::ensureRoot() {
20 if (!root_) {
21 root_ = std::make_unique<Node>();
22 root_->bounds = rootBounds_;
23 root_->depth = 0;
24 }
25 return root_.get();
26}
27
29 items_.clear();
30 results_.clear();
31 root_.reset();
32 ensureRoot();
33}
34
35bool Octree::contains(int id) const { return items_.find(id) != items_.end(); }
36
37bool Octree::insert(int id, float minX, float minY, float minZ, float maxX, float maxY,
38 float maxZ) {
39 AABB3 b = makeAABB3(minX, minY, minZ, maxX, maxY, maxZ);
40 if (!b.valid()) return false;
41 if (contains(id)) remove(id);
42 items_[id] = b;
43 if (!insertInto(*ensureRoot(), id, b)) {
44 ensureRoot()->itemIds.push_back(id);
45 }
46 return true;
47}
48
49bool Octree::remove(int id) {
50 if (!contains(id)) return false;
51 items_.erase(id);
52 rebuild();
53 return true;
54}
55
56bool Octree::update(int id, float minX, float minY, float minZ, float maxX, float maxY,
57 float maxZ) {
58 if (!contains(id)) return false;
59 return insert(id, minX, minY, minZ, maxX, maxY, maxZ);
60}
61
62void Octree::rebuild() {
63 results_.clear();
64 root_.reset();
65 ensureRoot();
66 for (const auto &kv : items_) {
67 if (!insertInto(*root_, kv.first, kv.second)) {
68 root_->itemIds.push_back(kv.first);
69 }
70 }
71}
72
73bool Octree::insertInto(Node &node, int id, const AABB3 &bounds) {
74 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)) {
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 < 8; ++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 Octree::split(Node &node) {
98 const float mx = node.bounds.centerX();
99 const float my = node.bounds.centerY();
100 const float mz = node.bounds.centerZ();
101 const float x0 = node.bounds.minX, x1 = node.bounds.maxX;
102 const float y0 = node.bounds.minY, y1 = node.bounds.maxY;
103 const float z0 = node.bounds.minZ, z1 = node.bounds.maxZ;
104 const AABB3 octs[8] = {
105 makeAABB3(x0, y0, z0, mx, my, mz), makeAABB3(mx, y0, z0, x1, my, mz),
106 makeAABB3(x0, my, z0, mx, y1, mz), makeAABB3(mx, my, z0, x1, y1, mz),
107 makeAABB3(x0, y0, mz, mx, my, z1), makeAABB3(mx, y0, mz, x1, my, z1),
108 makeAABB3(x0, my, mz, mx, y1, z1), makeAABB3(mx, my, mz, x1, y1, z1),
109 };
110 for (int i = 0; i < 8; ++i) {
111 node.children[i] = std::make_unique<Node>();
112 node.children[i]->bounds = octs[i];
113 node.children[i]->depth = node.depth + 1;
114 }
115
116 std::vector<int> remain;
117 remain.reserve(node.itemIds.size());
118 for (int id : node.itemIds) {
119 auto it = items_.find(id);
120 if (it == items_.end()) continue;
121 bool placed = false;
122 for (int i = 0; i < 8; ++i) {
123 if (node.children[i]->bounds.containsAABB(it->second)) {
124 node.children[i]->itemIds.push_back(id);
125 placed = true;
126 break;
127 }
128 }
129 if (!placed) remain.push_back(id);
130 }
131 node.itemIds.swap(remain);
132}
133
134void Octree::collect(Node &node, const AABB3 *box, float cx, float cy, float cz, float radius,
135 bool useSphere) {
136 if (box && !node.bounds.intersectsAABB(*box)) return;
137 if (useSphere && !node.bounds.intersectsSphere(cx, cy, cz, radius)) return;
138
139 for (int id : node.itemIds) {
140 auto it = items_.find(id);
141 if (it == items_.end()) continue;
142 const AABB3 &b = it->second;
143 bool hit = false;
144 if (box) {
145 hit = b.intersectsAABB(*box);
146 } else if (useSphere) {
147 hit = b.intersectsSphere(cx, cy, cz, radius);
148 } else {
149 hit = b.containsPoint(cx, cy, cz);
150 }
151 if (hit) results_.addUnique(id);
152 }
153
154 if (!node.isLeaf()) {
155 for (int i = 0; i < 8; ++i) {
156 if (node.children[i]) collect(*node.children[i], box, cx, cy, cz, radius, useSphere);
157 }
158 }
159}
160
161int Octree::queryPoint(float x, float y, float z) {
162 results_.clear();
163 collect(*ensureRoot(), nullptr, x, y, z, 0.f, false);
164 return results_.getCount();
165}
166
167int Octree::queryAABB(float minX, float minY, float minZ, float maxX, float maxY, float maxZ) {
168 results_.clear();
169 AABB3 box = makeAABB3(minX, minY, minZ, maxX, maxY, maxZ);
170 collect(*ensureRoot(), &box, 0.f, 0.f, 0.f, 0.f, false);
171 return results_.getCount();
172}
173
174int Octree::querySphere(float cx, float cy, float cz, float radius) {
175 results_.clear();
176 if (radius < 0.f) radius = 0.f;
177 collect(*ensureRoot(), nullptr, cx, cy, cz, radius, true);
178 return results_.getCount();
179}
180
181} // 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 z
Definition Grass.cpp:135
int x
Definition Grass.cpp:135
uint32_t b
bool insert(int id, float minX, float minY, float minZ, float maxX, float maxY, float maxZ)
插入一个 AABB 对象;false 表示越界或已存在。
Definition Octree.cpp:37
int queryPoint(float x, float y, float z)
查询:点 / AABB / 球体,命中写入结果缓冲区。
Definition Octree.cpp:161
int queryAABB(float minX, float minY, float minZ, float maxX, float maxY, float maxZ)
Definition Octree.cpp:167
bool update(int id, float minX, float minY, float minZ, float maxX, float maxY, float maxZ)
Definition Octree.cpp:56
int querySphere(float cx, float cy, float cz, float radius)
Definition Octree.cpp:174
bool contains(int id) const
对象是否存在。
Definition Octree.cpp:35
void clear()
清空全部对象。
Definition Octree.cpp:28
Octree(float minX, float minY, float minZ, float maxX, float maxY, float maxZ, int maxDepth=8, int maxPerNode=8)
创建覆盖 [minX..maxX]×[minY..maxY]×[minZ..maxZ] 的八叉树。
Definition Octree.cpp:7
bool remove(int id)
移除 / 更新一个对象。
Definition Octree.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
AABB3 makeAABB3(float minX, float minY, float minZ, float maxX, float maxY, float maxZ)
Definition Bounds.h:91
std::vector< NodeDesc > children
Definition NodeDesc.h:33
float height() const
Definition Bounds.h:52
bool valid() const
Definition Bounds.h:58
float width() const
Definition Bounds.h:51
float depth() const
Definition Bounds.h:53