IMP logo
IMP Reference Guide  2.18.0
The Integrative Modeling Platform
Rotation3D.h
Go to the documentation of this file.
1 /**
2  * \file IMP/algebra/Rotation3D.h \brief Simple 3D rotation class.
3  *
4  * Copyright 2007-2022 IMP Inventors. All rights reserved.
5  *
6  */
7 
8 #ifndef IMPALGEBRA_ROTATION_3D_H
9 #define IMPALGEBRA_ROTATION_3D_H
10 
11 #include <IMP/algebra/algebra_config.h>
12 #include "Vector3D.h"
13 #include "utility.h"
14 #include "constants.h"
15 #include "GeometricPrimitiveD.h"
16 #include <boost/serialization/access.hpp>
17 #include <boost/serialization/split_member.hpp>
18 #include <Eigen/Dense>
19 
20 #include <IMP/log.h>
21 #include <cmath>
22 #include <iostream>
23 #include <algorithm>
24 
25 IMPALGEBRA_BEGIN_NAMESPACE
26 
27 typedef Vector4D Rotation3DAdjoint;
28 typedef std::pair<Vector3D, Rotation3DAdjoint> RotatedVector3DAdjoint;
29 typedef std::pair<Rotation3DAdjoint, Rotation3DAdjoint>
30  ComposeRotation3DAdjoint;
31 
32 #if !defined(IMP_DOXYGEN) && !defined(SWIG)
33 class Rotation3D;
34 Rotation3D compose(const Rotation3D &a, const Rotation3D &b);
35 #endif
36 
37 //! 3D rotation class.
38 /** Rotations are currently represented using quaternions and a cached
39  copy of the rotation matrix. The quaternion allows for fast and
40  stable composition and the cached rotation matrix means that
41  rotations are performed quickly. See
42  https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation for
43  a comparison of different implementations of rotations.
44 
45  Currently the rotation can be initialized from either:
46  - XYZ Euler angles
47  - Rotation Matrix
48  - Quaternion
49  - angle/axis representation
50 
51  \geometry
52 */
53 class IMPALGEBRAEXPORT Rotation3D : public GeometricPrimitiveD<3> {
54  VectorD<4> v_;
55  mutable bool has_cache_;
56  mutable Vector3D matrix_[3];
57 
58  friend class boost::serialization::access;
59 
60  template<class Archive>
61  void save(Archive &ar, const unsigned int) const {
62  ar << v_;
63  }
64 
65  template<class Archive>
66  void load(Archive &ar, const unsigned int) {
67  ar >> v_;
68  has_cache_ = false;
69  }
70 
71  BOOST_SERIALIZATION_SPLIT_MEMBER()
72 
73  IMP_NO_SWIG(friend Rotation3D compose(const Rotation3D &a,
74  const Rotation3D &b));
75  void fill_cache() const {
76  IMP_USAGE_CHECK(get_is_valid(),
77  "Attempting to apply uninitialized rotation");
78  has_cache_ = true;
79  double v0s = get_squared(v_[0]);
80  double v1s = get_squared(v_[1]);
81  double v2s = get_squared(v_[2]);
82  double v3s = get_squared(v_[3]);
83  double v12 = v_[1] * v_[2];
84  double v01 = v_[0] * v_[1];
85  double v02 = v_[0] * v_[2];
86  double v23 = v_[2] * v_[3];
87  double v03 = v_[0] * v_[3];
88  double v13 = v_[1] * v_[3];
89  matrix_[0] =
90  Vector3D(v0s + v1s - v2s - v3s, 2 * (v12 - v03), 2 * (v13 + v02));
91  matrix_[1] =
92  Vector3D(2 * (v12 + v03), v0s - v1s + v2s - v3s, 2 * (v23 - v01));
93  matrix_[2] =
94  Vector3D(2 * (v13 - v02), 2 * (v23 + v01), v0s - v1s - v2s + v3s);
95  }
96 
97  // When copying preserve the cached rotation matrix, if present
98  void copy_cache(const Rotation3D &rot) {
99  has_cache_ = rot.has_cache_;
100  if (has_cache_) {
101  matrix_[0] = rot.matrix_[0];
102  matrix_[1] = rot.matrix_[1];
103  matrix_[2] = rot.matrix_[2];
104  }
105  }
106 
107  public:
108  //! Rotation3D copy constructor
109  Rotation3D(const Rotation3D &rot) : v_(rot.v_) {
110  copy_cache(rot);
111  }
112 
113  Rotation3D &operator=(const Rotation3D &rot) {
114  v_ = rot.v_;
115  copy_cache(rot);
116  return *this;
117  }
118 
119  //! Create a rotation from a vector of 4 quaternion coefficients.
120  //! @note: use assume_normalized with care - inputting an unnormalized
121  //! vector would result in unexpected results if it is true
122  explicit Rotation3D(const VectorD<4> &v,
123  bool assume_normalized=false)
124  : v_(assume_normalized ? v : v.get_unit_vector()),
125  has_cache_(false) {}
126 
127  //! Create an invalid rotation
128  Rotation3D() : v_(0, 0, 0, 0), has_cache_(false) {}
129  //! Create a rotation from a quaternion
130  /** \throw ValueException if the rotation is not a unit vector.
131  */
132  Rotation3D(double a, double b, double c, double d)
133  : v_(a, b, c, d), has_cache_(false) {
135  v_.get_squared_magnitude(), 1.0,
136  "Attempting to construct a rotation from a "
137  << " non-quaternion value. The coefficient vector"
138  << " must have a length of 1. Got: " << a << " " << b << " " << c
139  << " " << d << " gives " << v_.get_squared_magnitude());
140  if (a < 0) {
141  // make them canonical
142  v_ = -v_;
143  }
144  }
145  ~Rotation3D(){}
146 
147 #ifndef IMP_DOXYGEN
148  Vector3D get_rotated_no_cache(const Vector3D &o) const {
149  IMP_USAGE_CHECK(get_is_valid(),
150  "Attempting to access uninitialized rotation");
151  return Vector3D(
152  (v_[0] * v_[0] + v_[1] * v_[1] - v_[2] * v_[2] - v_[3] * v_[3]) * o[0] +
153  2 * (v_[1] * v_[2] - v_[0] * v_[3]) * o[1] +
154  2 * (v_[1] * v_[3] + v_[0] * v_[2]) * o[2],
155  2 * (v_[1] * v_[2] + v_[0] * v_[3]) * o[0] +
156  (v_[0] * v_[0] - v_[1] * v_[1] + v_[2] * v_[2] - v_[3] * v_[3]) *
157  o[1] +
158  2 * (v_[2] * v_[3] - v_[0] * v_[1]) * o[2],
159  2 * (v_[1] * v_[3] - v_[0] * v_[2]) * o[0] +
160  2 * (v_[2] * v_[3] + v_[0] * v_[1]) * o[1] +
161  (v_[0] * v_[0] - v_[1] * v_[1] - v_[2] * v_[2] + v_[3] * v_[3]) *
162  o[2]);
163  }
164 
165  //! Get only the requested rotation coordinate of the vector
166  double get_rotated_one_coordinate_no_cache(const Vector3D &o,
167  unsigned int coord) const {
168  IMP_USAGE_CHECK(get_is_valid(),
169  "Attempting to apply uninitialized rotation");
170  switch (coord) {
171  case 0:
172  return (v_[0] * v_[0] + v_[1] * v_[1] - v_[2] * v_[2] - v_[3] * v_[3]) *
173  o[0] +
174  2 * (v_[1] * v_[2] - v_[0] * v_[3]) * o[1] +
175  2 * (v_[1] * v_[3] + v_[0] * v_[2]) * o[2];
176  break;
177  case 1:
178  return 2 * (v_[1] * v_[2] + v_[0] * v_[3]) * o[0] +
179  (v_[0] * v_[0] - v_[1] * v_[1] + v_[2] * v_[2] - v_[3] * v_[3]) *
180  o[1] +
181  2 * (v_[2] * v_[3] - v_[0] * v_[1]) * o[2];
182 
183  break;
184  case 2:
185  return 2 * (v_[1] * v_[3] - v_[0] * v_[2]) * o[0] +
186  2 * (v_[2] * v_[3] + v_[0] * v_[1]) * o[1] +
187  (v_[0] * v_[0] - v_[1] * v_[1] - v_[2] * v_[2] + v_[3] * v_[3]) *
188  o[2];
189  break;
190  default:
191  IMP_THROW("Out of range coordinate " << coord, IndexException);
192  }
193  }
194 #endif
195  //! Rotate a vector around the origin
196  Vector3D get_rotated(const Vector3D &o) const {
197  if (!has_cache_) fill_cache();
198  return Vector3D(o * matrix_[0], o * matrix_[1], o * matrix_[2]);
199  }
200 
201 #ifndef SWIG
202  //! Get adjoint of inputs to `get_rotated` from adjoint of output
203  /** Compute the adjoint (reverse-mode sensitivity) of input vector
204  to `get_rotated` and this rotation from the adjoint of the
205  output vector.
206  */
207  void get_rotated_adjoint(const Vector3D &v, const Vector3D &Dw,
208  Vector3D *Dv, Rotation3DAdjoint *Dr) const;
209 #endif
210 
211  //! Get adjoint of inputs to `get_rotated` from adjoint of output
212  /** Compute the adjoint (reverse-mode sensitivity) of input vector
213  to `get_rotated` and this rotation from the adjoint of the
214  output vector.
215  */
216  RotatedVector3DAdjoint
217  get_rotated_adjoint(const Vector3D &v, const Vector3D &Dw) const;
218 
219  //! Get only the requested rotation coordinate of the vector
221  unsigned int coord) const {
222  if (!has_cache_) fill_cache();
223  return o * matrix_[coord];
224  }
225 
226  //! Rotate a vector around the origin
227  Vector3D operator*(const Vector3D &v) const { return get_rotated(v); }
228  Vector3D get_rotation_matrix_row(int i) const {
229  IMP_USAGE_CHECK((i >= 0) && (i <= 2), "row index out of range");
230  if (!has_cache_) fill_cache();
231  return matrix_[i];
232  }
233  IMP_SHOWABLE_INLINE(Rotation3D,
234  { out << v_[0] << " " << v_[1] << " " << v_[2] << " " << v_[3]; });
235 
236  //! Return the rotation which undoes this rotation.
237  inline Rotation3D get_inverse() const {
238  IMP_USAGE_CHECK(get_is_valid(),
239  "Attempting to invert uninitialized rotation");
240  Rotation3D ret(v_[0], -v_[1], -v_[2], -v_[3]);
241  return ret;
242  }
243 
244  //! Return the quaternion so that it can be stored
245  /** Note that there is no guarantee on which of the two
246  equivalent quaternions is returned.
247  */
248  const Vector4D &get_quaternion() const {
249  IMP_USAGE_CHECK(get_is_valid(),
250  "Attempting to access uninitialized rotation");
251  return v_;
252  }
253 
254  //! Multiply two rotations
255  Rotation3D operator*(const Rotation3D &q) const {
256  IMP_USAGE_CHECK(get_is_valid(),
257  "Attempting to compose uninitialized rotation");
258  return compose(*this, q);
259  }
260 
261  //! Compute the rotation which when composed with r gives this
262  Rotation3D operator/(const Rotation3D &r) const {
263  IMP_USAGE_CHECK(get_is_valid(),
264  "Attempting to compose uninitialized rotation");
265  return compose(*this, r.get_inverse());
266  }
267 
268  const Rotation3D &operator/=(const Rotation3D &r) {
269  *this = *this / r;
270  return *this;
271  }
272 
273  //! Return the gradient of rotated vector wrt the ith quaternion element.
274  /** Given the rotation \f$x = R(q) v\f$, where \f$v\f$ is a vector,
275  \f$q=(q_0,q_1,q_2,q_3)\f$ is the quaternion of the rotation with
276  elements \f$q_i\f$, and \f$R(q)\f$ is the corresponding rotation matrix,
277  the function returns the gradient \f$\nabla_{q_i} x\f$.
278 
279  This function just returns a single column from `get_jacobian()`, so it is
280  more efficient to call that function if all columns are needed.
281 
282  \param[in] v vector to be rotated by rotation \f$R(q)\f$
283  \param[in] wrt_unnorm Gradient is computed wrt unnormalized quaternion.
284  Rotation includes a normalization operation, and
285  the gradient is projected to the tangent space at
286  \f$q\f$.
287  */
288  Vector3D get_gradient_of_rotated(const Vector3D &v, unsigned int i,
289  bool wrt_unnorm = false) const;
290 
291  IMPALGEBRA_DEPRECATED_METHOD_DECL(2.12)
292  Vector3D get_derivative(const Vector3D &v, unsigned int i,
293  bool wrt_unnorm = true) const;
294 
295  //! Return the Jacobian of rotated vector wrt the quaternion.
296  /** Given the rotation \f$x = R(q) v\f$, where \f$v\f$ is a vector,
297  \f$q\f$ is the quaternion of the rotation, and \f$R(q)\f$ is the
298  corresponding rotation matrix, the function returns the 3x4 matrix
299  \f$J\f$ with elements \f$J_{ij}=\frac{\partial x_i}{\partial q_j}\f$.
300 
301  \param[in] v vector to be rotated by rotation \f$R(q)\f$
302  \param[in] wrt_unnorm Jacobian is computed wrt unnormalized quaternion.
303  Rotation includes a normalization operation, and
304  the columns are projected to the tangent space at
305  \f$q\f$.
306  */
307  Eigen::MatrixXd get_jacobian_of_rotated(
308  const Eigen::Vector3d &v, bool wrt_unnorm = false) const;
309 
310  IMPALGEBRA_DEPRECATED_METHOD_DECL(2.12)
311  Eigen::MatrixXd get_gradient(
312  const Eigen::Vector3d &v, bool wrt_unnorm = true) const;
313 
314  /** Return true is the rotation is valid, false if
315  invalid or not initialized (e.g., only initialized by
316  the empty constructor)
317  */
318  bool get_is_valid() const {
319  return v_.get_squared_magnitude() > 0; // TODO: add that magnitude ~ 1?
320  }
321 };
322 
324 
325 
326 //! Get gradient of quaternion product with respect to first quaternion.
327 /** Given the rotation \f$R(p)\f$ followed by \f$R(q)\f$, where \f$p\f$ and
328  \f$q\f$ are quaternions, the quaternion of the composed rotation
329  \f$R(s)=R(q) R(p)\f$ can be expressed through the Hamilton product of the
330  two quaternions \f$s(q,p) = q p\f$. This function returns the matrix
331  \f$J\f$ with elements \f$J_{ij}=\frac{\partial s_i}{\partial q_j}\f$.
332 
333  \param[in] q rotation corresponding to first quaternion
334  \param[in] p rotation corresponding to second quaternion
335  \param[in] wrt_unnorm Jacobian is computed wrt unnormalized quaternion.
336  Rotation includes a normalization operation, and
337  the columns are projected to the tangent space at
338  \f$q\f$.
339  */
340 IMPALGEBRAEXPORT Eigen::MatrixXd get_jacobian_of_composed_wrt_first(
341  const Rotation3D &q, const Rotation3D &p, bool wrt_unnorm = false);
342 
343 IMPALGEBRA_DEPRECATED_FUNCTION_DECL(2.12)
344 IMPALGEBRAEXPORT Eigen::MatrixXd
345  get_gradient_of_composed_with_respect_to_first(
346  const Rotation3D &q, const Rotation3D &p, bool wrt_unnorm = true);
347 
348 
349 //! Get Jacobian of quaternion product with respect to second quaternion.
350 /** Given the rotation \f$R(p)\f$ followed by \f$R(q)\f$, where \f$p\f$ and
351  \f$q\f$ are quaternions, the quaternion of the composed rotation
352  \f$R(s)=R(q) R(p)\f$ can be expressed through the Hamilton product of the
353  two quaternions \f$s(q,p) = q p\f$. This function returns the matrix
354  \f$J\f$ with elements \f$J_{ij}=\frac{\partial s_i}{\partial p_j}\f$.
355 
356  \param[in] q rotation corresponding to first quaternion
357  \param[in] p rotation corresponding to second quaternion
358  \param[in] wrt_unnorm Jacobian is computed wrt unnormalized quaternion.
359  Rotation includes a normalization operation, and
360  the columns are projected to the tangent space at
361  \f$p\f$.
362  */
363 IMPALGEBRAEXPORT Eigen::MatrixXd get_jacobian_of_composed_wrt_second(
364  const Rotation3D &q, const Rotation3D &p, bool wrt_unnorm = false);
365 
366 IMPALGEBRA_DEPRECATED_FUNCTION_DECL(2.12)
367 IMPALGEBRAEXPORT Eigen::MatrixXd
368  get_gradient_of_composed_with_respect_to_second(
369  const Rotation3D &q, const Rotation3D &p, bool wrt_unnorm = true);
370 
371 
372 //! Return a rotation that does not do anything
373 /** \see Rotation3D */
374 inline Rotation3D get_identity_rotation_3d() { return Rotation3D(1, 0, 0, 0); }
375 
376 //! Return a distance between the two rotations
377 /** The distance runs between 0 and 1. More precisely,
378  the distance returned is distance between the two
379  quaternion vectors properly normalized, divided
380  by sqrt(2).
381 
382  A vector with distance d from the unit vector
383  represents a rotation of
384 
385  \f$ \theta= \cos^{-1}\left(1-\sqrt{2}d\right)\f$
386  \see Rotation3D
387 */
388 inline double get_distance(const Rotation3D &r0, const Rotation3D &r1) {
389  double dot =
390  (r0.get_quaternion() - r1.get_quaternion()).get_squared_magnitude();
391  double odot =
392  (r0.get_quaternion() + r1.get_quaternion()).get_squared_magnitude();
393  double ans = std::min(dot, odot);
394  // TODO: barak - added static for efficiency
395  static const double s2 = std::sqrt(2.0);
396  double ret = ans / s2;
397  return std::max(std::min(ret, 1.0), 0.0);
398 }
399 
400 //! Generate a Rotation3D object from a rotation around an axis
401 //! that is assumed to be normalized
402 /**
403  \param[in] axis_norm the normalized rotation axis passing through (0,0,0)
404  \param[in] angle the rotation angle in radians in the
405  clockwise direction
406  \note https://en.wikipedia.org/wiki/Rotation_matrix
407  \note www.euclideanspace.com/maths/geometry/rotations/conversions/
408  angleToQuaternion/index.htm
409  \see Rotation3D
410 */
411 inline Rotation3D
413 (const Vector3D &axis_norm, double angle)
414 {
415  IMP_USAGE_CHECK(axis_norm.get_magnitude() - 1.0 < 1e-6,
416  "expected normalized vector as axis of rotation");
417  double s = std::sin(angle / 2);
418  double a, b, c, d;
419  a = std::cos(angle / 2);
420  b = axis_norm[0] * s;
421  c = axis_norm[1] * s;
422  d = axis_norm[2] * s;
423  return Rotation3D(a, b, c, d);
424 }
425 
426 
427 //! Generate a Rotation3D object from a rotation around an axis
428 /**
429  \param[in] axis the rotation axis passes through (0,0,0)
430  \param[in] angle the rotation angle in radians in the
431  clockwise direction
432  \note https://en.wikipedia.org/wiki/Rotation_matrix
433  \note www.euclideanspace.com/maths/geometry/rotations/conversions/
434  angleToQuaternion/index.htm
435  \see Rotation3D
436 */
437 inline Rotation3D
439 (const Vector3D &axis, double angle)
440 {
441  // normalize the vector
442  Vector3D axis_norm = axis.get_unit_vector();
443  return get_rotation_about_normalized_axis(axis_norm, angle);
444 }
445 
446 //! Create a rotation from the first vector to the second one.
447 /** \see Rotation3D
448  */
449 IMPALGEBRAEXPORT Rotation3D
451 
452 //! Generate a Rotation3D object from a rotation matrix
453 /**
454  \see Rotation3D
455 */
456 IMPALGEBRAEXPORT Rotation3D
457  get_rotation_from_matrix(double m00, double m01, double m02, double m10,
458  double m11, double m12, double m20, double m21,
459  double m22);
460 
461 //! Generate a Rotation3D object from a rotation matrix
462 /**
463  \see Rotation3D
464 */
465 IMPALGEBRAEXPORT Rotation3D get_rotation_from_matrix(Eigen::Matrix3d m);
466 
467 //! Pick a rotation at random from all possible rotations
468 /** \see Rotation3D */
469 IMPALGEBRAEXPORT Rotation3D get_random_rotation_3d();
470 
471 //! Pick a rotation at random near the provided one
472 /** This method generates a rotation that is within the provided
473  distance of center.
474  \param[in] center The center of the rotational volume
475  \param[in] distance See
476  get_distance(const Rotation3D&,const Rotation3D&)
477  for a full definition.
478 
479  \note The cost of this operation increases as distance goes to 0.
480 
481  \see Rotation3D
482 */
483 IMPALGEBRAEXPORT Rotation3D
484  get_random_rotation_3d(const Rotation3D &center, double distance);
485 
486 //! Cover the space of rotations evenly
487 /** If you care about the distance between samples instead of the number
488  of samples, the "surface area" of the set of rotations is pi^2. If
489  you allocate each sample a volume of 4/3 pi d^3 (to space them d apart),
490  Then you want 3/4 pi/d^3 points.
491 
492  Creates at least num_points rotations.
493 */
494 IMPALGEBRAEXPORT Rotation3Ds
495  get_uniform_cover_rotations_3d(unsigned int num_points);
496 
497 //! Generates a nondegenerate set of Euler angles with a delta resolution
498 /**
499 \param[in] delta sample every delta angles in radians.
500  */
502  double delta);
503 
504 //! Compute a rotation from an unnormalized quaternion
505 /** \see Rotation3D */
507  VectorD<4> uv = v.get_unit_vector();
508  return Rotation3D(uv[0], uv[1], uv[2], uv[3]);
509 }
510 
511 /** \see Rotation3D
512  */
513 inline Rotation3D compose(const Rotation3D &a, const Rotation3D &b) {
514  return Rotation3D(a.v_[0] * b.v_[0] - a.v_[1] * b.v_[1] - a.v_[2] * b.v_[2] -
515  a.v_[3] * b.v_[3],
516  a.v_[0] * b.v_[1] + a.v_[1] * b.v_[0] + a.v_[2] * b.v_[3] -
517  a.v_[3] * b.v_[2],
518  a.v_[0] * b.v_[2] - a.v_[1] * b.v_[3] + a.v_[2] * b.v_[0] +
519  a.v_[3] * b.v_[1],
520  a.v_[0] * b.v_[3] + a.v_[1] * b.v_[2] - a.v_[2] * b.v_[1] +
521  a.v_[3] * b.v_[0]);
522 }
523 
524 #ifndef SWIG
525 //! Get adjoint of inputs to `compose` from adjoint of output
526 /** Compute the adjoint (reverse-mode sensitivity) of input rotations
527  to `compose` from the adjoint of the output rotation.
528  */
529 IMPALGEBRAEXPORT void
530 compose_adjoint(const Rotation3D &A, const Rotation3D &B, Vector4D DC,
531  Rotation3DAdjoint *DA, Rotation3DAdjoint *DB);
532 #endif
533 
534 //! Get adjoint of inputs to `compose` from adjoint of output
535 /** Compute the adjoint (reverse-mode sensitivity) of input rotations
536  to `compose` from the adjoint of the output rotation.
537  */
538 IMPALGEBRAEXPORT ComposeRotation3DAdjoint
539 compose_adjoint(const Rotation3D &A, const Rotation3D &B, const Rotation3DAdjoint &DC);
540 
541 /** \name Euler Angles
542  There are many conventions for how to define Euler angles, based on choices
543  of which of the x,y,z axis to use in what order and whether the rotation
544  axis is in the body frame (and hence affected by previous rotations) or in
545  in a fixed frame. See
546  https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles
547  for a general description.
548 
549  - All Euler angles are specified in radians.
550  - Only x-y-z order is currently supported.
551  - To convert Euler angles in a different order, one can compose a Rotation3D
552  from three rotations using get_rotation_about_axis function.
553  @{
554 */
555 
556 //! Initialize a rotation in x-y-z order from three angles
557 /** \param[in] xr Rotation around the X axis in radians
558  \param[in] yr Rotation around the Y axis in radians
559  \param[in] zr Rotation around the Z axis in radians
560  \note The three rotations are represented in the original (fixed)
561  coordinate frame.
562  \see Rotation3D
563  \see FixedXYZ
564 */
565 IMPALGEBRAEXPORT Rotation3D
566  get_rotation_from_fixed_xyz(double xr, double yr, double zr);
567 
568 //! Initialize a rotation from Euler angles
569 /**
570  \param[in] phi Rotation around the Z axis in radians
571  \param[in] theta Rotation around the X axis in radians
572  \param[in] psi Rotation around the Z axis in radians
573  \note The first rotation is by an angle phi about the z-axis.
574  The second rotation is by an angle theta in [0,pi] about the
575  former x-axis , and the third rotation is by an angle psi
576  about the former z-axis.
577  \see Rotation3D
578 */
579 IMPALGEBRAEXPORT Rotation3D
580  get_rotation_from_fixed_zxz(double phi, double theta, double psi);
581 
582 //! Generate a rotation object from Euler Angles
583 /** \note The first rotation is by an angle about the z-axis.
584  The second rotation is by an angle about the new y-axis.
585  The third rotation is by an angle about the new z-axis.
586  \param[in] Rot First Euler angle (radians) defining the rotation (Z axis)
587  \param[in] Tilt Second Euler angle (radians) defining the rotation (Y axis)
588  \param[in] Psi Third Euler angle (radians) defining the rotation (Z axis)
589  \see Rotation3D
590 */
591 IMPALGEBRAEXPORT Rotation3D
592  get_rotation_from_fixed_zyz(double Rot, double Tilt, double Psi);
593 
594 //! A simple class for returning XYZ Euler angles
595 class FixedXYZ : public GeometricPrimitiveD<3> {
596  double v_[3];
597 
598  friend class boost::serialization::access;
599 
600  template<class Archive> void serialize(Archive &ar, const unsigned int) {
601  ar & v_[0] & v_[1] & v_[2];
602  }
603 
604  public:
605  FixedXYZ() {}
606  FixedXYZ(double x, double y, double z) {
607  v_[0] = x;
608  v_[1] = y;
609  v_[2] = z;
610  }
611  double get_x() const { return v_[0]; }
612  double get_y() const { return v_[1]; }
613  double get_z() const { return v_[2]; }
615  { out << v_[0] << " " << v_[1] << " " << v_[2]; });
616 };
617 
619 
620 //! The inverse of rotation_from_fixed_xyz()
621 /**
622  \see rotation_from_fixed_xyz()
623  \see Rotation3D
624  \see FixesXYZ
625 */
626 IMPALGEBRAEXPORT FixedXYZ get_fixed_xyz_from_rotation(const Rotation3D &r);
627 
628 /** @}*/
629 
630 //! Interpolate between two rotations
631 /** It f ==0, return b, if f==1 return a.
632  \see Rotation3D */
634  double f) {
635  VectorD<4> bq = b.get_quaternion(), aq = a.get_quaternion();
636  if (bq * aq < 0) bq = -bq;
637  return Rotation3D(f * aq + (1 - f) * bq);
638 }
639 
640 /** Return the rotation which takes the native x and y axes to the
641  given x and y axes.
642  The two axes must be perpendicular unit vectors.
643 */
644 IMPALGEBRAEXPORT Rotation3D
645  get_rotation_from_x_y_axes(const Vector3D &x, const Vector3D &y);
646 
647 //! Decompose a Rotation3D object into a rotation around an axis
648 /** For all identity rotations, returns the axis [1,0,0] and the angle 0.0.
649 
650  \note https://en.wikipedia.org/wiki/Rotation_matrix
651  \note www.euclideanspace.com/maths/geometry/rotations/conversions/
652  angleToQuaternion/index.htm
653  \see Rotation3D
654 
655  @return axis direction and rotation about the axis in Radians
656 */
657 IMPALGEBRAEXPORT std::pair<Vector3D, double> get_axis_and_angle(
658  const Rotation3D &rot);
659 
660 typedef std::pair<Vector3D, double> AxisAnglePair;
661 #ifndef IMP_DOXYGEN
662 typedef Vector<AxisAnglePair> AxisAnglePairs;
663 #endif
664 
665 IMPALGEBRA_END_NAMESPACE
666 #endif /* IMPALGEBRA_ROTATION_3D_H */
Vector3D get_rotated(const Vector3D &o) const
Rotate a vector around the origin.
Definition: Rotation3D.h:196
Rotation3D get_rotation_about_normalized_axis(const Vector3D &axis_norm, double angle)
Definition: Rotation3D.h:413
Rotation3D(const Rotation3D &rot)
Rotation3D copy constructor.
Definition: Rotation3D.h:109
Base class for geometric types.
#define IMP_SHOWABLE_INLINE(Name, how_to_show)
Declare the methods needed by an object that can be printed.
Rotation3D get_rotation_from_x_y_axes(const Vector3D &x, const Vector3D &y)
Rotation3D get_rotation_from_fixed_xyz(double xr, double yr, double zr)
Initialize a rotation in x-y-z order from three angles.
Rotation3D()
Create an invalid rotation.
Definition: Rotation3D.h:128
#define IMP_USAGE_CHECK_FLOAT_EQUAL(expra, exprb, message)
Definition: check_macros.h:178
Rotation2D compose(const Rotation2D &a, const Rotation2D &b)
Compose two rotations a and b.
Definition: Rotation2D.h:126
algebra::Rotation3Ds get_uniformly_sampled_rotations(double delta)
Generates a nondegenerate set of Euler angles with a delta resolution.
Rotation3D get_random_rotation_3d(const Rotation3D &center, double distance)
Pick a rotation at random near the provided one.
Rotation3D operator/(const Rotation3D &r) const
Compute the rotation which when composed with r gives this.
Definition: Rotation3D.h:262
A simple class for returning XYZ Euler angles.
Definition: Rotation3D.h:595
Rotation3D(const VectorD< 4 > &v, bool assume_normalized=false)
Definition: Rotation3D.h:122
Vector3D operator*(const Vector3D &v) const
Rotate a vector around the origin.
Definition: Rotation3D.h:227
Rotation3D compose(const Rotation3D &a, const Rotation3D &b)
Definition: Rotation3D.h:513
double get_rotated_one_coordinate(const Vector3D &o, unsigned int coord) const
Get only the requested rotation coordinate of the vector.
Definition: Rotation3D.h:220
VT get_unit_vector(VT vt)
Returns a unit vector pointing at the same direction as this vector.
Definition: VectorBaseD.h:247
Eigen::MatrixXd get_jacobian_of_composed_wrt_first(const Rotation3D &q, const Rotation3D &p, bool wrt_unnorm=false)
Get gradient of quaternion product with respect to first quaternion.
const Vector4D & get_quaternion() const
Return the quaternion so that it can be stored.
Definition: Rotation3D.h:248
VectorD< 4 > Vector4D
Definition: VectorD.h:425
Rotation3D get_rotation_about_axis(const Vector3D &axis, double angle)
Generate a Rotation3D object from a rotation around an axis.
Definition: Rotation3D.h:439
#define IMP_VALUES(Name, PluralName)
Define the type for storing sets of values.
Definition: value_macros.h:23
Base class for geometric types.
Functions to deal with very common math operations.
A Cartesian vector in D-dimensions.
Definition: VectorD.h:52
FixedXYZ get_fixed_xyz_from_rotation(const Rotation3D &r)
The inverse of rotation_from_fixed_xyz()
Rotation3D get_inverse() const
Return the rotation which undoes this rotation.
Definition: Rotation3D.h:237
Rotation3D get_rotation_from_fixed_zyz(double Rot, double Tilt, double Psi)
Generate a rotation object from Euler Angles.
std::pair< Vector3D, double > get_axis_and_angle(const Rotation3D &rot)
Decompose a Rotation3D object into a rotation around an axis.
double get_distance(const Rotation3D &r0, const Rotation3D &r1)
Return a distance between the two rotations.
Definition: Rotation3D.h:388
Rotation3D get_interpolated(const Rotation3D &a, const Rotation3D &b, double f)
Interpolate between two rotations.
Definition: Rotation3D.h:633
#define IMP_NO_SWIG(x)
Hide the line when SWIG is compiled or parses it.
Definition: swig_macros.h:18
Rotation3D get_rotation_from_vector4d(const VectorD< 4 > &v)
Compute a rotation from an unnormalized quaternion.
Definition: Rotation3D.h:506
Rotation3D get_rotation_taking_first_to_second(const Vector3D &v1, const Vector3D &v2)
Create a rotation from the first vector to the second one.
Rotation3Ds get_uniform_cover_rotations_3d(unsigned int num_points)
Cover the space of rotations evenly.
Various useful constants.
Rotation3D operator*(const Rotation3D &q) const
Multiply two rotations.
Definition: Rotation3D.h:255
3D rotation class.
Definition: Rotation3D.h:53
Eigen::MatrixXd get_jacobian_of_composed_wrt_second(const Rotation3D &q, const Rotation3D &p, bool wrt_unnorm=false)
Get Jacobian of quaternion product with respect to second quaternion.
#define IMP_THROW(message, exception_name)
Throw an exception with a message.
Definition: check_macros.h:50
Rotation3D(double a, double b, double c, double d)
Create a rotation from a quaternion.
Definition: Rotation3D.h:132
VectorD< 3 > Vector3D
Definition: VectorD.h:421
Rotation3D get_identity_rotation_3d()
Return a rotation that does not do anything.
Definition: Rotation3D.h:374
ComposeRotation3DAdjoint compose_adjoint(const Rotation3D &A, const Rotation3D &B, const Rotation3DAdjoint &DC)
Get adjoint of inputs to compose from adjoint of output.
Simple 3D vector class.
#define IMP_USAGE_CHECK(expr, message)
A runtime test for incorrect usage of a class or method.
Definition: check_macros.h:168
Logging and error reporting support.
Rotation3D get_rotation_from_fixed_zxz(double phi, double theta, double psi)
Initialize a rotation from Euler angles.
Rotation3D get_rotation_from_matrix(Eigen::Matrix3d m)
Generate a Rotation3D object from a rotation matrix.
IMP::Vector< Rotation3D > Rotation3Ds
Definition: Rotation3D.h:323