TrinityCore
Loading...
Searching...
No Matches
Position.cpp
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#include "Position.h"
19#include "ByteBuffer.h"
20#include "DB2Stores.h"
21#include "GridDefines.h"
22#include "StringFormat.h"
23#include "World.h"
24#include <G3D/g3dmath.h>
25
26bool Position::operator==(Position const& a) const
27{
28 return (G3D::fuzzyEq(a.m_positionX, m_positionX) &&
29 G3D::fuzzyEq(a.m_positionY, m_positionY) &&
30 G3D::fuzzyEq(a.m_positionZ, m_positionZ) &&
31 G3D::fuzzyEq(a.m_orientation, m_orientation));
32}
33
35{
36 m_positionX += offset.GetPositionX() * std::cos(GetOrientation()) - offset.GetPositionY() * std::sin(GetOrientation());
37 m_positionY += offset.GetPositionY() * std::cos(GetOrientation()) + offset.GetPositionX() * std::sin(GetOrientation());
38 m_positionZ += offset.GetPositionZ();
40}
41
46
48{
49 float dx = endPos.GetPositionX() - GetPositionX();
50 float dy = endPos.GetPositionY() - GetPositionY();
51
52 return
53 {
54 dx * std::cos(GetOrientation()) + dy * std::sin(GetOrientation()),
55 dy * std::cos(GetOrientation()) - dx * std::sin(GetOrientation()),
56 endPos.GetPositionZ() - GetPositionZ(),
58 };
59}
60
62{
63 Position ret(*this);
64 ret.RelocateOffset(offset);
65 return ret;
66}
67
68bool Position::IsWithinBox(Position const& boxOrigin, float length, float width, float height) const
69{
70 // rotate the WorldObject position instead of rotating the whole cube, that way we can make a simplified
71 // is-in-cube check and we have to calculate only one point instead of 4
72
73 // 2PI = 360*, keep in mind that ingame orientation is counter-clockwise
74 double rotation = 2 * M_PI - boxOrigin.GetOrientation();
75 double sinVal = std::sin(rotation);
76 double cosVal = std::cos(rotation);
77
78 float BoxDistX = GetPositionX() - boxOrigin.GetPositionX();
79 float BoxDistY = GetPositionY() - boxOrigin.GetPositionY();
80
81 float rotX = float(boxOrigin.GetPositionX() + BoxDistX * cosVal - BoxDistY * sinVal);
82 float rotY = float(boxOrigin.GetPositionY() + BoxDistY * cosVal + BoxDistX * sinVal);
83
84 // box edges are parallel to coordiante axis, so we can treat every dimension independently :D
85 float dz = GetPositionZ() - boxOrigin.GetPositionZ();
86 float dx = rotX - boxOrigin.GetPositionX();
87 float dy = rotY - boxOrigin.GetPositionY();
88 if ((std::fabs(dx) > length) ||
89 (std::fabs(dy) > width) ||
90 (std::fabs(dz) > height))
91 return false;
92
93 return true;
94}
95
96bool Position::IsWithinVerticalCylinder(Position const& cylinderOrigin, float radius, float height, bool isDoubleVertical) const
97{
98 float verticalDelta = GetPositionZ() - cylinderOrigin.GetPositionZ();
99 bool isValidPositionZ = isDoubleVertical ? std::abs(verticalDelta) <= height : 0 <= verticalDelta && verticalDelta <= height;
100
101 return isValidPositionZ && IsInDist2d(cylinderOrigin, radius);
102}
103
104bool Position::IsInPolygon2D(Position const& polygonOrigin, std::span<Position const> vertices) const
105{
106 float testX = GetPositionX();
107 float testY = GetPositionY();
108
109 //this method uses the ray tracing algorithm to determine if the point is in the polygon
110 bool locatedInPolygon = false;
111
112 for (std::size_t vertex = 0; vertex < vertices.size(); ++vertex)
113 {
114 std::size_t nextVertex;
115
116 //repeat loop for all sets of points
117 if (vertex == (vertices.size() - 1))
118 {
119 //if i is the last vertex, let j be the first vertex
120 nextVertex = 0;
121 }
122 else
123 {
124 //for all-else, let j=(i+1)th vertex
125 nextVertex = vertex + 1;
126 }
127
128 float vertX_i = polygonOrigin.GetPositionX() + vertices[vertex].GetPositionX();
129 float vertY_i = polygonOrigin.GetPositionY() + vertices[vertex].GetPositionY();
130 float vertX_j = polygonOrigin.GetPositionX() + vertices[nextVertex].GetPositionX();
131 float vertY_j = polygonOrigin.GetPositionY() + vertices[nextVertex].GetPositionY();
132
133 // following statement checks if testPoint.Y is below Y-coord of i-th vertex
134 bool belowLowY = vertY_i > testY;
135 // following statement checks if testPoint.Y is below Y-coord of i+1-th vertex
136 bool belowHighY = vertY_j > testY;
137
138 /* following statement is true if testPoint.Y satisfies either (only one is possible)
139 -->(i).Y < testPoint.Y < (i+1).Y OR
140 -->(i).Y > testPoint.Y > (i+1).Y
141
142 (Note)
143 Both of the conditions indicate that a point is located within the edges of the Y-th coordinate
144 of the (i)-th and the (i+1)- th vertices of the polygon. If neither of the above
145 conditions is satisfied, then it is assured that a semi-infinite horizontal line draw
146 to the right from the testpoint will NOT cross the line that connects vertices i and i+1
147 of the polygon
148 */
149 bool withinYsEdges = belowLowY != belowHighY;
150
151 if (withinYsEdges)
152 {
153 // this is the slope of the line that connects vertices i and i+1 of the polygon
154 float slopeOfLine = (vertX_j - vertX_i) / (vertY_j - vertY_i);
155
156 // this looks up the x-coord of a point lying on the above line, given its y-coord
157 float pointOnLine = (slopeOfLine * (testY - vertY_i)) + vertX_i;
158
159 //checks to see if x-coord of testPoint is smaller than the point on the line with the same y-coord
160 bool isLeftToLine = testX < pointOnLine;
161
162 if (isLeftToLine)
163 {
164 //this statement changes true to false (and vice-versa)
165 locatedInPolygon = !locatedInPolygon;
166 }//end if (isLeftToLine)
167 }//end if (withinYsEdges
168 }
169
170 return locatedInPolygon;
171}
172
173bool Position::HasInArc(float arc, Position const* obj, float border) const
174{
175 // always have self in arc
176 if (obj == this)
177 return true;
178
179 // move arc to range 0.. 2*pi
180 arc = NormalizeOrientation(arc);
181
182 // move angle to range -pi ... +pi
183 float angle = GetRelativeAngle(obj);
184 if (angle > float(M_PI))
185 angle -= 2.0f * float(M_PI);
186
187 float lborder = -1 * (arc / border); // in range -pi..0
188 float rborder = (arc / border); // in range 0..pi
189 return ((angle >= lborder) && (angle <= rborder));
190}
191
192bool Position::HasInLine(Position const* pos, float objSize, float width) const
193{
194 if (!HasInArc(float(M_PI), pos, 2.0f))
195 return false;
196
197 width += objSize;
198 float angle = GetRelativeAngle(pos);
199 return std::fabs(std::sin(angle)) * GetExactDist2d(pos->GetPositionX(), pos->GetPositionY()) < width;
200}
201
202std::string Position::ToString() const
203{
204 return Trinity::StringFormat("{}", *this);
205}
206
208{
209 // fmod only supports positive numbers. Thus we have
210 // to emulate negative numbers
211 if (o < 0)
212 return -std::fmod(-o, 2.0f * static_cast<float>(M_PI)) + 2.0f * static_cast<float>(M_PI);
213
214 return std::fmod(o, 2.0f * static_cast<float>(M_PI));
215}
216
218{
219 buf << float(streamer.Pos->GetPositionX());
220 buf << float(streamer.Pos->GetPositionY());
221 return buf;
222}
223
225{
226 buf >> streamer.Pos->m_positionX;
227 buf >> streamer.Pos->m_positionY;
228 return buf;
229}
230
232{
233 buf << float(streamer.Pos->GetPositionX());
234 buf << float(streamer.Pos->GetPositionY());
235 buf << float(streamer.Pos->GetPositionZ());
236 return buf;
237}
238
240{
241 buf >> streamer.Pos->m_positionX;
242 buf >> streamer.Pos->m_positionY;
243 buf >> streamer.Pos->m_positionZ;
244 return buf;
245}
246
248{
249 buf << float(streamer.Pos->GetPositionX());
250 buf << float(streamer.Pos->GetPositionY());
251 buf << float(streamer.Pos->GetPositionZ());
252 buf << float(streamer.Pos->GetOrientation());
253 return buf;
254}
255
257{
258 buf >> streamer.Pos->m_positionX;
259 buf >> streamer.Pos->m_positionY;
260 buf >> streamer.Pos->m_positionZ;
261 streamer.Pos->SetOrientation(buf.read<float>());
262 return buf;
263}
264
266{
267 int32 packed = 0;
268 packed |= (int32(streamer.Pos->GetPositionX() * 4.0f) & 0x7FF);
269 packed |= (int32(streamer.Pos->GetPositionY() * 4.0f) & 0x7FF) << 11;
270 packed |= (int32(streamer.Pos->GetPositionZ() * 4.0f) & 0x3FF) << 22;
271 buf << int32(packed);
272 return buf;
273}
274
276{
277 int32 packed;
278 buf >> packed;
279 streamer.Pos->Relocate(float((packed << 21) >> 21) * 0.25f, float((packed << 10) >> 21) * 0.25f, float(packed >> 22) * 0.25f);
280 return buf;
281}
282
283template <typename FormatContext>
284auto fmt::formatter<Position>::format(Position const& position, FormatContext& ctx) const -> decltype(ctx.out())
285{
286 return Trinity::StringFormatTo(ctx.out(), "X: {} Y: {} Z: {} O: {}",
287 position.GetPositionX(), position.GetPositionY(), position.GetPositionZ(), position.GetOrientation());
288}
289
290template <typename FormatContext>
291auto fmt::formatter<WorldLocation>::format(WorldLocation const& worldLocation, FormatContext& ctx) const -> decltype(ctx.out())
292{
293 ctx.advance_to(Trinity::StringFormatTo(ctx.out(), "MapID: {} ", worldLocation.GetMapId()));
294 return fmt::formatter<Position>::format(worldLocation, ctx);
295}
296
297template <typename FormatContext>
298auto fmt::formatter<TaggedPosition<Position::XY>>::format(TaggedPosition<Position::XY> const& position, FormatContext& ctx) const -> decltype(ctx.out())
299{
300 return Trinity::StringFormatTo(ctx.out(), "X: {} Y: {}",
301 position.Pos.GetPositionX(), position.Pos.GetPositionY());
302}
303
304template <typename FormatContext>
305auto fmt::formatter<TaggedPosition<Position::XYZ>>::format(TaggedPosition<Position::XYZ> const& position, FormatContext& ctx) const -> decltype(ctx.out())
306{
307 return Trinity::StringFormatTo(ctx.out(), "X: {} Y: {} Z: {}",
308 position.Pos.GetPositionX(), position.Pos.GetPositionY(), position.Pos.GetPositionZ());
309}
310
311template TC_GAME_API fmt::appender fmt::formatter<Position>::format<fmt::format_context>(Position const&, format_context&) const;
312template TC_GAME_API fmt::appender fmt::formatter<WorldLocation>::format<fmt::format_context>(WorldLocation const&, format_context&) const;
315
317{
318 MapEntry const* mapEntry = sMapStore.LookupEntry(m_mapId);
319 return Trinity::StringFormat("Map name: '{}' {}", mapEntry ? mapEntry->MapName[sWorld->GetDefaultDbcLocale()] : "<not found>", *this);
320}
#define M_PI
Definition Common.h:118
DB2Storage< MapEntry > sMapStore("Map.db2", &MapLoadInfo::Instance)
#define TC_GAME_API
Definition Define.h:129
int32_t int32
Definition Define.h:150
template TC_NETWORK_API fmt::appender Trinity::Net::Impl::AddressFormatter::format< fmt::format_context >(boost::asio::ip::address_v4 const &, fmt::format_context &) const
ByteBuffer & operator>>(ByteBuffer &buf, Position::Streamer< Position::XY > const &streamer)
Definition Position.cpp:224
ByteBuffer & operator<<(ByteBuffer &buf, Position::ConstStreamer< Position::XY > const &streamer)
Definition Position.cpp:217
std::string GetDebugInfo() const
Definition Position.cpp:316
uint32 m_mapId
Definition Position.h:218
#define sWorld
Definition World.h:916
bool IsValidMapCoord(float c)
OutputIt StringFormatTo(OutputIt out, FormatString< Args... > fmt, Args &&... args) noexcept
std::string StringFormat(FormatString< Args... > fmt, Args &&... args) noexcept
Default TC string format function.
LocalizedString MapName
Position const * Pos
Definition Position.h:53
Position * Pos
Definition Position.h:61
constexpr void SetOrientation(float orientation)
Definition Position.h:82
constexpr float GetPositionX() const
Definition Position.h:87
float m_positionZ
Definition Position.h:66
constexpr float GetPositionY() const
Definition Position.h:88
bool IsWithinVerticalCylinder(Position const &cylinderOrigin, float radius, float height, bool isDoubleVertical=false) const
Definition Position.cpp:96
float GetExactDist2d(const float x, const float y) const
Definition Position.h:117
float GetRelativeAngle(float x, float y) const
Definition Position.h:147
constexpr bool IsInDist2d(float x, float y, float dist) const
Definition Position.h:151
std::string ToString() const
Definition Position.cpp:202
static float NormalizeOrientation(float o)
Definition Position.cpp:207
Position GetPositionWithOffset(Position const &offset) const
Definition Position.cpp:61
Position GetPositionOffsetTo(Position const &endPos) const
Definition Position.cpp:47
float m_positionX
Definition Position.h:64
float m_positionY
Definition Position.h:65
bool HasInLine(Position const *pos, float objSize, float width) const
Definition Position.cpp:192
bool HasInArc(float arcangle, Position const *pos, float border=2.0f) const
Definition Position.cpp:173
bool IsInPolygon2D(Position const &polygonOrigin, std::span< Position const > vertices) const
Definition Position.cpp:104
bool IsPositionValid() const
Definition Position.cpp:42
bool operator==(Position const &a) const
Definition Position.cpp:26
constexpr void Relocate(float x, float y)
Definition Position.h:74
float m_orientation
Definition Position.h:69
void RelocateOffset(Position const &offset)
Definition Position.cpp:34
bool IsWithinBox(Position const &boxOrigin, float length, float width, float height) const
Definition Position.cpp:68
constexpr float GetOrientation() const
Definition Position.h:90
constexpr float GetPositionZ() const
Definition Position.h:89