tile2d
Loading...
Searching...
No Matches
spatial.hpp
1#pragma once
2
3#include "math.hpp"
4
11T2D_NAMESPACE_BEGIN
12
13template<typename Type, typename Int>
14class FreeList {
15public:
16 static constexpr Int endOfList = std::numeric_limits<Int>::max();
17 static constexpr size_t elementSize = sizeof(Type);
18
19public:
20 FreeList()
21 : firstFree(endOfList) {}
22
23 Int insert() {
24 if (m_elements.size() + 1 >= endOfList)
25 return endOfList;
26
27 if (firstFree == endOfList) {
28 m_elements.emplace_back();
29 firstFree = m_elements.size() - 1;
30 m_elements[firstFree].next = endOfList;
31 }
32
33 Int idx = firstFree;
34 Node& node = m_elements[idx];
35 firstFree = node.next;
36 node.emplace();
37
38 return idx;
39 }
40
41 Int insert(Type&& obj) {
42 if (firstFree == endOfList) {
43 m_elements.emplace_back();
44 firstFree = m_elements.size() - 1;
45 m_elements[firstFree].next = endOfList;
46 }
47
48 Int idx = firstFree;
49 Node& node = m_elements[idx];
50 firstFree = node.next;
51 node.emplace(std::forward<Type&&>(obj));
52
53 return idx;
54 }
55
56 void erase(Int idx) {
57 Node& node = m_elements[idx];
58
59 node.destroy();
60
61 if (firstFree == endOfList) {
62 node.next = endOfList;
63 } else {
64 node.next = firstFree;
65 }
66
67 firstFree = idx;
68 }
69
70 Type& get(Int idx) {
71 return *(Type*)m_elements[idx].element.data.data();
72 }
73
74 const Type& get(Int idx) const {
75 return *(Type*)m_elements[idx].element.data.data();
76 }
77
78 Type& operator[](Int idx) {
79 return get(idx);
80 }
81
82 const Type& operator[](Int idx) const {
83 return get(idx);
84 }
85
86private:
87 union Node {
88 Int next;
89
90 struct {
91 std::array<uint8_t, elementSize> data;
92 } element;
93
94 void emplace(Type&& obj) {
95 new(element.data.data())Type(obj);
96 }
97
98 void emplace() {
99 new(element.data.data())Type();
100 }
101
102 void destroy() noexcept {
103 Type* obj = (Type*)element.data.data();
104 obj->~Type();
105 }
106 };
107
108 Int firstFree;
109 std::vector<Node> m_elements;
110};
111
117template<class T, typename Int = int32_t>
118class Grid {
119 static inline const boost::thread::id mainThreadId = boost::this_thread::get_id();
120 using ivec2 = typename glm::vec<2, Int, glm::packed_lowp>;
121protected:
122 struct GridElement {
123 AABB<Float> aabb;
124 T data;
125 };
126public:
127 struct ParentCell {
128 void insert(uint16_t idx) {
129 elements.push_back(idx);
130 }
131
132 void erase(uint16_t idx) {
133 elements.erase(std::find(elements.begin(), elements.end(), idx));
134 }
135
136 std::vector<uint16_t> elements;
137 };
138
139 using GridMap = boost::unordered_flat_map<ivec2, ParentCell>;
140public:
146 Grid(Float cellSize = (Float)tcW)
147 : m_cellSize(cellSize), m_invCellSize(1.0f / cellSize) {
148 }
149
158 inline uint16_t insert(const AABB<Float>& aabb, const T& data) {
159 uint16_t idx = m_elementList.insert();
160 GridElement& element = m_elementList.get(idx);
161 element.aabb = aabb;
162 element.data = data;
163
164 const ivec2& min = getCellCoords(aabb.min());
165 const ivec2& max = getCellCoords(aabb.max());
166
167 for (auto y = min.y; y <= max.y; y++) {
168 for (auto x = min.x; x <= max.x; x++) {
169 m_cells[{x, y}].insert(idx);
170 }
171 }
172
173 return idx;
174 }
175
176
183 inline void relocate(uint16_t idx, const AABB<Float>& newAABB) {
184 GridElement& element = m_elementList.get(idx);
185
186 const ivec2& oldMin = getCellCoords(element.aabb.min());
187 const ivec2& oldMax = getCellCoords(element.aabb.max());
188 ivec2 newMin = getCellCoords(newAABB.min());
189 ivec2 newMax = getCellCoords(newAABB.max());
190
191 for (auto y = oldMin.y; y <= oldMax.y; y++) {
192 for (auto x = oldMin.x; x <= oldMax.x; x++) {
193 if (contains(newMin, newMax, { x, y }))
194 continue;
195
196 auto iter = m_cells.find({ x, y });
197 iter->second.erase(idx);
198 if (iter->second.elements.size() == 0)
199 m_possiblyEmptyCells.push_back({ x, y });
200 }
201 }
202
203 for (auto y = newMin.y; y <= newMax.y; y++) {
204 for (auto x = newMin.x; x <= newMax.x; x++) {
205 if (contains(oldMin, oldMax, { x, y }))
206 continue;
207
208 m_cells[{x, y}].insert(idx);
209 }
210 }
211
212 element.aabb = newAABB;
213 }
214
220 inline void erase(uint16_t idx) {
221 GridElement& element = m_elementList.get(idx);
222 const ivec2& min = getCellCoords(element.aabb.min());
223 const ivec2& max = getCellCoords(element.aabb.max());
224
225 for (auto y = min.y; y <= max.y; y++) {
226 for (auto x = min.x; x <= max.x; x++) {
227 m_cells[{x, y}].erase(idx);
228 }
229 }
230
231 m_elementList.erase(idx);
232 }
233
234 template<typename Callback>
235 void queryIntersects(const AABB<Float>& area, Callback&& clbk) const {
236 const ivec2 min = getCellCoords(area.min());
237 const ivec2 max = getCellCoords(area.max());
238
239 for (auto y = min.y; y <= max.y; y++) {
240 for (auto x = min.x; x <= max.x; x++) {
241 ivec2 coord(x, y);
242
243 auto iter = m_cells.find(coord);
244 if (iter == m_cells.end())
245 continue;
246
247 for (uint16_t idx : iter->second.elements) {
248 const GridElement& element = m_elementList.get(idx);
249
250 if (element.aabb.intersects(area)) {
251 clbk(element.data);
252 }
253 }
254 }
255 }
256 }
257
261 void cleanup() {
262 for (const ivec2& coord : m_possiblyEmptyCells) {
263 if (m_cells[coord].elements.size() == 0) {
264 m_cells.erase(coord);
265 }
266 }
267
268 m_possiblyEmptyCells.clear();
269 }
270
276 GridMap& gridMap() {
277 return m_cells;
278 }
279
280protected:
281 inline ivec2 getCellCoords(const vec2& coords) const {
282 ivec2 icoords;
283 icoords.x = floor<Int>(coords.x * m_invCellSize);
284 icoords.y = floor<Int>(coords.y * m_invCellSize);
285
286 return icoords;
287 }
288
289 bool contains(const Int& min, const Int& max, const Int& point) {
290 return min <= point && point <= max;
291 }
292
293 bool contains(const ivec2& min, const ivec2& max, const ivec2& point) {
294 return contains(min.x, max.x, point.x) && contains(min.y, max.y, point.y);
295 }
296
297protected:
298 Float m_invCellSize;
299 Float m_cellSize;
301
302 GridMap m_cells;
303 std::vector<ivec2> m_possiblyEmptyCells;
304};
305
306T2D_NAMESPACE_END
Definition spatial.hpp:14
Used for spatial indexing.
Definition spatial.hpp:118
void erase(uint16_t idx)
Erases an element.
Definition spatial.hpp:220
GridMap & gridMap()
Returns the map of all cells.
Definition spatial.hpp:276
void cleanup()
Removes empty cells, if any.
Definition spatial.hpp:261
uint16_t insert(const AABB< Float > &aabb, const T &data)
Inserts a new element into the grid.
Definition spatial.hpp:158
void relocate(uint16_t idx, const AABB< Float > &newAABB)
Relocates an already existing element within the grid.
Definition spatial.hpp:183
Grid(Float cellSize=(Float) tcW)
Constructs a new Grid.
Definition spatial.hpp:146
contains various functions and classes that are used for both convience and/or functionality that may...
Definition math.hpp:203
Definition spatial.hpp:122
Definition spatial.hpp:127