6 namespace btInverseDynamics
8 static const idScalar kIsZero = 5 * std::numeric_limits<idScalar>::epsilon();
9 // requirements for axis length deviation from 1.0
10 // experimentally set from random euler angle rotation matrices
11 static const idScalar kAxisLengthEpsilon = 10 * kIsZero;
22 for (int i = 0; i < v.size(); i++)
28 void setZero(mat33 &m)
41 void skew(vec3 &v, mat33 *result)
43 (*result)(0, 0) = 0.0;
44 (*result)(0, 1) = -v(2);
45 (*result)(0, 2) = v(1);
46 (*result)(1, 0) = v(2);
47 (*result)(1, 1) = 0.0;
48 (*result)(1, 2) = -v(0);
49 (*result)(2, 0) = -v(1);
50 (*result)(2, 1) = v(0);
51 (*result)(2, 2) = 0.0;
54 idScalar maxAbs(const vecx &v)
56 idScalar result = 0.0;
57 for (int i = 0; i < v.size(); i++)
59 const idScalar tmp = BT_ID_FABS(v(i));
68 idScalar maxAbs(const vec3 &v)
70 idScalar result = 0.0;
71 for (int i = 0; i < 3; i++)
73 const idScalar tmp = BT_ID_FABS(v(i));
82 #if (defined BT_ID_HAVE_MAT3X)
83 idScalar maxAbsMat3x(const mat3x &m)
85 // only used for tests -- so just loop here for portability
86 idScalar result = 0.0;
87 for (idArrayIdx col = 0; col < m.cols(); col++)
89 for (idArrayIdx row = 0; row < 3; row++)
91 result = BT_ID_MAX(result, std::fabs(m(row, col)));
97 void mul(const mat33 &a, const mat3x &b, mat3x *result)
99 if (b.cols() != result->cols())
101 bt_id_error_message("size missmatch. b.cols()= %d, result->cols()= %d\n",
102 static_cast<int>(b.cols()), static_cast<int>(result->cols()));
106 for (idArrayIdx col = 0; col < b.cols(); col++)
108 const idScalar x = a(0, 0) * b(0, col) + a(0, 1) * b(1, col) + a(0, 2) * b(2, col);
109 const idScalar y = a(1, 0) * b(0, col) + a(1, 1) * b(1, col) + a(1, 2) * b(2, col);
110 const idScalar z = a(2, 0) * b(0, col) + a(2, 1) * b(1, col) + a(2, 2) * b(2, col);
111 setMat3xElem(0, col, x, result);
112 setMat3xElem(1, col, y, result);
113 setMat3xElem(2, col, z, result);
116 void add(const mat3x &a, const mat3x &b, mat3x *result)
118 if (a.cols() != b.cols())
120 bt_id_error_message("size missmatch. a.cols()= %d, b.cols()= %d\n",
121 static_cast<int>(a.cols()), static_cast<int>(b.cols()));
124 for (idArrayIdx col = 0; col < b.cols(); col++)
126 for (idArrayIdx row = 0; row < 3; row++)
128 setMat3xElem(row, col, a(row, col) + b(row, col), result);
132 void sub(const mat3x &a, const mat3x &b, mat3x *result)
134 if (a.cols() != b.cols())
136 bt_id_error_message("size missmatch. a.cols()= %d, b.cols()= %d\n",
137 static_cast<int>(a.cols()), static_cast<int>(b.cols()));
140 for (idArrayIdx col = 0; col < b.cols(); col++)
142 for (idArrayIdx row = 0; row < 3; row++)
144 setMat3xElem(row, col, a(row, col) - b(row, col), result);
150 mat33 transformX(const idScalar &alpha)
153 const idScalar cos_alpha = BT_ID_COS(alpha);
154 const idScalar sin_alpha = BT_ID_SIN(alpha);
167 T(2, 1) = -sin_alpha;
173 mat33 transformY(const idScalar &beta)
176 const idScalar cos_beta = BT_ID_COS(beta);
177 const idScalar sin_beta = BT_ID_SIN(beta);
196 mat33 transformZ(const idScalar &gamma)
199 const idScalar cos_gamma = BT_ID_COS(gamma);
200 const idScalar sin_gamma = BT_ID_SIN(gamma);
208 T(1, 0) = -sin_gamma;
219 mat33 tildeOperator(const vec3 &v)
234 void getVecMatFromDH(idScalar theta, idScalar d, idScalar a, idScalar alpha, vec3 *r, mat33 *T)
236 const idScalar sa = BT_ID_SIN(alpha);
237 const idScalar ca = BT_ID_COS(alpha);
238 const idScalar st = BT_ID_SIN(theta);
239 const idScalar ct = BT_ID_COS(theta);
249 (*T)(1, 0) = st * ca;
250 (*T)(1, 1) = ct * ca;
253 (*T)(2, 0) = st * sa;
254 (*T)(2, 1) = ct * sa;
258 void bodyTParentFromAxisAngle(const vec3 &axis, const idScalar &angle, mat33 *T)
260 const idScalar c = BT_ID_COS(angle);
261 const idScalar s = -BT_ID_SIN(angle);
262 const idScalar one_m_c = 1.0 - c;
264 const idScalar &x = axis(0);
265 const idScalar &y = axis(1);
266 const idScalar &z = axis(2);
268 (*T)(0, 0) = x * x * one_m_c + c;
269 (*T)(0, 1) = x * y * one_m_c - z * s;
270 (*T)(0, 2) = x * z * one_m_c + y * s;
272 (*T)(1, 0) = x * y * one_m_c + z * s;
273 (*T)(1, 1) = y * y * one_m_c + c;
274 (*T)(1, 2) = y * z * one_m_c - x * s;
276 (*T)(2, 0) = x * z * one_m_c - y * s;
277 (*T)(2, 1) = y * z * one_m_c + x * s;
278 (*T)(2, 2) = z * z * one_m_c + c;
281 bool isPositiveDefinite(const mat33 &m)
283 // test if all upper left determinants are positive
288 if (m(0, 0) * m(1, 1) - m(0, 1) * m(1, 0) <= 0)
292 if ((m(0, 0) * (m(1, 1) * m(2, 2) - m(1, 2) * m(2, 1)) -
293 m(0, 1) * (m(1, 0) * m(2, 2) - m(1, 2) * m(2, 0)) +
294 m(0, 2) * (m(1, 0) * m(2, 1) - m(1, 1) * m(2, 0))) < 0)
301 bool isPositiveSemiDefinite(const mat33 &m)
303 // test if all upper left determinants are positive
308 if (m(0, 0) * m(1, 1) - m(0, 1) * m(1, 0) < 0)
312 if ((m(0, 0) * (m(1, 1) * m(2, 2) - m(1, 2) * m(2, 1)) -
313 m(0, 1) * (m(1, 0) * m(2, 2) - m(1, 2) * m(2, 0)) +
314 m(0, 2) * (m(1, 0) * m(2, 1) - m(1, 1) * m(2, 0))) < 0)
321 bool isPositiveSemiDefiniteFuzzy(const mat33 &m)
323 // test if all upper left determinants are positive
324 if (m(0, 0) < -kIsZero)
328 if (m(0, 0) * m(1, 1) - m(0, 1) * m(1, 0) < -kIsZero)
332 if ((m(0, 0) * (m(1, 1) * m(2, 2) - m(1, 2) * m(2, 1)) -
333 m(0, 1) * (m(1, 0) * m(2, 2) - m(1, 2) * m(2, 0)) +
334 m(0, 2) * (m(1, 0) * m(2, 1) - m(1, 1) * m(2, 0))) < -kIsZero)
341 idScalar determinant(const mat33 &m)
343 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) -
344 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);
347 bool isValidInertiaMatrix(const mat33 &I, const int index, bool has_fixed_joint)
349 // TODO(Thomas) do we really want this?
350 // in cases where the inertia tensor about the center of mass is zero,
351 // the determinant of the inertia tensor about the joint axis is almost
352 // zero and can have a very small negative value.
353 if (!isPositiveSemiDefiniteFuzzy(I))
356 "invalid inertia matrix for body %d, not positive definite "
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),
370 // check triangle inequality, must have I(i,i)+I(j,j)>=I(k,k)
371 if (!has_fixed_joint)
373 if (I(0, 0) + I(1, 1) < I(2, 2))
375 bt_id_error_message("invalid inertia tensor for body %d, I(0,0) + I(1,1) < I(2,2)\n", index);
378 "[%.20e %.20e %.20e;\n"
379 "%.20e %.20e %.20e;\n"
380 "%.20e %.20e %.20e]\n",
381 I(0, 0), I(0, 1), I(0, 2), I(1, 0), I(1, 1), I(1, 2), I(2, 0), I(2, 1),
385 if (I(0, 0) + I(1, 1) < I(2, 2))
387 bt_id_error_message("invalid inertia tensor for body %d, I(0,0) + I(1,1) < I(2,2)\n", index);
390 "[%.20e %.20e %.20e;\n"
391 "%.20e %.20e %.20e;\n"
392 "%.20e %.20e %.20e]\n",
393 I(0, 0), I(0, 1), I(0, 2), I(1, 0), I(1, 1), I(1, 2), I(2, 0), I(2, 1),
397 if (I(1, 1) + I(2, 2) < I(0, 0))
399 bt_id_error_message("invalid inertia tensor for body %d, I(1,1) + I(2,2) < I(0,0)\n", index);
402 "[%.20e %.20e %.20e;\n"
403 "%.20e %.20e %.20e;\n"
404 "%.20e %.20e %.20e]\n",
405 I(0, 0), I(0, 1), I(0, 2), I(1, 0), I(1, 1), I(1, 2), I(2, 0), I(2, 1),
410 // check positive/zero diagonal elements
411 for (int i = 0; i < 3; i++)
415 bt_id_error_message("invalid inertia tensor, I(%d,%d)= %e <0\n", i, i, I(i, i));
420 if (BT_ID_FABS(I(1, 0) - I(0, 1)) > kIsZero)
423 "invalid inertia tensor for body %d I(1,0)!=I(0,1). I(1,0)-I(0,1)= "
425 index, I(1, 0) - I(0, 1));
428 if (BT_ID_FABS(I(2, 0) - I(0, 2)) > kIsZero)
431 "invalid inertia tensor for body %d I(2,0)!=I(0,2). I(2,0)-I(0,2)= "
433 index, I(2, 0) - I(0, 2));
436 if (BT_ID_FABS(I(1, 2) - I(2, 1)) > kIsZero)
438 bt_id_error_message("invalid inertia tensor body %d I(1,2)!=I(2,1). I(1,2)-I(2,1)= %e\n", index,
445 bool isValidTransformMatrix(const mat33 &m)
447 #define print_mat(x) \
448 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), \
449 x(1, 0), x(1, 1), x(1, 2), x(2, 0), x(2, 1), x(2, 2))
451 // check for unit length column vectors
452 for (int i = 0; i < 3; i++)
454 const idScalar length_minus_1 =
455 BT_ID_FABS(m(0, i) * m(0, i) + m(1, i) * m(1, i) + m(2, i) * m(2, i) - 1.0);
456 if (length_minus_1 > kAxisLengthEpsilon)
459 "Not a valid rotation matrix (column %d not unit length)\n"
460 "column = [%.18e %.18e %.18e]\n"
461 "length-1.0= %.18e\n",
462 i, m(0, i), m(1, i), m(2, i), length_minus_1);
467 // check for orthogonal column vectors
468 if (BT_ID_FABS(m(0, 0) * m(0, 1) + m(1, 0) * m(1, 1) + m(2, 0) * m(2, 1)) > kAxisLengthEpsilon)
470 bt_id_error_message("Not a valid rotation matrix (columns 0 and 1 not orthogonal)\n");
474 if (BT_ID_FABS(m(0, 0) * m(0, 2) + m(1, 0) * m(1, 2) + m(2, 0) * m(2, 2)) > kAxisLengthEpsilon)
476 bt_id_error_message("Not a valid rotation matrix (columns 0 and 2 not orthogonal)\n");
480 if (BT_ID_FABS(m(0, 1) * m(0, 2) + m(1, 1) * m(1, 2) + m(2, 1) * m(2, 2)) > kAxisLengthEpsilon)
482 bt_id_error_message("Not a valid rotation matrix (columns 0 and 2 not orthogonal)\n");
486 // check determinant (rotation not reflection)
487 if (determinant(m) <= 0)
489 bt_id_error_message("Not a valid rotation matrix (determinant <=0)\n");
496 bool isUnitVector(const vec3 &vector)
498 return BT_ID_FABS(vector(0) * vector(0) + vector(1) * vector(1) + vector(2) * vector(2) - 1.0) <
502 vec3 rpyFromMatrix(const mat33 &rot)
505 rpy(2) = BT_ID_ATAN2(-rot(1, 0), rot(0, 0));
506 rpy(0) = BT_ID_ATAN2(-rot(2, 0), rot(2, 2));
507 rpy(1) = BT_ID_ATAN2(rot(2, 0), BT_ID_COS(rpy(2)) * rot(0, 0) - BT_ID_SIN(rpy(0)) * rot(1, 0));
510 } // namespace btInverseDynamics