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");
19Octree::Node *Octree::ensureRoot() {
21 root_ = std::make_unique<Node>();
22 root_->bounds = rootBounds_;
37bool Octree::insert(
int id,
float minX,
float minY,
float minZ,
float maxX,
float maxY,
40 if (!
b.valid())
return false;
43 if (!insertInto(*ensureRoot(),
id,
b)) {
44 ensureRoot()->itemIds.push_back(
id);
56bool Octree::update(
int id,
float minX,
float minY,
float minZ,
float maxX,
float maxY,
59 return insert(
id, minX, minY, minZ, maxX, maxY, maxZ);
62void Octree::rebuild() {
66 for (
const auto &kv : items_) {
67 if (!insertInto(*root_, kv.first, kv.second)) {
68 root_->itemIds.push_back(kv.first);
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)) {
81 node.itemIds.push_back(
id);
82 if (
static_cast<int>(
node.itemIds.size()) > maxPerNode_ &&
node.depth < maxDepth_) {
88 for (
int i = 0; i < 8; ++i) {
93 node.itemIds.push_back(
id);
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),
110 for (
int i = 0; i < 8; ++i) {
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;
122 for (
int i = 0; i < 8; ++i) {
123 if (
node.
children[i]->bounds.containsAABB(it->second)) {
129 if (!placed) remain.push_back(
id);
131 node.itemIds.swap(remain);
134void Octree::collect(Node &node,
const AABB3 *box,
float cx,
float cy,
float cz,
float radius,
136 if (box && !
node.bounds.intersectsAABB(*box))
return;
137 if (useSphere && !
node.bounds.intersectsSphere(
cx,
cy, cz, radius))
return;
139 for (
int id :
node.itemIds) {
140 auto it = items_.find(
id);
141 if (it == items_.end())
continue;
142 const AABB3 &
b = it->second;
145 hit =
b.intersectsAABB(*box);
146 }
else if (useSphere) {
147 hit =
b.intersectsSphere(
cx,
cy, cz, radius);
149 hit =
b.containsPoint(
cx,
cy, cz);
154 if (!
node.isLeaf()) {
155 for (
int i = 0; i < 8; ++i) {
163 collect(*ensureRoot(),
nullptr,
x,
y,
z, 0.f,
false);
170 collect(*ensureRoot(), &box, 0.f, 0.f, 0.f, 0.f,
false);
176 if (radius < 0.f) radius = 0.f;
177 collect(*ensureRoot(),
nullptr,
cx,
cy, cz, radius,
true);
bool insert(int id, float minX, float minY, float minZ, float maxX, float maxY, float maxZ)
插入一个 AABB 对象;false 表示越界或已存在。
int queryPoint(float x, float y, float z)
查询:点 / AABB / 球体,命中写入结果缓冲区。
int queryAABB(float minX, float minY, float minZ, float maxX, float maxY, float maxZ)
bool update(int id, float minX, float minY, float minZ, float maxX, float maxY, float maxZ)
int querySphere(float cx, float cy, float cz, float radius)
bool contains(int id) const
对象是否存在。
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] 的八叉树。
bool remove(int id)
移除 / 更新一个对象。
NodeDesc node(std::string id, std::vector< NodeDesc > children, std::string name)
AABB3 makeAABB3(float minX, float minY, float minZ, float maxX, float maxY, float maxZ)
std::vector< NodeDesc > children