Core/Grid:

- Simplified CellArea calculation (Original author: SilverIce)

- Removed unused code in Cell class (Original author: SilverIce)

- Improve some Visit functions.
This commit is contained in:
kaelima
2011-10-19 17:40:44 +01:00
parent d7e0190726
commit be0b2fcf97
25 changed files with 127 additions and 353 deletions
+22 -146
View File
@@ -46,140 +46,22 @@ inline Cell::Cell(float x, float y)
data.Part.reserved = 0;
}
template<class T, class CONTAINER>
inline void
Cell::Visit(const CellCoord& standing_cell, TypeContainerVisitor<T, CONTAINER> &visitor, Map &m) const
{
if (!standing_cell.IsCoordValid())
return;
uint16 district = (District)this->data.Part.reserved;
if (district == CENTER_DISTRICT)
{
m.Visit(*this, visitor);
return;
}
// set up the cell range based on the district
CellCoord begin_cell = standing_cell;
CellCoord end_cell = standing_cell;
switch (district)
{
case ALL_DISTRICT:
{
begin_cell.dec_x(1); begin_cell.dec_y(1); // upper left
end_cell.inc_x(1); end_cell.inc_y(1); // lower right
break;
}
case UPPER_LEFT_DISTRICT:
{
begin_cell.dec_x(1); begin_cell.dec_y(1); // upper left
break;
}
case UPPER_RIGHT_DISTRICT:
{
begin_cell.dec_y(1); // up
end_cell.inc_x(1); // right
break;
}
case LOWER_LEFT_DISTRICT:
{
begin_cell.dec_x(1); // left
end_cell.inc_y(1); // down
break;
}
case LOWER_RIGHT_DISTRICT:
{
end_cell.inc_x(1); end_cell.inc_y(1); // lower right
break;
}
case LEFT_DISTRICT:
{
begin_cell.dec_y(1); // up
end_cell.inc_x(1); end_cell.inc_y(1); // lower right
break;
}
case RIGHT_DISTRICT:
{
begin_cell.dec_x(1); begin_cell.dec_y(1); // upper left
end_cell.inc_y(1); // down
break;
}
case UPPER_DISTRICT:
{
begin_cell.dec_x(1); begin_cell.dec_y(1); // upper left
end_cell.inc_x(1); // right
break;
}
case LOWER_DISTRICT:
{
begin_cell.dec_x(1); // left
end_cell.inc_x(1); end_cell.inc_y(1); // lower right
break;
}
default:
{
ASSERT(false);
break;
}
}
// loop the cell range
for (uint32 x = begin_cell.x_coord; x <= end_cell.x_coord; x++)
{
for (uint32 y = begin_cell.y_coord; y <= end_cell.y_coord; y++)
{
CellCoord cellCoord(x, y);
Cell r_zone(cellCoord);
r_zone.data.Part.nocreate = this->data.Part.nocreate;
m.Visit(r_zone, visitor);
}
}
}
inline int CellHelper(const float radius)
{
if (radius < 1.0f)
return 0;
return (int)ceilf(radius/SIZE_OF_GRID_CELL);
}
inline CellArea Cell::CalculateCellArea(const WorldObject &obj, float radius)
{
return Cell::CalculateCellArea(obj.GetPositionX(), obj.GetPositionY(), radius);
}
inline CellArea Cell::CalculateCellArea(float x, float y, float radius)
{
if (radius <= 0.0f)
return CellArea();
{
CellCoord center = Trinity::ComputeCellCoord(x, y).normalize();
return CellArea(center, center);
}
//lets calculate object coord offsets from cell borders.
//TODO: add more correct/generic method for this task
const float x_offset = (x - CENTER_GRID_CELL_OFFSET)/SIZE_OF_GRID_CELL;
const float y_offset = (y - CENTER_GRID_CELL_OFFSET)/SIZE_OF_GRID_CELL;
CellCoord centerX = Trinity::ComputeCellCoord(x - radius, y - radius).normalize();
CellCoord centerY = Trinity::ComputeCellCoord(x + radius, y + radius).normalize();
const float x_val = floor(x_offset + CENTER_GRID_CELL_ID + 0.5f);
const float y_val = floor(y_offset + CENTER_GRID_CELL_ID + 0.5f);
const float x_off = (x_offset - x_val + CENTER_GRID_CELL_ID) * SIZE_OF_GRID_CELL;
const float y_off = (y_offset - y_val + CENTER_GRID_CELL_ID) * SIZE_OF_GRID_CELL;
const float tmp_diff = radius - CENTER_GRID_CELL_OFFSET;
//lets calculate upper/lower/right/left corners for cell search
int right = CellHelper(tmp_diff + x_off);
int left = CellHelper(tmp_diff - x_off);
int upper = CellHelper(tmp_diff + y_off);
int lower = CellHelper(tmp_diff - y_off);
return CellArea(right, left, upper, lower);
return CellArea(centerX, centerY);
}
template<class T, class CONTAINER>
inline void
Cell::Visit(const CellCoord& standing_cell, TypeContainerVisitor<T, CONTAINER> &visitor, Map &m, float radius, float x_off, float y_off) const
inline void Cell::Visit(CellCoord const& standing_cell, TypeContainerVisitor<T, CONTAINER>& visitor, Map& map, float radius, float x_off, float y_off) const
{
if (!standing_cell.IsCoordValid())
return;
@@ -189,7 +71,7 @@ Cell::Visit(const CellCoord& standing_cell, TypeContainerVisitor<T, CONTAINER> &
//maybe it is better to just return when radius <= 0.0f?
if (radius <= 0.0f)
{
m.Visit(*this, visitor);
map.Visit(*this, visitor);
return;
}
//lets limit the upper value for search radius
@@ -201,32 +83,28 @@ Cell::Visit(const CellCoord& standing_cell, TypeContainerVisitor<T, CONTAINER> &
//if radius fits inside standing cell
if (!area)
{
m.Visit(*this, visitor);
map.Visit(*this, visitor);
return;
}
CellCoord begin_cell = standing_cell;
CellCoord end_cell = standing_cell;
area.ResizeBorders(begin_cell, end_cell);
//visit all cells, found in CalculateCellArea()
//if radius is known to reach cell area more than 4x4 then we should call optimized VisitCircle
//currently this technique works with MAX_NUMBER_OF_CELLS 16 and higher, with lower values
//there are nothing to optimize because SIZE_OF_GRID_CELL is too big...
if (((end_cell.x_coord - begin_cell.x_coord) > 4) && ((end_cell.y_coord - begin_cell.y_coord) > 4))
if (((area.high_bound.x_coord - area.low_bound.x_coord) > 4) && ((area.high_bound.y_coord - area.low_bound.y_coord) > 4))
{
VisitCircle(visitor, m, begin_cell, end_cell);
VisitCircle(visitor, map, area.low_bound, area.high_bound);
return;
}
//ALWAYS visit standing cell first!!! Since we deal with small radiuses
//it is very essential to call visitor for standing cell firstly...
m.Visit(*this, visitor);
map.Visit(*this, visitor);
// loop the cell range
for (uint32 x = begin_cell.x_coord; x <= end_cell.x_coord; ++x)
for (uint32 x = area.low_bound.x_coord; x <= area.high_bound.x_coord; ++x)
{
for (uint32 y = begin_cell.y_coord; y <= end_cell.y_coord; ++y)
for (uint32 y = area.low_bound.y_coord; y <= area.high_bound.y_coord; ++y)
{
CellCoord cellCoord(x, y);
//lets skip standing cell since we already visited it
@@ -234,24 +112,22 @@ Cell::Visit(const CellCoord& standing_cell, TypeContainerVisitor<T, CONTAINER> &
{
Cell r_zone(cellCoord);
r_zone.data.Part.nocreate = this->data.Part.nocreate;
m.Visit(r_zone, visitor);
map.Visit(r_zone, visitor);
}
}
}
}
template<class T, class CONTAINER>
inline void
Cell::Visit(const CellCoord& l, TypeContainerVisitor<T, CONTAINER> &visitor, Map &m, const WorldObject &obj, float radius) const
inline void Cell::Visit(CellCoord const& standing_cell, TypeContainerVisitor<T, CONTAINER>& visitor, Map& map, WorldObject const& obj, float radius) const
{
//we should increase search radius by object's radius, otherwise
//we could have problems with huge creatures, which won't attack nearest players etc
Visit(l, visitor, m, radius + obj.GetObjectSize(), obj.GetPositionX(), obj.GetPositionY());
Visit(standing_cell, visitor, map, radius + obj.GetObjectSize(), obj.GetPositionX(), obj.GetPositionY());
}
template<class T, class CONTAINER>
inline void
Cell::VisitCircle(TypeContainerVisitor<T, CONTAINER> &visitor, Map &m, const CellCoord& begin_cell, const CellCoord& end_cell) const
inline void Cell::VisitCircle(TypeContainerVisitor<T, CONTAINER>& visitor, Map& map, CellCoord const& begin_cell, CellCoord const& end_cell) const
{
//here is an algorithm for 'filling' circum-squared octagon
uint32 x_shift = (uint32)ceilf((end_cell.x_coord - begin_cell.x_coord) * 0.3f - 0.5f);
@@ -267,7 +143,7 @@ Cell::VisitCircle(TypeContainerVisitor<T, CONTAINER> &visitor, Map &m, const Cel
CellCoord cellCoord(x, y);
Cell r_zone(cellCoord);
r_zone.data.Part.nocreate = this->data.Part.nocreate;
m.Visit(r_zone, visitor);
map.Visit(r_zone, visitor);
}
}
@@ -291,13 +167,13 @@ Cell::VisitCircle(TypeContainerVisitor<T, CONTAINER> &visitor, Map &m, const Cel
CellCoord cellCoord_left(x_start - step, y);
Cell r_zone_left(cellCoord_left);
r_zone_left.data.Part.nocreate = this->data.Part.nocreate;
m.Visit(r_zone_left, visitor);
map.Visit(r_zone_left, visitor);
//right trapezoid cell visit
CellCoord cellCoord_right(x_end + step, y);
Cell r_zone_right(cellCoord_right);
r_zone_right.data.Part.nocreate = this->data.Part.nocreate;
m.Visit(r_zone_right, visitor);
map.Visit(r_zone_right, visitor);
}
}
}