test_quaternion.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  1. // This file is part of OpenCV project.
  2. // It is subject to the license terms in the LICENSE file found in the top-level directory
  3. // of this distribution and at http://opencv.org/license.html.
  4. #include "test_precomp.hpp"
  5. #include <opencv2/ts/cuda_test.hpp> // EXPECT_MAT_NEAR
  6. #include <opencv2/core/quaternion.hpp>
  7. #include <opencv2/core/dualquaternion.hpp>
  8. namespace opencv_test{ namespace {
  9. class QuatTest: public ::testing::Test
  10. {
  11. protected:
  12. void SetUp() override
  13. {
  14. q1 = {1,2,3,4};
  15. q2 = {2.5,-2,3.5,4};
  16. q1Unit = {1 / sqrt(30), sqrt(2) /sqrt(15), sqrt(3) / sqrt(10), 2 * sqrt(2) / sqrt(15)};
  17. q1Inv = {1.0 / 30, -1.0 / 15, -1.0 / 10, -2.0 / 15};
  18. }
  19. double scalar = 2.5;
  20. double angle = CV_PI;
  21. double qNorm2 = 2;
  22. Vec<double, 3> axis{1, 1, 1};
  23. Vec<double, 3> unAxis{0, 0, 0};
  24. Vec<double, 3> unitAxis{1.0 / sqrt(3), 1.0 / sqrt(3), 1.0 / sqrt(3)};
  25. Quatd q3 = Quatd::createFromAngleAxis(angle, axis);
  26. Quatd q3UnitAxis = Quatd::createFromAngleAxis(angle, unitAxis);
  27. Quat<double> q3Norm2 = q3 * qNorm2;
  28. Quat<double> q1Inv;
  29. Quat<double> q1;
  30. Quat<double> q2;
  31. Quat<double> q1Unit;
  32. Quatd qNull{0, 0, 0, 0};
  33. Quatd qIdentity{1, 0, 0, 0};
  34. QuatAssumeType assumeUnit = QUAT_ASSUME_UNIT;
  35. };
  36. TEST_F(QuatTest, constructor)
  37. {
  38. Vec<double, 4> coeff{1, 2, 3, 4};
  39. EXPECT_EQ(Quat<double> (coeff), q1);
  40. EXPECT_EQ(q3, q3UnitAxis);
  41. EXPECT_ANY_THROW(Quatd::createFromAngleAxis(angle, unAxis));
  42. Matx33d R1{
  43. -1.0 / 3, 2.0 / 3 , 2.0 / 3,
  44. 2.0 / 3 , -1.0 / 3, 2.0 / 3,
  45. 2.0 / 3 , 2.0 / 3 , -1.0 / 3
  46. };
  47. Matx33d R2{
  48. -2.0 / 3, -2.0 / 3, -1.0 / 3,
  49. -2.0 / 3, 1.0 / 3, 2.0 / 3,
  50. -1.0 / 3, 2.0 / 3, -2.0 / 3
  51. };
  52. Matx33d R3{
  53. 0.818181818181, 0.181818181818, 0.54545455454,
  54. 0.545454545545, -0.54545454545, -0.6363636364,
  55. 0.181818181818, 0.818181818182, -0.5454545455
  56. };
  57. Matx33d R4{
  58. 0.818181818181, -0.181818181818, 0.54545455454,
  59. 0.545454545545, 0.54545454545, -0.6363636364,
  60. -0.181818181818, 0.818181818182, 0.5454545455
  61. };
  62. Quatd qMat = Quatd::createFromRotMat(R1);
  63. Quatd qMat2 = Quatd::createFromRotMat(R2);
  64. Quatd qMat3 = Quatd::createFromRotMat(R3);
  65. Quatd qMat4 = Quatd::createFromRotMat(R4);
  66. EXPECT_EQ(qMat2, Quatd(0, -0.408248290463, 0.816496580927, 0.408248904638));
  67. EXPECT_EQ(qMat3, Quatd(-0.426401432711,-0.852802865422, -0.213200716355, -0.2132007163));
  68. EXPECT_EQ(qMat, q3);
  69. EXPECT_EQ(qMat4, -Quatd(0.852802865422, 0.426401432711221, 0.2132007163556, 0.2132007163));
  70. Vec3d rot{angle / sqrt(3),angle / sqrt(3), angle / sqrt(3)};
  71. Quatd rotQuad{0, 1.0 / sqrt(3), 1. / sqrt(3), 1. / sqrt(3)};
  72. Quatd qRot = Quatd::createFromRvec(rot);
  73. EXPECT_EQ(qRot, rotQuad);
  74. EXPECT_EQ(Quatd::createFromRvec(Vec3d(0, 0, 0)), qIdentity);
  75. }
  76. TEST_F(QuatTest, basicfuns)
  77. {
  78. Quat<double> q1Conj{1, -2, -3, -4};
  79. EXPECT_EQ(q3Norm2.normalize(), q3);
  80. EXPECT_EQ(q1.norm(), sqrt(30));
  81. EXPECT_EQ(q1.normalize(), q1Unit);
  82. EXPECT_ANY_THROW(qNull.normalize());
  83. EXPECT_EQ(q1.conjugate(), q1Conj);
  84. EXPECT_EQ(q1.inv(), q1Inv);
  85. EXPECT_EQ(inv(q1), q1Inv);
  86. EXPECT_EQ(q3.inv(assumeUnit) * q3, qIdentity);
  87. EXPECT_EQ(q1.inv() * q1, qIdentity);
  88. EXPECT_ANY_THROW(inv(qNull));
  89. EXPECT_NO_THROW(q1.at(0));
  90. EXPECT_ANY_THROW(q1.at(4));
  91. Matx33d R{
  92. -2.0 / 3, 2.0 / 15 , 11.0 / 15,
  93. 2.0 / 3 , -1.0 / 3 , 2.0 / 3 ,
  94. 1.0 / 3 , 14.0 / 15, 2.0 / 15
  95. };
  96. Matx33d q1RotMat = q1.toRotMat3x3();
  97. EXPECT_MAT_NEAR(q1RotMat, R, 1e-6);
  98. Vec3d z_axis{0,0,1};
  99. Quatd q_unit1 = Quatd::createFromAngleAxis(angle, z_axis);
  100. Mat pointsA = (Mat_<double>(2, 3) << 1,0,0,1,0,1);
  101. pointsA = pointsA.t();
  102. Mat new_point = q_unit1.toRotMat3x3() * pointsA;
  103. Mat afterRo = (Mat_<double>(3, 2) << -1,-1,0,0,0,1);
  104. EXPECT_MAT_NEAR(afterRo, new_point, 1e-6);
  105. EXPECT_ANY_THROW(qNull.toRotVec());
  106. Vec3d rodVec{CV_PI/sqrt(3), CV_PI/sqrt(3), CV_PI/sqrt(3)};
  107. Vec3d q3Rod = q3.toRotVec();
  108. EXPECT_NEAR(q3Rod[0], rodVec[0], 1e-6);
  109. EXPECT_NEAR(q3Rod[1], rodVec[1], 1e-6);
  110. EXPECT_NEAR(q3Rod[2], rodVec[2], 1e-6);
  111. EXPECT_EQ(log(q1Unit, assumeUnit), log(q1Unit));
  112. EXPECT_EQ(log(qIdentity, assumeUnit), qNull);
  113. EXPECT_EQ(log(q3), Quatd(0, angle * unitAxis[0] / 2, angle * unitAxis[1] / 2, angle * unitAxis[2] / 2));
  114. EXPECT_ANY_THROW(log(qNull));
  115. EXPECT_EQ(log(Quatd(exp(1), 0, 0, 0)), qIdentity);
  116. EXPECT_EQ(exp(qIdentity), Quatd(exp(1), 0, 0, 0));
  117. EXPECT_EQ(exp(qNull), qIdentity);
  118. EXPECT_EQ(exp(Quatd(0, angle * unitAxis[0] / 2, angle * unitAxis[1] / 2, angle * unitAxis[2] / 2)), q3);
  119. EXPECT_EQ(power(q3, 2.0), Quatd::createFromAngleAxis(2*angle, axis));
  120. EXPECT_EQ(power(Quatd(0.5, 0.5, 0.5, 0.5), 2.0, assumeUnit), Quatd(-0.5,0.5,0.5,0.5));
  121. EXPECT_EQ(power(Quatd(0.5, 0.5, 0.5, 0.5), -2.0), Quatd(-0.5,-0.5,-0.5,-0.5));
  122. EXPECT_EQ(sqrt(q1), power(q1, 0.5));
  123. EXPECT_EQ(exp(q3 * log(q1)), power(q1, q3));
  124. EXPECT_EQ(exp(q1 * log(q3)), power(q3, q1, assumeUnit));
  125. EXPECT_EQ(crossProduct(q1, q3), (q1 * q3 - q3 * q1) / 2);
  126. EXPECT_EQ(sinh(qNull), qNull);
  127. EXPECT_EQ(sinh(q1), (exp(q1) - exp(-q1)) / 2);
  128. EXPECT_EQ(sinh(qIdentity), Quatd(sinh(1), 0, 0, 0));
  129. EXPECT_EQ(sinh(q1), Quatd(0.73233760604, -0.44820744998, -0.67231117497, -0.8964148999610843));
  130. EXPECT_EQ(cosh(qNull), qIdentity);
  131. EXPECT_EQ(cosh(q1), Quatd(0.961585117636, -0.34135217456, -0.51202826184, -0.682704349122));
  132. EXPECT_EQ(tanh(q1), sinh(q1) * inv(cosh(q1)));
  133. EXPECT_EQ(sin(qNull), qNull);
  134. EXPECT_EQ(sin(q1), Quatd(91.78371578403, 21.88648685303, 32.829730279543, 43.772973706058));
  135. EXPECT_EQ(cos(qNull), qIdentity);
  136. EXPECT_EQ(cos(q1), Quatd(58.9336461679, -34.0861836904, -51.12927553569, -68.17236738093));
  137. EXPECT_EQ(tan(q1), sin(q1)/cos(q1));
  138. EXPECT_EQ(sinh(asinh(q1)), q1);
  139. Quatd c1 = asinh(sinh(q1));
  140. EXPECT_EQ(sinh(c1), sinh(q1));
  141. EXPECT_EQ(cosh(acosh(q1)), q1);
  142. c1 = acosh(cosh(q1));
  143. EXPECT_EQ(cosh(c1), cosh(q1));
  144. EXPECT_EQ(tanh(atanh(q1)), q1);
  145. c1 = atanh(tanh(q1));
  146. EXPECT_EQ(tanh(q1), tanh(c1));
  147. EXPECT_EQ(asin(sin(q1)), q1);
  148. EXPECT_EQ(sin(asin(q1)), q1);
  149. EXPECT_EQ(acos(cos(q1)), q1);
  150. EXPECT_EQ(cos(acos(q1)), q1);
  151. EXPECT_EQ(atan(tan(q3)), q3);
  152. EXPECT_EQ(tan(atan(q1)), q1);
  153. }
  154. TEST_F(QuatTest, test_operator)
  155. {
  156. Quatd minusQ{-1, -2, -3, -4};
  157. Quatd qAdd{3.5, 0, 6.5, 8};
  158. Quatd qMinus{-1.5, 4, -0.5, 0};
  159. Quatd qMultq{-20, 1, -5, 27};
  160. Quatd qMults{2.5, 5.0, 7.5, 10.0};
  161. Quatd qDvss{1.0 / 2.5, 2.0 / 2.5, 3.0 / 2.5, 4.0 / 2.5};
  162. Quatd qOrigin(q1);
  163. EXPECT_EQ(-q1, minusQ);
  164. EXPECT_EQ(q1 + q2, qAdd);
  165. EXPECT_EQ(q1 + scalar, Quatd(3.5, 2, 3, 4));
  166. EXPECT_EQ(scalar + q1, Quatd(3.5, 2, 3, 4));
  167. EXPECT_EQ(q1 + 2.0, Quatd(3, 2, 3, 4));
  168. EXPECT_EQ(2.0 + q1, Quatd(3, 2, 3, 4));
  169. EXPECT_EQ(q1 - q2, qMinus);
  170. EXPECT_EQ(q1 - scalar, Quatd(-1.5, 2, 3, 4));
  171. EXPECT_EQ(scalar - q1, Quatd(1.5, -2, -3, -4));
  172. EXPECT_EQ(q1 - 2.0, Quatd(-1, 2, 3, 4));
  173. EXPECT_EQ(2.0 - q1, Quatd(1, -2, -3, -4));
  174. EXPECT_EQ(q1 * q2, qMultq);
  175. EXPECT_EQ(q1 * scalar, qMults);
  176. EXPECT_EQ(scalar * q1, qMults);
  177. EXPECT_EQ(q1 / q1, qIdentity);
  178. EXPECT_EQ(q1 / scalar, qDvss);
  179. q1 += q2;
  180. EXPECT_EQ(q1, qAdd);
  181. q1 -= q2;
  182. EXPECT_EQ(q1, qOrigin);
  183. q1 *= q2;
  184. EXPECT_EQ(q1, qMultq);
  185. q1 /= q2;
  186. EXPECT_EQ(q1, qOrigin);
  187. q1 *= scalar;
  188. EXPECT_EQ(q1, qMults);
  189. q1 /= scalar;
  190. EXPECT_EQ(q1, qOrigin);
  191. EXPECT_NO_THROW(q1[0]);
  192. EXPECT_NO_THROW(q1.at(0));
  193. EXPECT_ANY_THROW(q1[4]);
  194. EXPECT_ANY_THROW(q1.at(4));
  195. }
  196. TEST_F(QuatTest, quatAttrs)
  197. {
  198. double angleQ1 = 2 * acos(1.0 / sqrt(30));
  199. Vec3d axis1{0.3713906763541037, 0.557086014, 0.742781352};
  200. Vec<double, 3> q1axis1 = q1.getAxis();
  201. EXPECT_EQ(angleQ1, q1.getAngle());
  202. EXPECT_EQ(angleQ1, q1Unit.getAngle());
  203. EXPECT_EQ(angleQ1, q1Unit.getAngle(assumeUnit));
  204. EXPECT_EQ(0, qIdentity.getAngle());
  205. EXPECT_ANY_THROW(qNull.getAxis());
  206. EXPECT_NEAR(axis1[0], q1axis1[0], 1e-6);
  207. EXPECT_NEAR(axis1[1], q1axis1[1], 1e-6);
  208. EXPECT_NEAR(axis1[2], q1axis1[2], 1e-6);
  209. EXPECT_NEAR(q3Norm2.norm(), qNorm2, 1e-6);
  210. EXPECT_EQ(q3Norm2.getAngle(), angle);
  211. EXPECT_NEAR(axis1[0], axis1[0], 1e-6);
  212. EXPECT_NEAR(axis1[1], axis1[1], 1e-6);
  213. EXPECT_NEAR(axis1[2], axis1[2], 1e-6);
  214. }
  215. TEST_F(QuatTest, interpolation)
  216. {
  217. Quatd qNoRot = Quatd::createFromAngleAxis(0, axis);
  218. Quatd qLerpInter(1.0 / 2, sqrt(3) / 6, sqrt(3) / 6, sqrt(3) / 6);
  219. EXPECT_EQ(Quatd::lerp(qNoRot, q3, 0), qNoRot);
  220. EXPECT_EQ(Quatd::lerp(qNoRot, q3, 1), q3);
  221. EXPECT_EQ(Quatd::lerp(qNoRot, q3, 0.5), qLerpInter);
  222. Quatd q3NrNn2 = qNoRot * qNorm2;
  223. EXPECT_EQ(Quatd::nlerp(q3NrNn2, q3Norm2, 0), qNoRot);
  224. EXPECT_EQ(Quatd::nlerp(q3NrNn2, q3Norm2, 1), q3);
  225. EXPECT_EQ(Quatd::nlerp(q3NrNn2, q3Norm2, 0.5), qLerpInter.normalize());
  226. EXPECT_EQ(Quatd::nlerp(qNoRot, q3, 0, assumeUnit), qNoRot);
  227. EXPECT_EQ(Quatd::nlerp(qNoRot, q3, 1, assumeUnit), q3);
  228. EXPECT_EQ(Quatd::nlerp(qNoRot, q3, 0.5, assumeUnit), qLerpInter.normalize());
  229. Quatd q3Minus(-q3);
  230. EXPECT_EQ(Quatd::nlerp(qNoRot, q3, 0.4), -Quatd::nlerp(qNoRot, q3Minus, 0.4));
  231. EXPECT_EQ(Quatd::slerp(qNoRot, q3, 0, assumeUnit), qNoRot);
  232. EXPECT_EQ(Quatd::slerp(qNoRot, q3, 1, assumeUnit), q3);
  233. EXPECT_EQ(Quatd::slerp(qNoRot, q3, 0.5, assumeUnit), -Quatd::nlerp(qNoRot, -q3, 0.5, assumeUnit));
  234. EXPECT_EQ(Quatd::slerp(qNoRot, q1, 0.5), Quatd(0.76895194, 0.2374325, 0.35614876, 0.47486501));
  235. EXPECT_EQ(Quatd::slerp(-qNoRot, q1, 0.5), Quatd(0.76895194, 0.2374325, 0.35614876, 0.47486501));
  236. EXPECT_EQ(Quatd::slerp(qNoRot, -q1, 0.5), -Quatd::slerp(-qNoRot, q1, 0.5));
  237. Quat<double> tr1 = Quatd::createFromAngleAxis(0, axis);
  238. Quat<double> tr2 = Quatd::createFromAngleAxis(angle / 2, axis);
  239. Quat<double> tr3 = Quatd::createFromAngleAxis(angle, axis);
  240. Quat<double> tr4 = Quatd::createFromAngleAxis(angle, Vec3d{-1/sqrt(2),0,1/(sqrt(2))});
  241. EXPECT_ANY_THROW(Quatd::spline(qNull, tr1, tr2, tr3, 0));
  242. EXPECT_EQ(Quatd::spline(tr1, tr2, tr3, tr4, 0), tr2);
  243. EXPECT_EQ(Quatd::spline(tr1, tr2, tr3, tr4, 1), tr3);
  244. EXPECT_EQ(Quatd::spline(tr1, tr2, tr3, tr4, 0.6, assumeUnit), Quatd::spline(tr1, tr2, tr3, tr4, 0.6));
  245. EXPECT_EQ(Quatd::spline(tr1, tr2, tr3, tr3, 0.5), Quatd::spline(tr1, -tr2, tr3, tr3, 0.5));
  246. EXPECT_EQ(Quatd::spline(tr1, tr2, tr3, tr3, 0.5), -Quatd::spline(-tr1, -tr2, -tr3, tr3, 0.5));
  247. EXPECT_EQ(Quatd::spline(tr1, tr2, tr3, tr3, 0.5), Quatd(0.336889853392, 0.543600719487, 0.543600719487, 0.543600719487));
  248. }
  249. static const Quatd qEuler[24] = {
  250. Quatd(0.7233214, 0.3919013, 0.2005605, 0.5319728), //INT_XYZ
  251. Quatd(0.8223654, 0.0222635, 0.3604221, 0.4396766), //INT_XZY
  252. Quatd(0.822365, 0.439677, 0.0222635, 0.360422), //INT_YXZ
  253. Quatd(0.723321, 0.531973, 0.391901, 0.20056), //INT_YZX
  254. Quatd(0.723321, 0.20056, 0.531973, 0.391901), //INT_ZXY
  255. Quatd(0.822365, 0.360422, 0.439677, 0.0222635), //INT_ZYX
  256. Quatd(0.653285, 0.65328, 0.369641, -0.0990435), //INT_XYX
  257. Quatd(0.653285, 0.65328, 0.0990435, 0.369641), //INT_XZX
  258. Quatd(0.653285, 0.369641, 0.65328, 0.0990435), //INT_YXY
  259. Quatd(0.653285, -0.0990435, 0.65328, 0.369641), //INT_YZY
  260. Quatd(0.653285, 0.369641, -0.0990435, 0.65328), //INT_ZXZ
  261. Quatd(0.653285, 0.0990435, 0.369641, 0.65328), //INT_ZYZ
  262. Quatd(0.822365, 0.0222635, 0.439677, 0.360422), //EXT_XYZ
  263. Quatd(0.723321, 0.391901, 0.531973, 0.20056), //EXT_XZY
  264. Quatd(0.723321, 0.20056, 0.391901, 0.531973), //EXT_YXZ
  265. Quatd(0.822365, 0.360422, 0.0222635, 0.439677), //EXT_YZX
  266. Quatd(0.822365, 0.439677, 0.360422, 0.0222635), //EXT_ZXY
  267. Quatd(0.723321, 0.531973, 0.20056, 0.391901), //EXT_ZYX
  268. Quatd(0.653285, 0.65328, 0.369641, 0.0990435), //EXT_XYX
  269. Quatd(0.653285, 0.65328, -0.0990435, 0.369641), //EXT_XZX
  270. Quatd(0.653285, 0.369641, 0.65328, -0.0990435), //EXT_YXY
  271. Quatd(0.653285, 0.0990435, 0.65328, 0.369641), //EXT_YZY
  272. Quatd(0.653285, 0.369641, 0.0990435, 0.65328), //EXT_ZXZ
  273. Quatd(0.653285, -0.0990435, 0.369641, 0.65328) //EXT_ZYZ
  274. };
  275. TEST_F(QuatTest, EulerAngles)
  276. {
  277. Vec3d test_angle = {0.523598, 0.78539, 1.04719};
  278. for (QuatEnum::EulerAnglesType i = QuatEnum::EulerAnglesType::INT_XYZ; i <= QuatEnum::EulerAnglesType::EXT_ZYZ; i = (QuatEnum::EulerAnglesType)(i + 1))
  279. {
  280. SCOPED_TRACE(cv::format("EulerAnglesType=%d", i));
  281. Quatd q = Quatd::createFromEulerAngles(test_angle, i);
  282. EXPECT_EQ(q, qEuler[i]);
  283. Vec3d Euler_Angles = q.toEulerAngles(i);
  284. EXPECT_NEAR(Euler_Angles[0], test_angle[0], 1e-6);
  285. EXPECT_NEAR(Euler_Angles[1], test_angle[1], 1e-6);
  286. EXPECT_NEAR(Euler_Angles[2], test_angle[2], 1e-6);
  287. }
  288. Quatd qEuler0 = {0, 0, 0, 0};
  289. EXPECT_ANY_THROW(qEuler0.toEulerAngles(QuatEnum::INT_XYZ));
  290. Quatd qEulerLock1 = {0.5612665, 0.43042, 0.5607083, 0.4304935};
  291. Vec3d test_angle_lock1 = {1.3089878, CV_PI * 0.5, 0};
  292. Vec3d Euler_Angles_solute_1 = qEulerLock1.toEulerAngles(QuatEnum::INT_XYZ);
  293. EXPECT_NEAR(Euler_Angles_solute_1[0], test_angle_lock1[0], 1e-6);
  294. EXPECT_NEAR(Euler_Angles_solute_1[1], test_angle_lock1[1], 1e-6);
  295. EXPECT_NEAR(Euler_Angles_solute_1[2], test_angle_lock1[2], 1e-6);
  296. Quatd qEulerLock2 = {0.7010574, 0.0922963, 0.7010573, -0.0922961};
  297. Vec3d test_angle_lock2 = {-0.2618, CV_PI * 0.5, 0};
  298. Vec3d Euler_Angles_solute_2 = qEulerLock2.toEulerAngles(QuatEnum::INT_ZYX);
  299. EXPECT_NEAR(Euler_Angles_solute_2[0], test_angle_lock2[0], 1e-6);
  300. EXPECT_NEAR(Euler_Angles_solute_2[1], test_angle_lock2[1], 1e-6);
  301. EXPECT_NEAR(Euler_Angles_solute_2[2], test_angle_lock2[2], 1e-6);
  302. Vec3d test_angle6 = {CV_PI * 0.25, CV_PI * 0.5, CV_PI * 0.25};
  303. Vec3d test_angle7 = {CV_PI * 0.5, CV_PI * 0.5, 0};
  304. EXPECT_EQ(Quatd::createFromEulerAngles(test_angle6, QuatEnum::INT_ZXY), Quatd::createFromEulerAngles(test_angle7, QuatEnum::INT_ZXY));
  305. }
  306. class DualQuatTest: public ::testing::Test
  307. {
  308. protected:
  309. double scalar = 2.5;
  310. double angle = CV_PI;
  311. Vec<double, 3> axis{1, 1, 1};
  312. Vec<double, 3> unAxis{0, 0, 0};
  313. Vec<double, 3> unitAxis{1.0 / sqrt(3), 1.0 / sqrt(3), 1.0 / sqrt(3)};
  314. DualQuatd dq1{1, 2, 3, 4, 5, 6, 7, 8};
  315. Vec3d trans{0, 0, 5};
  316. double rotation_angle = 2.0 / 3 * CV_PI;
  317. DualQuatd dq2 = DualQuatd::createFromAngleAxisTrans(rotation_angle, axis, trans);
  318. DualQuatd dqAllOne{1, 1, 1, 1, 1, 1, 1, 1};
  319. DualQuatd dqAllZero{0, 0, 0, 0, 0, 0, 0, 0};
  320. DualQuatd dqIdentity{1, 0, 0, 0, 0, 0, 0, 0};
  321. DualQuatd dqTrans{1, 0, 0, 0, 0, 2, 3, 4};
  322. DualQuatd dqOnlyTrans{0, 0, 0, 0, 0, 2, 3, 4};
  323. DualQuatd dualNumber1{-3,0,0,0,-31.1,0,0,0};
  324. DualQuatd dualNumber2{4,0,0,0,5.1,0,0,0};
  325. };
  326. TEST_F(DualQuatTest, constructor)
  327. {
  328. EXPECT_EQ(dq1, DualQuatd::createFromQuat(Quatd(1, 2, 3, 4), Quatd(5, 6, 7, 8)));
  329. EXPECT_EQ(dq2 * dq2.conjugate(), dqIdentity);
  330. EXPECT_NEAR(dq2.getRotation(QUAT_ASSUME_UNIT).norm(), 1, 1e-6);
  331. EXPECT_NEAR(dq2.getRealPart().dot(dq2.getDualPart()), 0, 1e-6);
  332. EXPECT_MAT_NEAR(dq2.getTranslation(QUAT_ASSUME_UNIT), trans, 1e-6);
  333. DualQuatd q_conj = DualQuatd::createFromQuat(dq2.getRealPart().conjugate(), -dq2.getDualPart().conjugate());
  334. DualQuatd q{1,0,0,0,0,3,0,0};
  335. EXPECT_EQ(dq2 * q * q_conj, DualQuatd(1,0,0,0,0,0,3,5));
  336. Matx44d R1 = dq2.toMat();
  337. DualQuatd dq3 = DualQuatd::createFromMat(R1);
  338. EXPECT_EQ(dq3, dq2);
  339. axis = axis / std::sqrt(axis.dot(axis));
  340. Vec3d moment = 1.0 / 2 * (trans.cross(axis) + axis.cross(trans.cross(axis)) *
  341. std::cos(rotation_angle / 2) / std::sin(rotation_angle / 2));
  342. double d = trans.dot(axis);
  343. DualQuatd dq4 = DualQuatd::createFromPitch(rotation_angle, d, axis, moment);
  344. EXPECT_EQ(dq4, dq3);
  345. EXPECT_EQ(dq2, DualQuatd::createFromAffine3(dq2.toAffine3()));
  346. EXPECT_EQ(dq1.normalize(), DualQuatd::createFromAffine3(dq1.toAffine3()));
  347. }
  348. TEST_F(DualQuatTest, test_operator)
  349. {
  350. DualQuatd dq_origin{1, 2, 3, 4, 5, 6, 7, 8};
  351. EXPECT_EQ(dq1 - dqAllOne, DualQuatd(0, 1, 2, 3, 4, 5, 6, 7));
  352. EXPECT_EQ(-dq1, DualQuatd(-1, -2, -3, -4, -5, -6, -7, -8));
  353. EXPECT_EQ(dq1 + dqAllOne, DualQuatd(2, 3, 4, 5, 6, 7, 8, 9));
  354. EXPECT_EQ(dq1 / dq1, dqIdentity);
  355. DualQuatd dq3{-4, 1, 3, 2, -15.5, 0, -3, 8.5};
  356. EXPECT_EQ(dq1 * dq2, dq3);
  357. EXPECT_EQ(dq3 / dq2, dq1);
  358. DualQuatd dq12{2, 4, 6, 8, 10, 12, 14, 16};
  359. EXPECT_EQ(dq1 * 2.0, dq12);
  360. EXPECT_EQ(2.0 * dq1, dq12);
  361. EXPECT_EQ(dq1 - 1.0, DualQuatd(0, 2, 3, 4, 5, 6, 7, 8));
  362. EXPECT_EQ(1.0 - dq1, DualQuatd(0, -2, -3, -4, -5, -6, -7, -8));
  363. EXPECT_EQ(dq1 + 1.0, DualQuatd(2, 2, 3, 4, 5, 6, 7, 8));
  364. EXPECT_EQ(1.0 + dq1, DualQuatd(2, 2, 3, 4, 5, 6, 7, 8));
  365. dq1 += dq2;
  366. EXPECT_EQ(dq1, dq_origin + dq2);
  367. dq1 -= dq2;
  368. EXPECT_EQ(dq1, dq_origin);
  369. dq1 *= dq2;
  370. EXPECT_EQ(dq1, dq_origin * dq2);
  371. dq1 /= dq2;
  372. EXPECT_EQ(dq1, dq_origin);
  373. }
  374. TEST_F(DualQuatTest, basic_ops)
  375. {
  376. EXPECT_EQ(dq1.getRealPart(), Quatd(1, 2, 3, 4));
  377. EXPECT_EQ(dq1.getDualPart(), Quatd(5, 6, 7, 8));
  378. EXPECT_EQ((dq1 * dq2).conjugate(), conjugate(dq1 * dq2));
  379. EXPECT_EQ(dq1.conjugate(), DualQuatd::createFromQuat(dq1.getRealPart().conjugate(), dq1.getDualPart().conjugate()));
  380. EXPECT_EQ((dq2 * dq1).conjugate(), dq1.conjugate() * dq2.conjugate());
  381. EXPECT_EQ(dq1.conjugate() * dq1, dq1.norm() * dq1.norm());
  382. EXPECT_EQ(dq1.conjugate() * dq1, dq1.norm().power(2.0));
  383. EXPECT_EQ(dualNumber2.power(2.0), DualQuatd(16, 0, 0, 0, 40.8, 0, 0, 0));
  384. EXPECT_EQ(dq1.power(2.0), (2.0 * dq1.log()).exp());
  385. EXPECT_EQ(power(dq1, 2.0), (exp(2.0 * log(dq1))));
  386. EXPECT_EQ(dq2.power(3.0 / 2, QUAT_ASSUME_UNIT).power(4.0 / 3, QUAT_ASSUME_UNIT), dq2 * dq2);
  387. EXPECT_EQ(dq2.power(-0.5).power(2.0), dq2.inv());
  388. EXPECT_EQ(power(dq1, dq2), exp(dq2 * log(dq1)));
  389. EXPECT_EQ(power(dq2, dq1, QUAT_ASSUME_UNIT), exp(dq1 * log(dq2)));
  390. EXPECT_EQ((dq2.norm() * dq1).power(2.0), dq1.power(2.0) * dq2.norm().power(2.0));
  391. DualQuatd q1norm = dq1.normalize();
  392. EXPECT_EQ(dq2.norm(), dqIdentity);
  393. EXPECT_NEAR(q1norm.getRealPart().norm(), 1, 1e-6);
  394. EXPECT_NEAR(q1norm.getRealPart().dot(q1norm.getDualPart()), 0, 1e-6);
  395. EXPECT_NEAR(dq1.getRotation().norm(), 1, 1e-6);
  396. EXPECT_NEAR(dq2.getRotation(QUAT_ASSUME_UNIT).norm(), 1, 1e-6);
  397. EXPECT_NEAR(dq2.getRotation(QUAT_ASSUME_UNIT).norm(), 1, 1e-6);
  398. EXPECT_MAT_NEAR(Mat(dq2.getTranslation()), Mat(trans), 1e-6);
  399. EXPECT_MAT_NEAR(Mat(q1norm.getTranslation(QUAT_ASSUME_UNIT)), Mat(dq1.getTranslation()), 1e-6);
  400. EXPECT_EQ(dq2.getTranslation(), dq2.getTranslation(QUAT_ASSUME_UNIT));
  401. EXPECT_EQ(dq1.inv() * dq1, dqIdentity);
  402. EXPECT_EQ(inv(dq1) * dq1, dqIdentity);
  403. EXPECT_EQ(dq2.inv(QUAT_ASSUME_UNIT) * dq2, dqIdentity);
  404. EXPECT_EQ(inv(dq2, QUAT_ASSUME_UNIT) * dq2, dqIdentity);
  405. EXPECT_EQ(dq2.inv(), dq2.conjugate());
  406. EXPECT_EQ(dqIdentity.inv(), dqIdentity);
  407. EXPECT_ANY_THROW(dqAllZero.inv());
  408. EXPECT_EQ(dqAllZero.exp(), dqIdentity);
  409. EXPECT_EQ(exp(dqAllZero), dqIdentity);
  410. EXPECT_ANY_THROW(log(dqAllZero));
  411. EXPECT_EQ(log(dqIdentity), dqAllZero);
  412. EXPECT_EQ(dqIdentity.log(), dqAllZero);
  413. EXPECT_EQ(dualNumber1 * dualNumber2, dualNumber2 * dualNumber1);
  414. EXPECT_EQ(dualNumber2.exp().log(), dualNumber2);
  415. EXPECT_EQ(dq2.log(QUAT_ASSUME_UNIT).exp(), dq2);
  416. EXPECT_EQ(exp(log(dq2, QUAT_ASSUME_UNIT)), dq2);
  417. EXPECT_EQ(dqIdentity.log(QUAT_ASSUME_UNIT).exp(), dqIdentity);
  418. EXPECT_EQ(dq1.log().exp(), dq1);
  419. EXPECT_EQ(dqTrans.log().exp(), dqTrans);
  420. EXPECT_MAT_NEAR(q1norm.toMat(QUAT_ASSUME_UNIT), dq1.toMat(), 1e-6);
  421. Matx44d R1 = dq2.toMat();
  422. Mat point = (Mat_<double>(4, 1) << 3, 0, 0, 1);
  423. Mat new_point = R1 * point;
  424. Mat after = (Mat_<double>(4, 1) << 0, 3, 5 ,1);
  425. EXPECT_MAT_NEAR(new_point, after, 1e-6);
  426. Vec<double, 8> vec = dq1.toVec();
  427. EXPECT_EQ(DualQuatd(vec), dq1);
  428. Affine3d afd = q1norm.toAffine3(QUAT_ASSUME_UNIT);
  429. EXPECT_MAT_NEAR(Mat(afd.translation()), Mat(q1norm.getTranslation(QUAT_ASSUME_UNIT)), 1e-6);
  430. Affine3d dq1_afd = dq1.toAffine3();
  431. EXPECT_MAT_NEAR(dq1_afd.matrix, afd.matrix, 1e-6);
  432. EXPECT_ANY_THROW(dqAllZero.toAffine3());
  433. }
  434. TEST_F(DualQuatTest, interpolation)
  435. {
  436. DualQuatd dq = DualQuatd::createFromAngleAxisTrans(8 * CV_PI / 5, Vec3d{0, 0, 1}, Vec3d{0, 0, 10});
  437. EXPECT_EQ(DualQuatd::sclerp(dqIdentity, dq, 0.5), DualQuatd::sclerp(-dqIdentity, dq, 0.5, false));
  438. EXPECT_EQ(DualQuatd::sclerp(dqIdentity, dq, 0), -dqIdentity);
  439. EXPECT_EQ(DualQuatd::sclerp(dqIdentity, dq2, 1), dq2);
  440. EXPECT_EQ(DualQuatd::sclerp(dqIdentity, dq2, 0.4, false, QUAT_ASSUME_UNIT), DualQuatd(0.91354546, 0.23482951, 0.23482951, 0.23482951, -0.23482951, -0.47824988, 0.69589767, 0.69589767));
  441. EXPECT_EQ(DualQuatd::dqblend(dqIdentity, dq1.normalize(), 0.2, QUAT_ASSUME_UNIT), DualQuatd::dqblend(dqIdentity, -dq1, 0.2));
  442. EXPECT_EQ(DualQuatd::dqblend(dqIdentity, dq2, 0.4), DualQuatd(0.91766294, 0.22941573, 0.22941573, 0.22941573, -0.21130397, -0.48298049, 0.66409818, 0.66409818));
  443. DualQuatd gdb = DualQuatd::gdqblend(Vec<DualQuatd, 3>{dqIdentity, dq, dq2}, Vec3d{0.4, 0, 0.6}, QUAT_ASSUME_UNIT);
  444. EXPECT_EQ(gdb, DualQuatd::dqblend(dqIdentity, dq2, 0.6));
  445. EXPECT_ANY_THROW(DualQuatd::gdqblend(Vec<DualQuatd, 1>{dq2}, Vec2d{0.5, 0.5}));
  446. Mat gdqb_d(1, 2, CV_64FC(7));
  447. gdqb_d.at<Vec<double, 7>>(0, 0) = Vec<double, 7>{1,2,3,4,5,6,7};
  448. gdqb_d.at<Vec<double, 7>>(0, 1) = Vec<double, 7>{1,2,3,4,5,6,7};
  449. EXPECT_ANY_THROW(DualQuatd::gdqblend(gdqb_d, Vec2d{0.5, 0.5}));
  450. Mat gdqb_f(1, 2, CV_32FC(8));
  451. gdqb_f.at<Vec<float, 8>>(0, 0) = Vec<float, 8>{1.f,2.f,3.f,4.f,5.f,6.f,7.f,8.f};
  452. gdqb_f.at<Vec<float, 8>>(0, 1) = Vec<float, 8>{1.f,2.f,3.f,4.f,5.f,6.f,7.f,8.f};
  453. EXPECT_ANY_THROW(DualQuatd::gdqblend(gdqb_f, Vec2d{0.5, 0.5}));
  454. EXPECT_ANY_THROW(DualQuatd::gdqblend(Vec<DualQuatd, 3>{dqIdentity, dq, dq2}, Vec3f{0.4f, 0.f, 0.6f}, QUAT_ASSUME_UNIT));
  455. EXPECT_EQ(gdb, DualQuatd::gdqblend(Vec<DualQuatd, 3>{dqIdentity, dq * dualNumber1, -dq2}, Vec3d{0.4, 0, 0.6}));
  456. }
  457. }} // namespace