00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <cmath>
00023 #include <limits>
00024
00025
00026 #include "Math/Math.h"
00027
00028 #include "Math/GenVector/3DConversions.h"
00029
00030 #include "Math/GenVector/Rotation3D.h"
00031 #include "Math/GenVector/AxisAngle.h"
00032 #include "Math/GenVector/EulerAngles.h"
00033 #include "Math/GenVector/Quaternion.h"
00034 #include "Math/GenVector/RotationZYX.h"
00035 #include "Math/GenVector/RotationX.h"
00036 #include "Math/GenVector/RotationY.h"
00037 #include "Math/GenVector/RotationZ.h"
00038
00039
00040 namespace ROOT {
00041 namespace Math {
00042 namespace gv_detail {
00043
00044 enum ERotation3DMatrixIndex
00045 { kXX = Rotation3D::kXX, kXY = Rotation3D::kXY, kXZ = Rotation3D::kXZ
00046 , kYX = Rotation3D::kYX, kYY = Rotation3D::kYY, kYZ = Rotation3D::kYZ
00047 , kZX = Rotation3D::kZX, kZY = Rotation3D::kZY, kZZ = Rotation3D::kZZ
00048 };
00049
00050
00051
00052 void convert( Rotation3D const & from, AxisAngle & to)
00053 {
00054
00055 double m[9];
00056 from.GetComponents(m, m+9);
00057
00058 const double uZ = m[kYX] - m[kXY];
00059 const double uY = m[kXZ] - m[kZX];
00060 const double uX = m[kZY] - m[kYZ];
00061
00062
00063
00064
00065 if ( std::fabs( uX ) < 8.*std::numeric_limits<double>::epsilon() &&
00066 std::fabs( uY ) < 8.*std::numeric_limits<double>::epsilon() &&
00067 std::fabs( uZ ) < 8.*std::numeric_limits<double>::epsilon() ) {
00068 Quaternion tmp;
00069 convert (from,tmp);
00070 convert (tmp,to);
00071 return;
00072 }
00073
00074 AxisAngle::AxisVector u;
00075
00076 u.SetCoordinates( uX, uY, uZ );
00077
00078 static const double pi = M_PI;
00079
00080 double angle;
00081 const double cosdelta = (m[kXX] + m[kYY] + m[kZZ] - 1.0) / 2.0;
00082 if (cosdelta > 1.0) {
00083 angle = 0;
00084 } else if (cosdelta < -1.0) {
00085 angle = pi;
00086 } else {
00087 angle = std::acos( cosdelta );
00088 }
00089
00090
00091
00092 to.SetComponents(u, angle);
00093 to.Rectify();
00094
00095 }
00096
00097 static void correctByPi ( double& psi, double& phi ) {
00098 static const double pi = M_PI;
00099 if (psi > 0) {
00100 psi -= pi;
00101 } else {
00102 psi += pi;
00103 }
00104 if (phi > 0) {
00105 phi -= pi;
00106 } else {
00107 phi += pi;
00108 }
00109 }
00110
00111 void convert( Rotation3D const & from, EulerAngles & to)
00112 {
00113
00114
00115
00116
00117 double r[9];
00118 from.GetComponents(r,r+9);
00119
00120 double phi, theta, psi;
00121 double psiPlusPhi, psiMinusPhi;
00122 static const double pi = M_PI;
00123 static const double pi_2 = M_PI_2;
00124
00125 theta = (std::fabs(r[kZZ]) <= 1.0) ? std::acos(r[kZZ]) :
00126 (r[kZZ] > 0.0) ? 0 : pi;
00127
00128 double cosTheta = r[kZZ];
00129 if (cosTheta > 1) cosTheta = 1;
00130 if (cosTheta < -1) cosTheta = -1;
00131
00132
00133
00134
00135
00136 if (cosTheta == 1) {
00137 psiPlusPhi = atan2 ( r[kXY] - r[kYX], r[kXX] + r[kYY] );
00138 psiMinusPhi = 0;
00139 } else if (cosTheta >= 0) {
00140 psiPlusPhi = atan2 ( r[kXY] - r[kYX], r[kXX] + r[kYY] );
00141 double s = -r[kXY] - r[kYX];
00142 double c = r[kXX] - r[kYY];
00143 psiMinusPhi = atan2 ( s, c );
00144 } else if (cosTheta > -1) {
00145 psiMinusPhi = atan2 ( -r[kXY] - r[kYX], r[kXX] - r[kYY] );
00146 double s = r[kXY] - r[kYX];
00147 double c = r[kXX] + r[kYY];
00148 psiPlusPhi = atan2 ( s, c );
00149 } else {
00150 psiMinusPhi = atan2 ( -r[kXY] - r[kYX], r[kXX] - r[kYY] );
00151 psiPlusPhi = 0;
00152 }
00153
00154 psi = .5 * (psiPlusPhi + psiMinusPhi);
00155 phi = .5 * (psiPlusPhi - psiMinusPhi);
00156
00157
00158
00159
00160
00161
00162 double w[4];
00163 w[0] = r[kXZ]; w[1] = r[kZX]; w[2] = r[kYZ]; w[3] = -r[kZY];
00164
00165
00166 double maxw = std::fabs(w[0]);
00167 int imax = 0;
00168 for (int i = 1; i < 4; ++i) {
00169 if (std::fabs(w[i]) > maxw) {
00170 maxw = std::fabs(w[i]);
00171 imax = i;
00172 }
00173 }
00174
00175
00176 switch (imax) {
00177 case 0:
00178 if (w[0] > 0 && psi < 0) correctByPi ( psi, phi );
00179 if (w[0] < 0 && psi > 0) correctByPi ( psi, phi );
00180 break;
00181 case 1:
00182 if (w[1] > 0 && phi < 0) correctByPi ( psi, phi );
00183 if (w[1] < 0 && phi > 0) correctByPi ( psi, phi );
00184 break;
00185 case 2:
00186 if (w[2] > 0 && std::fabs(psi) > pi_2) correctByPi ( psi, phi );
00187 if (w[2] < 0 && std::fabs(psi) < pi_2) correctByPi ( psi, phi );
00188 break;
00189 case 3:
00190 if (w[3] > 0 && std::fabs(phi) > pi_2) correctByPi ( psi, phi );
00191 if (w[3] < 0 && std::fabs(phi) < pi_2) correctByPi ( psi, phi );
00192 break;
00193 }
00194
00195 to.SetComponents( phi, theta, psi );
00196
00197 }
00198
00199
00200 void convert( Rotation3D const & from, Quaternion & to)
00201 {
00202
00203
00204 double m[9];
00205 from.GetComponents(m, m+9);
00206
00207 const double d0 = m[kXX] + m[kYY] + m[kZZ];
00208 const double d1 = + m[kXX] - m[kYY] - m[kZZ];
00209 const double d2 = - m[kXX] + m[kYY] - m[kZZ];
00210 const double d3 = - m[kXX] - m[kYY] + m[kZZ];
00211
00212
00213
00214
00215 if ( d0 >= d1 && d0 >= d2 && d0 >= d3 ) {
00216 const double q0 = .5*std::sqrt(1+d0);
00217 const double f = .25/q0;
00218 const double q1 = f*(m[kZY]-m[kYZ]);
00219 const double q2 = f*(m[kXZ]-m[kZX]);
00220 const double q3 = f*(m[kYX]-m[kXY]);
00221 to.SetComponents(q0,q1,q2,q3);
00222 to.Rectify();
00223 return;
00224 } else if ( d1 >= d2 && d1 >= d3 ) {
00225 const double q1 = .5*std::sqrt(1+d1);
00226 const double f = .25/q1;
00227 const double q0 = f*(m[kZY]-m[kYZ]);
00228 const double q2 = f*(m[kXY]+m[kYX]);
00229 const double q3 = f*(m[kXZ]+m[kZX]);
00230 to.SetComponents(q0,q1,q2,q3);
00231 to.Rectify();
00232 return;
00233 } else if ( d2 >= d3 ) {
00234 const double q2 = .5*std::sqrt(1+d2);
00235 const double f = .25/q2;
00236 const double q0 = f*(m[kXZ]-m[kZX]);
00237 const double q1 = f*(m[kXY]+m[kYX]);
00238 const double q3 = f*(m[kYZ]+m[kZY]);
00239 to.SetComponents(q0,q1,q2,q3);
00240 to.Rectify();
00241 return;
00242 } else {
00243 const double q3 = .5*std::sqrt(1+d3);
00244 const double f = .25/q3;
00245 const double q0 = f*(m[kYX]-m[kXY]);
00246 const double q1 = f*(m[kXZ]+m[kZX]);
00247 const double q2 = f*(m[kYZ]+m[kZY]);
00248 to.SetComponents(q0,q1,q2,q3);
00249 to.Rectify();
00250 return;
00251 }
00252 }
00253
00254
00255 void convert( Rotation3D const & from, RotationZYX & to)
00256 {
00257
00258
00259
00260
00261
00262
00263
00264
00265 static const double pi_2 = M_PI_2;
00266
00267 double r[9];
00268 from.GetComponents(r,r+9);
00269
00270 double phi,theta,psi = 0;
00271
00272
00273 double sinTheta = r[kXZ];
00274 if ( sinTheta < -1.0) sinTheta = -1.0;
00275 if ( sinTheta > 1.0) sinTheta = 1.0;
00276 theta = std::asin( sinTheta );
00277
00278
00279
00280
00281
00282
00283
00284
00285 double psiPlusPhi = 0;
00286 double psiMinusPhi = 0;
00287
00288
00289 if (sinTheta > - 1.0)
00290 psiPlusPhi = atan2 ( r[kYX] + r[kZY], r[kYY] - r[kZX] );
00291
00292
00293 if (sinTheta < 1.0)
00294 psiMinusPhi = atan2 ( r[kZY] - r[kYX] , r[kYY] + r[kZX] );
00295
00296 psi = .5 * (psiPlusPhi + psiMinusPhi);
00297 phi = .5 * (psiPlusPhi - psiMinusPhi);
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314 double w[4];
00315 w[0] = -r[kYZ]; w[1] = -r[kXY]; w[2] = r[kZZ]; w[3] = r[kXX];
00316
00317
00318 double maxw = std::fabs(w[0]);
00319 int imax = 0;
00320 for (int i = 1; i < 4; ++i) {
00321 if (std::fabs(w[i]) > maxw) {
00322 maxw = std::fabs(w[i]);
00323 imax = i;
00324 }
00325 }
00326
00327
00328
00329 switch (imax) {
00330 case 0:
00331 if (w[0] > 0 && psi < 0) correctByPi ( psi, phi );
00332 if (w[0] < 0 && psi > 0) correctByPi ( psi, phi );
00333 break;
00334 case 1:
00335 if (w[1] > 0 && phi < 0) correctByPi ( psi, phi );
00336 if (w[1] < 0 && phi > 0) correctByPi ( psi, phi );
00337 break;
00338 case 2:
00339 if (w[2] > 0 && std::fabs(psi) > pi_2) correctByPi ( psi, phi );
00340 if (w[2] < 0 && std::fabs(psi) < pi_2) correctByPi ( psi, phi );
00341 break;
00342 case 3:
00343 if (w[3] > 0 && std::fabs(phi) > pi_2) correctByPi ( psi, phi );
00344 if (w[3] < 0 && std::fabs(phi) < pi_2) correctByPi ( psi, phi );
00345 break;
00346 }
00347
00348 to.SetComponents(phi, theta, psi);
00349
00350 }
00351
00352
00353
00354
00355 void convert( AxisAngle const & from, Rotation3D & to)
00356 {
00357
00358
00359 const double sinDelta = std::sin( from.Angle() );
00360 const double cosDelta = std::cos( from.Angle() );
00361 const double oneMinusCosDelta = 1.0 - cosDelta;
00362
00363 const AxisAngle::AxisVector & u = from.Axis();
00364 const double uX = u.X();
00365 const double uY = u.Y();
00366 const double uZ = u.Z();
00367
00368 double m[9];
00369
00370 m[kXX] = oneMinusCosDelta * uX * uX + cosDelta;
00371 m[kXY] = oneMinusCosDelta * uX * uY - sinDelta * uZ;
00372 m[kXZ] = oneMinusCosDelta * uX * uZ + sinDelta * uY;
00373
00374 m[kYX] = oneMinusCosDelta * uY * uX + sinDelta * uZ;
00375 m[kYY] = oneMinusCosDelta * uY * uY + cosDelta;
00376 m[kYZ] = oneMinusCosDelta * uY * uZ - sinDelta * uX;
00377
00378 m[kZX] = oneMinusCosDelta * uZ * uX - sinDelta * uY;
00379 m[kZY] = oneMinusCosDelta * uZ * uY + sinDelta * uX;
00380 m[kZZ] = oneMinusCosDelta * uZ * uZ + cosDelta;
00381
00382 to.SetComponents(m,m+9);
00383 }
00384
00385 void convert( AxisAngle const & from , EulerAngles & to )
00386 {
00387
00388
00389
00390 Rotation3D tmp;
00391 convert(from,tmp);
00392 convert(tmp,to);
00393 }
00394
00395 void convert( AxisAngle const & from, Quaternion & to)
00396 {
00397
00398
00399 double s = std::sin (from.Angle()/2);
00400 DisplacementVector3D< Cartesian3D<double> > axis = from.Axis();
00401
00402 to.SetComponents( std::cos(from.Angle()/2),
00403 s*axis.X(),
00404 s*axis.Y(),
00405 s*axis.Z()
00406 );
00407 }
00408
00409 void convert( AxisAngle const & from , RotationZYX & to )
00410 {
00411
00412
00413 Rotation3D tmp;
00414 convert(from,tmp);
00415 convert(tmp,to);
00416 }
00417
00418
00419
00420
00421
00422 void convert( EulerAngles const & from, Rotation3D & to)
00423 {
00424
00425
00426 typedef double Scalar;
00427 const Scalar sPhi = std::sin( from.Phi() );
00428 const Scalar cPhi = std::cos( from.Phi() );
00429 const Scalar sTheta = std::sin( from.Theta() );
00430 const Scalar cTheta = std::cos( from.Theta() );
00431 const Scalar sPsi = std::sin( from.Psi() );
00432 const Scalar cPsi = std::cos( from.Psi() );
00433 to.SetComponents
00434 ( cPsi*cPhi-sPsi*cTheta*sPhi, cPsi*sPhi+sPsi*cTheta*cPhi, sPsi*sTheta
00435 , -sPsi*cPhi-cPsi*cTheta*sPhi, -sPsi*sPhi+cPsi*cTheta*cPhi, cPsi*sTheta
00436 , sTheta*sPhi, -sTheta*cPhi, cTheta
00437 );
00438 }
00439
00440 void convert( EulerAngles const & from, AxisAngle & to)
00441 {
00442
00443
00444 Quaternion q;
00445 convert (from, q);
00446 convert (q, to);
00447 }
00448
00449 void convert( EulerAngles const & from, Quaternion & to)
00450 {
00451
00452
00453 typedef double Scalar;
00454 const Scalar plus = (from.Phi()+from.Psi())/2;
00455 const Scalar minus = (from.Phi()-from.Psi())/2;
00456 const Scalar sPlus = std::sin( plus );
00457 const Scalar cPlus = std::cos( plus );
00458 const Scalar sMinus = std::sin( minus );
00459 const Scalar cMinus = std::cos( minus );
00460 const Scalar sTheta = std::sin( from.Theta()/2 );
00461 const Scalar cTheta = std::cos( from.Theta()/2 );
00462
00463 to.SetComponents ( cTheta*cPlus, -sTheta*cMinus, -sTheta*sMinus, -cTheta*sPlus );
00464
00465 }
00466
00467 void convert( EulerAngles const & from , RotationZYX & to )
00468 {
00469
00470
00471 Rotation3D tmp;
00472 convert(from,tmp);
00473 convert(tmp,to);
00474 }
00475
00476
00477
00478
00479
00480 void convert( Quaternion const & from, Rotation3D & to)
00481 {
00482
00483
00484 const double q0 = from.U();
00485 const double q1 = from.I();
00486 const double q2 = from.J();
00487 const double q3 = from.K();
00488 const double q00 = q0*q0;
00489 const double q01 = q0*q1;
00490 const double q02 = q0*q2;
00491 const double q03 = q0*q3;
00492 const double q11 = q1*q1;
00493 const double q12 = q1*q2;
00494 const double q13 = q1*q3;
00495 const double q22 = q2*q2;
00496 const double q23 = q2*q3;
00497 const double q33 = q3*q3;
00498
00499 to.SetComponents (
00500 q00+q11-q22-q33 , 2*(q12-q03) , 2*(q02+q13),
00501 2*(q12+q03) , q00-q11+q22-q33 , 2*(q23-q01),
00502 2*(q13-q02) , 2*(q23+q01) , q00-q11-q22+q33 );
00503
00504 }
00505
00506 void convert( Quaternion const & from, AxisAngle & to)
00507 {
00508
00509
00510 double u = from.U();
00511 if ( u >= 0 ) {
00512 if ( u > 1 ) u = 1;
00513 const double angle = 2.0 * std::acos ( from.U() );
00514 DisplacementVector3D< Cartesian3D<double> >
00515 axis (from.I(), from.J(), from.K());
00516 to.SetComponents ( axis, angle );
00517 } else {
00518 if ( u < -1 ) u = -1;
00519 const double angle = 2.0 * std::acos ( -from.U() );
00520 DisplacementVector3D< Cartesian3D<double> >
00521 axis (-from.I(), -from.J(), -from.K());
00522 to.SetComponents ( axis, angle );
00523 }
00524 }
00525
00526 void convert( Quaternion const & from, EulerAngles & to )
00527 {
00528
00529
00530
00531
00532 Rotation3D tmp;
00533 convert(from,tmp);
00534 convert(tmp,to);
00535 }
00536
00537 void convert( Quaternion const & from , RotationZYX & to )
00538 {
00539
00540
00541 Rotation3D tmp;
00542 convert(from,tmp);
00543 convert(tmp,to);
00544 }
00545
00546
00547
00548 void convert( RotationZYX const & from, Rotation3D & to) {
00549
00550
00551 double phi,theta,psi = 0;
00552 from.GetComponents(phi,theta,psi);
00553 to.SetComponents( std::cos(theta)*std::cos(phi),
00554 - std::cos(theta)*std::sin(phi),
00555 std::sin(theta),
00556
00557 std::cos(psi)*std::sin(phi) + std::sin(psi)*std::sin(theta)*std::cos(phi),
00558 std::cos(psi)*std::cos(phi) - std::sin(psi)*std::sin(theta)*std::sin(phi),
00559 -std::sin(psi)*std::cos(theta),
00560
00561 std::sin(psi)*std::sin(phi) - std::cos(psi)*std::sin(theta)*std::cos(phi),
00562 std::sin(psi)*std::cos(phi) + std::cos(psi)*std::sin(theta)*std::sin(phi),
00563 std::cos(psi)*std::cos(theta)
00564 );
00565
00566 }
00567 void convert( RotationZYX const & from, AxisAngle & to) {
00568
00569
00570 Rotation3D tmp;
00571 convert(from,tmp);
00572 convert(tmp,to);
00573 }
00574 void convert( RotationZYX const & from, EulerAngles & to) {
00575
00576
00577 Rotation3D tmp;
00578 convert(from,tmp);
00579 convert(tmp,to);
00580 }
00581 void convert( RotationZYX const & from, Quaternion & to) {
00582 double phi,theta,psi = 0;
00583 from.GetComponents(phi,theta,psi);
00584
00585 double sphi2 = std::sin(phi/2);
00586 double cphi2 = std::cos(phi/2);
00587 double stheta2 = std::sin(theta/2);
00588 double ctheta2 = std::cos(theta/2);
00589 double spsi2 = std::sin(psi/2);
00590 double cpsi2 = std::cos(psi/2);
00591 to.SetComponents( cphi2 * cpsi2 * ctheta2 - sphi2 * spsi2 * stheta2,
00592 sphi2 * cpsi2 * stheta2 + cphi2 * spsi2 * ctheta2,
00593 cphi2 * cpsi2 * stheta2 - sphi2 * spsi2 * ctheta2,
00594 sphi2 * cpsi2 * ctheta2 + cphi2 * spsi2 * stheta2
00595 );
00596 }
00597
00598
00599
00600
00601
00602 void convert( RotationX const & from, Rotation3D & to)
00603 {
00604
00605
00606 const double c = from.CosAngle();
00607 const double s = from.SinAngle();
00608 to.SetComponents ( 1, 0, 0,
00609 0, c, -s,
00610 0, s, c );
00611 }
00612
00613 void convert( RotationX const & from, AxisAngle & to)
00614 {
00615
00616
00617 DisplacementVector3D< Cartesian3D<double> > axis (1, 0, 0);
00618 to.SetComponents ( axis, from.Angle() );
00619 }
00620
00621 void convert( RotationX const & from , EulerAngles & to )
00622 {
00623
00624
00625
00626 Rotation3D tmp;
00627 convert(from,tmp);
00628 convert(tmp,to);
00629 }
00630
00631 void convert( RotationX const & from, Quaternion & to)
00632 {
00633
00634
00635 to.SetComponents (std::cos(from.Angle()/2), std::sin(from.Angle()/2), 0, 0);
00636 }
00637
00638 void convert( RotationX const & from , RotationZYX & to )
00639 {
00640
00641 to.SetComponents(0,0,from.Angle());
00642 }
00643
00644
00645
00646
00647
00648 void convert( RotationY const & from, Rotation3D & to)
00649 {
00650
00651
00652 const double c = from.CosAngle();
00653 const double s = from.SinAngle();
00654 to.SetComponents ( c, 0, s,
00655 0, 1, 0,
00656 -s, 0, c );
00657 }
00658
00659 void convert( RotationY const & from, AxisAngle & to)
00660 {
00661
00662
00663 DisplacementVector3D< Cartesian3D<double> > axis (0, 1, 0);
00664 to.SetComponents ( axis, from.Angle() );
00665 }
00666
00667 void convert( RotationY const & from, EulerAngles & to )
00668 {
00669
00670
00671
00672 Rotation3D tmp;
00673 convert(from,tmp);
00674 convert(tmp,to);
00675 }
00676
00677 void convert( RotationY const & from , RotationZYX & to )
00678 {
00679
00680 to.SetComponents(0,from.Angle(),0);
00681 }
00682
00683
00684 void convert( RotationY const & from, Quaternion & to)
00685 {
00686
00687
00688 to.SetComponents (std::cos(from.Angle()/2), 0, std::sin(from.Angle()/2), 0);
00689 }
00690
00691
00692
00693
00694
00695
00696 void convert( RotationZ const & from, Rotation3D & to)
00697 {
00698
00699
00700 const double c = from.CosAngle();
00701 const double s = from.SinAngle();
00702 to.SetComponents ( c, -s, 0,
00703 s, c, 0,
00704 0, 0, 1 );
00705 }
00706
00707 void convert( RotationZ const & from, AxisAngle & to)
00708 {
00709
00710
00711 DisplacementVector3D< Cartesian3D<double> > axis (0, 0, 1);
00712 to.SetComponents ( axis, from.Angle() );
00713 }
00714
00715 void convert( RotationZ const & from , EulerAngles & to )
00716 {
00717
00718
00719
00720 Rotation3D tmp;
00721 convert(from,tmp);
00722 convert(tmp,to);
00723 }
00724
00725 void convert( RotationZ const & from , RotationZYX & to )
00726 {
00727
00728 to.SetComponents(from.Angle(),0,0);
00729 }
00730
00731 void convert( RotationZ const & from, Quaternion & to)
00732 {
00733
00734
00735 to.SetComponents (std::cos(from.Angle()/2), 0, 0, std::sin(from.Angle()/2));
00736 }
00737
00738 }
00739 }
00740 }