ML Reference
|
00001 // **InsertLicense** code 00002 //---------------------------------------------------------------------------------- 00014 //---------------------------------------------------------------------------------- 00015 00016 #ifndef __mlQuaternion_H 00017 #define __mlQuaternion_H 00018 00019 // Resolves system dependencies and load project settings. 00020 #ifndef __mlLinearAlgebraSystem_H 00021 #include "mlLinearAlgebraSystem.h" 00022 #endif 00023 00024 // 3D double vector. 00025 #ifndef __mlVector3_H 00026 #include "mlVector3.h" 00027 #endif 00028 00029 00030 ML_LA_START_NAMESPACE 00031 00032 //-------------------------------------------------------- 00036 //-------------------------------------------------------- 00037 template <typename DT> 00038 class TQuaternion { 00039 00040 public: 00041 //------------------------------------------------------ 00043 00044 //------------------------------------------------------ 00045 union { 00046 // We use a union to make the members accessible 00047 // either 00048 // - as named members qx, qy, qz and qw, 00049 // - as array[0..3] and 00050 // - vector (qv,qw) via an access method qv(). 00051 // We also provide indexing operators [] on the array. 00052 // Note: 00053 // The real part qw is stored in the last component. 00054 00055 //------------------------------------------------------ 00058 //------------------------------------------------------ 00059 struct { 00060 DT qx; 00061 DT qy; 00062 DT qz; 00063 DT qw; 00064 }; 00065 00066 //------------------------------------------------------ 00073 //------------------------------------------------------ 00074 DT array[4]; 00075 }; 00077 00078 00079 //------------------------------------------------------ 00081 00082 //------------------------------------------------------ 00084 inline TQuaternion() : 00085 qx(0), qy(0), qz(0), qw(0) { } 00086 00089 inline explicit TQuaternion(DT d) : 00090 qx(0), qy(0), qz(0), qw(d) 00091 { 00092 ML_TRACE_IN_TIME_CRITICAL("TQuaternion(DT d)"); 00093 } 00094 00099 template <typename DT2> 00100 inline explicit TQuaternion(const TQuaternion<DT2> &q2) 00101 { 00102 ML_TRACE_IN_TIME_CRITICAL("TQuaternion(const TQuaternion<DT2> &q2)"); 00103 00104 qx = static_cast<DT>(q2.qx); 00105 qy = static_cast<DT>(q2.qy); 00106 qz = static_cast<DT>(q2.qz); 00107 qw = static_cast<DT>(q2.qw); 00108 } 00109 00117 inline explicit TQuaternion(DT x, DT y, DT z, DT w) 00118 { 00119 ML_TRACE_IN_TIME_CRITICAL("TQuaternion(DT x, DT y, DT z, DT w)"); 00120 00121 qx = x; 00122 qy = y; 00123 qz = z; 00124 qw = w; 00125 } 00126 00135 inline explicit TQuaternion(const FloatingPointVector<DT,4> &v) 00136 { 00137 ML_TRACE_IN_TIME_CRITICAL("TQuaternion(const FloatingPointVector<DT,4> &v)"); 00138 qx = v[1]; 00139 qy = v[2]; 00140 qz = v[3]; 00141 qw = v[0]; 00142 } 00143 00148 inline explicit TQuaternion(const FloatingPointVector<DT, 3, Vector3DataContainer<DT> > &v, DT w) : 00149 qx(v[0]), qy(v[1]), qz(v[2]), qw(w) 00150 { 00151 ML_TRACE_IN_TIME_CRITICAL("TQuaternion(const FloatingPointVector<DT, 3> &v, DT w)"); 00152 } 00153 00155 00156 00157 //------------------------------------------------------------------------- 00159 00160 //------------------------------------------------------------------------- 00161 00164 inline FloatingPointVector<DT, 3, Vector3DataContainer<DT> > getImaginaryPart() const 00165 { 00166 return qv(); 00167 } 00168 00170 inline DT getRealPart() const 00171 { 00172 return qw; 00173 } 00174 00182 inline const FloatingPointVector<DT, 3, Vector3DataContainer<DT> > &qv() const 00183 { 00184 return reinterpret_cast<const FloatingPointVector<DT, 3, Vector3DataContainer<DT> >&>(qx); 00185 } 00186 00191 inline FloatingPointVector<DT, 3, Vector3DataContainer<DT> > &qv() 00192 { 00193 return reinterpret_cast<FloatingPointVector<DT, 3, Vector3DataContainer<DT> >&>(qx); 00194 } 00195 00199 inline void set(const FloatingPointVector<DT, 3, Vector3DataContainer<DT> > &v, const DT w) 00200 { 00201 ML_TRACE_IN_TIME_CRITICAL("TQuaternion::set(const FloatingPointVector<DT, 3> &v, const DT w)"); 00202 00203 qx = v[0]; 00204 qy = v[1]; 00205 qz = v[2]; 00206 qw = w; 00207 } 00208 00211 inline void set(const DT x, const DT y, const DT z, const DT w) 00212 { 00213 ML_TRACE_IN_TIME_CRITICAL("TQuaternion::set(const DT x, const DT y, const DT z, const DT w)"); 00214 00215 qx = x; 00216 qy = y; 00217 qz = z; 00218 qw = w; 00219 } 00220 00226 inline Tmat4<DT> getAsMat4(bool *isConvertible=NULL) const 00227 { 00228 ML_TRACE_IN("TQuaternion::getAsMat4() const"); 00229 00230 // Create return value. 00231 Tmat4<DT> m; 00232 ML_TRY 00233 { 00234 // Check whether conversion is possible. 00235 const DT n=norm(); 00236 if (0==n) { 00237 if (!isConvertible){ 00238 ML_PRINT_ERROR("TQuaternion::getAsMat4() const, quaternion is not convertible to 4x4 matrix", 00239 ML_BAD_PARAMETER, 00240 "Returning Quaterion"); 00241 } 00242 else{ 00243 *isConvertible = false; 00244 } 00245 m = Tmat4<DT>::getIdentity(); 00246 } 00247 else{ 00248 // Conversion is possible. 00249 const DT s = 2./n; 00250 //s is a compressed factor 00251 //it originates from the constant factor 2 and the normalization 00252 //factor for the vector "1/sqrt(norm(vector))" 00253 //To normalize the vector each component is divided by "1/sqrt(norm(vector))" 00254 //So each vector component qx,qy,qz has to get its own factor to normalize 00255 //the vector while calculating the matrix. However, as s is multiplied 00256 //always to a pair of 2 multiplied vector components, the factor can be 00257 //pulled in front of the addition (c.f. m11). As pairs of vector components 00258 //are added, the sqrt vanishes and what is left is the factor 2./norm(vector) 00259 //where norm is what is defined as "norm()" inside the mlQuaternion.h. 00260 00261 // q0 = qw, first column. 00262 const DT qxqx = qx*qx; 00263 const DT qyqy = qy*qy; 00264 const DT qzqz = qz*qz; 00265 00266 const DT qxqy = qx*qy; 00267 const DT qxqz = qx*qz; 00268 const DT qxqw = qx*qw; 00269 00270 const DT qyqz = qy*qz; 00271 const DT qyqw = qy*qw; 00272 00273 const DT qzqw = qz*qw; 00274 00275 const DT m11 = 1 - s * (qyqy + qzqz); 00276 const DT m12 = s * (qxqy - qzqw); 00277 const DT m13 = s * (qxqz + qyqw); 00278 00279 const DT m21 = s * (qxqy + qzqw); 00280 const DT m22 = 1 - s * (qxqx + qzqz); 00281 const DT m23 = s * (qyqz - qxqw); 00282 00283 const DT m31 = s * (qxqz - qyqw); 00284 const DT m32 = s * (qyqz + qxqw); 00285 const DT m33 = 1 - s * (qxqx + qyqy); 00286 00287 // Construct matrix from precomputed values 00288 m.set(0); 00289 m[0][0] = m11; 00290 m[0][1] = m12; 00291 m[0][2] = m13; 00292 m[0][3] = 0.0; 00293 00294 m[1][0] = m21; 00295 m[1][1] = m22; 00296 m[1][2] = m23; 00297 m[1][3] = 0.0; 00298 00299 m[2][0] = m31; 00300 m[2][1] = m32; 00301 m[2][2] = m33; 00302 m[2][3] = 0.0; 00303 00304 m[3][0] = 0.0; 00305 m[3][1] = 0.0; 00306 m[3][2] = 0.0; 00307 m[3][3] = 1.0; 00308 00309 if (isConvertible){ *isConvertible = true; } 00310 00311 } // else 00312 00313 } 00314 ML_CATCH_RETHROW; 00315 return m; 00316 } 00317 00319 00320 00321 //------------------------------------------------------------------------- 00323 00324 //------------------------------------------------------------------------- 00325 00329 inline DT operator[](const size_t i) const { return array[i]; } 00330 00334 inline DT &operator[](const size_t i) { return array[i]; } 00335 00337 inline TQuaternion<DT> &operator=(const TQuaternion<DT> &q) 00338 { 00339 if (this != &q){ 00340 qx = q.qx; 00341 qy = q.qy; 00342 qz = q.qz; 00343 qw = q.qw; 00344 } 00345 return *this; 00346 } 00348 00349 00350 //------------------------------------------------------ 00352 00353 //------------------------------------------------------ 00354 00356 inline TQuaternion<DT> operator + (const TQuaternion<DT> &b) const { return TQuaternion<DT>(qx+b.qx, qy+b.qy, qz+b.qz, qw+b.qw); } 00358 inline TQuaternion<DT> &operator += (const TQuaternion<DT> &b) { qx+=b.qx; qy+=b.qy; qz+=b.qz; qw+=b.qw; return *this; } 00359 00361 inline TQuaternion<DT> operator - (const TQuaternion<DT> &b) const { return TQuaternion<DT>(qx-b.qx, qy-b.qy, qz-b.qz, qw-b.qw); } 00363 inline TQuaternion<DT> &operator -= (const TQuaternion<DT> &b) { qx-=b.qx; qy-=b.qy; qz-=b.qz; qw-=b.qw; return *this; } 00364 00366 inline TQuaternion<DT> operator * (const TQuaternion<DT> &b) const { return mult(b); } 00368 inline TQuaternion<DT> &operator *= (const TQuaternion<DT> &b) { *this = mult(b); return *this; } 00369 00371 inline TQuaternion<DT> operator / (DT d) const 00372 { 00373 ML_TRACE_IN("TQuaternion::operator/"); 00374 00375 TQuaternion<DT> retVal(*this); 00376 ML_TRY 00377 { 00378 ML_CHECK_FLOAT(d); 00379 retVal /= d; 00380 } 00381 ML_CATCH_RETHROW; 00382 return retVal; 00383 } 00384 00386 inline TQuaternion<DT> &operator /= (DT d) 00387 { 00388 ML_TRACE_IN("TQuaternion::operator/="); 00389 ML_TRY 00390 { 00391 ML_CHECK_FLOAT(d); 00392 qx/=d; qy/=d; qz/=d; qw/=d; 00393 } 00394 ML_CATCH_RETHROW; 00395 return *this; 00396 } 00397 00398 00400 inline TQuaternion<DT> operator / (const TQuaternion<DT> &q) const 00401 { 00402 return TQuaternion<DT>(div(q)); 00403 } 00404 00409 inline TQuaternion<DT> compDiv(const TQuaternion<DT> &b, bool *isError=NULL) const 00410 { 00411 ML_TRACE_IN( "TQuaternion::compDiv/ " ); 00412 00413 // Initialize return value with default quaternion. 00414 TQuaternion<DT> retVal(0,0,0,1); 00415 ML_TRY 00416 { 00417 if (!isError){ 00418 // No error flag passed. Handle error if necessary. 00419 ML_CHECK_FLOAT(b.qx); 00420 ML_CHECK_FLOAT(b.qy); 00421 ML_CHECK_FLOAT(b.qz); 00422 ML_CHECK_FLOAT(b.qw); 00423 retVal.set(qx/b.qx, qy/b.qy, qz/b.qz, qw/b.qw); 00424 } 00425 else{ 00426 // Error flag is available. Return *isError as true in case of error 00427 *isError = (b.qx == 0) || 00428 (b.qy == 0) || 00429 (b.qz == 0) || 00430 (b.qw == 0); 00431 00432 retVal = *isError ? 00433 TQuaternion<DT>(b.qx != 0 ? qx/b.qx : qx, 00434 b.qy != 0 ? qy/b.qy : qy, 00435 b.qz != 0 ? qz/b.qz : qz, 00436 b.qw != 0 ? qw/b.qw : qw) : 00437 TQuaternion<DT>(qx/b.qx, 00438 qy/b.qy, 00439 qz/b.qz, 00440 qw/b.qw); 00441 } 00442 } 00443 ML_CATCH_RETHROW; 00444 return retVal; 00445 } 00446 00449 inline bool operator == (const TQuaternion<DT> &b) const { return MLValuesAreEqualWOM(qx, b.qx) && 00450 MLValuesAreEqualWOM(qy, b.qy) && 00451 MLValuesAreEqualWOM(qz, b.qz) && 00452 MLValuesAreEqualWOM(qw, b.qw); } 00455 inline bool operator != (const TQuaternion<DT> &b) const { return !operator==(b); } 00457 00458 00459 00461 inline DT dot(const TQuaternion<DT> &p) const { return qx*p.qx + qy*p.qy + qz*p.qz + qw*p.qw; } 00462 00465 inline TQuaternion<DT> odd(const TQuaternion<DT> &p) const { return TQuaternion<DT>(qy*p.qz - qz*p.qy, 00466 qz*p.qx - qx*p.qz, 00467 qx*p.qy - qy*p.qx, 00468 0); } 00469 00472 inline TQuaternion<DT> even(const TQuaternion<DT> &p) const { return TQuaternion<DT>(qw*p.qx + qx*p.qw, 00473 qw*p.qy + qy*p.qw, 00474 qw*p.qz + qz*p.qw, 00475 qw*p.qw - qx*p.qx - qy*p.qy - qz*p.qz); } 00476 00478 inline TQuaternion<DT> mult(const TQuaternion<DT> &q) const { Tvec3<DT> img(qv()); Tvec3<DT> qimg(q.qv()); return TQuaternion<DT>(img.cross(qimg) + img*q.qw + qw*qimg, qw*q.qw - img.dot(qimg)); } 00479 00481 inline TQuaternion<DT> euclideanMult(const TQuaternion<DT> &q) const { return conjugate().mult(q); } 00482 00484 inline TQuaternion<DT> outer(const TQuaternion<DT> &q) const { return (euclideanMult(q) - q.euclideanMult(*this)) / 2; } 00485 00486 00495 inline TQuaternion<DT> div(const TQuaternion<DT> &d, bool *isError=NULL) const 00496 { 00497 ML_TRACE_IN("TQuaternion::div()"); 00498 00499 // Initialize return value with default quaternion. 00500 TQuaternion<DT> retVal(0,0,0,1); 00501 ML_TRY 00502 { 00503 if (d == TQuaternion<DT>(0,0,0,0)){ 00504 if (isError == NULL){ 00505 // No error flag passed. Handle error if necessary. 00506 ML_PRINT_ERROR("TQuaternion::div() const, quaternion is not divisible", 00507 ML_BAD_PARAMETER, 00508 "Returning unchanged quaternion"); 00509 retVal.set(qx,qy,qz,qw); 00510 } 00511 else{ 00512 // Error flag pointer is available. Return *isError as true in case of error 00513 *isError = true; 00514 retVal.set(qx,qy,qz,qw); 00515 } 00516 } 00517 else{ 00518 if (isError != NULL){ *isError = false; } 00519 retVal.set((d.qw*qx - d.qx*qw - d.qy*qz + d.qz*qy)/(d.qw*d.qw + d.qx*d.qx + d.qy*d.qy + d.qz*d.qz), 00520 (d.qw*qy + d.qx*qz - d.qy*qw - d.qz*qx)/(d.qw*d.qw + d.qx*d.qx + d.qy*d.qy + d.qz*d.qz), 00521 (d.qw*qz - d.qx*qy + d.qy*qx - d.qz*qw)/(d.qw*d.qw + d.qx*d.qx + d.qy*d.qy + d.qz*d.qz), 00522 (d.qw*qw + d.qx*qx + d.qy*qy + d.qz*qz)/(d.qw*d.qw + d.qx*d.qx + d.qy*d.qy + d.qz*d.qz)); 00523 } 00524 } 00525 ML_CATCH_RETHROW; 00526 return retVal; 00527 } 00528 00529 00531 inline TQuaternion<DT> mult(DT s) const { return TQuaternion<DT>(qx*s, qy*s, qz*s, qw*s); } 00532 00534 inline TQuaternion<DT> add(const TQuaternion<DT> &b) const { return TQuaternion<DT>(qx+b.qx, qy+b.qy, qz+b.qz, qw+b.qw); } 00535 00537 inline TQuaternion<DT> add(DT s) const { return TQuaternion<DT>(qx, qy, qz, qw+s); } 00538 00540 inline TQuaternion<DT> conjugate() const { return TQuaternion<DT>(-qx, -qy, -qz, qw); } 00541 00543 inline TQuaternion<DT> negate() const { return TQuaternion<DT>(-qx, -qy, -qz, -qw); } 00544 00546 inline DT norm() const { return qx*qx + qy*qy + qz*qz + qw*qw; } 00547 00548 00551 inline DT norm2() const { return static_cast<DT>(::sqrt(qx*qx + qy*qy + qz*qz + qw*qw)); } 00552 00555 inline DT absoluteValue() const { return static_cast<DT>(::sqrt(norm())); } 00556 00561 inline TQuaternion<DT> normalize(bool *isError=NULL) const 00562 { 00563 ML_TRACE_IN("TQuaternion::normalize()"); 00564 00565 // Initialize return value with default quaternion. 00566 TQuaternion<DT> retVal(0,0,0,1); 00567 ML_TRY 00568 { 00569 const DT n=norm2(); 00570 if (MLValueIs0WOM(n)){ 00571 // Error! Check whether we have a pointer to a return error code value. 00572 if (isError == NULL){ 00573 // No, post an error. 00574 ML_PRINT_ERROR("TQuaternion::normalize() const, quaternion can not be normalized", 00575 ML_BAD_PARAMETER, 00576 "Returning default quaternion"); 00577 } 00578 else{ 00579 // Yes, set return code. 00580 *isError = true; 00581 } 00582 } 00583 else{ 00584 // Non zero => no error. 00585 if (isError){ *isError = false; } 00586 retVal.set(qx/n, qy/n, qz/n, qw/n); 00587 } 00588 } 00589 ML_CATCH_RETHROW; 00590 00591 return retVal; 00592 } 00593 00600 inline TQuaternion<DT> arg(bool *isError=NULL) const 00601 { 00602 ML_TRACE_IN("TQuaternion::arg() const"); 00603 00604 // Initialize return value with default quaternion. 00605 TQuaternion<DT> retVal(0,0,0,1); 00606 ML_TRY 00607 { 00608 // Norm2 must be non-zero to avoid divisions by zero. 00609 const DT n=norm2(); 00610 if (MLValueIs0WOM(n)){ 00611 // Error! Check whether we have a pointer to a return error code value. 00612 if (isError == NULL){ 00613 // No, post an error. 00614 ML_PRINT_ERROR("TQuaternion::arg() const, quaternion can not be normalized", 00615 ML_BAD_PARAMETER, 00616 "Returning default quaternion"); 00617 } 00618 else{ 00619 // Yes, set return code. 00620 *isError = true; 00621 } 00622 } 00623 else{ 00624 // Non zero => no error. 00625 if (isError != NULL){ *isError = false; } 00626 retVal = acos(qw/n); 00627 } 00628 } 00629 ML_CATCH_RETHROW; 00630 return retVal; 00631 } 00632 00637 inline TQuaternion<DT> sgn(bool *isError=NULL) const 00638 { 00639 ML_TRACE_IN("TQuaternion::sgn()"); 00640 00641 // Initialize return value with default quaternion. 00642 TQuaternion<DT> retVal(0,0,0,1); 00643 ML_TRY 00644 { 00645 const DT absVal = absoluteValue(); 00646 if (isError != NULL){ 00647 // Set error return value. 00648 if (absVal==0){ 00649 *isError = true; 00650 } 00651 else{ 00652 // No error. 00653 *isError = false; 00654 retVal = *this / absVal; 00655 } 00656 } 00657 else{ 00658 // Post error is absVal == 0. 00659 ML_CHECK_FLOAT(absVal); 00660 retVal = *this / absVal; 00661 } 00662 } 00663 ML_CATCH_RETHROW; 00664 return retVal; 00665 } 00666 00672 inline TQuaternion<DT> inverse(bool* isInvertible=NULL) const 00673 { 00674 ML_TRACE_IN("TQuaternion::inverse()"); 00675 00676 // Initialize return value with default quaternion. 00677 TQuaternion<DT> retVal(0,0,0,1); 00678 ML_TRY 00679 { 00680 const DT n=norm(); 00681 if (MLValueIs0WOM(n)) { 00682 if (isInvertible==NULL){ 00683 ML_PRINT_ERROR("TQuaternion::() const, quaternion is not invertable", 00684 ML_BAD_PARAMETER, 00685 "Returning default quaternion"); 00686 } 00687 else{ 00688 *isInvertible = false; 00689 } 00690 retVal = TQuaternion<DT>(); 00691 } 00692 else{ 00693 if (isInvertible != NULL){ *isInvertible = true; } 00694 retVal = conjugate().mult(1/n); 00695 } 00696 } 00697 ML_CATCH_RETHROW; 00698 return retVal; 00699 } 00700 00706 // return TQuaternion(::sqrt(norm2())*::sin(0.5*acos(qw/norm2()))*(1/qv().length())*Tvec3<DT>(qx,qy,qz), 00707 inline TQuaternion<DT> sqrt(bool *isError=NULL) const 00708 { 00709 ML_TRACE_IN("TQuaternion::sqrt() const"); 00710 00711 // Initialize return value with default quaternion. 00712 TQuaternion<DT> retVal(0,0,0,1); 00713 ML_TRY 00714 { 00715 // Precalculate constants and check for 0 division. 00716 const DT n2 = norm2(); 00717 const DT lqv = qv().length(); 00718 if (MLValueIs0WOM(n2) || MLValueIs0WOM(lqv)){ 00719 // Error! Check whether we have a pointer to a return error code value. 00720 if (isError == NULL){ 00721 // No, post an error. 00722 ML_PRINT_ERROR("TQuaternion::sqrt() const, sqrt of quaternion cannot be calculated", 00723 ML_BAD_PARAMETER, 00724 "Returning default quaternion"); 00725 } 00726 else{ 00727 // Yes, set return code. 00728 *isError = true; 00729 } 00730 } 00731 else{ 00732 // Calculate sqrt, lqv and n2 are non 0 here. 00733 const DT sqrtSin = ::sqrt(n2)*::sin(0.5*acos(qw/n2)); 00734 const DT sqrtSinF = sqrtSin*(1/lqv); 00735 retVal.set(sqrtSinF*qx, sqrtSinF*qy, sqrtSinF*qz, ::sqrt(n2) * ::cos(0.5*acos(qw/n2))); 00736 00737 // Non zero => no error. 00738 if (isError != NULL){ *isError = false; } 00739 } 00740 } 00741 ML_CATCH_RETHROW; 00742 return retVal; 00743 } 00744 00745 00750 00752 inline TQuaternion<DT> exp() const 00753 { 00754 ML_TRACE_IN("TQuaternion::exp() const"); 00755 00756 // Initialize return value with default quaternion. 00757 TQuaternion<DT> retVal(0,0,0,1); 00758 ML_TRY 00759 { 00760 const DT len = qv().length(); 00761 if (MLValueIs0WOM(len)){ 00762 retVal = TQuaternion<DT>(0,0,0,::cos(len)).mult(::exp(qw)); 00763 } 00764 else{ 00765 retVal = TQuaternion<DT>((qv()/len) * static_cast<DT>(::sin(len)), ::cos(len)).mult(::exp(qw)); 00766 } 00767 } 00768 ML_CATCH_RETHROW; 00769 return retVal; 00770 } 00771 00772 00774 inline TQuaternion<DT> ln() const 00775 { 00776 ML_TRACE_IN("TQuaternion::exp() const"); 00777 00778 // Initialize return value with default quaternion. 00779 TQuaternion<DT> retVal(0,0,0,1); 00780 ML_TRY 00781 { 00782 const DT n2 = norm2(); 00783 const DT qvLen = qv().length(); 00784 if (MLValueIs0WOM(qvLen)){ 00785 retVal.set(0, 0, 0, log10(n2)); 00786 } 00787 else{ 00788 // n2 is always non 0 if qvLen is non-zero, thus no check is necessary. 00789 retVal.set(qv()/qvLen * static_cast<DT>(acos(qw/n2)), log10(n2)); 00790 } 00791 } 00792 ML_CATCH_RETHROW; 00793 return retVal; 00794 } 00795 00796 00798 inline TQuaternion<DT> pow(const TQuaternion<DT> &quat) const {return ln().mult(quat).exp(); } 00799 00800 00805 00807 TQuaternion<DT> sin() const 00808 { 00809 ML_TRACE_IN("TQuaternion<DT>::sinh() const"); 00810 00811 TQuaternion<DT> retVal; 00812 ML_TRY 00813 { 00814 const Tvec3<DT> &v = qv(); 00815 const DT len = v.length(); 00816 // In case of len == 0 be sure not to divide by zero but setting vector to 0 vector. 00817 // Then the quaternion method behaves like the normal function on real values. 00818 retVal.set((!MLValueIs0WOM(len) ? 00819 static_cast<DT>(::cos(qw)) * v / len * static_cast<DT>(::sinh(len)) : 00820 Tvec3<DT>(0.0)), 00821 ::sin(qw)*::cosh(len) 00822 ); 00823 } 00824 ML_CATCH_RETHROW; 00825 return retVal; 00826 } 00827 00829 TQuaternion<DT> cos() const 00830 { 00831 ML_TRACE_IN("TQuaternion<DT>::sinh() const"); 00832 00833 TQuaternion<DT> retVal; 00834 ML_TRY 00835 { 00836 const Tvec3<DT> &v = qv(); 00837 const DT len = v.length(); 00838 // In case of len == 0 be sure not to divide by zero but setting vector to 0 vector. 00839 // Then the quaternion method behaves like the normal function on real values. 00840 retVal.set((!MLValueIs0WOM(len) ? 00841 static_cast<DT>(-1)*static_cast<DT>(::sin(qw))*qv()/len*static_cast<DT>(::sinh(len)) : 00842 Tvec3<DT>(0.0)), 00843 ::cos(qw)*::cosh(len) 00844 ); 00845 00846 } 00847 ML_CATCH_RETHROW; 00848 return retVal; 00849 } 00850 00852 inline TQuaternion<DT> tan(bool *isError=NULL) const { return sin().div(cos(), isError); } 00853 00855 inline TQuaternion<DT> cotan(bool *isError=NULL) const { return cos().div(sin(), isError); } 00856 00857 00858 00863 00865 TQuaternion<DT> sinh() const 00866 { 00867 ML_TRACE_IN("TQuaternion<DT>::sinh() const"); 00868 00869 TQuaternion<DT> retVal; 00870 ML_TRY 00871 { 00872 const Tvec3<DT> &v = qv(); 00873 const DT len = v.length(); 00874 // In case of len == 0 be sure not to divide by zero but setting vector to 0 vector. 00875 // Then the quaternion method behaves like the normal function on real values. 00876 retVal.set((!MLValueIs0WOM(len) ? 00877 static_cast<DT>(::cosh(qw))*v/len*static_cast<DT>(::sin(len)) : 00878 Tvec3<DT>(0.0)), 00879 ::sinh(qw)*::cos(len) 00880 ); 00881 } 00882 ML_CATCH_RETHROW; 00883 return retVal; 00884 } 00885 00887 TQuaternion<DT> cosh() const 00888 { 00889 ML_TRACE_IN("TQuaternion<DT>::cosh() const"); 00890 00891 TQuaternion<DT> retVal; 00892 ML_TRY 00893 { 00894 const Tvec3<DT> &v = qv(); 00895 const DT len = v.length(); 00896 // In case of len == 0 be sure not to divide by zero but setting vector to 0 vector. 00897 // Then the quaternion method behaves like the normal function on real values. 00898 retVal.set((!MLValueIs0WOM(len) ? 00899 static_cast<DT>(::sinh(qw))*v/len*static_cast<DT>(::sin(len)) : 00900 Tvec3<DT>(0.0)), 00901 ::cosh(qw)*::cos(len) 00902 ); 00903 } 00904 ML_CATCH_RETHROW; 00905 return retVal; 00906 } 00907 00909 inline TQuaternion<DT> tanh(bool *isError=NULL) const 00910 { 00911 ML_TRACE_IN("TQuaternion<DT>::tanh(bool *isError=NULL) const"); 00912 00913 TQuaternion<DT> retVal; 00914 ML_TRY 00915 { 00916 retVal = sinh().div(cosh(), isError); 00917 } 00918 ML_CATCH_RETHROW; 00919 return retVal; 00920 } 00921 00923 inline TQuaternion<DT> cotanh(bool *isError=NULL) const 00924 { 00925 ML_TRACE_IN("TQuaternion<DT>::cotanh(bool *isError=NULL) const"); 00926 00927 TQuaternion<DT> retVal; 00928 ML_TRY 00929 { 00930 retVal = cosh().div(sinh(), isError); 00931 } 00932 ML_CATCH_RETHROW; 00933 return retVal; 00934 } 00935 00936 00937 00942 00944 inline TQuaternion<DT> arcsinh() const { return add(mult(*this).add(TQuaternion<DT>( 1)).sqrt()).ln(); } 00945 00947 inline TQuaternion<DT> arccosh() const { return add(mult(*this).add(TQuaternion<DT>(-1)).sqrt()).ln(); } 00948 00950 inline TQuaternion<DT> arctanh() const { return TQuaternion<DT>((TQuaternion<DT>(qx,qy,qz,qw+1).ln()-TQuaternion<DT>(-qx, -qy, -qz, 1-qw).ln())/0.5); } 00951 00952 00962 #define _ML_QUATERNION_CALC_CHECKED(FUNC_NAME, CALC_EXPR) \ 00963 ML_TRACE_IN("TQuaternion<DT>::" FUNC_NAME "() const"); \ 00964 \ 00965 TQuaternion<DT> retVal; \ 00966 ML_TRY \ 00967 { \ 00968 const Tvec3<DT> &v = qv(); \ 00969 const DT len = v.length(); \ 00970 if (MLValueIs0WOM(len)){ \ 00971 /* Error! Check whether we have a pointer to a return error code value. */ \ 00972 if (isError == NULL){ \ 00973 /* No, post an error. */ \ 00974 ML_PRINT_ERROR("TQuaternion::" FUNC_NAME "() const, " FUNC_NAME \ 00975 " of quaternion cannot be calculated", \ 00976 ML_BAD_PARAMETER, \ 00977 "Returning default quaternion"); \ 00978 } \ 00979 else{ \ 00980 /* Yes, set return code, retVal is left on default. */ \ 00981 *isError = true; \ 00982 } \ 00983 } \ 00984 else{ \ 00985 /* Define return values. */ \ 00986 if (isError != NULL){ *isError = false; } \ 00987 retVal = CALC_EXPR; \ 00988 } \ 00989 } \ 00990 ML_CATCH_RETHROW; \ 00991 return retVal; \ 00992 00993 00994 00996 #define _ML_QUAT_CALC_EXP TQuaternion<DT>(-v/len,0).mult(mult(TQuaternion<DT>(-v/len,0)).arcsinh()); 00997 00998 00999 01000 01001 01003 TQuaternion<DT> arcsin(bool *isError=NULL) const 01004 { 01005 _ML_QUATERNION_CALC_CHECKED("arcsin", _ML_QUAT_CALC_EXP); 01006 } 01007 #undef _ML_QUAT_CALC_EXP 01008 01009 01010 01012 #define _ML_QUAT_CALC_EXP TQuaternion<DT>(-v/len,0).mult(arccosh()); 01013 01014 TQuaternion<DT> arccos(bool *isError=NULL) const 01015 { 01016 _ML_QUATERNION_CALC_CHECKED("arccos", _ML_QUAT_CALC_EXP); 01017 } 01018 #undef _ML_QUAT_CALC_EXP 01019 01020 01021 01023 #define _ML_QUAT_CALC_EXP TQuaternion<DT>(-v/len,0).mult(mult(TQuaternion<DT>(-v/len,0)).arctanh()); 01024 01025 TQuaternion<DT> arctan(bool *isError=NULL) const 01026 { 01027 _ML_QUATERNION_CALC_CHECKED("arctan", _ML_QUAT_CALC_EXP); 01028 } 01029 #undef _ML_QUAT_CALC_EXP 01030 01031 01032 // Undefine _ML_QUATERNION_CALC_CHECKED, it is not needed any more. 01033 #undef _ML_QUATERNION_CALC_CHECKED 01034 }; 01035 01036 01037 //----------------------------------------------------------------------------------- 01039 01040 //----------------------------------------------------------------------------------- 01042 typedef TQuaternion<MLfloat> Quaternionf; 01043 01045 typedef TQuaternion<MLdouble> Quaterniond; 01046 01048 typedef TQuaternion<MLldouble> Quaternionld; 01049 01051 typedef TQuaternion<MLdouble> Quaternion; 01053 01054 01055 ML_LA_END_NAMESPACE 01056 01057 01058 01059 01060 //------------------------------------------------------------------------- 01062 01063 01064 01065 01066 01067 //------------------------------------------------------------------------- 01068 #ifdef _ML_IMPLEMENT_GLOBAL_QUATERNION_OPERATORS 01069 #ifndef _ML_IMPLEMENT_GLOBAL_QUATERNION_FUNCS_AND_OPS_IN_GLOBAL_NAMESPACE 01070 ML_LA_START_NAMESPACE 01071 #endif 01072 01073 //----------------------------- 01074 // Addition 01075 //----------------------------- 01077 template <typename DT> 01078 inline ML_LA_NAMESPACE::TQuaternion<DT> operator+(DT d, const ML_LA_NAMESPACE::TQuaternion<DT> &q){ 01079 return ML_LA_NAMESPACE::TQuaternion<DT>(q.qx, q.qy, q.qz, q.qw+d); 01080 } 01081 01083 template <typename DT> 01084 inline ML_LA_NAMESPACE::TQuaternion<DT> operator+(const ML_LA_NAMESPACE::TQuaternion<DT> &q, DT d){ 01085 return ML_LA_NAMESPACE::TQuaternion<DT>(q.qx, q.qy, q.qz, q.qw+d); 01086 } 01087 01089 template <typename DT> 01090 inline ML_LA_NAMESPACE::TQuaternion<DT> operator+(const ML_LA_NAMESPACE::TQuaternion<DT> &qa, 01091 const ML_LA_NAMESPACE::TQuaternion<DT> &qb){ 01092 return qa.operator+(qb); 01093 } 01094 01095 01096 01097 //----------------------------- 01098 // Subtraction 01099 //----------------------------- 01101 template <typename DT> 01102 inline ML_LA_NAMESPACE::TQuaternion<DT> operator-(DT d, const ML_LA_NAMESPACE::TQuaternion<DT> &q){ 01103 return ML_LA_NAMESPACE::TQuaternion<DT>(-q.qx, -q.qy, -q.qz, d-q.qw); 01104 } 01105 01107 template <typename DT> 01108 inline ML_LA_NAMESPACE::TQuaternion<DT> operator-(const ML_LA_NAMESPACE::TQuaternion<DT> &q, DT d){ 01109 return ML_LA_NAMESPACE::TQuaternion<DT>(q.qx, q.qy, q.qz, q.qw-d); 01110 } 01111 01113 template <typename DT> 01114 inline ML_LA_NAMESPACE::TQuaternion<DT> operator-(const ML_LA_NAMESPACE::TQuaternion<DT> &qa, 01115 const ML_LA_NAMESPACE::TQuaternion<DT> &qb){ 01116 return qa.operator-(qb); 01117 } 01118 01119 01121 template <typename DT> 01122 inline ML_LA_NAMESPACE::TQuaternion<DT> operator*(DT d, const ML_LA_NAMESPACE::TQuaternion<DT> &q){ 01123 return q.mult(d); 01124 } 01125 01127 template <typename DT> 01128 inline ML_LA_NAMESPACE::TQuaternion<DT> operator*(const ML_LA_NAMESPACE::TQuaternion<DT> &q, DT d){ 01129 return q.mult(d); 01130 } 01131 01133 template <typename DT> 01134 inline ML_LA_NAMESPACE::TQuaternion<DT> operator*(const ML_LA_NAMESPACE::TQuaternion<DT> &qa, 01135 const ML_LA_NAMESPACE::TQuaternion<DT> &qb){ 01136 return qa.operator*(qb); 01137 } 01139 01140 #ifndef _ML_IMPLEMENT_GLOBAL_QUATERNION_FUNCS_AND_OPS_IN_GLOBAL_NAMESPACE 01141 ML_LA_END_NAMESPACE 01142 #endif 01143 01144 #endif // _ML_IMPLEMENT_GLOBAL_QUATERNION_OPERATORS 01145 01146 01147 01148 //------------------------------------------------------------------------- 01150 01151 01152 01153 01154 01155 //------------------------------------------------------------------------- 01156 #ifdef _ML_IMPLEMENT_GLOBAL_QUATERNION_FUNCTIONS 01157 #ifndef _ML_IMPLEMENT_GLOBAL_QUATERNION_FUNCS_AND_OPS_IN_GLOBAL_NAMESPACE 01158 ML_LA_START_NAMESPACE 01159 #endif 01160 01163 #ifdef _ML_IMPLEMENT_QUATERNION_SQRT 01164 template <typename DT> 01165 inline ML_LA_NAMESPACE::TQuaternion<DT> sqrt (const ML_LA_NAMESPACE::TQuaternion<DT> &q) { return q.sqrt(); } 01166 #endif 01167 01169 template <typename DT> 01170 inline ML_LA_NAMESPACE::TQuaternion<DT> exp (const ML_LA_NAMESPACE::TQuaternion<DT> &q) { return q.exp(); } 01171 01173 template <typename DT> 01174 inline ML_LA_NAMESPACE::TQuaternion<DT> ln (const ML_LA_NAMESPACE::TQuaternion<DT> &q) { return q.ln(); } 01175 01177 template <typename DT> 01178 inline ML_LA_NAMESPACE::TQuaternion<DT> sin (const ML_LA_NAMESPACE::TQuaternion<DT> &q) { return q.sin(); } 01179 01181 template <typename DT> 01182 inline ML_LA_NAMESPACE::TQuaternion<DT> cos (const ML_LA_NAMESPACE::TQuaternion<DT> &q) { return q.cos(); } 01183 01185 template <typename DT> 01186 inline ML_LA_NAMESPACE::TQuaternion<DT> tan (const ML_LA_NAMESPACE::TQuaternion<DT> &q) { return q.tan(); } 01187 01189 template <typename DT> 01190 inline ML_LA_NAMESPACE::TQuaternion<DT> cotan (const ML_LA_NAMESPACE::TQuaternion<DT> &q) { return q.cotan(); } 01191 01193 template <typename DT> 01194 inline ML_LA_NAMESPACE::TQuaternion<DT> sinh (const ML_LA_NAMESPACE::TQuaternion<DT> &q) { return q.sinh(); } 01195 01197 template <typename DT> 01198 inline ML_LA_NAMESPACE::TQuaternion<DT> cosh (const ML_LA_NAMESPACE::TQuaternion<DT> &q) { return q.cosh(); } 01199 01201 template <typename DT> 01202 inline ML_LA_NAMESPACE::TQuaternion<DT> tanh (const ML_LA_NAMESPACE::TQuaternion<DT> &q) { return q.tanh(); } 01203 01205 template <typename DT> 01206 inline ML_LA_NAMESPACE::TQuaternion<DT> cotanh (const ML_LA_NAMESPACE::TQuaternion<DT> &q) { return q.cotanh(); } 01207 01209 template <typename DT> 01210 inline ML_LA_NAMESPACE::TQuaternion<DT> arcsinh(const ML_LA_NAMESPACE::TQuaternion<DT> &q) { return q.arcsinh(); } 01211 01213 template <typename DT> 01214 inline ML_LA_NAMESPACE::TQuaternion<DT> arccosh(const ML_LA_NAMESPACE::TQuaternion<DT> &q) { return q.arccosh(); } 01215 01217 template <typename DT> 01218 inline ML_LA_NAMESPACE::TQuaternion<DT> arctanh(const ML_LA_NAMESPACE::TQuaternion<DT> &q) { return q.arctanh(); } 01219 01221 template <typename DT> 01222 inline ML_LA_NAMESPACE::TQuaternion<DT> arcsin (const ML_LA_NAMESPACE::TQuaternion<DT> &q) { return q.arcsin(); } 01223 01225 template <typename DT> 01226 inline ML_LA_NAMESPACE::TQuaternion<DT> arccos (const ML_LA_NAMESPACE::TQuaternion<DT> &q) { return q.arccos(); } 01227 01229 template <typename DT> 01230 inline ML_LA_NAMESPACE::TQuaternion<DT> arctan (const ML_LA_NAMESPACE::TQuaternion<DT> &q) { return q.arctan(); } 01231 01232 01233 #ifndef _ML_IMPLEMENT_GLOBAL_QUATERNION_FUNCS_AND_OPS_IN_GLOBAL_NAMESPACE 01234 ML_LA_END_NAMESPACE 01235 #endif 01236 01237 #endif // _ML_IMPLEMENT_GLOBAL_QUATERNION_FUNCTIONS 01238 01239 01240 01241 //----------------------------------------------------------------------------------- 01242 // Stream output for std::ostream and dyadic multiplication of TQuaternion and scalar. 01243 //----------------------------------------------------------------------------------- 01244 namespace std { 01245 01247 template <typename DT> 01248 inline ostream& operator<<(ostream& s, const ML_NAMESPACE::TQuaternion<DT> &v){ 01249 return s << "(" << v.qx << "," << v.qy << "," << v.qz << "," << v.qw << ")"; 01250 }; 01251 01252 } 01253 01254 01255 #endif // __mlQuaternion_H