Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.
 
 
 

382 rindas
10 KiB

  1. //
  2. // Lol Engine
  3. //
  4. // Copyright: (c) 2010-2014 Sam Hocevar <sam@hocevar.net>
  5. // This program is free software; you can redistribute it and/or
  6. // modify it under the terms of the Do What The Fuck You Want To
  7. // Public License, Version 2, as published by Sam Hocevar. See
  8. // http://www.wtfpl.net/ for more details.
  9. //
  10. //
  11. // The complex, quaternion and dual quaternion classes
  12. // ---------------------------------------------------
  13. //
  14. #if !defined __LOL_MATH_TRANSFORM_H__
  15. #define __LOL_MATH_TRANSFORM_H__
  16. #include <ostream>
  17. namespace lol
  18. {
  19. #if !LOL_FEATURE_CXX11_CONSTEXPR
  20. # define constexpr /* */
  21. #endif
  22. /*
  23. * 2-element transforms: complex numbers
  24. */
  25. template<typename T>
  26. struct cmplx_t : public linear_ops::base<T>
  27. {
  28. static int const count = 2;
  29. typedef T element;
  30. typedef cmplx_t<T> type;
  31. inline constexpr cmplx_t() {}
  32. inline constexpr cmplx_t(T X) : x(X), y(T(0)) {}
  33. inline constexpr cmplx_t(T X, T Y) : x(X), y(Y) {}
  34. template<typename U>
  35. explicit inline constexpr cmplx_t(cmplx_t<U> const &z)
  36. : x(z.x), y(z.y) {}
  37. LOL_COMMON_MEMBER_OPS(x)
  38. inline cmplx_t<T> operator *(cmplx_t<T> const &val) const
  39. {
  40. return cmplx_t<T>(x * val.x - y * val.y, x * val.y + y * val.x);
  41. }
  42. inline cmplx_t<T> operator *=(cmplx_t<T> const &val)
  43. {
  44. return *this = (*this) * val;
  45. }
  46. inline cmplx_t<T> operator ~() const
  47. {
  48. return cmplx_t<T>(x, -y);
  49. }
  50. template<typename U>
  51. friend std::ostream &operator<<(std::ostream &stream, cmplx_t<U> const &v);
  52. T x, y;
  53. };
  54. static_assert(sizeof(i8cmplx) == 2, "sizeof(i8cmplx) == 2");
  55. static_assert(sizeof(i16cmplx) == 4, "sizeof(i16cmplx) == 4");
  56. static_assert(sizeof(icmplx) == 8, "sizeof(icmplx) == 8");
  57. static_assert(sizeof(i64cmplx) == 16, "sizeof(i64cmplx) == 16");
  58. static_assert(sizeof(f16cmplx) == 4, "sizeof(f16cmplx) == 4");
  59. static_assert(sizeof(cmplx) == 8, "sizeof(cmplx) == 8");
  60. static_assert(sizeof(dcmplx) == 16, "sizeof(dcmplx) == 16");
  61. /*
  62. * 4-element transforms: quaternions
  63. */
  64. template<typename T>
  65. struct quat_t : public linear_ops::base<T>
  66. {
  67. static int const count = 4;
  68. typedef T element;
  69. typedef quat_t<T> type;
  70. /* Default constructor and copy constructor */
  71. inline constexpr quat_t() : w(), x(), y(), z() {}
  72. inline constexpr quat_t(quat_t<T> const &q)
  73. : w(q.w), x(q.x), y(q.y), z(q.z) {}
  74. /* Explicit constructor for type conversion */
  75. template<typename U>
  76. explicit inline constexpr quat_t(quat_t<U> const &q)
  77. : w(q.w), x(q.x), y(q.y), z(q.z) {}
  78. /* Various explicit constructors */
  79. explicit inline constexpr quat_t(T W, T X, T Y, T Z)
  80. : w(W), x(X), y(Y), z(Z) {}
  81. explicit inline constexpr quat_t(T W)
  82. : w(W), x(0), y(0), z(0) {}
  83. explicit quat_t(mat_t<T,3,3> const &m);
  84. explicit quat_t(mat_t<T,4,4> const &m);
  85. LOL_COMMON_MEMBER_OPS(w)
  86. inline quat_t operator *(quat_t const &val) const
  87. {
  88. vec_t<T,3> v1(x, y, z);
  89. vec_t<T,3> v2(val.x, val.y, val.z);
  90. vec_t<T,3> v3 = cross(v1, v2) + w * v2 + val.w * v1;
  91. return quat_t(w * val.w - dot(v1, v2), v3.x, v3.y, v3.z);
  92. }
  93. inline quat_t operator *=(quat_t const &val)
  94. {
  95. return *this = (*this * val);
  96. }
  97. /* Create a unit quaternion representing a rotation around an axis. */
  98. static quat_t rotate(T degrees, T x, T y, T z);
  99. static quat_t rotate(T degrees, vec_t<T,3> const &v);
  100. /* Create a unit quaternion representing a rotation between two vectors.
  101. * Input vectors need not be normalised. */
  102. static quat_t rotate(vec_t<T,3> const &src, vec_t<T,3> const &dst);
  103. /* Convert from Euler angles. The axes in fromeuler_xyx are
  104. * x, then y', then x", ie. the axes are attached to the model.
  105. * If you want to rotate around static axes, just reverse the order
  106. * of the arguments. Angle values are in degrees. */
  107. static quat_t fromeuler_xyx(vec_t<T,3> const &v);
  108. static quat_t fromeuler_xzx(vec_t<T,3> const &v);
  109. static quat_t fromeuler_yxy(vec_t<T,3> const &v);
  110. static quat_t fromeuler_yzy(vec_t<T,3> const &v);
  111. static quat_t fromeuler_zxz(vec_t<T,3> const &v);
  112. static quat_t fromeuler_zyz(vec_t<T,3> const &v);
  113. static quat_t fromeuler_xyx(T phi, T theta, T psi);
  114. static quat_t fromeuler_xzx(T phi, T theta, T psi);
  115. static quat_t fromeuler_yxy(T phi, T theta, T psi);
  116. static quat_t fromeuler_yzy(T phi, T theta, T psi);
  117. static quat_t fromeuler_zxz(T phi, T theta, T psi);
  118. static quat_t fromeuler_zyz(T phi, T theta, T psi);
  119. /* Convert from Tait-Bryan angles (incorrectly called Euler angles,
  120. * but since everyone does it…). The axes in fromeuler_xyz are
  121. * x, then y', then z", ie. the axes are attached to the model.
  122. * If you want to apply yaw around x, pitch around y, and roll
  123. * around z, use fromeuler_xyz. Angle values are in degrees.
  124. * If you want to rotate around static axes, reverse the order in
  125. * the function name (_zyx instead of _xyz) AND reverse the order
  126. * of the arguments. */
  127. static quat_t fromeuler_xyz(vec_t<T,3> const &v);
  128. static quat_t fromeuler_xzy(vec_t<T,3> const &v);
  129. static quat_t fromeuler_yxz(vec_t<T,3> const &v);
  130. static quat_t fromeuler_yzx(vec_t<T,3> const &v);
  131. static quat_t fromeuler_zxy(vec_t<T,3> const &v);
  132. static quat_t fromeuler_zyx(vec_t<T,3> const &v);
  133. static quat_t fromeuler_xyz(T phi, T theta, T psi);
  134. static quat_t fromeuler_xzy(T phi, T theta, T psi);
  135. static quat_t fromeuler_yxz(T phi, T theta, T psi);
  136. static quat_t fromeuler_yzx(T phi, T theta, T psi);
  137. static quat_t fromeuler_zxy(T phi, T theta, T psi);
  138. static quat_t fromeuler_zyx(T phi, T theta, T psi);
  139. inline quat_t operator ~() const
  140. {
  141. return quat_t(w, -x, -y, -z);
  142. }
  143. inline vec_t<T,3> transform(vec_t<T,3> const &v) const
  144. {
  145. quat_t p = quat_t(0, v.x, v.y, v.z);
  146. quat_t q = *this * p / *this;
  147. return vec_t<T,3>(q.x, q.y, q.z);
  148. }
  149. inline vec_t<T,4> transform(vec_t<T,4> const &v) const
  150. {
  151. quat_t p = quat_t(0, v.x, v.y, v.z);
  152. quat_t q = *this * p / *this;
  153. return vec_t<T,4>(q.x, q.y, q.z, v.w);
  154. }
  155. inline vec_t<T,3> operator *(vec_t<T,3> const &v) const
  156. {
  157. return transform(v);
  158. }
  159. inline vec_t<T,4> operator *(vec_t<T,4> const &v) const
  160. {
  161. return transform(v);
  162. }
  163. inline vec_t<T,3> axis()
  164. {
  165. vec_t<T,3> v(x, y, z);
  166. T n2 = sqlength(v);
  167. if (n2 <= (T)1e-6)
  168. return vec_t<T,3>::axis_x;
  169. return normalize(v);
  170. }
  171. inline T angle()
  172. {
  173. vec_t<T,3> v(x, y, z);
  174. T n2 = sqlength(v);
  175. if (n2 <= (T)1e-6)
  176. return (T)0;
  177. return (T)2 * lol::atan2(lol::sqrt(n2), w);
  178. }
  179. template<typename U>
  180. friend std::ostream &operator<<(std::ostream &stream, quat_t<U> const &v);
  181. /* XXX: storage order is wxyz, unlike vectors! */
  182. T w, x, y, z;
  183. };
  184. static_assert(sizeof(i8quat) == 4, "sizeof(i8quat) == 4");
  185. static_assert(sizeof(i16quat) == 8, "sizeof(i16quat) == 8");
  186. static_assert(sizeof(iquat) == 16, "sizeof(iquat) == 16");
  187. static_assert(sizeof(i64quat) == 32, "sizeof(i64quat) == 32");
  188. static_assert(sizeof(f16quat) == 8, "sizeof(f16quat) == 8");
  189. static_assert(sizeof(quat) == 16, "sizeof(quat) == 16");
  190. static_assert(sizeof(dquat) == 32, "sizeof(dquat) == 32");
  191. /*
  192. * Common operations on transforms
  193. */
  194. template<typename T>
  195. static inline T dot(cmplx_t<T> const &t1, cmplx_t<T> const &t2)
  196. {
  197. T ret(0);
  198. for (size_t i = 0; i < sizeof(t1) / sizeof(T); ++i)
  199. ret += t1[i] * t2[i];
  200. return ret;
  201. }
  202. template<typename T>
  203. static inline T sqlength(cmplx_t<T> const &t)
  204. {
  205. return dot(t, t);
  206. }
  207. template<typename T>
  208. static inline T length(cmplx_t<T> const &t)
  209. {
  210. /* FIXME: this is not very nice */
  211. return (T)sqrt((double)sqlength(t));
  212. }
  213. template<typename T>
  214. static inline T norm(cmplx_t<T> const &t)
  215. {
  216. return length(t);
  217. }
  218. template<typename T>
  219. static inline cmplx_t<T> normalize(cmplx_t<T> const &z)
  220. {
  221. T norm = (T)length(z);
  222. return norm ? z / norm : cmplx_t<T>(T(0));
  223. }
  224. /* XXX: duplicate */
  225. template<typename T>
  226. static inline T dot(quat_t<T> const &t1, quat_t<T> const &t2)
  227. {
  228. T ret(0);
  229. for (size_t i = 0; i < sizeof(t1) / sizeof(T); ++i)
  230. ret += t1[i] * t2[i];
  231. return ret;
  232. }
  233. template<typename T>
  234. static inline T sqlength(quat_t<T> const &t)
  235. {
  236. return dot(t, t);
  237. }
  238. template<typename T>
  239. static inline T length(quat_t<T> const &t)
  240. {
  241. /* FIXME: this is not very nice */
  242. return (T)sqrt((double)sqlength(t));
  243. }
  244. template<typename T>
  245. static inline T norm(quat_t<T> const &t)
  246. {
  247. return length(t);
  248. }
  249. template<typename T>
  250. static inline quat_t<T> normalize(quat_t<T> const &z)
  251. {
  252. T norm = (T)length(z);
  253. return norm ? z / norm : quat_t<T>(T(0));
  254. }
  255. /*
  256. * Complex numbers only
  257. */
  258. template<typename T>
  259. static inline cmplx_t<T> re(cmplx_t<T> const &z)
  260. {
  261. return ~z / sqlength(z);
  262. }
  263. template<typename T>
  264. static inline cmplx_t<T> operator /(T a, cmplx_t<T> const &b)
  265. {
  266. return a * re(b);
  267. }
  268. template<typename T>
  269. static inline cmplx_t<T> operator /(cmplx_t<T> a, cmplx_t<T> const &b)
  270. {
  271. return a * re(b);
  272. }
  273. template<typename T>
  274. static inline bool operator ==(cmplx_t<T> const &a, T b)
  275. {
  276. return (a.x == b) && !a.y;
  277. }
  278. template<typename T>
  279. static inline bool operator !=(cmplx_t<T> const &a, T b)
  280. {
  281. return (a.x != b) || a.y;
  282. }
  283. template<typename T>
  284. static inline bool operator ==(T a, cmplx_t<T> const &b) { return b == a; }
  285. template<typename T>
  286. static inline bool operator !=(T a, cmplx_t<T> const &b) { return b != a; }
  287. /*
  288. * Quaternions only
  289. */
  290. template<typename T>
  291. static inline quat_t<T> re(quat_t<T> const &q)
  292. {
  293. return ~q / sqlength(q);
  294. }
  295. template<typename T>
  296. static inline quat_t<T> operator /(T x, quat_t<T> const &y)
  297. {
  298. return x * re(y);
  299. }
  300. template<typename T>
  301. static inline quat_t<T> operator /(quat_t<T> const &x, quat_t<T> const &y)
  302. {
  303. return x * re(y);
  304. }
  305. template<typename T>
  306. extern quat_t<T> slerp(quat_t<T> const &qa, quat_t<T> const &qb, T f);
  307. #if !LOL_FEATURE_CXX11_CONSTEXPR
  308. #undef constexpr
  309. #endif
  310. } /* namespace lol */
  311. #endif // __LOL_MATH_TRANSFORM_H__