[11659] Rewrite object pos selector.

* Instead coordinates use angle projections to expected pos distance circle.
  This let do mostly only angle comparison and then speedup checks.
* Fixed some long existed bugs in algo and simplify code. Possible more work need.
This commit is contained in:
VladimirMangos 2011-06-21 21:43:06 +04:00
parent e776dbbfc8
commit 15bb164d72
4 changed files with 292 additions and 294 deletions

View file

@ -1703,8 +1703,8 @@ namespace MaNGOS
class NearUsedPosDo
{
public:
NearUsedPosDo(WorldObject const& obj, WorldObject const* searcher, float angle, ObjectPosSelector& selector)
: i_object(obj), i_searcher(searcher), i_angle(angle), i_selector(selector) {}
NearUsedPosDo(WorldObject const& obj, WorldObject const* searcher, float absAngle, ObjectPosSelector& selector)
: i_object(obj), i_searcher(searcher), i_absAngle(absAngle), i_selector(selector) {}
void operator()(Corpse*) const {}
void operator()(DynamicObject*) const {}
@ -1712,13 +1712,12 @@ namespace MaNGOS
void operator()(Creature* c) const
{
// skip self or target
if(c==i_searcher || c==&i_object)
if (c == i_searcher || c == &i_object)
return;
float x,y,z;
float x, y, z;
if( !c->isAlive() || c->hasUnitState(UNIT_STAT_NOT_MOVE) ||
!c->GetMotionMaster()->GetDestination(x,y,z) )
if (c->IsStopped() || !c->GetMotionMaster()->GetDestination(x, y, z))
{
x = c->GetPositionX();
y = c->GetPositionY();
@ -1728,10 +1727,10 @@ namespace MaNGOS
}
template<class T>
void operator()(T* u) const
void operator()(T* u) const
{
// skip self or target
if(u==i_searcher || u==&i_object)
if (u == i_searcher || u == &i_object)
return;
float x,y;
@ -1745,26 +1744,32 @@ namespace MaNGOS
// we must add used pos that can fill places around center
void add(WorldObject* u, float x, float y) const
{
// dist include size of u and i_object
float dx = i_object.GetPositionX() - x;
float dy = i_object.GetPositionY() - y;
float dist2d = sqrt((dx * dx) + (dy * dy));
float delta = i_selector.m_searcherSize + u->GetObjectBoundingRadius();
// u is too nearest/far away to i_object
if(!i_object.IsInRange2d(x,y,i_selector.m_dist - i_selector.m_size,i_selector.m_dist + i_selector.m_size))
if (dist2d < i_selector.m_searcherDist - delta ||
dist2d >= i_selector.m_searcherDist + delta)
return;
float angle = i_object.GetAngle(u)-i_angle;
float angle = i_object.GetAngle(u) - i_absAngle;
// move angle to range -pi ... +pi
while( angle > M_PI_F)
while (angle > M_PI_F)
angle -= 2.0f * M_PI_F;
while(angle < -M_PI_F)
while (angle < -M_PI_F)
angle += 2.0f * M_PI_F;
// dist include size of u
float dist2d = i_object.GetDistance2d(x,y);
i_selector.AddUsedPos(u->GetObjectBoundingRadius(), angle, dist2d + i_object.GetObjectBoundingRadius());
i_selector.AddUsedArea(u->GetObjectBoundingRadius(), angle, dist2d);
}
private:
WorldObject const& i_object;
WorldObject const* i_searcher;
float i_angle;
float i_absAngle;
ObjectPosSelector& i_selector;
};
} // namespace MaNGOS
@ -1782,16 +1787,16 @@ void WorldObject::GetNearPoint2D(float &x, float &y, float distance2d, float abs
void WorldObject::GetNearPoint(WorldObject const* searcher, float &x, float &y, float &z, float searcher_bounding_radius, float distance2d, float absAngle) const
{
GetNearPoint2D(x, y, distance2d+searcher_bounding_radius, absAngle);
GetNearPoint2D(x, y, distance2d + searcher_bounding_radius, absAngle);
z = GetPositionZ();
// if detection disabled, return first point
if(!sWorld.getConfig(CONFIG_BOOL_DETECT_POS_COLLISION))
{
if (searcher)
searcher->UpdateAllowedPositionZ(x,y,z); // update to LOS height if available
searcher->UpdateAllowedPositionZ(x, y, z); // update to LOS height if available
else
UpdateGroundPositionZ(x,y,z);
UpdateGroundPositionZ(x, y, z);
return;
}
@ -1801,113 +1806,79 @@ void WorldObject::GetNearPoint(WorldObject const* searcher, float &x, float &y,
bool first_los_conflict = false; // first point LOS problems
// prepare selector for work
ObjectPosSelector selector(GetPositionX(), GetPositionY(), GetObjectBoundingRadius(), distance2d+searcher_bounding_radius);
ObjectPosSelector selector(GetPositionX(), GetPositionY(), distance2d + searcher_bounding_radius + GetObjectBoundingRadius(), searcher_bounding_radius);
// adding used positions around object
{
MaNGOS::NearUsedPosDo u_do(*this,searcher,absAngle,selector);
MaNGOS::WorldObjectWorker<MaNGOS::NearUsedPosDo> worker(this,u_do);
MaNGOS::NearUsedPosDo u_do(*this, searcher, absAngle, selector);
MaNGOS::WorldObjectWorker<MaNGOS::NearUsedPosDo> worker(this, u_do);
Cell::VisitAllObjects(this, worker, distance2d);
Cell::VisitAllObjects(this, worker, distance2d + searcher_bounding_radius);
}
// maybe can just place in primary position
if( selector.CheckOriginal() )
if (selector.CheckOriginalAngle())
{
if (searcher)
searcher->UpdateAllowedPositionZ(x,y,z); // update to LOS height if available
searcher->UpdateAllowedPositionZ(x, y, z); // update to LOS height if available
else
UpdateGroundPositionZ(x,y,z);
UpdateGroundPositionZ(x, y, z);
if(IsWithinLOS(x,y,z))
if (IsWithinLOS(x, y, z))
return;
first_los_conflict = true; // first point have LOS problems
}
float angle; // candidate of angle for free pos
// special case when one from list empty and then empty side preferred
if(selector.FirstAngle(angle))
{
GetNearPoint2D(x,y,distance2d,absAngle+angle);
z = GetPositionZ();
if (searcher)
searcher->UpdateAllowedPositionZ(x,y,z); // update to LOS height if available
else
UpdateGroundPositionZ(x,y,z);
if(IsWithinLOS(x,y,z))
return;
}
// set first used pos in lists
selector.InitializeAngle();
float angle; // candidate of angle for free pos
// select in positions after current nodes (selection one by one)
while(selector.NextAngle(angle)) // angle for free pos
while (selector.NextAngle(angle)) // angle for free pos
{
GetNearPoint2D(x,y,distance2d,absAngle+angle);
GetNearPoint2D(x, y, distance2d + searcher_bounding_radius, absAngle + angle);
z = GetPositionZ();
if (searcher)
searcher->UpdateAllowedPositionZ(x,y,z); // update to LOS height if available
searcher->UpdateAllowedPositionZ(x, y, z); // update to LOS height if available
else
UpdateGroundPositionZ(x,y,z);
UpdateGroundPositionZ(x, y, z);
if(IsWithinLOS(x,y,z))
if (IsWithinLOS(x, y, z))
return;
}
// BAD NEWS: not free pos (or used or have LOS problems)
// Attempt find _used_ pos without LOS problem
if(!first_los_conflict)
if (!first_los_conflict)
{
x = first_x;
y = first_y;
if (searcher)
searcher->UpdateAllowedPositionZ(x,y,z); // update to LOS height if available
searcher->UpdateAllowedPositionZ(x, y, z); // update to LOS height if available
else
UpdateGroundPositionZ(x,y,z);
UpdateGroundPositionZ(x, y, z);
return;
}
// special case when one from list empty and then empty side preferred
if( selector.IsNonBalanced() )
{
if(!selector.FirstAngle(angle)) // _used_ pos
{
GetNearPoint2D(x,y,distance2d,absAngle+angle);
z = GetPositionZ();
if (searcher)
searcher->UpdateAllowedPositionZ(x,y,z); // update to LOS height if available
else
UpdateGroundPositionZ(x,y,z);
if(IsWithinLOS(x,y,z))
return;
}
}
// set first used pos in lists
selector.InitializeAngle();
// select in positions after current nodes (selection one by one)
while(selector.NextUsedAngle(angle)) // angle for used pos but maybe without LOS problem
while (selector.NextUsedAngle(angle)) // angle for used pos but maybe without LOS problem
{
GetNearPoint2D(x,y,distance2d,absAngle+angle);
GetNearPoint2D(x, y, distance2d + searcher_bounding_radius, absAngle + angle);
z = GetPositionZ();
if (searcher)
searcher->UpdateAllowedPositionZ(x,y,z); // update to LOS height if available
searcher->UpdateAllowedPositionZ(x, y, z); // update to LOS height if available
else
UpdateGroundPositionZ(x,y,z);
UpdateGroundPositionZ(x, y, z);
if(IsWithinLOS(x,y,z))
if (IsWithinLOS(x, y, z))
return;
}
@ -1916,9 +1887,9 @@ void WorldObject::GetNearPoint(WorldObject const* searcher, float &x, float &y,
y = first_y;
if (searcher)
searcher->UpdateAllowedPositionZ(x,y,z); // update to LOS height if available
searcher->UpdateAllowedPositionZ(x, y, z); // update to LOS height if available
else
UpdateGroundPositionZ(x,y,z);
UpdateGroundPositionZ(x, y, z);
}
void WorldObject::SetPhaseMask(uint32 newPhaseMask, bool update)