/*
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
#ifndef Trinity_game_Position_h__
#define Trinity_game_Position_h__
#include "Define.h"
#include
#include
#include
class ByteBuffer;
struct TC_GAME_API Position
{
constexpr Position()
: m_positionX(0.0f), m_positionY(0.0f), m_positionZ(0.0f), m_orientation(0.0f) { }
constexpr Position(float x, float y)
: m_positionX(x), m_positionY(y), m_positionZ(0.0f), m_orientation(0.0f) { }
constexpr Position(float x, float y, float z)
: m_positionX(x), m_positionY(y), m_positionZ(z), m_orientation(0.0f) { }
constexpr Position(float x, float y, float z, float o)
: m_positionX(x), m_positionY(y), m_positionZ(z), m_orientation(NormalizeOrientationConstexprWrapper(o)) { }
// streamer tags
struct XY;
struct XYZ;
struct XYZO;
struct PackedXYZ;
template
struct ConstStreamer
{
explicit ConstStreamer(Position const& pos) : Pos(&pos) { }
Position const* Pos;
};
template
struct Streamer
{
explicit Streamer(Position& pos) : Pos(&pos) { }
operator ConstStreamer() const { return ConstStreamer(*Pos); }
Position* Pos;
};
float m_positionX;
float m_positionY;
float m_positionZ;
// Better to limit access to _orientation field, to guarantee the value is normalized
private:
float m_orientation;
public:
bool operator==(Position const& a) const;
constexpr void Relocate(float x, float y) { m_positionX = x; m_positionY = y; }
constexpr void Relocate(float x, float y, float z) { Relocate(x, y); m_positionZ = z; }
constexpr void Relocate(float x, float y, float z, float o) { Relocate(x, y, z); SetOrientation(o); }
constexpr void Relocate(Position const& pos) { *this = pos; }
constexpr void Relocate(Position const* pos) { *this = *pos; }
void RelocateOffset(Position const& offset);
constexpr void SetOrientation(float orientation)
{
m_orientation = NormalizeOrientationConstexprWrapper(orientation);
}
constexpr float GetPositionX() const { return m_positionX; }
constexpr float GetPositionY() const { return m_positionY; }
constexpr float GetPositionZ() const { return m_positionZ; }
constexpr float GetOrientation() const { return m_orientation; }
constexpr void GetPosition(float& x, float& y) const { x = m_positionX; y = m_positionY; }
constexpr void GetPosition(float& x, float& y, float& z) const { GetPosition(x, y); z = m_positionZ; }
constexpr void GetPosition(float& x, float& y, float& z, float& o) const { GetPosition(x, y, z); o = m_orientation; }
constexpr Position GetPosition() const { return *this; }
Streamer PositionXYStream() { return Streamer(*this); }
ConstStreamer PositionXYStream() const { return ConstStreamer(*this); }
Streamer PositionXYZStream() { return Streamer(*this); }
ConstStreamer PositionXYZStream() const { return ConstStreamer(*this); }
Streamer PositionXYZOStream() { return Streamer(*this); }
ConstStreamer PositionXYZOStream() const { return ConstStreamer(*this); }
Streamer PositionPackedXYZStream() { return Streamer(*this); }
ConstStreamer PositionPackedXYZStream() const { return ConstStreamer(*this); }
bool IsPositionValid() const;
constexpr float GetExactDist2dSq(const float x, const float y) const
{
float dx = x - m_positionX;
float dy = y - m_positionY;
return dx*dx + dy*dy;
}
constexpr float GetExactDist2dSq(Position const& pos) const { return GetExactDist2dSq(pos.m_positionX, pos.m_positionY); }
constexpr float GetExactDist2dSq(Position const* pos) const { return GetExactDist2dSq(*pos); }
float GetExactDist2d(const float x, const float y) const { return std::sqrt(GetExactDist2dSq(x, y)); }
float GetExactDist2d(Position const& pos) const { return GetExactDist2d(pos.m_positionX, pos.m_positionY); }
float GetExactDist2d(Position const* pos) const { return GetExactDist2d(*pos); }
constexpr float GetExactDistSq(float x, float y, float z) const
{
float dz = z - m_positionZ;
return GetExactDist2dSq(x, y) + dz*dz;
}
constexpr float GetExactDistSq(Position const& pos) const { return GetExactDistSq(pos.m_positionX, pos.m_positionY, pos.m_positionZ); }
constexpr float GetExactDistSq(Position const* pos) const { return GetExactDistSq(*pos); }
float GetExactDist(float x, float y, float z) const { return std::sqrt(GetExactDistSq(x, y, z)); }
float GetExactDist(Position const& pos) const { return GetExactDist(pos.m_positionX, pos.m_positionY, pos.m_positionZ); }
float GetExactDist(Position const* pos) const { return GetExactDist(*pos); }
void GetPositionOffsetTo(Position const & endPos, Position & retOffset) const;
Position GetPositionWithOffset(Position const& offset) const;
float GetAbsoluteAngle(float x, float y) const
{
float dx = x - m_positionX;
float dy = y - m_positionY;
return NormalizeOrientation(std::atan2(dy, dx));
}
float GetAbsoluteAngle(Position const& pos) const { return GetAbsoluteAngle(pos.m_positionX, pos.m_positionY); }
float GetAbsoluteAngle(Position const* pos) const { return GetAbsoluteAngle(*pos); }
float ToAbsoluteAngle(float relAngle) const { return NormalizeOrientation(relAngle + m_orientation); }
float ToRelativeAngle(float absAngle) const { return NormalizeOrientation(absAngle - m_orientation); }
float GetRelativeAngle(float x, float y) const { return ToRelativeAngle(GetAbsoluteAngle(x, y)); }
float GetRelativeAngle(Position const& pos) const { return ToRelativeAngle(GetAbsoluteAngle(pos)); }
float GetRelativeAngle(Position const* pos) const { return ToRelativeAngle(GetAbsoluteAngle(pos)); }
constexpr bool IsInDist2d(float x, float y, float dist) const { return GetExactDist2dSq(x, y) < dist * dist; }
constexpr bool IsInDist2d(Position const& pos, float dist) const { return GetExactDist2dSq(pos) < dist * dist; }
constexpr bool IsInDist2d(Position const* pos, float dist) const { return GetExactDist2dSq(pos) < dist * dist; }
constexpr bool IsInDist(float x, float y, float z, float dist) const { return GetExactDistSq(x, y, z) < dist * dist; }
constexpr bool IsInDist(Position const& pos, float dist) const { return GetExactDistSq(pos) < dist * dist; }
constexpr bool IsInDist(Position const* pos, float dist) const { return GetExactDistSq(pos) < dist * dist; }
bool IsWithinBox(Position const& boxOrigin, float length, float width, float height) const;
bool IsWithinVerticalCylinder(Position const& cylinderOrigin, float radius, float height, bool isDoubleVertical = false) const;
bool IsInPolygon2D(Position const& polygonOrigin, std::span vertices) const;
bool HasInArc(float arcangle, Position const* pos, float border = 2.0f) const;
bool HasInLine(Position const* pos, float objSize, float width) const;
std::string ToString() const;
// constrain arbitrary radian orientation to interval [0,2*PI)
static float NormalizeOrientation(float o);
private:
static constexpr float NormalizeOrientationConstexprWrapper(float o)
{
if (std::is_constant_evaluated())
{
if (o < 0.0f || o >= 2.0f * static_cast(M_PI))
throw "Compile time Position initialization requires orientation to be in 0-2pi range";
return o;
}
else
{
return NormalizeOrientation(o);
}
}
};
#define MAPID_INVALID 0xFFFFFFFF
class TC_GAME_API WorldLocation : public Position
{
public:
constexpr WorldLocation() : m_mapId(MAPID_INVALID) { }
constexpr WorldLocation(uint32 mapId, float x, float y) : Position(x, y), m_mapId(mapId) { }
constexpr WorldLocation(uint32 mapId, float x, float y, float z) : Position(x, y, z), m_mapId(mapId) { }
constexpr WorldLocation(uint32 mapId, float x, float y, float z, float o) : Position(x, y, z, o), m_mapId(mapId) { }
constexpr WorldLocation(uint32 mapId, Position const& position) : Position(position), m_mapId(mapId) { }
constexpr void WorldRelocate(WorldLocation const& loc) { m_mapId = loc.GetMapId(); Relocate(loc); }
constexpr void WorldRelocate(WorldLocation const* loc) { m_mapId = loc->GetMapId(); Relocate(loc); }
constexpr void WorldRelocate(uint32 mapId, Position const& pos) { m_mapId = mapId; Relocate(pos); }
constexpr void WorldRelocate(uint32 mapId, float x, float y, float z, float o)
{
m_mapId = mapId;
Relocate(x, y, z, o);
}
constexpr WorldLocation GetWorldLocation() const
{
return *this;
}
constexpr uint32 GetMapId() const { return m_mapId; }
uint32 m_mapId;
std::string GetDebugInfo() const;
};
TC_GAME_API ByteBuffer& operator<<(ByteBuffer& buf, Position::ConstStreamer const& streamer);
TC_GAME_API ByteBuffer& operator>>(ByteBuffer& buf, Position::Streamer const& streamer);
TC_GAME_API ByteBuffer& operator<<(ByteBuffer& buf, Position::ConstStreamer const& streamer);
TC_GAME_API ByteBuffer& operator>>(ByteBuffer& buf, Position::Streamer const& streamer);
TC_GAME_API ByteBuffer& operator<<(ByteBuffer& buf, Position::ConstStreamer const& streamer);
TC_GAME_API ByteBuffer& operator>>(ByteBuffer& buf, Position::Streamer const& streamer);
TC_GAME_API ByteBuffer& operator<<(ByteBuffer& buf, Position::ConstStreamer const& streamer);
template
struct TaggedPosition
{
constexpr TaggedPosition() { }
constexpr TaggedPosition(float x, float y) : Pos(x, y) { }
constexpr TaggedPosition(float x, float y, float z) : Pos(x, y, z) { }
constexpr TaggedPosition(float x, float y, float z, float o) : Pos(x, y, z, o) { }
constexpr TaggedPosition(Position const& pos) : Pos(pos) { }
constexpr TaggedPosition& operator=(Position const& pos)
{
Pos.Relocate(pos);
return *this;
}
constexpr operator Position() const { return Pos; }
friend constexpr bool operator==(TaggedPosition const& left, TaggedPosition const& right) { return left.Pos == right.Pos; }
friend constexpr bool operator!=(TaggedPosition const& left, TaggedPosition const& right) { return left.Pos != right.Pos; }
friend ByteBuffer& operator<<(ByteBuffer& buf, TaggedPosition const& tagged) { return buf << Position::ConstStreamer(tagged.Pos); }
friend ByteBuffer& operator>>(ByteBuffer& buf, TaggedPosition& tagged) { return buf >> Position::Streamer(tagged.Pos); }
Position Pos;
};
#endif // Trinity_game_Position_h__