💿🐜 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.

443 lines
10 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. * Normalizes a quaternion.
  141. */
  142. template <class T>
  143. quaternion<T> normalize(const quaternion<T>& x);
  144. /**
  145. * Creates a rotation from an angle and axis.
  146. *
  147. * @param angle Angle of rotation (in radians).
  148. * @param axis Axis of rotation
  149. * @return Quaternion representing the rotation.
  150. */
  151. template <class T>
  152. quaternion<T> angle_axis(T angle, const vector<T, 3>& axis);
  153. /**
  154. * Calculates the minimum rotation between two normalized direction vectors.
  155. *
  156. * @param source Normalized source direction.
  157. * @param destination Normalized destination direction.
  158. * @return Quaternion representing the minimum rotation between the source and destination vectors.
  159. */
  160. template <class T>
  161. quaternion<T> rotation(const vector<T, 3>& source, const vector<T, 3>& destination);
  162. /**
  163. * Performs spherical linear interpolation between two quaternions.
  164. *
  165. * @param x First quaternion.
  166. * @param y Second quaternion.
  167. * @param a Interpolation factor.
  168. * @return Interpolated quaternion.
  169. */
  170. template <class T>
  171. quaternion<T> slerp(const quaternion<T>& x, const quaternion<T>& y, T a);
  172. /**
  173. * Subtracts a quaternion from another quaternion.
  174. *
  175. * @param x First quaternion.
  176. * @param y Second quaternion.
  177. * @return Difference between the quaternions.
  178. */
  179. template <class T>
  180. quaternion<T> sub(const quaternion<T>& x, const quaternion<T>& y);
  181. /**
  182. * Converts a 3x3 rotation matrix to a quaternion.
  183. *
  184. * @param m Rotation matrix.
  185. * @return Unit quaternion representing the rotation described by `m`.
  186. */
  187. template <class T>
  188. quaternion<T> quaternion_cast(const matrix<T, 3, 3>& m);
  189. template <class T>
  190. inline quaternion<T> add(const quaternion<T>& x, const quaternion<T>& y)
  191. {
  192. return {x.w + y.w, x.x + y.x, x.y + y.y, x.z + y.z};
  193. }
  194. template <class T>
  195. inline quaternion<T> conjugate(const quaternion<T>& x)
  196. {
  197. return {x.w, -x.x, -x.y, -x.z};
  198. }
  199. template <class T>
  200. inline T dot(const quaternion<T>& x, const quaternion<T>& y)
  201. {
  202. return {x.w * y.w + x.x * y.x + x.y * y.y + x.z * y.z};
  203. }
  204. template <class T>
  205. inline quaternion<T> div(const quaternion<T>& q, T s)
  206. {
  207. return {q.w / s, q.x / s, q.y / s, q.z / s}
  208. }
  209. template <class T>
  210. inline T length(const quaternion<T>& x)
  211. {
  212. return std::sqrt(x.w * x.w + x.x * x.x + x.y * x.y + x.z * x.z);
  213. }
  214. template <class T>
  215. inline T length_squared(const quaternion<T>& x)
  216. {
  217. return x.w * x.w + x.x * x.x + x.y * x.y + x.z * x.z;
  218. }
  219. template <class T>
  220. inline quaternion<T> lerp(const quaternion<T>& x, const quaternion<T>& y, T a)
  221. {
  222. return
  223. {
  224. x.w * (T(1) - a) + y.w * a,
  225. x.x * (T(1) - a) + y.x * a,
  226. x.y * (T(1) - a) + y.y * a,
  227. x.z * (T(1) - a) + y.z * a
  228. };
  229. }
  230. template <class T>
  231. quaternion<T> look_rotation(const vector<T, 3>& forward, vector<T, 3> up)
  232. {
  233. vector<T, 3> right = normalize(cross(forward, up));
  234. up = cross(right, forward);
  235. matrix<T, 3, 3> m =
  236. {{
  237. {right[0], up[0], -forward[0]},
  238. {right[1], up[1], -forward[1]},
  239. {right[2], up[2], -forward[2]}
  240. }};
  241. // Convert to quaternion
  242. return normalize(quaternion_cast(m));
  243. }
  244. template <class T>
  245. matrix<T, 3, 3> matrix_cast(const quaternion<T>& q)
  246. {
  247. T wx = q.w * q.x;
  248. T wy = q.w * q.y;
  249. T wz = q.w * q.z;
  250. T xx = q.x * q.x;
  251. T xy = q.x * q.y;
  252. T xz = q.x * q.z;
  253. T yy = q.y * q.y;
  254. T yz = q.y * q.z;
  255. T zz = q.z * q.z;
  256. return
  257. {{
  258. {T(1) - (yy + zz) * T(2), (xy + wz) * T(2), (xz - wy) * T(2)},
  259. {(xy - wz) * T(2), T(1) - (xx + zz) * T(2), (yz + wx) * T(2)},
  260. {(xz + wy) * T(2), (yz - wx) * T(2), T(1) - (xx + yy) * T(2)}
  261. }};
  262. }
  263. template <class T>
  264. quaternion<T> mul(const quaternion<T>& x, const quaternion<T>& y)
  265. {
  266. return
  267. {
  268. -x.x * y.x - x.y * y.y - x.z * y.z + x.w * y.w,
  269. x.x * y.w + x.y * y.z - x.z * y.y + x.w * y.x,
  270. -x.x * y.z + x.y * y.w + x.z * y.x + x.w * y.y,
  271. x.x * y.y - x.y * y.x + x.z * y.w + x.w * y.z
  272. };
  273. }
  274. template <class T>
  275. inline quaternion<T> mul(const quaternion<T>& q, T s)
  276. {
  277. return {q.w * s, q.x * s, q.y * s, q.z * s};
  278. }
  279. template <class T>
  280. vector<T, 3> mul(const quaternion<T>& q, const vector<T, 3>& v)
  281. {
  282. const T r = q.w; // Real part
  283. const vector<T, 3>& i = reinterpret_cast<const vector<T, 3>&>(q.x); // Imaginary part
  284. return i * dot(i, v) * T(2) + v * (r * r - dot(i, i)) + cross(i, v) * r * T(2);
  285. }
  286. template <class T>
  287. inline quaternion<T> negate(const quaternion<T>& x)
  288. {
  289. return {-x.w, -x.x, -x.y, -x.z};
  290. }
  291. template <class T>
  292. inline quaternion<T> normalize(const quaternion<T>& x)
  293. {
  294. return mul(x, T(1) / length(x));
  295. }
  296. template <class T>
  297. quaternion<T> angle_axis(T angle, const vector<T, 3>& axis)
  298. {
  299. T s = std::sin(angle * T(0.5));
  300. return {static_cast<T>(std::cos(angle * T(0.5))), axis.x * s, axis.y * s, axis.z * s};
  301. }
  302. template <class T>
  303. quaternion<T> rotation(const vector<T, 3>& source, const vector<T, 3>& destination)
  304. {
  305. quaternion<T> q;
  306. q.w = dot(source, destination);
  307. reinterpret_cast<vector<T, 3>&>(q.x) = cross(source, destination);
  308. q.w += length(q);
  309. return normalize(q);
  310. }
  311. template <class T>
  312. quaternion<T> slerp(const quaternion<T>& x, const quaternion<T>& y, T a)
  313. {
  314. T cos_theta = dot(x, y);
  315. constexpr T epsilon = T(0.0005);
  316. if (cos_theta > T(1) - epsilon)
  317. {
  318. return normalize(lerp(x, y, a));
  319. }
  320. cos_theta = std::max<T>(T(-1), std::min<T>(T(1), cos_theta));
  321. T theta = static_cast<T>(std::acos(cos_theta)) * a;
  322. quaternion<T> z = normalize(sub(y, mul(x, cos_theta)));
  323. return add(mul(x, static_cast<T>(std::cos(theta))), mul(z, static_cast<T>(std::sin(theta))));
  324. }
  325. template <class T>
  326. inline quaternion<T> sub(const quaternion<T>& x, const quaternion<T>& y)
  327. {
  328. return {x.w - y.w, x.x - y.x, x.y - y.y, x.z - y.z};
  329. }
  330. template <class T>
  331. quaternion<T> quaternion_cast(const matrix<T, 3, 3>& m)
  332. {
  333. T r;
  334. vector<T, 3> i;
  335. T trace = m[0][0] + m[1][1] + m[2][2];
  336. if (trace > T(0))
  337. {
  338. T s = T(0.5) / std::sqrt(trace + T(1));
  339. r = T(0.25) / s;
  340. i =
  341. {
  342. (m[2][1] - m[1][2]) * s,
  343. (m[0][2] - m[2][0]) * s,
  344. (m[1][0] - m[0][1]) * s
  345. };
  346. }
  347. else
  348. {
  349. if (m[0][0] > m[1][1] && m[0][0] > m[2][2])
  350. {
  351. T s = T(2) * std::sqrt(T(1) + m[0][0] - m[1][1] - m[2][2]);
  352. r = (m[2][1] - m[1][2]) / s;
  353. i =
  354. {
  355. T(0.25) * s,
  356. (m[0][1] + m[1][0]) / s,
  357. (m[0][2] + m[2][0]) / s
  358. };
  359. }
  360. else if (m[1][1] > m[2][2])
  361. {
  362. T s = T(2) * std::sqrt(T(1) + m[1][1] - m[0][0] - m[2][2]);
  363. r = (m[0][2] - m[2][0]) / s;
  364. i =
  365. {
  366. (m[0][1] + m[1][0]) / s,
  367. T(0.25) * s,
  368. (m[1][2] + m[2][1]) / s
  369. };
  370. }
  371. else
  372. {
  373. T s = T(2) * std::sqrt(T(1) + m[2][2] - m[0][0] - m[1][1]);
  374. r = (m[1][0] - m[0][1]) / s;
  375. i =
  376. {
  377. (m[0][2] + m[2][0]) / s,
  378. (m[1][2] + m[2][1]) / s,
  379. T(0.25) * s
  380. };
  381. }
  382. }
  383. return {r, i.x, i.y, i.z};
  384. }
  385. /// @}
  386. } // namespace math
  387. #endif // ANTKEEPER_MATH_QUATERNION_FUNCTIONS_HPP