载入中...
搜索中...
未找到
SpatialHash2D.cpp
浏览该文件的文档.
2
3#include "common/Exception.h"
4
5#include <algorithm>
6#include <cmath>
7
8namespace eve::spatial {
9
10SpatialHash2D::SpatialHash2D(float cellSize) { setCellSize(cellSize); }
11
12void SpatialHash2D::setCellSize(float cellSize) {
13 if (cellSize <= 0.f) {
14 throw Exception("SpatialHash2D: cellSize must be > 0");
15 }
16 if (!items_.empty() && cellSize != cellSize_) {
17 // Rebuild with new size.
18 auto snapshot = items_;
19 clear();
20 cellSize_ = cellSize;
21 for (const auto &kv : snapshot) {
22 insert(kv.first, kv.second.minX, kv.second.minY, kv.second.maxX, kv.second.maxY);
23 }
24 return;
25 }
26 cellSize_ = cellSize;
27}
28
30 items_.clear();
31 cells_.clear();
32 results_.clear();
33}
34
35bool SpatialHash2D::contains(int id) const { return items_.find(id) != items_.end(); }
36
37void SpatialHash2D::cellRange(const AABB2 &b, int &minCX, int &minCY, int &maxCX,
38 int &maxCY) const {
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_));
43}
44
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) {
50 cells_[cellKey2(cx, cy)].push_back(id);
51 }
52 }
53}
54
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) {
60 auto it = cells_.find(cellKey2(cx, cy));
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);
65 }
66 }
67}
68
69bool SpatialHash2D::insert(int id, float minX, float minY, float maxX, float maxY) {
70 AABB2 b = makeAABB2(minX, minY, maxX, maxY);
71 if (!b.valid()) return false;
72 if (contains(id)) remove(id);
73 items_[id] = b;
74 insertCells(id, b);
75 return true;
76}
77
79 auto it = items_.find(id);
80 if (it == items_.end()) return false;
81 eraseCells(id, it->second);
82 items_.erase(it);
83 return true;
84}
85
86bool SpatialHash2D::update(int id, float minX, float minY, float maxX, float maxY) {
87 if (!contains(id)) return false;
88 return insert(id, minX, minY, maxX, maxY);
89}
90
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) {
93 results_.clear();
94 std::unordered_set<int> seen;
95 for (int y = minCY; y <= maxCY; ++y) {
96 for (int x = minCX; x <= maxCX; ++x) {
97 auto it = cells_.find(cellKey2(x, y));
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;
104 bool hit = false;
105 if (rect) {
106 hit = b.intersectsAABB(*rect);
107 } else if (useCircle) {
108 hit = b.intersectsCircle(cx, cy, radius);
109 } else if (usePoint) {
110 hit = b.containsPoint(cx, cy);
111 }
112 if (hit) results_.addUnchecked(id);
113 }
114 }
115 }
116}
117
118int SpatialHash2D::queryPoint(float x, float y) {
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);
122 return results_.getCount();
123}
124
125int SpatialHash2D::queryRect(float minX, float minY, float maxX, float maxY) {
126 AABB2 rect = makeAABB2(minX, minY, maxX, maxY);
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);
130 return results_.getCount();
131}
132
133int SpatialHash2D::queryCircle(float cx, float cy, float radius) {
134 if (radius < 0.f) radius = 0.f;
135 AABB2 rect = makeAABB2(cx - radius, cy - radius, cx + radius, cy + radius);
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);
139 return results_.getCount();
140}
141
142} // 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 x
Definition Grass.cpp:135
uint32_t b
void addUnchecked(int id)
Definition QueryIds.h:22
int getCount() const
Definition QueryIds.h:24
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)
Definition Bounds.h:85
uint64_t cellKey2(int cx, int cy)
Integer cell key for spatial hashing (stable across platforms for reasonable ranges).
Definition Bounds.h:99
bool intersectsAABB(const AABB2 &o) const
Definition Bounds.h:30