00001
00002
00003
00004
00005
00006
00007
00008 #ifndef IMPALGEBRA_ROTATION_3D_H
00009 #define IMPALGEBRA_ROTATION_3D_H
00010
00011 #include "algebra_config.h"
00012 #include "Vector3D.h"
00013 #include "utility.h"
00014 #include <IMP/constants.h>
00015
00016 #include <IMP/log.h>
00017 #include <cmath>
00018 #include <iostream>
00019 #include <algorithm>
00020
00021 IMPALGEBRA_BEGIN_NAMESPACE
00022
00023 #if !defined(IMP_DOXYGEN) && !defined(SWIG)
00024 class Rotation3D;
00025 Rotation3D compose(const Rotation3D &a, const Rotation3D &b) ;
00026 #endif
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045 class IMPALGEBRAEXPORT Rotation3D {
00046 VectorD<4> v_;
00047 mutable bool has_cache_;
00048 mutable VectorD<3> matrix_[3];
00049 IMP_NO_SWIG(friend Rotation3D compose(const Rotation3D &a,
00050 const Rotation3D &b));
00051 void fill_cache() const {
00052 if (has_cache_) return;
00053 has_cache_=true;
00054 matrix_[0]= VectorD<3>(v_[0]*v_[0]+v_[1]*v_[1]-v_[2]*v_[2]-v_[3]*v_[3],
00055 2*(v_[1]*v_[2]-v_[0]*v_[3]),
00056 2*(v_[1]*v_[3]+v_[0]*v_[2]));
00057 matrix_[1]= VectorD<3>(2*(v_[1]*v_[2]+v_[0]*v_[3]),
00058 v_[0]*v_[0]-v_[1]*v_[1]+v_[2]*v_[2]-v_[3]*v_[3],
00059 2*(v_[2]*v_[3]-v_[0]*v_[1]));
00060 matrix_[2]= VectorD<3>(2*(v_[1]*v_[3]-v_[0]*v_[2]),
00061 2*(v_[2]*v_[3]+v_[0]*v_[1]),
00062 v_[0]*v_[0]-v_[1]*v_[1]-v_[2]*v_[2]+v_[3]*v_[3]);
00063 }
00064 public:
00065
00066 Rotation3D(const VectorD<4> &v): v_(v.get_unit_vector()){}
00067
00068
00069 Rotation3D():v_(0,0,0,0) {}
00070
00071
00072
00073 Rotation3D(double a, double b, double c, double d): v_(a,b,c,d),
00074 has_cache_(false) {
00075 IMP_USAGE_CHECK(std::abs(v_.get_squared_magnitude() - 1.0) < .1,
00076 "Attempting to construct a rotation from a "
00077 << " non-quaternion value. The coefficient vector"
00078 << " must have a length of 1. Got: "
00079 << a << " " << b << " " << c << " " << d
00080 << " gives " << v_.get_squared_magnitude());
00081 if (a<0) {
00082
00083 v_=-v_;
00084 }
00085
00086 }
00087 ~Rotation3D();
00088
00089
00090 #ifndef IMP_DOXYGEN
00091 VectorD<3> get_rotated_no_cache(const VectorD<3> &o) const {
00092 return VectorD<3>((v_[0]*v_[0]+v_[1]*v_[1]-v_[2]*v_[2]-v_[3]*v_[3])*o[0]
00093 + 2*(v_[1]*v_[2]-v_[0]*v_[3])*o[1]
00094 + 2*(v_[1]*v_[3]+v_[0]*v_[2])*o[2],
00095 2*(v_[1]*v_[2]+v_[0]*v_[3])*o[0]
00096 + (v_[0]*v_[0]-v_[1]*v_[1]+v_[2]*v_[2]-v_[3]*v_[3])*o[1]
00097 + 2*(v_[2]*v_[3]-v_[0]*v_[1])*o[2],
00098 2*(v_[1]*v_[3]-v_[0]*v_[2])*o[0]
00099 + 2*(v_[2]*v_[3]+v_[0]*v_[1])*o[1]
00100 + (v_[0]*v_[0]-v_[1]*v_[1]-v_[2]*v_[2]+v_[3]*v_[3])*o[2]);
00101 }
00102
00103
00104 double get_rotated_one_coordinate_no_cache(const VectorD<3> &o,
00105 unsigned int coord) const {
00106 switch(coord) {
00107 case 0:
00108 return (v_[0]*v_[0]+v_[1]*v_[1]-v_[2]*v_[2]-v_[3]*v_[3])*o[0]
00109 + 2*(v_[1]*v_[2]-v_[0]*v_[3])*o[1]
00110 + 2*(v_[1]*v_[3]+v_[0]*v_[2])*o[2];
00111 break;
00112 case 1:
00113 return 2*(v_[1]*v_[2]+v_[0]*v_[3])*o[0]
00114 + (v_[0]*v_[0]-v_[1]*v_[1]+v_[2]*v_[2]-v_[3]*v_[3])*o[1]
00115 + 2*(v_[2]*v_[3]-v_[0]*v_[1])*o[2];
00116
00117 break;
00118 case 2:
00119 return 2*(v_[1]*v_[3]-v_[0]*v_[2])*o[0]
00120 + 2*(v_[2]*v_[3]+v_[0]*v_[1])*o[1]
00121 + (v_[0]*v_[0]-v_[1]*v_[1]-v_[2]*v_[2]+v_[3]*v_[3])*o[2];
00122 break;
00123 default:
00124 IMP_THROW("Out of range coordinate " << coord,
00125 IndexException);
00126 }
00127 }
00128 #endif
00129
00130 VectorD<3> get_rotated(const VectorD<3> &o) const {
00131 IMP_USAGE_CHECK(v_.get_squared_magnitude() >0,
00132 "Attempting to apply uninitialized rotation");
00133 fill_cache();
00134 return VectorD<3>(o*matrix_[0],
00135 o*matrix_[1],
00136 o*matrix_[2]);
00137 }
00138
00139
00140 double get_rotated_one_coordinate(const VectorD<3> &o,
00141 unsigned int coord) const {
00142 IMP_USAGE_CHECK(v_.get_squared_magnitude() >0,
00143 "Attempting to apply uninitialized rotation");
00144 fill_cache();
00145 return o*matrix_[coord];
00146 }
00147
00148
00149 VectorD<3> operator*(const VectorD<3> &v) const {
00150 return get_rotated(v);
00151 }
00152
00153 IMP_SHOWABLE_INLINE({out << v_[0] << " " << v_[1]<< " " <<v_[2]
00154 << " " <<v_[3];})
00155
00156
00157 Rotation3D get_inverse() const;
00158
00159
00160 const VectorD<4>& get_quaternion() const {
00161 return v_;
00162 }
00163
00164
00165
00166
00167
00168 const VectorD<4> get_quaternion(const VectorD<4> &q) const {
00169 if (v_*q < 0) return -v_;
00170 else return v_;
00171 }
00172
00173
00174 Rotation3D operator*(const Rotation3D& q) const {
00175 return compose(*this, q);
00176 }
00177
00178
00179 Rotation3D operator/(const Rotation3D &r) const {
00180 return compose(*this, r.get_inverse());
00181 }
00182
00183 const Rotation3D &operator/=(const Rotation3D &r) {
00184 *this= *this/r;
00185 return *this;
00186 }
00187
00188
00189
00190 const VectorD<3> get_derivative(const VectorD<3> &o, unsigned int i) const {
00191
00192
00193
00194 double t4 = v_[0]*o[0] - v_[3]*o[1] + v_[2]*o[2];
00195 double t5 = square(v_[0]);
00196 double t6 = square(v_[1]);
00197 double t7 = square(v_[2]);
00198 double t8 = square(v_[3]);
00199 double t9 = t5 + t6 + t7 + t8;
00200 double t10 = 1.0/t9;
00201 double t11 = 2*t4*t10;
00202 double t14 = v_[1]*v_[2];
00203 double t15 = v_[0]*v_[3];
00204
00205 double t19 = v_[1]*v_[3];
00206 double t20 = v_[0]*v_[2];
00207 double t25 = square(t9);
00208 double t26 = 1.0/t25;
00209
00210 double t27 = ((t5 + t6 - t7 - t8)*o[0] + 2*(t14 - t15)*o[1]
00211 + 2*(t19 + t20)*o[2])*t26;
00212
00213 double t34 = v_[3]*o[0] + v_[0]*o[1] - v_[1]*o[2];
00214 double t35 = 2*t34*t10;
00215 double t41 = v_[2]*v_[3];
00216 double t42 = v_[0]*v_[1];
00217
00218 double t47 = (2*(t14 + t15)*o[0] + (t5 - t6 + t7 - t8)*o[1]
00219 + 2*(t41 - t42)*o[2])*t26;
00220
00221 double t54 = -v_[2]*o[0] + v_[1]*o[1] + v_[0]*o[2];
00222 double t55 = 2*t54*t10;
00223
00224 double t65 = (2*(t19 - t20)*o[0] + 2*(t41 + t42)*o[1]
00225 + (t5 - t6 - t7 + t8)*o[2])*t26;
00226
00227 double t73 = 2*(v_[1]*o[0] + v_[2]*o[1] + v_[3]*o[2])*t10;
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246 switch (i) {
00247 case 0:
00248 return VectorD<3>(t11 - 2*t27*v_[0],
00249 t35 - 2*t47*v_[0],
00250 t55 - 2*t65*v_[0]);
00251 case 1:
00252 return VectorD<3>(t73 - 2*t27*v_[1],
00253 -2*t54*t10 - 2*t47*v_[1],
00254 t35 - 2*t65*v_[1]);
00255 case 2:
00256 return VectorD<3>(t55 - 2*t27*v_[2],
00257 t73 - 2*t47*v_[2],
00258 -2*t4*t10 - 2*t65*v_[2]);
00259 case 3:
00260 return VectorD<3>(-2*t34*t10 - 2*t27*v_[3],
00261 t11 - 2*t47*v_[3],
00262 t73 - 2*t65*v_[3]);
00263 default:
00264 throw IndexException("Invalid derivative component");
00265 };
00266 return VectorD<3>(0,0,0);
00267 }
00268 };
00269
00270
00271 IMP_OUTPUT_OPERATOR(Rotation3D);
00272
00273 typedef std::vector<Rotation3D> Rotation3Ds;
00274
00275
00276
00277
00278 inline Rotation3D get_identity_rotation_3d() {
00279 return Rotation3D(1,0,0,0);
00280 }
00281
00282
00283
00284
00285
00286
00287
00288
00289 inline double get_distance(const Rotation3D &r0,
00290 const Rotation3D &r1) {
00291 double dot= std::abs(r0.get_quaternion()*r1.get_quaternion());
00292 if (dot >1) dot=1;
00293 if (dot < -1) dot=-1;
00294 double theta= std::acos(dot);
00295 return 2.0*theta/PI;
00296 }
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307 inline Rotation3D get_rotation_in_radians_about_axis(const VectorD<3>& axis,
00308 double angle)
00309 {
00310
00311 VectorD<3> axis_norm = axis.get_unit_vector();
00312 double s = std::sin(angle/2);
00313 double a,b,c,d;
00314 a = std::cos(angle/2);
00315 b = axis_norm[0]*s;
00316 c = axis_norm[1]*s;
00317 d = axis_norm[2]*s;
00318 return Rotation3D(a,b,c,d);
00319 }
00320
00321
00322
00323
00324 inline Rotation3D get_rotation_taking_first_to_second(const VectorD<3> &v1,
00325 const VectorD<3> &v2) {
00326 VectorD<3> v1_norm = v1.get_unit_vector();
00327 VectorD<3> v2_norm = v2.get_unit_vector();
00328
00329 VectorD<3> vv = get_vector_product(v1_norm,v2_norm);
00330
00331 double dot = v1_norm*v2_norm;
00332 dot = ( dot < -1.0 ? -1.0 : ( dot > 1.0 ? 1.0 : dot ) );
00333 double angle = std::acos(dot);
00334
00335 if (std::abs(dot) == 1.0) {
00336 IMP_LOG(VERBOSE," the input vectors are (anti)parallel "<<std::endl);
00337 return get_rotation_in_radians_about_axis(get_orthogonal_vector(v1),
00338 angle);
00339 }
00340 return get_rotation_in_radians_about_axis(vv,angle);
00341 }
00342
00343
00344
00345
00346
00347 IMPALGEBRAEXPORT Rotation3D
00348 get_rotation_from_matrix(double m00,double m01,double m02,
00349 double m10,double m11,double m12,
00350 double m20,double m21,double m22);
00351
00352
00353
00354
00355
00356
00357 IMPALGEBRAEXPORT Rotation3D get_random_rotation_3d();
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372 IMPALGEBRAEXPORT Rotation3D get_random_rotation_3d(const Rotation3D ¢er,
00373 double distance);
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384 IMPALGEBRAEXPORT Rotation3Ds
00385 get_uniform_cover_rotations_3d(unsigned int num_points);
00386
00387
00388
00389 inline Rotation3D get_rotation_from_vector4d(const VectorD<4> &v) {
00390 VectorD<4> uv= v.get_unit_vector();
00391 return Rotation3D(uv[0], uv[1], uv[2], uv[3]);
00392 }
00393
00394
00395
00396
00397 inline Rotation3D compose(const Rotation3D &a, const Rotation3D &b) {
00398 return Rotation3D(a.v_[0]*b.v_[0] - a.v_[1]*b.v_[1]
00399 - a.v_[2]*b.v_[2] - a.v_[3]*b.v_[3],
00400 a.v_[0]*b.v_[1] + a.v_[1]*b.v_[0]
00401 + a.v_[2]*b.v_[3] - a.v_[3]*b.v_[2],
00402 a.v_[0]*b.v_[2] - a.v_[1]*b.v_[3]
00403 + a.v_[2]*b.v_[0] + a.v_[3]*b.v_[1],
00404 a.v_[0]*b.v_[3] + a.v_[1]*b.v_[2]
00405 - a.v_[2]*b.v_[1] + a.v_[3]*b.v_[0]);
00406 }
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431 IMPALGEBRAEXPORT Rotation3D get_rotation_from_fixed_xyz(double xr,
00432 double yr,
00433 double zr);
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446 IMPALGEBRAEXPORT Rotation3D get_rotation_from_fixed_zxz(double phi,
00447 double theta,
00448 double psi);
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460 IMPALGEBRAEXPORT Rotation3D get_rotation_from_fixed_zyz(double Rot,
00461 double Tilt,
00462 double Psi);
00463
00464
00465
00466
00467
00468
00469
00470 class FixedZYZ {
00471 double v_[3];
00472 public:
00473 FixedZYZ(){}
00474 FixedZYZ(double rot, double tilt, double psi)
00475 {v_[0]=rot; v_[1]= tilt; v_[2]=psi;}
00476 double get_rot() const {
00477 return v_[0];
00478 }
00479 double get_tilt() const {
00480 return v_[1];
00481 }
00482 double get_psi() const {
00483 return v_[2];
00484 }
00485 IMP_SHOWABLE_INLINE({out << v_[0] << " " << v_[1]
00486 << " " << v_[2];});
00487 };
00488
00489
00490
00491
00492
00493
00494
00495 class FixedXYZ {
00496 double v_[3];
00497 public:
00498 FixedXYZ(){}
00499 FixedXYZ(double x, double y, double z)
00500 {v_[0]=x; v_[1]= y; v_[2]=z;}
00501 double get_x() const {
00502 return v_[0];
00503 }
00504 double get_y() const {
00505 return v_[1];
00506 }
00507 double get_z() const {
00508 return v_[2];
00509 }
00510 IMP_SHOWABLE_INLINE({
00511 out << v_[0] << " " << v_[1] << " " << v_[2];
00512 });
00513 };
00514
00515
00516 IMP_OUTPUT_OPERATOR(FixedZYZ);
00517
00518
00519
00520
00521
00522
00523
00524 IMPALGEBRAEXPORT FixedZYZ get_fixed_zyz_from_rotation(const Rotation3D &r);
00525
00526
00527
00528
00529
00530
00531
00532
00533 IMPALGEBRAEXPORT FixedXYZ get_fixed_xyz_from_rotation(const Rotation3D &r);
00534
00535
00536
00537
00538
00539
00540
00541 inline Rotation3D interpolate(const Rotation3D &a,
00542 const Rotation3D &b,
00543 double f) {
00544 return f*a.get_quaternion()+(1-f)*b.get_quaternion(a.get_quaternion());
00545 }
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555 inline std::pair<VectorD<3>,double> get_axis_and_angle(
00556 const Rotation3D &rot) {
00557 VectorD<4> q = rot.get_quaternion();
00558 double a,b,c,d;
00559 a=q[0];b=q[1];c=q[2];d=q[3];
00560
00561 double angle = std::acos(a)*2;
00562 double s = std::sin(angle/2);
00563 VectorD<3> axis(b/s,c/s,d/s);
00564 return std::pair<VectorD<3>,double>(axis.get_unit_vector(),angle);
00565 }
00566
00567 typedef std::pair<VectorD<3>,double> AxisAnglePair;
00568 #ifndef IMP_DOXYGEN
00569 typedef std::vector<AxisAnglePair> AxisAnglePairs;
00570 #endif
00571
00572 IMPALGEBRA_END_NAMESPACE
00573 #endif