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) {
108 hit =
b.intersectsCircle(
cx,
cy, radius);
109 }
else if (usePoint) {
110 hit =
b.containsPoint(
cx,
cy);
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);
134 if (radius < 0.f) radius = 0.f;
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);
void addUnchecked(int id)
bool contains(int id) const
bool update(int id, float minX, float minY, float maxX, float maxY)
void setCellSize(float cellSize)
SpatialHash2D(float cellSize=64.f)
int queryPoint(float x, float y)
int queryRect(float minX, float minY, float maxX, float maxY)
int queryCircle(float cx, float cy, float radius)
bool insert(int id, float minX, float minY, float maxX, float maxY)
AABB2 makeAABB2(float minX, float minY, float maxX, float maxY)
uint64_t cellKey2(int cx, int cy)
Integer cell key for spatial hashing (stable across platforms for reasonable ranges).
bool intersectsAABB(const AABB2 &o) const