💿🐜 Antkeeper source code https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

490 lines
12 KiB

  1. /*
  2. * Copyright (C) 2020 Christopher J. Howard
  3. *
  4. * This file is part of Antkeeper source code.
  5. *
  6. * Antkeeper source code is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Antkeeper source code is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #ifndef ANTKEEPER_MATH_QUATERNION_FUNCTIONS_HPP
  20. #define ANTKEEPER_MATH_QUATERNION_FUNCTIONS_HPP
  21. #include "math/matrix-type.hpp"
  22. #include "math/quaternion-type.hpp"
  23. #include "math/vector-type.hpp"
  24. #include "math/vector-functions.hpp"
  25. #include <cmath>
  26. namespace math {
  27. /// @addtogroup quaternion
  28. /// @{
  29. /**
  30. * Adds two quaternions.
  31. *
  32. * @param x First quaternion.
  33. * @param y Second quaternion.
  34. * @return Sum of the two quaternions.
  35. */
  36. template <class T>
  37. quaternion<T> add(const quaternion<T>& x, const quaternion<T>& y);
  38. /**
  39. * Calculates the conjugate of a quaternion.
  40. *
  41. * @param x Quaternion from which the conjugate will be calculated.
  42. * @return Conjugate of the quaternion.
  43. */
  44. template <class T>
  45. quaternion<T> conjugate(const quaternion<T>& x);
  46. /**
  47. * Calculates the dot product of two quaternions.
  48. *
  49. * @param x First quaternion.
  50. * @param y Second quaternion.
  51. * @return Dot product of the two quaternions.
  52. */
  53. template <class T>
  54. T dot(const quaternion<T>& x, const quaternion<T>& y);
  55. /**
  56. * Divides a quaternion by a scalar.
  57. *
  58. * @param q Quaternion.
  59. * @param s Scalar.
  60. * @return Result of the division.
  61. */
  62. template <class T>
  63. quaternion<T> div(const quaternion<T>& q, T s);
  64. /**
  65. * Calculates the length of a quaternion.
  66. *
  67. * @param x Quaternion to calculate the length of.
  68. * @return Length of the quaternion.
  69. */
  70. template <class T>
  71. T length(const quaternion<T>& x);
  72. /**
  73. * Calculates the squared length of a quaternion. The squared length can be calculated faster than the length because a call to `std::sqrt` is saved.
  74. *
  75. * @param x Quaternion to calculate the squared length of.
  76. * @return Squared length of the quaternion.
  77. */
  78. template <class T>
  79. T length_squared(const quaternion<T>& x);
  80. /**
  81. * Performs linear interpolation between two quaternions.
  82. *
  83. * @param x First quaternion.
  84. * @param y Second quaternion.
  85. * @param a Interpolation factor.
  86. * @return Interpolated quaternion.
  87. */
  88. template <class T>
  89. quaternion<T> lerp(const quaternion<T>& x, const quaternion<T>& y, T a);
  90. /**
  91. * Creates a unit quaternion rotation using forward and up vectors.
  92. *
  93. * @param forward Unit forward vector.
  94. * @param up Unit up vector.
  95. * @return Unit rotation quaternion.
  96. */
  97. template <class T>
  98. quaternion<T> look_rotation(const vector<T, 3>& forward, vector<T, 3> up);
  99. /**
  100. * Converts a quaternion to a rotation matrix.
  101. *
  102. * @param q Unit quaternion.
  103. * @return Matrix representing the rotation described by `q`.
  104. */
  105. template <class T>
  106. matrix<T, 3, 3> matrix_cast(const quaternion<T>& q);
  107. /**
  108. * Multiplies two quaternions.
  109. *
  110. * @param x First quaternion.
  111. * @param y Second quaternion.
  112. * @return Product of the two quaternions.
  113. */
  114. template <class T>
  115. quaternion<T> mul(const quaternion<T>& x, const quaternion<T>& y);
  116. /**
  117. * Multiplies a quaternion by a scalar.
  118. *
  119. * @param q Quaternion.
  120. * @param s Scalar.
  121. * @return Product of the quaternion and scalar.
  122. */
  123. template <class T>
  124. quaternion<T> mul(const quaternion<T>& q, T s);
  125. /**
  126. * Rotates a 3-dimensional vector by a quaternion.
  127. *
  128. * @param q Unit quaternion.
  129. * @param v Vector.
  130. * @return Rotated vector.
  131. */
  132. template <class T>
  133. vector<T, 3> mul(const quaternion<T>& q, const vector<T, 3>& v);
  134. /**
  135. * Negates a quaternion.
  136. */
  137. template <class T>
  138. quaternion<T> negate(const quaternion<T>& x);
  139. /**
  140. * Performs normalized linear interpolation between two quaternions.
  141. *
  142. * @param x First quaternion.
  143. * @param y Second quaternion.
  144. * @param a Interpolation factor.
  145. * @return Interpolated quaternion.
  146. */
  147. template <class T>
  148. quaternion<T> nlerp(const quaternion<T>& x, const quaternion<T>& y, T a);
  149. /**
  150. * Normalizes a quaternion.
  151. */
  152. template <class T>
  153. quaternion<T> normalize(const quaternion<T>& x);
  154. /**
  155. * Creates a rotation from an angle and axis.
  156. *
  157. * @param angle Angle of rotation (in radians).
  158. * @param axis Axis of rotation
  159. * @return Quaternion representing the rotation.
  160. */
  161. template <class T>
  162. quaternion<T> angle_axis(T angle, const vector<T, 3>& axis);
  163. /**
  164. * Calculates the minimum rotation between two normalized direction vectors.
  165. *
  166. * @param source Normalized source direction.
  167. * @param destination Normalized destination direction.
  168. * @return Quaternion representing the minimum rotation between the source and destination vectors.
  169. */
  170. template <class T>
  171. quaternion<T> rotation(const vector<T, 3>& source, const vector<T, 3>& destination);
  172. /**
  173. * Performs spherical linear interpolation between two quaternions.
  174. *
  175. * @param x First quaternion.
  176. * @param y Second quaternion.
  177. * @param a Interpolation factor.
  178. * @return Interpolated quaternion.
  179. */
  180. template <class T>
  181. quaternion<T> slerp(const quaternion<T>& x, const quaternion<T>& y, T a);
  182. /**
  183. * Subtracts a quaternion from another quaternion.
  184. *
  185. * @param x First quaternion.
  186. * @param y Second quaternion.
  187. * @return Difference between the quaternions.
  188. */
  189. template <class T>
  190. quaternion<T> sub(const quaternion<T>& x, const quaternion<T>& y);
  191. /**
  192. * Converts a 3x3 rotation matrix to a quaternion.
  193. *
  194. * @param m Rotation matrix.
  195. * @return Unit quaternion representing the rotation described by `m`.
  196. */
  197. template <class T>
  198. quaternion<T> quaternion_cast(const matrix<T, 3, 3>& m);
  199. /**
  200. * Types casts each quaternion component and returns a quaternion of the casted type.
  201. *
  202. * @tparam T2 Target quaternion component type.
  203. * @tparam T1 Source quaternion component type.
  204. * @param q Quaternion to type cast.
  205. * @return Type-casted quaternion.
  206. */
  207. template <class T2, class T1>
  208. quaternion<T2> type_cast(const quaternion<T1>& q);
  209. template <class T>
  210. inline quaternion<T> add(const quaternion<T>& x, const quaternion<T>& y)
  211. {
  212. return {x.w + y.w, x.x + y.x, x.y + y.y, x.z + y.z};
  213. }
  214. template <class T>
  215. inline quaternion<T> conjugate(const quaternion<T>& x)
  216. {
  217. return {x.w, -x.x, -x.y, -x.z};
  218. }
  219. template <class T>
  220. inline T dot(const quaternion<T>& x, const quaternion<T>& y)
  221. {
  222. return {x.w * y.w + x.x * y.x + x.y * y.y + x.z * y.z};
  223. }
  224. template <class T>
  225. inline quaternion<T> div(const quaternion<T>& q, T s)
  226. {
  227. return {q.w / s, q.x / s, q.y / s, q.z / s}
  228. }
  229. template <class T>
  230. inline T length(const quaternion<T>& x)
  231. {
  232. return std::sqrt(x.w * x.w + x.x * x.x + x.y * x.y + x.z * x.z);
  233. }
  234. template <class T>
  235. inline T length_squared(const quaternion<T>& x)
  236. {
  237. return x.w * x.w + x.x * x.x + x.y * x.y + x.z * x.z;
  238. }
  239. template <class T>
  240. inline quaternion<T> lerp(const quaternion<T>& x, const quaternion<T>& y, T a)
  241. {
  242. return
  243. {
  244. (y.w - x.w) * a + x.w,
  245. (y.x - x.x) * a + x.x,
  246. (y.y - x.y) * a + x.y,
  247. (y.z - x.z) * a + x.z
  248. };
  249. }
  250. template <class T>
  251. quaternion<T> look_rotation(const vector<T, 3>& forward, vector<T, 3> up)
  252. {
  253. vector<T, 3> right = normalize(cross(forward, up));
  254. up = cross(right, forward);
  255. matrix<T, 3, 3> m =
  256. {{
  257. {right[0], up[0], -forward[0]},
  258. {right[1], up[1], -forward[1]},
  259. {right[2], up[2], -forward[2]}
  260. }};
  261. // Convert to quaternion
  262. return normalize(quaternion_cast(m));
  263. }
  264. template <class T>
  265. matrix<T, 3, 3> matrix_cast(const quaternion<T>& q)
  266. {
  267. T wx = q.w * q.x;
  268. T wy = q.w * q.y;
  269. T wz = q.w * q.z;
  270. T xx = q.x * q.x;
  271. T xy = q.x * q.y;
  272. T xz = q.x * q.z;
  273. T yy = q.y * q.y;
  274. T yz = q.y * q.z;
  275. T zz = q.z * q.z;
  276. return
  277. {{
  278. {T(1) - (yy + zz) * T(2), (xy + wz) * T(2), (xz - wy) * T(2)},
  279. {(xy - wz) * T(2), T(1) - (xx + zz) * T(2), (yz + wx) * T(2)},
  280. {(xz + wy) * T(2), (yz - wx) * T(2), T(1) - (xx + yy) * T(2)}
  281. }};
  282. }
  283. template <class T>
  284. quaternion<T> mul(const quaternion<T>& x, const quaternion<T>& y)
  285. {
  286. return
  287. {
  288. -x.x * y.x - x.y * y.y - x.z * y.z + x.w * y.w,
  289. x.x * y.w + x.y * y.z - x.z * y.y + x.w * y.x,
  290. -x.x * y.z + x.y * y.w + x.z * y.x + x.w * y.y,
  291. x.x * y.y - x.y * y.x + x.z * y.w + x.w * y.z
  292. };
  293. }
  294. template <class T>
  295. inline quaternion<T> mul(const quaternion<T>& q, T s)
  296. {
  297. return {q.w * s, q.x * s, q.y * s, q.z * s};
  298. }
  299. template <class T>
  300. vector<T, 3> mul(const quaternion<T>& q, const vector<T, 3>& v)
  301. {
  302. const T r = q.w; // Real part
  303. const vector<T, 3>& i = reinterpret_cast<const vector<T, 3>&>(q.x); // Imaginary part
  304. return i * dot(i, v) * T(2) + v * (r * r - dot(i, i)) + cross(i, v) * r * T(2);
  305. }
  306. template <class T>
  307. inline quaternion<T> negate(const quaternion<T>& x)
  308. {
  309. return {-x.w, -x.x, -x.y, -x.z};
  310. }
  311. template <class T>
  312. quaternion<T> nlerp(const quaternion<T>& x, const quaternion<T>& y, T a)
  313. {
  314. if (dot(x, y) < T(0))
  315. {
  316. return normalize(add(mul(x, T(1) - a), mul(y, -a)));
  317. }
  318. else
  319. {
  320. return normalize(add(mul(x, T(1) - a), mul(y, a)));
  321. }
  322. }
  323. template <class T>
  324. inline quaternion<T> normalize(const quaternion<T>& x)
  325. {
  326. return mul(x, T(1) / length(x));
  327. }
  328. template <class T>
  329. quaternion<T> angle_axis(T angle, const vector<T, 3>& axis)
  330. {
  331. T s = std::sin(angle * T(0.5));
  332. return {static_cast<T>(std::cos(angle * T(0.5))), axis.x * s, axis.y * s, axis.z * s};
  333. }
  334. template <class T>
  335. quaternion<T> rotation(const vector<T, 3>& source, const vector<T, 3>& destination)
  336. {
  337. quaternion<T> q;
  338. q.w = dot(source, destination);
  339. reinterpret_cast<vector<T, 3>&>(q.x) = cross(source, destination);
  340. q.w += length(q);
  341. return normalize(q);
  342. }
  343. template <class T>
  344. quaternion<T> slerp(const quaternion<T>& x, const quaternion<T>& y, T a)
  345. {
  346. T cos_theta = dot(x, y);
  347. constexpr T epsilon = T(0.0005);
  348. if (cos_theta > T(1) - epsilon)
  349. {
  350. return normalize(lerp(x, y, a));
  351. }
  352. cos_theta = std::max<T>(T(-1), std::min<T>(T(1), cos_theta));
  353. T theta = static_cast<T>(std::acos(cos_theta)) * a;
  354. quaternion<T> z = normalize(sub(y, mul(x, cos_theta)));
  355. return add(mul(x, static_cast<T>(std::cos(theta))), mul(z, static_cast<T>(std::sin(theta))));
  356. }
  357. template <class T>
  358. inline quaternion<T> sub(const quaternion<T>& x, const quaternion<T>& y)
  359. {
  360. return {x.w - y.w, x.x - y.x, x.y - y.y, x.z - y.z};
  361. }
  362. template <class T>
  363. quaternion<T> quaternion_cast(const matrix<T, 3, 3>& m)
  364. {
  365. T r;
  366. vector<T, 3> i;
  367. T trace = m[0][0] + m[1][1] + m[2][2];
  368. if (trace > T(0))
  369. {
  370. T s = T(0.5) / std::sqrt(trace + T(1));
  371. r = T(0.25) / s;
  372. i =
  373. {
  374. (m[2][1] - m[1][2]) * s,
  375. (m[0][2] - m[2][0]) * s,
  376. (m[1][0] - m[0][1]) * s
  377. };
  378. }
  379. else
  380. {
  381. if (m[0][0] > m[1][1] && m[0][0] > m[2][2])
  382. {
  383. T s = T(2) * std::sqrt(T(1) + m[0][0] - m[1][1] - m[2][2]);
  384. r = (m[2][1] - m[1][2]) / s;
  385. i =
  386. {
  387. T(0.25) * s,
  388. (m[0][1] + m[1][0]) / s,
  389. (m[0][2] + m[2][0]) / s
  390. };
  391. }
  392. else if (m[1][1] > m[2][2])
  393. {
  394. T s = T(2) * std::sqrt(T(1) + m[1][1] - m[0][0] - m[2][2]);
  395. r = (m[0][2] - m[2][0]) / s;
  396. i =
  397. {
  398. (m[0][1] + m[1][0]) / s,
  399. T(0.25) * s,
  400. (m[1][2] + m[2][1]) / s
  401. };
  402. }
  403. else
  404. {
  405. T s = T(2) * std::sqrt(T(1) + m[2][2] - m[0][0] - m[1][1]);
  406. r = (m[1][0] - m[0][1]) / s;
  407. i =
  408. {
  409. (m[0][2] + m[2][0]) / s,
  410. (m[1][2] + m[2][1]) / s,
  411. T(0.25) * s
  412. };
  413. }
  414. }
  415. return {r, i.x, i.y, i.z};
  416. }
  417. template <class T2, class T1>
  418. inline quaternion<T2> type_cast(const quaternion<T1>& q)
  419. {
  420. return quaternion<T2>
  421. {
  422. static_cast<T2>(q.w),
  423. static_cast<T2>(q.x),
  424. static_cast<T2>(q.y),
  425. static_cast<T2>(q.z)
  426. };
  427. }
  428. /// @}
  429. } // namespace math
  430. #endif // ANTKEEPER_MATH_QUATERNION_FUNCTIONS_HPP