quaternion.cpp 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. /*
  2. * quaternion.cpp
  3. * Copyright (C) Andrew Tridgell 2012
  4. *
  5. * This file is free software: you can redistribute it and/or modify it
  6. * under the terms of the GNU General Public License as published by the
  7. * Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This file is distributed in the hope that it will be useful, but
  11. * WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  13. * See the GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License along
  16. * with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #pragma GCC optimize("O2")
  19. #include "AP_Math.h"
  20. // return the rotation matrix equivalent for this quaternion
  21. void Quaternion::rotation_matrix(Matrix3f &m) const
  22. {
  23. const float q3q3 = q3 * q3;
  24. const float q3q4 = q3 * q4;
  25. const float q2q2 = q2 * q2;
  26. const float q2q3 = q2 * q3;
  27. const float q2q4 = q2 * q4;
  28. const float q1q2 = q1 * q2;
  29. const float q1q3 = q1 * q3;
  30. const float q1q4 = q1 * q4;
  31. const float q4q4 = q4 * q4;
  32. m.a.x = 1.0f-2.0f*(q3q3 + q4q4);
  33. m.a.y = 2.0f*(q2q3 - q1q4);
  34. m.a.z = 2.0f*(q2q4 + q1q3);
  35. m.b.x = 2.0f*(q2q3 + q1q4);
  36. m.b.y = 1.0f-2.0f*(q2q2 + q4q4);
  37. m.b.z = 2.0f*(q3q4 - q1q2);
  38. m.c.x = 2.0f*(q2q4 - q1q3);
  39. m.c.y = 2.0f*(q3q4 + q1q2);
  40. m.c.z = 1.0f-2.0f*(q2q2 + q3q3);
  41. }
  42. // return the rotation matrix equivalent for this quaternion after normalization
  43. void Quaternion::rotation_matrix_norm(Matrix3f &m) const
  44. {
  45. const float q1q1 = q1 * q1;
  46. const float q1q2 = q1 * q2;
  47. const float q1q3 = q1 * q3;
  48. const float q1q4 = q1 * q4;
  49. const float q2q2 = q2 * q2;
  50. const float q2q3 = q2 * q3;
  51. const float q2q4 = q2 * q4;
  52. const float q3q3 = q3 * q3;
  53. const float q3q4 = q3 * q4;
  54. const float q4q4 = q4 * q4;
  55. const float invs = 1.0f / (q1q1 + q2q2 + q3q3 + q4q4);
  56. m.a.x = ( q2q2 - q3q3 - q4q4 + q1q1)*invs;
  57. m.a.y = 2.0f*(q2q3 - q1q4)*invs;
  58. m.a.z = 2.0f*(q2q4 + q1q3)*invs;
  59. m.b.x = 2.0f*(q2q3 + q1q4)*invs;
  60. m.b.y = (-q2q2 + q3q3 - q4q4 + q1q1)*invs;
  61. m.b.z = 2.0f*(q3q4 - q1q2)*invs;
  62. m.c.x = 2.0f*(q2q4 - q1q3)*invs;
  63. m.c.y = 2.0f*(q3q4 + q1q2)*invs;
  64. m.c.z = (-q2q2 - q3q3 + q4q4 + q1q1)*invs;
  65. }
  66. // return the rotation matrix equivalent for this quaternion
  67. // Thanks to Martin John Baker
  68. // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
  69. void Quaternion::from_rotation_matrix(const Matrix3f &m)
  70. {
  71. const float &m00 = m.a.x;
  72. const float &m11 = m.b.y;
  73. const float &m22 = m.c.z;
  74. const float &m10 = m.b.x;
  75. const float &m01 = m.a.y;
  76. const float &m20 = m.c.x;
  77. const float &m02 = m.a.z;
  78. const float &m21 = m.c.y;
  79. const float &m12 = m.b.z;
  80. float &qw = q1;
  81. float &qx = q2;
  82. float &qy = q3;
  83. float &qz = q4;
  84. const float tr = m00 + m11 + m22;
  85. if (tr > 0) {
  86. const float S = sqrtf(tr+1) * 2;
  87. qw = 0.25f * S;
  88. qx = (m21 - m12) / S;
  89. qy = (m02 - m20) / S;
  90. qz = (m10 - m01) / S;
  91. } else if ((m00 > m11) && (m00 > m22)) {
  92. const float S = sqrtf(1.0f + m00 - m11 - m22) * 2.0f;
  93. qw = (m21 - m12) / S;
  94. qx = 0.25f * S;
  95. qy = (m01 + m10) / S;
  96. qz = (m02 + m20) / S;
  97. } else if (m11 > m22) {
  98. const float S = sqrtf(1.0f + m11 - m00 - m22) * 2.0f;
  99. qw = (m02 - m20) / S;
  100. qx = (m01 + m10) / S;
  101. qy = 0.25f * S;
  102. qz = (m12 + m21) / S;
  103. } else {
  104. const float S = sqrtf(1.0f + m22 - m00 - m11) * 2.0f;
  105. qw = (m10 - m01) / S;
  106. qx = (m02 + m20) / S;
  107. qy = (m12 + m21) / S;
  108. qz = 0.25f * S;
  109. }
  110. }
  111. // convert a vector from earth to body frame
  112. void Quaternion::earth_to_body(Vector3f &v) const
  113. {
  114. Matrix3f m;
  115. rotation_matrix(m);
  116. v = m * v;
  117. }
  118. // create a quaternion from Euler angles
  119. void Quaternion::from_euler(float roll, float pitch, float yaw)
  120. {
  121. const float cr2 = cosf(roll*0.5f);
  122. const float cp2 = cosf(pitch*0.5f);
  123. const float cy2 = cosf(yaw*0.5f);
  124. const float sr2 = sinf(roll*0.5f);
  125. const float sp2 = sinf(pitch*0.5f);
  126. const float sy2 = sinf(yaw*0.5f);
  127. q1 = cr2*cp2*cy2 + sr2*sp2*sy2;
  128. q2 = sr2*cp2*cy2 - cr2*sp2*sy2;
  129. q3 = cr2*sp2*cy2 + sr2*cp2*sy2;
  130. q4 = cr2*cp2*sy2 - sr2*sp2*cy2;
  131. }
  132. // create a quaternion from Euler angles
  133. void Quaternion::from_vector312(float roll ,float pitch, float yaw)
  134. {
  135. Matrix3f m;
  136. m.from_euler312(roll, pitch, yaw);
  137. from_rotation_matrix(m);
  138. }
  139. void Quaternion::from_axis_angle(Vector3f v)
  140. {
  141. const float theta = v.length();
  142. if (is_zero(theta)) {
  143. q1 = 1.0f;
  144. q2=q3=q4=0.0f;
  145. return;
  146. }
  147. v /= theta;
  148. from_axis_angle(v,theta);
  149. }
  150. void Quaternion::from_axis_angle(const Vector3f &axis, float theta)
  151. {
  152. // axis must be a unit vector as there is no check for length
  153. if (is_zero(theta)) {
  154. q1 = 1.0f;
  155. q2=q3=q4=0.0f;
  156. return;
  157. }
  158. const float st2 = sinf(theta/2.0f);
  159. q1 = cosf(theta/2.0f);
  160. q2 = axis.x * st2;
  161. q3 = axis.y * st2;
  162. q4 = axis.z * st2;
  163. }
  164. void Quaternion::rotate(const Vector3f &v)
  165. {
  166. Quaternion r;
  167. r.from_axis_angle(v);
  168. (*this) *= r;
  169. }
  170. void Quaternion::to_axis_angle(Vector3f &v)
  171. {
  172. const float l = sqrtf(sq(q2)+sq(q3)+sq(q4));
  173. v = Vector3f(q2,q3,q4);
  174. if (!is_zero(l)) {
  175. v /= l;
  176. v *= wrap_PI(2.0f * atan2f(l,q1));
  177. }
  178. }
  179. void Quaternion::from_axis_angle_fast(Vector3f v)
  180. {
  181. const float theta = v.length();
  182. if (is_zero(theta)) {
  183. q1 = 1.0f;
  184. q2=q3=q4=0.0f;
  185. return;
  186. }
  187. v /= theta;
  188. from_axis_angle_fast(v,theta);
  189. }
  190. void Quaternion::from_axis_angle_fast(const Vector3f &axis, float theta)
  191. {
  192. const float t2 = theta/2.0f;
  193. const float sqt2 = sq(t2);
  194. const float st2 = t2-sqt2*t2/6.0f;
  195. q1 = 1.0f-(sqt2/2.0f)+sq(sqt2)/24.0f;
  196. q2 = axis.x * st2;
  197. q3 = axis.y * st2;
  198. q4 = axis.z * st2;
  199. }
  200. void Quaternion::rotate_fast(const Vector3f &v)
  201. {
  202. const float theta = v.length();
  203. if (is_zero(theta)) {
  204. return;
  205. }
  206. const float t2 = theta/2.0f;
  207. const float sqt2 = sq(t2);
  208. float st2 = t2-sqt2*t2/6.0f;
  209. st2 /= theta;
  210. //"rotation quaternion"
  211. const float w2 = 1.0f-(sqt2/2.0f)+sq(sqt2)/24.0f;
  212. const float x2 = v.x * st2;
  213. const float y2 = v.y * st2;
  214. const float z2 = v.z * st2;
  215. //copy our quaternion
  216. const float w1 = q1;
  217. const float x1 = q2;
  218. const float y1 = q3;
  219. const float z1 = q4;
  220. //do the multiply into our quaternion
  221. q1 = w1*w2 - x1*x2 - y1*y2 - z1*z2;
  222. q2 = w1*x2 + x1*w2 + y1*z2 - z1*y2;
  223. q3 = w1*y2 - x1*z2 + y1*w2 + z1*x2;
  224. q4 = w1*z2 + x1*y2 - y1*x2 + z1*w2;
  225. }
  226. // get euler roll angle
  227. float Quaternion::get_euler_roll() const
  228. {
  229. return (atan2f(2.0f*(q1*q2 + q3*q4), 1.0f - 2.0f*(q2*q2 + q3*q3)));
  230. }
  231. // get euler pitch angle
  232. float Quaternion::get_euler_pitch() const
  233. {
  234. return safe_asin(2.0f*(q1*q3 - q4*q2));
  235. }
  236. // get euler yaw angle
  237. float Quaternion::get_euler_yaw() const
  238. {
  239. return atan2f(2.0f*(q1*q4 + q2*q3), 1.0f - 2.0f*(q3*q3 + q4*q4));
  240. }
  241. // create eulers from a quaternion
  242. void Quaternion::to_euler(float &roll, float &pitch, float &yaw) const
  243. {
  244. roll = get_euler_roll();
  245. pitch = get_euler_pitch();
  246. yaw = get_euler_yaw();
  247. }
  248. // create eulers from a quaternion
  249. Vector3f Quaternion::to_vector312(void) const
  250. {
  251. Matrix3f m;
  252. rotation_matrix(m);
  253. return m.to_euler312();
  254. }
  255. float Quaternion::length(void) const
  256. {
  257. return sqrtf(sq(q1) + sq(q2) + sq(q3) + sq(q4));
  258. }
  259. Quaternion Quaternion::inverse(void) const
  260. {
  261. return Quaternion(q1, -q2, -q3, -q4);
  262. }
  263. void Quaternion::normalize(void)
  264. {
  265. const float quatMag = length();
  266. if (!is_zero(quatMag)) {
  267. const float quatMagInv = 1.0f/quatMag;
  268. q1 *= quatMagInv;
  269. q2 *= quatMagInv;
  270. q3 *= quatMagInv;
  271. q4 *= quatMagInv;
  272. }
  273. }
  274. Quaternion Quaternion::operator*(const Quaternion &v) const
  275. {
  276. Quaternion ret;
  277. const float &w1 = q1;
  278. const float &x1 = q2;
  279. const float &y1 = q3;
  280. const float &z1 = q4;
  281. const float w2 = v.q1;
  282. const float x2 = v.q2;
  283. const float y2 = v.q3;
  284. const float z2 = v.q4;
  285. ret.q1 = w1*w2 - x1*x2 - y1*y2 - z1*z2;
  286. ret.q2 = w1*x2 + x1*w2 + y1*z2 - z1*y2;
  287. ret.q3 = w1*y2 - x1*z2 + y1*w2 + z1*x2;
  288. ret.q4 = w1*z2 + x1*y2 - y1*x2 + z1*w2;
  289. return ret;
  290. }
  291. Quaternion &Quaternion::operator*=(const Quaternion &v)
  292. {
  293. const float w1 = q1;
  294. const float x1 = q2;
  295. const float y1 = q3;
  296. const float z1 = q4;
  297. const float w2 = v.q1;
  298. const float x2 = v.q2;
  299. const float y2 = v.q3;
  300. const float z2 = v.q4;
  301. q1 = w1*w2 - x1*x2 - y1*y2 - z1*z2;
  302. q2 = w1*x2 + x1*w2 + y1*z2 - z1*y2;
  303. q3 = w1*y2 - x1*z2 + y1*w2 + z1*x2;
  304. q4 = w1*z2 + x1*y2 - y1*x2 + z1*w2;
  305. return *this;
  306. }
  307. Quaternion Quaternion::operator/(const Quaternion &v) const
  308. {
  309. Quaternion ret;
  310. const float &quat0 = q1;
  311. const float &quat1 = q2;
  312. const float &quat2 = q3;
  313. const float &quat3 = q4;
  314. const float rquat0 = v.q1;
  315. const float rquat1 = v.q2;
  316. const float rquat2 = v.q3;
  317. const float rquat3 = v.q4;
  318. ret.q1 = (rquat0*quat0 + rquat1*quat1 + rquat2*quat2 + rquat3*quat3);
  319. ret.q2 = (rquat0*quat1 - rquat1*quat0 - rquat2*quat3 + rquat3*quat2);
  320. ret.q3 = (rquat0*quat2 + rquat1*quat3 - rquat2*quat0 - rquat3*quat1);
  321. ret.q4 = (rquat0*quat3 - rquat1*quat2 + rquat2*quat1 - rquat3*quat0);
  322. return ret;
  323. }
  324. // angular difference in radians between quaternions
  325. Quaternion Quaternion::angular_difference(const Quaternion &v) const
  326. {
  327. return v.inverse() * *this;
  328. }