IDMath.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510
  1. #include "IDMath.hpp"
  2. #include <cmath>
  3. #include <limits>
  4. namespace btInverseDynamics
  5. {
  6. static const idScalar kIsZero = 5 * std::numeric_limits<idScalar>::epsilon();
  7. // requirements for axis length deviation from 1.0
  8. // experimentally set from random euler angle rotation matrices
  9. static const idScalar kAxisLengthEpsilon = 10 * kIsZero;
  10. void setZero(vec3 &v)
  11. {
  12. v(0) = 0;
  13. v(1) = 0;
  14. v(2) = 0;
  15. }
  16. void setZero(vecx &v)
  17. {
  18. for (int i = 0; i < v.size(); i++)
  19. {
  20. v(i) = 0;
  21. }
  22. }
  23. void setZero(mat33 &m)
  24. {
  25. m(0, 0) = 0;
  26. m(0, 1) = 0;
  27. m(0, 2) = 0;
  28. m(1, 0) = 0;
  29. m(1, 1) = 0;
  30. m(1, 2) = 0;
  31. m(2, 0) = 0;
  32. m(2, 1) = 0;
  33. m(2, 2) = 0;
  34. }
  35. void skew(vec3 &v, mat33 *result)
  36. {
  37. (*result)(0, 0) = 0.0;
  38. (*result)(0, 1) = -v(2);
  39. (*result)(0, 2) = v(1);
  40. (*result)(1, 0) = v(2);
  41. (*result)(1, 1) = 0.0;
  42. (*result)(1, 2) = -v(0);
  43. (*result)(2, 0) = -v(1);
  44. (*result)(2, 1) = v(0);
  45. (*result)(2, 2) = 0.0;
  46. }
  47. idScalar maxAbs(const vecx &v)
  48. {
  49. idScalar result = 0.0;
  50. for (int i = 0; i < v.size(); i++)
  51. {
  52. const idScalar tmp = BT_ID_FABS(v(i));
  53. if (tmp > result)
  54. {
  55. result = tmp;
  56. }
  57. }
  58. return result;
  59. }
  60. idScalar maxAbs(const vec3 &v)
  61. {
  62. idScalar result = 0.0;
  63. for (int i = 0; i < 3; i++)
  64. {
  65. const idScalar tmp = BT_ID_FABS(v(i));
  66. if (tmp > result)
  67. {
  68. result = tmp;
  69. }
  70. }
  71. return result;
  72. }
  73. #if (defined BT_ID_HAVE_MAT3X)
  74. idScalar maxAbsMat3x(const mat3x &m)
  75. {
  76. // only used for tests -- so just loop here for portability
  77. idScalar result = 0.0;
  78. for (idArrayIdx col = 0; col < m.cols(); col++)
  79. {
  80. for (idArrayIdx row = 0; row < 3; row++)
  81. {
  82. result = BT_ID_MAX(result, std::fabs(m(row, col)));
  83. }
  84. }
  85. return result;
  86. }
  87. void mul(const mat33 &a, const mat3x &b, mat3x *result)
  88. {
  89. if (b.cols() != result->cols())
  90. {
  91. bt_id_error_message("size missmatch. b.cols()= %d, result->cols()= %d\n",
  92. static_cast<int>(b.cols()), static_cast<int>(result->cols()));
  93. abort();
  94. }
  95. for (idArrayIdx col = 0; col < b.cols(); col++)
  96. {
  97. const idScalar x = a(0, 0) * b(0, col) + a(0, 1) * b(1, col) + a(0, 2) * b(2, col);
  98. const idScalar y = a(1, 0) * b(0, col) + a(1, 1) * b(1, col) + a(1, 2) * b(2, col);
  99. const idScalar z = a(2, 0) * b(0, col) + a(2, 1) * b(1, col) + a(2, 2) * b(2, col);
  100. setMat3xElem(0, col, x, result);
  101. setMat3xElem(1, col, y, result);
  102. setMat3xElem(2, col, z, result);
  103. }
  104. }
  105. void add(const mat3x &a, const mat3x &b, mat3x *result)
  106. {
  107. if (a.cols() != b.cols())
  108. {
  109. bt_id_error_message("size missmatch. a.cols()= %d, b.cols()= %d\n",
  110. static_cast<int>(a.cols()), static_cast<int>(b.cols()));
  111. abort();
  112. }
  113. for (idArrayIdx col = 0; col < b.cols(); col++)
  114. {
  115. for (idArrayIdx row = 0; row < 3; row++)
  116. {
  117. setMat3xElem(row, col, a(row, col) + b(row, col), result);
  118. }
  119. }
  120. }
  121. void sub(const mat3x &a, const mat3x &b, mat3x *result)
  122. {
  123. if (a.cols() != b.cols())
  124. {
  125. bt_id_error_message("size missmatch. a.cols()= %d, b.cols()= %d\n",
  126. static_cast<int>(a.cols()), static_cast<int>(b.cols()));
  127. abort();
  128. }
  129. for (idArrayIdx col = 0; col < b.cols(); col++)
  130. {
  131. for (idArrayIdx row = 0; row < 3; row++)
  132. {
  133. setMat3xElem(row, col, a(row, col) - b(row, col), result);
  134. }
  135. }
  136. }
  137. #endif
  138. mat33 transformX(const idScalar &alpha)
  139. {
  140. mat33 T;
  141. const idScalar cos_alpha = BT_ID_COS(alpha);
  142. const idScalar sin_alpha = BT_ID_SIN(alpha);
  143. // [1 0 0]
  144. // [0 c s]
  145. // [0 -s c]
  146. T(0, 0) = 1.0;
  147. T(0, 1) = 0.0;
  148. T(0, 2) = 0.0;
  149. T(1, 0) = 0.0;
  150. T(1, 1) = cos_alpha;
  151. T(1, 2) = sin_alpha;
  152. T(2, 0) = 0.0;
  153. T(2, 1) = -sin_alpha;
  154. T(2, 2) = cos_alpha;
  155. return T;
  156. }
  157. mat33 transformY(const idScalar &beta)
  158. {
  159. mat33 T;
  160. const idScalar cos_beta = BT_ID_COS(beta);
  161. const idScalar sin_beta = BT_ID_SIN(beta);
  162. // [c 0 -s]
  163. // [0 1 0]
  164. // [s 0 c]
  165. T(0, 0) = cos_beta;
  166. T(0, 1) = 0.0;
  167. T(0, 2) = -sin_beta;
  168. T(1, 0) = 0.0;
  169. T(1, 1) = 1.0;
  170. T(1, 2) = 0.0;
  171. T(2, 0) = sin_beta;
  172. T(2, 1) = 0.0;
  173. T(2, 2) = cos_beta;
  174. return T;
  175. }
  176. mat33 transformZ(const idScalar &gamma)
  177. {
  178. mat33 T;
  179. const idScalar cos_gamma = BT_ID_COS(gamma);
  180. const idScalar sin_gamma = BT_ID_SIN(gamma);
  181. // [ c s 0]
  182. // [-s c 0]
  183. // [ 0 0 1]
  184. T(0, 0) = cos_gamma;
  185. T(0, 1) = sin_gamma;
  186. T(0, 2) = 0.0;
  187. T(1, 0) = -sin_gamma;
  188. T(1, 1) = cos_gamma;
  189. T(1, 2) = 0.0;
  190. T(2, 0) = 0.0;
  191. T(2, 1) = 0.0;
  192. T(2, 2) = 1.0;
  193. return T;
  194. }
  195. mat33 tildeOperator(const vec3 &v)
  196. {
  197. mat33 m;
  198. m(0, 0) = 0.0;
  199. m(0, 1) = -v(2);
  200. m(0, 2) = v(1);
  201. m(1, 0) = v(2);
  202. m(1, 1) = 0.0;
  203. m(1, 2) = -v(0);
  204. m(2, 0) = -v(1);
  205. m(2, 1) = v(0);
  206. m(2, 2) = 0.0;
  207. return m;
  208. }
  209. void getVecMatFromDH(idScalar theta, idScalar d, idScalar a, idScalar alpha, vec3 *r, mat33 *T)
  210. {
  211. const idScalar sa = BT_ID_SIN(alpha);
  212. const idScalar ca = BT_ID_COS(alpha);
  213. const idScalar st = BT_ID_SIN(theta);
  214. const idScalar ct = BT_ID_COS(theta);
  215. (*r)(0) = a;
  216. (*r)(1) = -sa * d;
  217. (*r)(2) = ca * d;
  218. (*T)(0, 0) = ct;
  219. (*T)(0, 1) = -st;
  220. (*T)(0, 2) = 0.0;
  221. (*T)(1, 0) = st * ca;
  222. (*T)(1, 1) = ct * ca;
  223. (*T)(1, 2) = -sa;
  224. (*T)(2, 0) = st * sa;
  225. (*T)(2, 1) = ct * sa;
  226. (*T)(2, 2) = ca;
  227. }
  228. void bodyTParentFromAxisAngle(const vec3 &axis, const idScalar &angle, mat33 *T)
  229. {
  230. const idScalar c = BT_ID_COS(angle);
  231. const idScalar s = -BT_ID_SIN(angle);
  232. const idScalar one_m_c = 1.0 - c;
  233. const idScalar &x = axis(0);
  234. const idScalar &y = axis(1);
  235. const idScalar &z = axis(2);
  236. (*T)(0, 0) = x * x * one_m_c + c;
  237. (*T)(0, 1) = x * y * one_m_c - z * s;
  238. (*T)(0, 2) = x * z * one_m_c + y * s;
  239. (*T)(1, 0) = x * y * one_m_c + z * s;
  240. (*T)(1, 1) = y * y * one_m_c + c;
  241. (*T)(1, 2) = y * z * one_m_c - x * s;
  242. (*T)(2, 0) = x * z * one_m_c - y * s;
  243. (*T)(2, 1) = y * z * one_m_c + x * s;
  244. (*T)(2, 2) = z * z * one_m_c + c;
  245. }
  246. bool isPositiveDefinite(const mat33 &m)
  247. {
  248. // test if all upper left determinants are positive
  249. if (m(0, 0) <= 0)
  250. { // upper 1x1
  251. return false;
  252. }
  253. if (m(0, 0) * m(1, 1) - m(0, 1) * m(1, 0) <= 0)
  254. { // upper 2x2
  255. return false;
  256. }
  257. if ((m(0, 0) * (m(1, 1) * m(2, 2) - m(1, 2) * m(2, 1)) -
  258. m(0, 1) * (m(1, 0) * m(2, 2) - m(1, 2) * m(2, 0)) +
  259. m(0, 2) * (m(1, 0) * m(2, 1) - m(1, 1) * m(2, 0))) < 0)
  260. {
  261. return false;
  262. }
  263. return true;
  264. }
  265. bool isPositiveSemiDefinite(const mat33 &m)
  266. {
  267. // test if all upper left determinants are positive
  268. if (m(0, 0) < 0)
  269. { // upper 1x1
  270. return false;
  271. }
  272. if (m(0, 0) * m(1, 1) - m(0, 1) * m(1, 0) < 0)
  273. { // upper 2x2
  274. return false;
  275. }
  276. if ((m(0, 0) * (m(1, 1) * m(2, 2) - m(1, 2) * m(2, 1)) -
  277. m(0, 1) * (m(1, 0) * m(2, 2) - m(1, 2) * m(2, 0)) +
  278. m(0, 2) * (m(1, 0) * m(2, 1) - m(1, 1) * m(2, 0))) < 0)
  279. {
  280. return false;
  281. }
  282. return true;
  283. }
  284. bool isPositiveSemiDefiniteFuzzy(const mat33 &m)
  285. {
  286. // test if all upper left determinants are positive
  287. if (m(0, 0) < -kIsZero)
  288. { // upper 1x1
  289. return false;
  290. }
  291. if (m(0, 0) * m(1, 1) - m(0, 1) * m(1, 0) < -kIsZero)
  292. { // upper 2x2
  293. return false;
  294. }
  295. if ((m(0, 0) * (m(1, 1) * m(2, 2) - m(1, 2) * m(2, 1)) -
  296. m(0, 1) * (m(1, 0) * m(2, 2) - m(1, 2) * m(2, 0)) +
  297. m(0, 2) * (m(1, 0) * m(2, 1) - m(1, 1) * m(2, 0))) < -kIsZero)
  298. {
  299. return false;
  300. }
  301. return true;
  302. }
  303. idScalar determinant(const mat33 &m)
  304. {
  305. return m(0, 0) * m(1, 1) * m(2, 2) + m(0, 1) * m(1, 2) * m(2, 0) + m(0, 2) * m(1, 0) * m(2, 1) -
  306. m(0, 2) * m(1, 1) * m(2, 0) - m(0, 0) * m(1, 2) * m(2, 1) - m(0, 1) * m(1, 0) * m(2, 2);
  307. }
  308. bool isValidInertiaMatrix(const mat33 &I, const int index, bool has_fixed_joint)
  309. {
  310. // TODO(Thomas) do we really want this?
  311. // in cases where the inertia tensor about the center of mass is zero,
  312. // the determinant of the inertia tensor about the joint axis is almost
  313. // zero and can have a very small negative value.
  314. if (!isPositiveSemiDefiniteFuzzy(I))
  315. {
  316. bt_id_error_message(
  317. "invalid inertia matrix for body %d, not positive definite "
  318. "(fixed joint)\n",
  319. index);
  320. bt_id_error_message(
  321. "matrix is:\n"
  322. "[%.20e %.20e %.20e;\n"
  323. "%.20e %.20e %.20e;\n"
  324. "%.20e %.20e %.20e]\n",
  325. I(0, 0), I(0, 1), I(0, 2), I(1, 0), I(1, 1), I(1, 2), I(2, 0), I(2, 1),
  326. I(2, 2));
  327. return false;
  328. }
  329. // check triangle inequality, must have I(i,i)+I(j,j)>=I(k,k)
  330. if (!has_fixed_joint)
  331. {
  332. if (I(0, 0) + I(1, 1) < I(2, 2))
  333. {
  334. bt_id_error_message("invalid inertia tensor for body %d, I(0,0) + I(1,1) < I(2,2)\n", index);
  335. bt_id_error_message(
  336. "matrix is:\n"
  337. "[%.20e %.20e %.20e;\n"
  338. "%.20e %.20e %.20e;\n"
  339. "%.20e %.20e %.20e]\n",
  340. I(0, 0), I(0, 1), I(0, 2), I(1, 0), I(1, 1), I(1, 2), I(2, 0), I(2, 1),
  341. I(2, 2));
  342. return false;
  343. }
  344. if (I(0, 0) + I(1, 1) < I(2, 2))
  345. {
  346. bt_id_error_message("invalid inertia tensor for body %d, I(0,0) + I(1,1) < I(2,2)\n", index);
  347. bt_id_error_message(
  348. "matrix is:\n"
  349. "[%.20e %.20e %.20e;\n"
  350. "%.20e %.20e %.20e;\n"
  351. "%.20e %.20e %.20e]\n",
  352. I(0, 0), I(0, 1), I(0, 2), I(1, 0), I(1, 1), I(1, 2), I(2, 0), I(2, 1),
  353. I(2, 2));
  354. return false;
  355. }
  356. if (I(1, 1) + I(2, 2) < I(0, 0))
  357. {
  358. bt_id_error_message("invalid inertia tensor for body %d, I(1,1) + I(2,2) < I(0,0)\n", index);
  359. bt_id_error_message(
  360. "matrix is:\n"
  361. "[%.20e %.20e %.20e;\n"
  362. "%.20e %.20e %.20e;\n"
  363. "%.20e %.20e %.20e]\n",
  364. I(0, 0), I(0, 1), I(0, 2), I(1, 0), I(1, 1), I(1, 2), I(2, 0), I(2, 1),
  365. I(2, 2));
  366. return false;
  367. }
  368. }
  369. // check positive/zero diagonal elements
  370. for (int i = 0; i < 3; i++)
  371. {
  372. if (I(i, i) < 0)
  373. { // accept zero
  374. bt_id_error_message("invalid inertia tensor, I(%d,%d)= %e <0\n", i, i, I(i, i));
  375. return false;
  376. }
  377. }
  378. // check symmetry
  379. if (BT_ID_FABS(I(1, 0) - I(0, 1)) > kIsZero)
  380. {
  381. bt_id_error_message(
  382. "invalid inertia tensor for body %d I(1,0)!=I(0,1). I(1,0)-I(0,1)= "
  383. "%e\n",
  384. index, I(1, 0) - I(0, 1));
  385. return false;
  386. }
  387. if (BT_ID_FABS(I(2, 0) - I(0, 2)) > kIsZero)
  388. {
  389. bt_id_error_message(
  390. "invalid inertia tensor for body %d I(2,0)!=I(0,2). I(2,0)-I(0,2)= "
  391. "%e\n",
  392. index, I(2, 0) - I(0, 2));
  393. return false;
  394. }
  395. if (BT_ID_FABS(I(1, 2) - I(2, 1)) > kIsZero)
  396. {
  397. bt_id_error_message("invalid inertia tensor body %d I(1,2)!=I(2,1). I(1,2)-I(2,1)= %e\n", index,
  398. I(1, 2) - I(2, 1));
  399. return false;
  400. }
  401. return true;
  402. }
  403. bool isValidTransformMatrix(const mat33 &m)
  404. {
  405. #define print_mat(x) \
  406. bt_id_error_message("matrix is [%e, %e, %e; %e, %e, %e; %e, %e, %e]\n", x(0, 0), x(0, 1), x(0, 2), \
  407. x(1, 0), x(1, 1), x(1, 2), x(2, 0), x(2, 1), x(2, 2))
  408. // check for unit length column vectors
  409. for (int i = 0; i < 3; i++)
  410. {
  411. const idScalar length_minus_1 =
  412. BT_ID_FABS(m(0, i) * m(0, i) + m(1, i) * m(1, i) + m(2, i) * m(2, i) - 1.0);
  413. if (length_minus_1 > kAxisLengthEpsilon)
  414. {
  415. bt_id_error_message(
  416. "Not a valid rotation matrix (column %d not unit length)\n"
  417. "column = [%.18e %.18e %.18e]\n"
  418. "length-1.0= %.18e\n",
  419. i, m(0, i), m(1, i), m(2, i), length_minus_1);
  420. print_mat(m);
  421. return false;
  422. }
  423. }
  424. // check for orthogonal column vectors
  425. if (BT_ID_FABS(m(0, 0) * m(0, 1) + m(1, 0) * m(1, 1) + m(2, 0) * m(2, 1)) > kAxisLengthEpsilon)
  426. {
  427. bt_id_error_message("Not a valid rotation matrix (columns 0 and 1 not orthogonal)\n");
  428. print_mat(m);
  429. return false;
  430. }
  431. if (BT_ID_FABS(m(0, 0) * m(0, 2) + m(1, 0) * m(1, 2) + m(2, 0) * m(2, 2)) > kAxisLengthEpsilon)
  432. {
  433. bt_id_error_message("Not a valid rotation matrix (columns 0 and 2 not orthogonal)\n");
  434. print_mat(m);
  435. return false;
  436. }
  437. if (BT_ID_FABS(m(0, 1) * m(0, 2) + m(1, 1) * m(1, 2) + m(2, 1) * m(2, 2)) > kAxisLengthEpsilon)
  438. {
  439. bt_id_error_message("Not a valid rotation matrix (columns 0 and 2 not orthogonal)\n");
  440. print_mat(m);
  441. return false;
  442. }
  443. // check determinant (rotation not reflection)
  444. if (determinant(m) <= 0)
  445. {
  446. bt_id_error_message("Not a valid rotation matrix (determinant <=0)\n");
  447. print_mat(m);
  448. return false;
  449. }
  450. return true;
  451. }
  452. bool isUnitVector(const vec3 &vector)
  453. {
  454. return BT_ID_FABS(vector(0) * vector(0) + vector(1) * vector(1) + vector(2) * vector(2) - 1.0) <
  455. kIsZero;
  456. }
  457. vec3 rpyFromMatrix(const mat33 &rot)
  458. {
  459. vec3 rpy;
  460. rpy(2) = BT_ID_ATAN2(-rot(1, 0), rot(0, 0));
  461. rpy(0) = BT_ID_ATAN2(-rot(2, 0), rot(2, 2));
  462. rpy(1) = BT_ID_ATAN2(rot(2, 0), BT_ID_COS(rpy(2)) * rot(0, 0) - BT_ID_SIN(rpy(0)) * rot(1, 0));
  463. return rpy;
  464. }
  465. } // namespace btInverseDynamics