TrinityCore
Loading...
Searching...
No Matches
RegularGrid.h
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#ifndef _REGULAR_GRID_H
19#define _REGULAR_GRID_H
20
21#include "Errors.h"
22#include "IteratorPair.h"
23#include <G3D/Ray.h>
24#include <G3D/BoundsTrait.h>
25#include <memory>
26#include <span>
27#include <unordered_map>
28
29template<class Node>
31 static Node * makeNode(int /*x*/, int /*y*/) { return new Node();}
32};
33
34template<class T,
35class Node,
36class NodeCreatorFunc = NodeCreator<Node>,
37class BoundsFunc = BoundsTrait<T>
38>
40{
41public:
42
43 enum{
44 CELL_NUMBER = 64,
45 };
46
47 #define CELL_SIZE 533.33333f
48
49 typedef std::unordered_multimap<T const*, Node*> MemberTable;
50
52 std::unique_ptr<Node> nodes[CELL_NUMBER][CELL_NUMBER] = { };
53
54 void insert(T const& value)
55 {
56 G3D::AABox bounds = G3D::AABox::empty();
57 BoundsFunc::getBounds(value, bounds);
58 Cell low = Cell::ComputeCell(bounds.low().x, bounds.low().y);
59 Cell high = Cell::ComputeCell(bounds.high().x, bounds.high().y);
60 for (int x = low.x; x <= high.x; ++x)
61 {
62 for (int y = low.y; y <= high.y; ++y)
63 {
64 Node& node = getGrid(x, y);
65 node.insert(value);
66 memberTable.emplace(&value, &node);
67 }
68 }
69 }
70
71 void remove(T const& value)
72 {
73 for (auto& p : Trinity::Containers::MapEqualRange(memberTable, &value))
74 p.second->remove(value);
75 // Remove the member
76 memberTable.erase(&value);
77 }
78
79 void balance()
80 {
81 for (int x = 0; x < CELL_NUMBER; ++x)
82 for (int y = 0; y < CELL_NUMBER; ++y)
83 if (Node* n = nodes[x][y].get())
84 n->balance();
85 }
86
87 bool contains(T const& value) const { return memberTable.contains(&value); }
88 bool empty() const { return memberTable.empty(); }
89
90 struct Cell
91 {
92 int x, y;
93
94 friend bool operator==(Cell const&, Cell const&) = default;
95
96 static Cell ComputeCell(float fx, float fy)
97 {
98 return { .x = int(fx * (1.f / CELL_SIZE) + (CELL_NUMBER / 2)), .y = int(fy * (1.f / CELL_SIZE) + (CELL_NUMBER / 2)) };
99 }
100
101 bool isValid() const { return x >= 0 && x < CELL_NUMBER && y >= 0 && y < CELL_NUMBER; }
102 };
103
104 Node& getGrid(int x, int y)
105 {
106 ASSERT(x < CELL_NUMBER && y < CELL_NUMBER);
107 if (!nodes[x][y])
108 nodes[x][y].reset(NodeCreatorFunc::makeNode(x, y));
109 return *nodes[x][y];
110 }
111
112 template<typename RayCallback>
113 void intersectRay(G3D::Ray const& ray, RayCallback& intersectCallback, float max_dist)
114 {
115 intersectRay(ray, intersectCallback, max_dist, ray.origin() + ray.direction() * max_dist);
116 }
117
118 template<typename RayCallback>
119 void intersectRay(G3D::Ray const& ray, RayCallback& intersectCallback, float& max_dist, G3D::Vector3 const& end)
120 {
121 Cell cell = Cell::ComputeCell(ray.origin().x, ray.origin().y);
122 if (!cell.isValid())
123 return;
124
125 Cell last_cell = Cell::ComputeCell(end.x, end.y);
126
127 if (cell == last_cell)
128 {
129 if (Node* node = nodes[cell.x][cell.y].get())
130 node->intersectRay(ray, intersectCallback, max_dist);
131 return;
132 }
133
134 float voxel = (float)CELL_SIZE;
135 float kx_inv = ray.invDirection().x, bx = ray.origin().x;
136 float ky_inv = ray.invDirection().y, by = ray.origin().y;
137
138 int stepX, stepY;
139 float tMaxX, tMaxY;
140 if (kx_inv >= 0)
141 {
142 stepX = 1;
143 float x_border = (cell.x+1) * voxel;
144 tMaxX = (x_border - bx) * kx_inv;
145 }
146 else
147 {
148 stepX = -1;
149 float x_border = (cell.x-1) * voxel;
150 tMaxX = (x_border - bx) * kx_inv;
151 }
152
153 if (ky_inv >= 0)
154 {
155 stepY = 1;
156 float y_border = (cell.y+1) * voxel;
157 tMaxY = (y_border - by) * ky_inv;
158 }
159 else
160 {
161 stepY = -1;
162 float y_border = (cell.y-1) * voxel;
163 tMaxY = (y_border - by) * ky_inv;
164 }
165
166 //int Cycles = std::max((int)ceilf(max_dist/tMaxX),(int)ceilf(max_dist/tMaxY));
167 //int i = 0;
168
169 float tDeltaX = voxel * std::fabs(kx_inv);
170 float tDeltaY = voxel * std::fabs(ky_inv);
171 do
172 {
173 if (Node* node = nodes[cell.x][cell.y].get())
174 {
175 //float enterdist = max_dist;
176 node->intersectRay(ray, intersectCallback, max_dist);
177 }
178 if (cell == last_cell)
179 break;
180 if (tMaxX < tMaxY)
181 {
182 tMaxX += tDeltaX;
183 cell.x += stepX;
184 }
185 else
186 {
187 tMaxY += tDeltaY;
188 cell.y += stepY;
189 }
190 //++i;
191 } while (cell.isValid());
192 }
193
194 template<typename IsectCallback>
195 void intersectPoint(G3D::Vector3 const& point, IsectCallback& intersectCallback)
196 {
197 Cell cell = Cell::ComputeCell(point.x, point.y);
198 if (!cell.isValid())
199 return;
200 if (Node* node = nodes[cell.x][cell.y].get())
201 node->intersectPoint(point, intersectCallback);
202 }
203
204 // Optimized verson of intersectRay function for rays with vertical directions
205 template<typename RayCallback>
206 void intersectZAllignedRay(G3D::Ray const& ray, RayCallback& intersectCallback, float& max_dist)
207 {
208 Cell cell = Cell::ComputeCell(ray.origin().x, ray.origin().y);
209 if (!cell.isValid())
210 return;
211 if (Node* node = nodes[cell.x][cell.y].get())
212 node->intersectRay(ray, intersectCallback, max_dist);
213 }
214
215 std::span<T const* const> getObjects(int x, int y) const
216 {
217 if (Node* n = nodes[x][y].get())
218 return n->getObjects();
219 return {};
220 }
221};
222
223#undef CELL_SIZE
224
225#endif
#define TC_COMMON_API
Definition Define.h:99
#define ASSERT
Definition Errors.h:80
#define CELL_SIZE
Definition RegularGrid.h:47
void remove(T const &value)
Definition RegularGrid.h:71
Node & getGrid(int x, int y)
std::span< T const *const > getObjects(int x, int y) const
MemberTable memberTable
Definition RegularGrid.h:51
void intersectPoint(G3D::Vector3 const &point, IsectCallback &intersectCallback)
void intersectRay(G3D::Ray const &ray, RayCallback &intersectCallback, float &max_dist, G3D::Vector3 const &end)
void insert(T const &value)
Definition RegularGrid.h:54
std::unordered_multimap< T const *, Node * > MemberTable
Definition RegularGrid.h:49
void intersectZAllignedRay(G3D::Ray const &ray, RayCallback &intersectCallback, float &max_dist)
bool empty() const
Definition RegularGrid.h:88
bool contains(T const &value) const
Definition RegularGrid.h:87
void intersectRay(G3D::Ray const &ray, RayCallback &intersectCallback, float max_dist)
auto MapEqualRange(M &map, typename M::key_type const &key)
static Node * makeNode(int, int)
Definition RegularGrid.h:31
static Cell ComputeCell(float fx, float fy)
Definition RegularGrid.h:96
friend bool operator==(Cell const &, Cell const &)=default
bool isValid() const