2 * Copyright (C) 2005-2013 MaNGOS <http://getmangos.com/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #ifndef MANGOS_CELLIMPL_H
20 #define MANGOS_CELLIMPL_H
27 inline Cell::Cell(CellPair
const& p
)
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 data
.Part
.nocreate
= 0;
34 data
.Part
.reserved
= 0;
37 inline CellArea
Cell::CalculateCellArea(float x
, float y
, float radius
)
41 CellPair center
= MaNGOS::ComputeCellPair(x
, y
).normalize();
42 return CellArea(center
, center
);
47 MaNGOS::ComputeCellPair(x
- radius
, y
- radius
).normalize(),
48 MaNGOS::ComputeCellPair(x
+ radius
, y
+ radius
).normalize()
52 template<class T
, class CONTAINER
>
54 Cell::Visit(const CellPair
& standing_cell
, TypeContainerVisitor
<T
, CONTAINER
>& visitor
, Map
& m
, const WorldObject
& obj
, float radius
) const
56 Cell::Visit(standing_cell
, visitor
, m
, obj
.GetPositionX(), obj
.GetPositionY(), radius
+ obj
.GetObjectBoundingRadius());
60 template<class T
, class CONTAINER
>
62 Cell::Visit(const CellPair
& standing_cell
, TypeContainerVisitor
<T
, CONTAINER
>& visitor
, Map
& m
, float x
, float y
, float radius
) const
64 if (standing_cell
.x_coord
>= TOTAL_NUMBER_OF_CELLS_PER_MAP
|| standing_cell
.y_coord
>= TOTAL_NUMBER_OF_CELLS_PER_MAP
)
67 // no jokes here... Actually placing ASSERT() here was good idea, but
68 // we had some problems with DynamicObjects, which pass radius = 0.0f (DB issue?)
69 // maybe it is better to just return when radius <= 0.0f?
72 m
.Visit(*this, visitor
);
75 // lets limit the upper value for search radius
79 // lets calculate object coord offsets from cell borders.
80 CellArea area
= Cell::CalculateCellArea(x
, y
, radius
);
81 // if radius fits inside standing cell
84 m
.Visit(*this, visitor
);
88 CellPair
& begin_cell
= area
.low_bound
;
89 CellPair
& end_cell
= area
.high_bound
;
90 // visit all cells, found in CalculateCellArea()
91 // if radius is known to reach cell area more than 4x4 then we should call optimized VisitCircle
92 // currently this technique works with MAX_NUMBER_OF_CELLS 16 and higher, with lower values
93 // there are nothing to optimize because SIZE_OF_GRID_CELL is too big...
94 if (((end_cell
.x_coord
- begin_cell
.x_coord
) > 4) && ((end_cell
.y_coord
- begin_cell
.y_coord
) > 4))
96 VisitCircle(visitor
, m
, begin_cell
, end_cell
);
100 // ALWAYS visit standing cell first!!! Since we deal with small radiuses
101 // it is very essential to call visitor for standing cell firstly...
102 m
.Visit(*this, visitor
);
104 // loop the cell range
105 for (uint32 x
= begin_cell
.x_coord
; x
<= end_cell
.x_coord
; ++x
)
107 for (uint32 y
= begin_cell
.y_coord
; y
<= end_cell
.y_coord
; ++y
)
109 CellPair
cell_pair(x
, y
);
110 // lets skip standing cell since we already visited it
111 if (cell_pair
!= standing_cell
)
113 Cell
r_zone(cell_pair
);
114 r_zone
.data
.Part
.nocreate
= data
.Part
.nocreate
;
115 m
.Visit(r_zone
, visitor
);
121 template<class T
, class CONTAINER
>
123 Cell::VisitCircle(TypeContainerVisitor
<T
, CONTAINER
>& visitor
, Map
& m
, const CellPair
& begin_cell
, const CellPair
& end_cell
) const
125 // here is an algorithm for 'filling' circum-squared octagon
126 uint32 x_shift
= (uint32
)ceilf((end_cell
.x_coord
- begin_cell
.x_coord
) * 0.3f
- 0.5f
);
127 // lets calculate x_start/x_end coords for central strip...
128 const uint32 x_start
= begin_cell
.x_coord
+ x_shift
;
129 const uint32 x_end
= end_cell
.x_coord
- x_shift
;
131 // visit central strip with constant width...
132 for (uint32 x
= x_start
; x
<= x_end
; ++x
)
134 for (uint32 y
= begin_cell
.y_coord
; y
<= end_cell
.y_coord
; ++y
)
136 CellPair
cell_pair(x
, y
);
137 Cell
r_zone(cell_pair
);
138 r_zone
.data
.Part
.nocreate
= data
.Part
.nocreate
;
139 m
.Visit(r_zone
, visitor
);
143 // if x_shift == 0 then we have too small cell area, which were already
144 // visited at previous step, so just return from procedure...
148 uint32 y_start
= end_cell
.y_coord
;
149 uint32 y_end
= begin_cell
.y_coord
;
150 // now we are visiting borders of an octagon...
151 for (uint32 step
= 1; step
<= (x_start
- begin_cell
.x_coord
); ++step
)
153 // each step reduces strip height by 2 cells...
156 for (uint32 y
= y_start
; y
>= y_end
; --y
)
158 // we visit cells symmetrically from both sides, heading from center to sides and from up to bottom
159 // e.g. filling 2 trapezoids after filling central cell strip...
160 CellPair
cell_pair_left(x_start
- step
, y
);
161 Cell
r_zone_left(cell_pair_left
);
162 r_zone_left
.data
.Part
.nocreate
= data
.Part
.nocreate
;
163 m
.Visit(r_zone_left
, visitor
);
165 // right trapezoid cell visit
166 CellPair
cell_pair_right(x_end
+ step
, y
);
167 Cell
r_zone_right(cell_pair_right
);
168 r_zone_right
.data
.Part
.nocreate
= data
.Part
.nocreate
;
169 m
.Visit(r_zone_right
, visitor
);
175 inline void Cell::VisitGridObjects(const WorldObject
* center_obj
, T
& visitor
, float radius
, bool dont_load
)
177 CellPair
p(MaNGOS::ComputeCellPair(center_obj
->GetPositionX(), center_obj
->GetPositionY()));
181 TypeContainerVisitor
<T
, GridTypeMapContainer
> gnotifier(visitor
);
182 cell
.Visit(p
, gnotifier
, *center_obj
->GetMap(), *center_obj
, radius
);
186 inline void Cell::VisitWorldObjects(const WorldObject
* center_obj
, T
& visitor
, float radius
, bool dont_load
)
188 CellPair
p(MaNGOS::ComputeCellPair(center_obj
->GetPositionX(), center_obj
->GetPositionY()));
192 TypeContainerVisitor
<T
, WorldTypeMapContainer
> gnotifier(visitor
);
193 cell
.Visit(p
, gnotifier
, *center_obj
->GetMap(), *center_obj
, radius
);
197 inline void Cell::VisitAllObjects(const WorldObject
* center_obj
, T
& visitor
, float radius
, bool dont_load
)
199 CellPair
p(MaNGOS::ComputeCellPair(center_obj
->GetPositionX(), center_obj
->GetPositionY()));
203 TypeContainerVisitor
<T
, GridTypeMapContainer
> gnotifier(visitor
);
204 TypeContainerVisitor
<T
, WorldTypeMapContainer
> wnotifier(visitor
);
205 cell
.Visit(p
, gnotifier
, *center_obj
->GetMap(), *center_obj
, radius
);
206 cell
.Visit(p
, wnotifier
, *center_obj
->GetMap(), *center_obj
, radius
);
210 inline void Cell::VisitGridObjects(float x
, float y
, Map
* map
, T
& visitor
, float radius
, bool dont_load
)
212 CellPair
p(MaNGOS::ComputeCellPair(x
, y
));
216 TypeContainerVisitor
<T
, GridTypeMapContainer
> gnotifier(visitor
);
217 cell
.Visit(p
, gnotifier
, *map
, x
, y
, radius
);
221 inline void Cell::VisitWorldObjects(float x
, float y
, Map
* map
, T
& visitor
, float radius
, bool dont_load
)
223 CellPair
p(MaNGOS::ComputeCellPair(x
, y
));
227 TypeContainerVisitor
<T
, WorldTypeMapContainer
> gnotifier(visitor
);
228 cell
.Visit(p
, gnotifier
, *map
, x
, y
, radius
);
232 inline void Cell::VisitAllObjects(float x
, float y
, Map
* map
, T
& visitor
, float radius
, bool dont_load
)
234 CellPair
p(MaNGOS::ComputeCellPair(x
, y
));
238 TypeContainerVisitor
<T
, GridTypeMapContainer
> gnotifier(visitor
);
239 TypeContainerVisitor
<T
, WorldTypeMapContainer
> wnotifier(visitor
);
240 cell
.Visit(p
, gnotifier
, *map
, x
, y
, radius
);
241 cell
.Visit(p
, wnotifier
, *map
, x
, y
, radius
);