Cry_Vector2.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. // Description : Common matrix class
  9. #pragma once
  10. #include <AzCore/RTTI/TypeInfo.h>
  11. #include "Cry_Math.h"
  12. template<class F>
  13. struct Vec2_tpl
  14. {
  15. typedef F value_type;
  16. enum
  17. {
  18. component_count = 2
  19. };
  20. F x, y;
  21. #ifdef _DEBUG
  22. ILINE Vec2_tpl()
  23. {
  24. if constexpr (sizeof(F) == 4)
  25. {
  26. uint32* p = alias_cast<uint32*>(&x);
  27. p[0] = F32NAN;
  28. p[1] = F32NAN;
  29. }
  30. if constexpr (sizeof(F) == 8)
  31. {
  32. uint64* p = alias_cast<uint64*>(&x);
  33. p[0] = F64NAN;
  34. p[1] = F64NAN;
  35. }
  36. }
  37. #else
  38. ILINE Vec2_tpl() {}
  39. #endif
  40. ILINE Vec2_tpl(type_zero)
  41. : x(0)
  42. , y(0) {}
  43. ILINE Vec2_tpl(F vx, F vy) { x = vx; y = vy; }
  44. explicit ILINE Vec2_tpl(F m) { x = y = m; }
  45. ILINE Vec2_tpl& set(F nx, F ny) { x = F(nx); y = F(ny); return *this; }
  46. template<class F1>
  47. ILINE Vec2_tpl(const Vec2_tpl<F1>& src) { x = F(src.x); y = F(src.y); }
  48. template<class F1>
  49. ILINE explicit Vec2_tpl(const Vec3_tpl<F1>& src) { x = F(src.x); y = F(src.y); }
  50. template<class F1>
  51. ILINE explicit Vec2_tpl(const F1* psrc) { x = F(psrc[0]); y = F(psrc[1]); }
  52. explicit ILINE Vec2_tpl(const Vec3_tpl<F>& v)
  53. : x((F)v.x)
  54. , y((F)v.y) { assert(this->IsValid()); }
  55. Vec2_tpl& operator=(const Vec2_tpl& src) = default;
  56. ILINE int operator!() const { return x == 0 && y == 0; }
  57. // The default Normalize function is in fact "safe". 0 vectors remain unchanged.
  58. Vec2_tpl& Normalize()
  59. {
  60. F fInvLen = isqrt_safe_tpl(x * x + y * y);
  61. x *= fInvLen;
  62. y *= fInvLen;
  63. return *this;
  64. }
  65. // Normalize if non-0, otherwise set to specified "safe" value.
  66. Vec2_tpl& NormalizeSafe(const struct Vec2_tpl<F>& safe = Vec2_tpl<F>(0, 0))
  67. {
  68. F fLen2 = x * x + y * y;
  69. if (fLen2 > 0.0f)
  70. {
  71. F fInvLen = isqrt_tpl(fLen2);
  72. x *= fInvLen;
  73. y *= fInvLen;
  74. }
  75. else
  76. {
  77. *this = safe;
  78. }
  79. return *this;
  80. }
  81. Vec2_tpl GetNormalized() const
  82. {
  83. F fInvLen = isqrt_safe_tpl(x * x + y * y);
  84. return *this * fInvLen;
  85. }
  86. Vec2_tpl GetNormalizedSafe(const struct Vec2_tpl<F>& safe = Vec2_tpl<F>(1, 0)) const
  87. {
  88. F fLen2 = x * x + y * y;
  89. if (fLen2 > 0.0f)
  90. {
  91. F fInvLen = isqrt_tpl(fLen2);
  92. return *this * fInvLen;
  93. }
  94. else
  95. {
  96. return safe;
  97. }
  98. }
  99. ILINE bool IsEquivalent(const Vec2_tpl<F>& v1, F epsilon = VEC_EPSILON) const
  100. {
  101. assert(v1.IsValid());
  102. assert(this->IsValid());
  103. return ((fabs_tpl(x - v1.x) <= epsilon) && (fabs_tpl(y - v1.y) <= epsilon));
  104. }
  105. ILINE static bool IsEquivalent(const Vec2_tpl<F>& v0, const Vec2_tpl<F>& v1, F epsilon = VEC_EPSILON)
  106. {
  107. assert(v0.IsValid());
  108. assert(v1.IsValid());
  109. return ((fabs_tpl(v0.x - v1.x) <= epsilon) && (fabs_tpl(v0.y - v1.y) <= epsilon));
  110. }
  111. ILINE F GetLength() const
  112. {
  113. return sqrt_tpl(x * x + y * y);
  114. }
  115. ILINE F GetLengthSquared() const
  116. {
  117. return x * x + y * y;
  118. }
  119. ILINE F GetLength2() const
  120. {
  121. return x * x + y * y;
  122. }
  123. void SetLength(F fLen)
  124. {
  125. F fLenMe = GetLength2();
  126. if (fLenMe < 0.00001f * 0.00001f)
  127. {
  128. return;
  129. }
  130. fLenMe = fLen * isqrt_tpl(fLenMe);
  131. x *= fLenMe;
  132. y *= fLenMe;
  133. }
  134. ILINE F area() const { return x * y; }
  135. ILINE F& operator[](int idx) { return *((F*)&x + idx); }
  136. ILINE F operator[](int idx) const { return *((F*)&x + idx); }
  137. ILINE operator F*() { return &x; }
  138. ILINE Vec2_tpl& flip() { x = -x; y = -y; return *this; }
  139. ILINE Vec2_tpl& zero() { x = y = 0; return *this; }
  140. ILINE Vec2_tpl rot90ccw() const { return Vec2_tpl(-y, x); }
  141. ILINE Vec2_tpl rot90cw() const { return Vec2_tpl(y, -x); }
  142. #ifdef quotient_h
  143. quotient_tpl<F> fake_atan2() const
  144. {
  145. quotient_tpl<F> res;
  146. int quad = -(signnz(x * x - y * y) - 1 >> 1); // hope the optimizer will remove complement shifts and adds
  147. if (quad)
  148. {
  149. res.x = -y;
  150. res.y = x;
  151. }
  152. else
  153. {
  154. res.x = x;
  155. res.y = y;
  156. }
  157. int sgny = signnz(res.y);
  158. quad |= 1 - sgny; //(res.y<0)<<1;
  159. res.x *= sgny;
  160. res.y *= sgny;
  161. res += 1 + (quad << 1);
  162. return res;
  163. }
  164. #endif
  165. ILINE F atan2() const { return atan2_tpl(y, x); }
  166. ILINE Vec2_tpl operator-() const { return Vec2_tpl(-x, -y); }
  167. ILINE Vec2_tpl operator*(F k) const { return Vec2_tpl(x * k, y * k); }
  168. ILINE Vec2_tpl& operator*=(F k) { x *= k; y *= k; return *this; }
  169. ILINE Vec2_tpl operator/(F k) const { return *this * ((F)1.0 / k); }
  170. ILINE Vec2_tpl& operator/=(F k) { return *this *= ((F)1.0 / k); }
  171. // bool operator==(const Vec2_tpl<F> &vec) { return x == vec.x && y == vec.y; }
  172. ILINE bool operator!=(const Vec2_tpl<F>& vec) { return !(*this == vec); }
  173. ILINE friend bool operator==(const Vec2_tpl<F>& left, const Vec2_tpl<F>& right) { return left.x == right.x && left.y == right.y; }
  174. ILINE friend bool operator!=(const Vec2_tpl<F>& left, const Vec2_tpl<F>& right) { return !(left == right); }
  175. ILINE bool IsZero(F e = (F)0.0) const
  176. {
  177. return (fabs_tpl(x) <= e) && (fabs_tpl(y) <= e);
  178. }
  179. // IsZeroSlow would be a better name [5/20/2010 evgeny]
  180. ILINE bool IsZeroFast(F e = (F)0.0003) const
  181. {
  182. return (fabs_tpl(x) + fabs_tpl(y)) <= e;
  183. }
  184. ILINE F Dot(const Vec2_tpl& rhs) const {return x * rhs.x + y * rhs.y; }
  185. /// returns a vector perpendicular to this one (this->Cross(newVec) points "up")
  186. ILINE Vec2_tpl Perp() const {return Vec2_tpl(-y, x); }
  187. // The size of the "paralell-trapets" area spanned by the two vectors.
  188. ILINE F Cross (const Vec2_tpl<F>& v) const
  189. {
  190. return float (x * v.y - y * v.x);
  191. }
  192. /*!
  193. * Linear-Interpolation between Vec3 (lerp)
  194. *
  195. * Example:
  196. * Vec3 r=Vec3::CreateLerp( p, q, 0.345f );
  197. */
  198. ILINE void SetLerp(const Vec2_tpl<F>& p, const Vec2_tpl<F>& q, F t) { *this = p * (1.0f - t) + q * t; }
  199. ILINE static Vec2_tpl<F> CreateLerp(const Vec2_tpl<F>& p, const Vec2_tpl<F>& q, F t) { return p * (1.0f - t) + q * t; }
  200. /*!
  201. * Spherical-Interpolation between 3d-vectors (geometrical slerp)
  202. * both vectors are assumed to be normalized.
  203. *
  204. * Example:
  205. * Vec3 r=Vec3::CreateSlerp( p, q, 0.5674f );
  206. */
  207. void SetSlerp(const Vec2_tpl<F>& p, const Vec2_tpl<F>& q, F t)
  208. {
  209. assert((fabs_tpl(1 - (p | p))) < 0.005); //check if unit-vector
  210. assert((fabs_tpl(1 - (q | q))) < 0.005); //check if unit-vector
  211. // calculate cosine using the "inner product" between two vectors: p*q=cos(radiant)
  212. F cosine = (p | q);
  213. //we explore the special cases where the both vectors are very close together,
  214. //in which case we approximate using the more economical LERP and avoid "divisions by zero" since sin(Angle) = 0 as Angle=0
  215. if (cosine >= (F)0.99)
  216. {
  217. SetLerp(p, q, t); //perform LERP:
  218. this->Normalize();
  219. }
  220. else
  221. {
  222. //perform SLERP: because of the LERP-check above, a "division by zero" is not possible
  223. F rad = acos_tpl(cosine);
  224. F scale_0 = sin_tpl((1 - t) * rad);
  225. F scale_1 = sin_tpl(t * rad);
  226. *this = (p * scale_0 + q * scale_1) / sin_tpl(rad);
  227. this->Normalize();
  228. }
  229. }
  230. ILINE static Vec2_tpl<F> CreateSlerp(const Vec2_tpl<F>& p, const Vec2_tpl<F>& q, F t)
  231. {
  232. Vec2_tpl<F> v;
  233. v.SetSlerp(p, q, t);
  234. return v;
  235. }
  236. bool IsValid() const
  237. {
  238. if (!NumberValid(x))
  239. {
  240. return false;
  241. }
  242. if (!NumberValid(y))
  243. {
  244. return false;
  245. }
  246. return true;
  247. }
  248. ILINE F GetDistance(const Vec2_tpl<F>& vec1) const
  249. {
  250. return sqrt_tpl((x - vec1.x) * (x - vec1.x) + (y - vec1.y) * (y - vec1.y));
  251. }
  252. };
  253. ///////////////////////////////////////////////////////////////////////////////
  254. // Typedefs //
  255. ///////////////////////////////////////////////////////////////////////////////
  256. typedef Vec2_tpl<f32> Vec2; // always 32 bit
  257. typedef Vec2_tpl<int32> Vec2i;
  258. #if defined(LINUX64)
  259. typedef Vec2_tpl<int> vector2l;
  260. #else
  261. typedef Vec2_tpl<long> vector2l;
  262. #endif
  263. template<class F>
  264. Vec2_tpl<F> operator*(F op1, const Vec2_tpl<F>& op2) {return Vec2_tpl<F>(op1 * op2.x, op1 * op2.y); }
  265. template<class F1, class F2>
  266. F1 operator*(const Vec2_tpl<F1>& op1, const Vec2_tpl<F2>& op2) { return op1.x * op2.x + op1.y * op2.y; } // dot product
  267. template<class F1, class F2>
  268. F1 operator|(const Vec2_tpl<F1>& op1, const Vec2_tpl<F2>& op2) { return op1.x * op2.x + op1.y * op2.y; } // dot product
  269. template<class F1, class F2>
  270. F1 operator^(const Vec2_tpl<F1>& op1, const Vec2_tpl<F2>& op2) { return op1.x * op2.y - op1.y * op2.x; } // cross product
  271. template<class F1, class F2>
  272. Vec2_tpl<F1> operator+(const Vec2_tpl<F1>& op1, const Vec2_tpl<F2>& op2)
  273. {
  274. return Vec2_tpl<F1>(op1.x + op2.x, op1.y + op2.y);
  275. }
  276. template<class F1, class F2>
  277. Vec2_tpl<F1> operator-(const Vec2_tpl<F1>& op1, const Vec2_tpl<F2>& op2)
  278. {
  279. return Vec2_tpl<F1>(op1.x - op2.x, op1.y - op2.y);
  280. }
  281. template<class F1, class F2>
  282. Vec2_tpl<F1>& operator+=(Vec2_tpl<F1>& op1, const Vec2_tpl<F2>& op2)
  283. {
  284. op1.x += op2.x;
  285. op1.y += op2.y;
  286. return op1;
  287. }
  288. template<class F1, class F2>
  289. Vec2_tpl<F1>& operator-=(Vec2_tpl<F1>& op1, const Vec2_tpl<F2>& op2)
  290. {
  291. op1.x -= op2.x;
  292. op1.y -= op2.y;
  293. return op1;
  294. }
  295. template<class F>
  296. bool operator==(const Vec2_tpl<F>& left, const Vec2_tpl<F>& right)
  297. {
  298. return left.x == right.x && left.y == right.y;
  299. }
  300. template<>
  301. ILINE Vec2 clamp_tpl<Vec2>(Vec2 X, Vec2 Min, Vec2 Max)
  302. {
  303. return Vec2(clamp_tpl(X.x, Min.x, Max.x), clamp_tpl(X.y, Min.y, Max.y));
  304. }
  305. // declare common constants. Must be done after the class for compiler conformance
  306. // (msvc and clang handle instantiation differently)
  307. const Vec2_tpl<float> Vec2_Zero(0, 0);
  308. const Vec2_tpl<float> Vec2_OneX(1, 0);
  309. const Vec2_tpl<float> Vec2_OneY(0, 1);
  310. const Vec2_tpl<float> Vec2_One(1, 1);
  311. namespace AZ
  312. {
  313. AZ_TYPE_INFO_SPECIALIZE(Vec2, "{844131BA-9565-42F3-8482-6F65A6D5FC59}");
  314. }