TrinityCore
Loading...
Searching...
No Matches
CellImpl.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 TRINITY_CELLIMPL_H
19#define TRINITY_CELLIMPL_H
20
21#include <cmath>
22
23#include "Cell.h"
24#include "Map.h"
25#include "Object.h"
26
27inline Cell::Cell(CellCoord const& p) : data()
28{
29 data.Part.grid_x = p.x_coord / MAX_NUMBER_OF_CELLS;
30 data.Part.grid_y = p.y_coord / MAX_NUMBER_OF_CELLS;
31 data.Part.cell_x = p.x_coord % MAX_NUMBER_OF_CELLS;
32 data.Part.cell_y = p.y_coord % MAX_NUMBER_OF_CELLS;
33}
34
35inline CellArea Cell::CalculateCellArea(float x, float y, float radius)
36{
37 if (radius <= 0.0f)
38 {
40 return CellArea(center, center);
41 }
42
43 CellCoord centerX = Trinity::ComputeCellCoord(x - radius, y - radius).normalize();
44 CellCoord centerY = Trinity::ComputeCellCoord(x + radius, y + radius).normalize();
45
46 return CellArea(centerX, centerY);
47}
48
49template<class T, class CONTAINER>
50inline void Cell::Visit(CellCoord const& standing_cell, TypeContainerVisitor<T, CONTAINER>& visitor, Map& map, WorldObject const& obj, float radius) const
51{
52 //we should increase search radius by object's radius, otherwise
53 //we could have problems with huge creatures, which won't attack nearest players etc
54 Visit(standing_cell, visitor, map, obj.GetPositionX(), obj.GetPositionY(), radius + obj.GetCombatReach());
55}
56
57template<class T, class CONTAINER>
58inline void Cell::Visit(CellCoord const& standing_cell, TypeContainerVisitor<T, CONTAINER>& visitor, Map& map, float x_off, float y_off, float radius) const
59{
60 if (!standing_cell.IsCoordValid())
61 return;
62
63 //no jokes here... Actually placing ASSERT() here was good idea, but
64 //we had some problems with DynamicObjects, which pass radius = 0.0f (DB issue?)
65 //maybe it is better to just return when radius <= 0.0f?
66 if (radius <= 0.0f)
67 {
68 map.Visit(*this, visitor);
69 return;
70 }
71 //lets limit the upper value for search radius
72 if (radius > SIZE_OF_GRIDS)
73 radius = SIZE_OF_GRIDS;
74
75 //lets calculate object coord offsets from cell borders.
76 CellArea area = Cell::CalculateCellArea(x_off, y_off, radius);
77 //if radius fits inside standing cell
78 if (!area)
79 {
80 map.Visit(*this, visitor);
81 return;
82 }
83
84 //visit all cells, found in CalculateCellArea()
85 //if radius is known to reach cell area more than 4x4 then we should call optimized VisitCircle
86 //currently this technique works with MAX_NUMBER_OF_CELLS 16 and higher, with lower values
87 //there are nothing to optimize because SIZE_OF_GRID_CELL is too big...
88 if ((area.high_bound.x_coord > (area.low_bound.x_coord + 4)) && (area.high_bound.y_coord > (area.low_bound.y_coord + 4)))
89 {
90 VisitCircle(visitor, map, area.low_bound, area.high_bound);
91 return;
92 }
93
94 //ALWAYS visit standing cell first!!! Since we deal with small radiuses
95 //it is very essential to call visitor for standing cell firstly...
96 map.Visit(*this, visitor);
97
98 // loop the cell range
99 for (uint32 x = area.low_bound.x_coord; x <= area.high_bound.x_coord; ++x)
100 {
101 for (uint32 y = area.low_bound.y_coord; y <= area.high_bound.y_coord; ++y)
102 {
103 CellCoord cellCoord(x, y);
104 //lets skip standing cell since we already visited it
105 if (cellCoord != standing_cell)
106 {
107 Cell r_zone(cellCoord);
108 r_zone.data.Part.nocreate = this->data.Part.nocreate;
109 map.Visit(r_zone, visitor);
110 }
111 }
112 }
113}
114
115template<class T, class CONTAINER>
116inline void Cell::VisitCircle(TypeContainerVisitor<T, CONTAINER>& visitor, Map& map, CellCoord const& begin_cell, CellCoord const& end_cell) const
117{
118 //here is an algorithm for 'filling' circum-squared octagon
119 uint32 x_shift = (uint32)ceilf((end_cell.x_coord - begin_cell.x_coord) * 0.3f - 0.5f);
120 //lets calculate x_start/x_end coords for central strip...
121 const uint32 x_start = begin_cell.x_coord + x_shift;
122 const uint32 x_end = end_cell.x_coord - x_shift;
123
124 //visit central strip with constant width...
125 for (uint32 x = x_start; x <= x_end; ++x)
126 {
127 for (uint32 y = begin_cell.y_coord; y <= end_cell.y_coord; ++y)
128 {
129 CellCoord cellCoord(x, y);
130 Cell r_zone(cellCoord);
131 r_zone.data.Part.nocreate = this->data.Part.nocreate;
132 map.Visit(r_zone, visitor);
133 }
134 }
135
136 //if x_shift == 0 then we have too small cell area, which were already
137 //visited at previous step, so just return from procedure...
138 if (x_shift == 0)
139 return;
140
141 uint32 y_start = end_cell.y_coord;
142 uint32 y_end = begin_cell.y_coord;
143 //now we are visiting borders of an octagon...
144 for (uint32 step = 1; step <= (x_start - begin_cell.x_coord); ++step)
145 {
146 //each step reduces strip height by 2 cells...
147 y_end += 1;
148 y_start -= 1;
149 for (uint32 y = y_start; y >= y_end; --y)
150 {
151 //we visit cells symmetrically from both sides, heading from center to sides and from up to bottom
152 //e.g. filling 2 trapezoids after filling central cell strip...
153 CellCoord cellCoord_left(x_start - step, y);
154 Cell r_zone_left(cellCoord_left);
155 r_zone_left.data.Part.nocreate = this->data.Part.nocreate;
156 map.Visit(r_zone_left, visitor);
157
158 //right trapezoid cell visit
159 CellCoord cellCoord_right(x_end + step, y);
160 Cell r_zone_right(cellCoord_right);
161 r_zone_right.data.Part.nocreate = this->data.Part.nocreate;
162 map.Visit(r_zone_right, visitor);
163 }
164 }
165}
166
167template<class T>
168inline void Cell::VisitGridObjects(WorldObject const* center_obj, T& visitor, float radius, bool dont_load /*= true*/)
169{
170 CellCoord p(Trinity::ComputeCellCoord(center_obj->GetPositionX(), center_obj->GetPositionY()));
171 Cell cell(p);
172 if (dont_load)
173 cell.SetNoCreate();
174
176 cell.Visit(p, gnotifier, *center_obj->GetMap(), *center_obj, radius);
177}
178
179template<class T>
180inline void Cell::VisitWorldObjects(WorldObject const* center_obj, T& visitor, float radius, bool dont_load /*= true*/)
181{
182 CellCoord p(Trinity::ComputeCellCoord(center_obj->GetPositionX(), center_obj->GetPositionY()));
183 Cell cell(p);
184 if (dont_load)
185 cell.SetNoCreate();
186
188 cell.Visit(p, wnotifier, *center_obj->GetMap(), *center_obj, radius);
189}
190
191template<class T>
192inline void Cell::VisitAllObjects(WorldObject const* center_obj, T& visitor, float radius, bool dont_load /*= true*/)
193{
194 CellCoord p(Trinity::ComputeCellCoord(center_obj->GetPositionX(), center_obj->GetPositionY()));
195 Cell cell(p);
196 if (dont_load)
197 cell.SetNoCreate();
198
200 cell.Visit(p, wnotifier, *center_obj->GetMap(), *center_obj, radius);
202 cell.Visit(p, gnotifier, *center_obj->GetMap(), *center_obj, radius);
203}
204
205template<class T>
206inline void Cell::VisitGridObjects(float x, float y, Map* map, T& visitor, float radius, bool dont_load /*= true*/)
207{
209 Cell cell(p);
210 if (dont_load)
211 cell.SetNoCreate();
212
214 cell.Visit(p, gnotifier, *map, x, y, radius);
215}
216
217template<class T>
218inline void Cell::VisitWorldObjects(float x, float y, Map* map, T& visitor, float radius, bool dont_load /*= true*/)
219{
221 Cell cell(p);
222 if (dont_load)
223 cell.SetNoCreate();
224
226 cell.Visit(p, wnotifier, *map, x, y, radius);
227}
228
229template<class T>
230inline void Cell::VisitAllObjects(float x, float y, Map* map, T& visitor, float radius, bool dont_load /*= true*/)
231{
233 Cell cell(p);
234 if (dont_load)
235 cell.SetNoCreate();
236
238 cell.Visit(p, wnotifier, *map, x, y, radius);
240 cell.Visit(p, gnotifier, *map, x, y, radius);
241}
242
243#endif
uint32_t uint32
Definition Define.h:133
#define MAX_NUMBER_OF_CELLS
Definition GridDefines.h:34
#define SIZE_OF_GRIDS
Definition GridDefines.h:38
Definition Map.h:281
void Visit(Cell const &cell, TypeContainerVisitor< T, CONTAINER > &visitor)
Definition Map.h:935
Map * GetMap() const
Definition Object.h:449
virtual float GetCombatReach() const
Definition Object.h:358
CellCoord ComputeCellCoord(float x, float y)
CellCoord high_bound
Definition Cell.h:43
CellCoord low_bound
Definition Cell.h:42
Definition Cell.h:47
static void VisitAllObjects(WorldObject const *obj, T &visitor, float radius, bool dont_load=true)
Definition CellImpl.h:192
void SetNoCreate()
Definition Cell.h:75
Cell()
Definition Cell.h:48
union Cell::@256 data
static void VisitGridObjects(WorldObject const *obj, T &visitor, float radius, bool dont_load=true)
Definition CellImpl.h:168
struct Cell::@256::@257 Part
static void VisitWorldObjects(WorldObject const *obj, T &visitor, float radius, bool dont_load=true)
Definition CellImpl.h:180
void VisitCircle(TypeContainerVisitor< T, CONTAINER > &, Map &, CellCoord const &, CellCoord const &) const
Definition CellImpl.h:116
void Visit(CellCoord const &, TypeContainerVisitor< T, CONTAINER > &visitor, Map &, WorldObject const &obj, float radius) const
Definition CellImpl.h:50
static CellArea CalculateCellArea(float x, float y, float radius)
Definition CellImpl.h:35
uint8 nocreate
Definition Cell.h:93
bool IsCoordValid() const
uint32 x_coord
uint32 y_coord
CoordPair & normalize()
float GetPositionX() const
Definition Position.h:79
float GetPositionY() const
Definition Position.h:80