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) {
75 if (!
node.bounds.intersectsAABB(
bounds))
return false;
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) {
89 if (
node.children[i] &&
node.children[i]->bounds.containsAABB(
bounds)) {
90 return insertInto(*
node.children[i],
id,
bounds);
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) {
111 node.children[i] = std::make_unique<Node>();
112 node.children[i]->bounds = octs[i];
113 node.children[i]->depth =
node.depth + 1;
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)) {
124 node.children[i]->itemIds.push_back(
id);
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) {
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);
177 collect(*ensureRoot(),
nullptr,
cx,
cy, cz,
radius,
true);
EVENGINE_API_FOUNDATION public API.
bool insert(int id, float minX, float minY, float minZ, float maxX, float maxY, float maxZ)
Inserts an item AABB; false if out of bounds or id already present.
int queryPoint(float x, float y, float z)
Finds items overlapping a point; fills the result buffer.
int queryAABB(float minX, float minY, float minZ, float maxX, float maxY, float maxZ)
Finds items overlapping an AABB; fills the result buffer.
bool update(int id, float minX, float minY, float minZ, float maxX, float maxY, float maxZ)
Moves an existing item to a new AABB; false if unknown or out of bounds.
int querySphere(float cx, float cy, float cz, float radius)
Finds items overlapping a sphere; fills the result buffer.
bool contains(int id) const
True if the id is currently stored.
void clear()
Removes all stored entries.
Octree(float minX, float minY, float minZ, float maxX, float maxY, float maxZ, int maxDepth=8, int maxPerNode=8)
Creates an octree covering the given 3D bounds.
bool remove(int id)
Removes an item by id; false if unknown.
void clear()
Removes all stored entries.
int getCount() const
Number of stored ids.
void addUnique(int id)
Appends id if not already present.
AABB3 makeAABB3(float minX, float minY, float minZ, float maxX, float maxY, float maxZ)
Builds a normalized 3D AABB (swaps inverted mins/maxes).
Axis-aligned 3D bounding box (min/max inclusive).
float height() const
Extent along Y (max - min).
bool valid() const
True when min <= max on every axis.
float width() const
Extent along X (max - min).
float depth() const
Extent along Z (max - min).