13 if (cellSize <= 0.f) {
14 throw Exception(
"SpatialHash2D: cellSize must be > 0");
16 if (!items_.empty() && cellSize != cellSize_) {
18 auto snapshot = items_;
21 for (
const auto &kv : snapshot) {
22 insert(kv.first, kv.second.minX, kv.second.minY, kv.second.maxX, kv.second.maxY);
37void SpatialHash2D::cellRange(
const AABB2 &
b,
int &minCX,
int &minCY,
int &maxCX,
39 minCX =
static_cast<int>(std::floor(
b.minX / cellSize_));
40 minCY =
static_cast<int>(std::floor(
b.minY / cellSize_));
41 maxCX =
static_cast<int>(std::floor(
b.maxX / cellSize_));
42 maxCY =
static_cast<int>(std::floor(
b.maxY / cellSize_));
45void SpatialHash2D::insertCells(
int id,
const AABB2 &
b) {
46 int minCX, minCY, maxCX, maxCY;
47 cellRange(
b, minCX, minCY, maxCX, maxCY);
48 for (
int cy = minCY;
cy <= maxCY; ++
cy) {
49 for (
int cx = minCX;
cx <= maxCX; ++
cx) {
55void SpatialHash2D::eraseCells(
int id,
const AABB2 &
b) {
56 int minCX, minCY, maxCX, maxCY;
57 cellRange(
b, minCX, minCY, maxCX, maxCY);
58 for (
int cy = minCY;
cy <= maxCY; ++
cy) {
59 for (
int cx = minCX;
cx <= maxCX; ++
cx) {
61 if (it == cells_.end())
continue;
62 auto &vec = it->second;
63 vec.erase(std::remove(vec.begin(), vec.end(),
id), vec.end());
64 if (vec.empty()) cells_.erase(it);
71 if (!
b.valid())
return false;
79 auto it = items_.find(
id);
80 if (it == items_.end())
return false;
81 eraseCells(
id, it->second);
88 return insert(
id, minX, minY, maxX, maxY);
91void SpatialHash2D::queryCells(
int minCX,
int minCY,
int maxCX,
int maxCY,
const AABB2 *rect,
92 float cx,
float cy,
float radius,
bool useCircle,
bool usePoint) {
94 std::unordered_set<int> seen;
95 for (
int y = minCY;
y <= maxCY; ++
y) {
96 for (
int x = minCX;
x <= maxCX; ++
x) {
98 if (it == cells_.end())
continue;
99 for (
int id : it->
second) {
100 if (!seen.insert(
id).second)
continue;
101 auto item = items_.find(
id);
102 if (item == items_.end())
continue;
103 const AABB2 &
b = item->second;
107 }
else if (useCircle) {
109 }
else if (usePoint) {
119 const int cx =
static_cast<int>(std::floor(
x / cellSize_));
120 const int cy =
static_cast<int>(std::floor(
y / cellSize_));
121 queryCells(
cx,
cy,
cx,
cy,
nullptr,
x,
y, 0.f,
false,
true);
127 int minCX, minCY, maxCX, maxCY;
128 cellRange(rect, minCX, minCY, maxCX, maxCY);
129 queryCells(minCX, minCY, maxCX, maxCY, &rect, 0.f, 0.f, 0.f,
false,
false);
136 int minCX, minCY, maxCX, maxCY;
137 cellRange(rect, minCX, minCY, maxCX, maxCY);
138 queryCells(minCX, minCY, maxCX, maxCY,
nullptr,
cx,
cy,
radius,
true,
false);
EVENGINE_API_FOUNDATION public API.
void clear()
Removes all stored entries.
void addUnchecked(int id)
Appends id without uniqueness checks.
int getCount() const
Number of stored ids.
void clear()
Removes all stored entries.
bool remove(int id)
Removes an item by id; false if unknown.
bool contains(int id) const
True if the id is currently stored.
bool update(int id, float minX, float minY, float maxX, float maxY)
Moves an existing item to a new AABB; false if unknown or out of bounds.
void setCellSize(float cellSize)
Sets cell size and clears existing entries.
SpatialHash2D(float cellSize=64.f)
Creates a 2D spatial hash with the given cell size.
int queryPoint(float x, float y)
Finds items overlapping a point; fills the result buffer.
int queryRect(float minX, float minY, float maxX, float maxY)
Finds items overlapping an AABB; fills the result buffer.
int queryCircle(float cx, float cy, float radius)
Finds items overlapping a circle; fills the result buffer.
bool insert(int id, float minX, float minY, float maxX, float maxY)
Inserts an item AABB; false if out of bounds or id already present.
AABB2 makeAABB2(float minX, float minY, float maxX, float maxY)
Builds a normalized 2D AABB (swaps inverted mins/maxes).
uint64_t cellKey2(int cx, int cy)
Integer cell key for spatial hashing (stable across platforms for reasonable ranges).
Axis-aligned 2D bounding box (min/max inclusive).
bool intersectsAABB(const AABB2 &o) const
True if the boxes overlap (inclusive edges).