IMP  2.2.1
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-2014 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 <IMP/algebra/eigen3/Eigen/Dense>
17 
18 #include <IMP/base/log.h>
19 #include <cmath>
20 #include <iostream>
21 #include <algorithm>
22 
23 IMPALGEBRA_BEGIN_NAMESPACE
24 
25 #if !defined(IMP_DOXYGEN) && !defined(SWIG)
26 class Rotation3D;
27 Rotation3D compose(const Rotation3D &a, const Rotation3D &b);
28 #endif
29 
30 //! 3D rotation class.
31 /** Rotations are currently represented using quaternions and a cached
32  copy of the rotation matrix. The quaternion allows for fast and
33  stable composition and the cached rotation matrix means that
34  rotations are performed quickly. See
35  http://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation for
36  a comparison of different implementations of rotations.
37 
38  Currently the rotation can be initialized from either:
39  - XYZ Euler angles
40  - Rotation Matrix
41  - Quaternion
42  - angle/axis representation
43 
44  \geometry
45 */
46 class IMPALGEBRAEXPORT Rotation3D : public GeometricPrimitiveD<3> {
47  VectorD<4> v_;
48  mutable bool has_cache_;
49  mutable Vector3D matrix_[3];
50  IMP_NO_SWIG(friend Rotation3D compose(const Rotation3D &a,
51  const Rotation3D &b));
52  void fill_cache() const {
53  IMP_USAGE_CHECK(v_.get_squared_magnitude() > 0,
54  "Attempting to apply uninitialized rotation");
55  has_cache_ = true;
56  double v0s = get_squared(v_[0]);
57  double v1s = get_squared(v_[1]);
58  double v2s = get_squared(v_[2]);
59  double v3s = get_squared(v_[3]);
60  double v12 = v_[1] * v_[2];
61  double v01 = v_[0] * v_[1];
62  double v02 = v_[0] * v_[2];
63  double v23 = v_[2] * v_[3];
64  double v03 = v_[0] * v_[3];
65  double v13 = v_[1] * v_[3];
66  matrix_[0] =
67  Vector3D(v0s + v1s - v2s - v3s, 2 * (v12 - v03), 2 * (v13 + v02));
68  matrix_[1] =
69  Vector3D(2 * (v12 + v03), v0s - v1s + v2s - v3s, 2 * (v23 - v01));
70  matrix_[2] =
71  Vector3D(2 * (v13 - v02), 2 * (v23 + v01), v0s - v1s - v2s + v3s);
72  }
73 
74  public:
75  IMP_CXX11_DEFAULT_COPY_CONSTRUCTOR(Rotation3D);
76 
77  //! Create a rotation from a vector of 4 quaternion coefficients.
78  //! @note: use assume_normalize with care - inputting an unnormalized
79  //! vector would result in unexpected results if it is true
80  explicit Rotation3D(const VectorD<4> &v,
81  bool assume_normalized=false)
82  : v_(assume_normalized ? v : v.get_unit_vector()),
83  has_cache_(false) {}
84 
85  //! Create an invalid rotation
86  Rotation3D() : v_(0, 0, 0, 0), has_cache_(false) {}
87  //! Create a rotation from a quaternion
88  /** \throw base::ValueException if the rotation is not a unit vector.
89  */
90  Rotation3D(double a, double b, double c, double d)
91  : v_(a, b, c, d), has_cache_(false) {
93  v_.get_squared_magnitude(), 1.0,
94  "Attempting to construct a rotation from a "
95  << " non-quaternion value. The coefficient vector"
96  << " must have a length of 1. Got: " << a << " " << b << " " << c
97  << " " << d << " gives " << v_.get_squared_magnitude());
98  if (a < 0) {
99  // make them canonical
100  v_ = -v_;
101  }
102  }
103  ~Rotation3D();
104 
105 #ifndef IMP_DOXYGEN
106  Vector3D get_rotated_no_cache(const Vector3D &o) const {
107  IMP_USAGE_CHECK(v_.get_squared_magnitude() > 0,
108  "Attempting to access uninitialized rotation");
109  return Vector3D(
110  (v_[0] * v_[0] + v_[1] * v_[1] - v_[2] * v_[2] - v_[3] * v_[3]) * o[0] +
111  2 * (v_[1] * v_[2] - v_[0] * v_[3]) * o[1] +
112  2 * (v_[1] * v_[3] + v_[0] * v_[2]) * o[2],
113  2 * (v_[1] * v_[2] + v_[0] * v_[3]) * o[0] +
114  (v_[0] * v_[0] - v_[1] * v_[1] + v_[2] * v_[2] - v_[3] * v_[3]) *
115  o[1] +
116  2 * (v_[2] * v_[3] - v_[0] * v_[1]) * o[2],
117  2 * (v_[1] * v_[3] - v_[0] * v_[2]) * o[0] +
118  2 * (v_[2] * v_[3] + v_[0] * v_[1]) * o[1] +
119  (v_[0] * v_[0] - v_[1] * v_[1] - v_[2] * v_[2] + v_[3] * v_[3]) *
120  o[2]);
121  }
122 
123  //! Gets only the requested rotation coordinate of the vector
124  double get_rotated_one_coordinate_no_cache(const Vector3D &o,
125  unsigned int coord) const {
126  IMP_USAGE_CHECK(v_.get_squared_magnitude() > 0,
127  "Attempting to apply uninitialized rotation");
128  switch (coord) {
129  case 0:
130  return (v_[0] * v_[0] + v_[1] * v_[1] - v_[2] * v_[2] - v_[3] * v_[3]) *
131  o[0] +
132  2 * (v_[1] * v_[2] - v_[0] * v_[3]) * o[1] +
133  2 * (v_[1] * v_[3] + v_[0] * v_[2]) * o[2];
134  break;
135  case 1:
136  return 2 * (v_[1] * v_[2] + v_[0] * v_[3]) * o[0] +
137  (v_[0] * v_[0] - v_[1] * v_[1] + v_[2] * v_[2] - v_[3] * v_[3]) *
138  o[1] +
139  2 * (v_[2] * v_[3] - v_[0] * v_[1]) * o[2];
140 
141  break;
142  case 2:
143  return 2 * (v_[1] * v_[3] - v_[0] * v_[2]) * o[0] +
144  2 * (v_[2] * v_[3] + v_[0] * v_[1]) * o[1] +
145  (v_[0] * v_[0] - v_[1] * v_[1] - v_[2] * v_[2] + v_[3] * v_[3]) *
146  o[2];
147  break;
148  default:
149  IMP_THROW("Out of range coordinate " << coord, base::IndexException);
150  }
151  }
152 #endif
153  //! Rotate a vector around the origin
154  Vector3D get_rotated(const Vector3D &o) const {
155  IMP_USAGE_CHECK(v_.get_squared_magnitude() > 0,
156  "Attempting to apply uninitialized rotation");
157  if (!has_cache_) fill_cache();
158  return Vector3D(o * matrix_[0], o * matrix_[1], o * matrix_[2]);
159  }
160 
161  //! Gets only the requested rotation coordinate of the vector
163  unsigned int coord) const {
164  IMP_USAGE_CHECK(v_.get_squared_magnitude() > 0,
165  "Attempting to apply uninitialized rotation");
166  if (!has_cache_) fill_cache();
167  return o * matrix_[coord];
168  }
169 
170  //! Rotate a vector around the origin
171  Vector3D operator*(const Vector3D &v) const { return get_rotated(v); }
172  Vector3D get_rotation_matrix_row(int i) const {
173  IMP_USAGE_CHECK((i >= 0) && (i <= 2), "row index out of range");
174  if (!has_cache_) fill_cache();
175  return matrix_[i];
176  }
177  IMP_SHOWABLE_INLINE(Rotation3D,
178  { out << v_[0] << " " << v_[1] << " " << v_[2] << " " << v_[3]; });
179 
180  //! Return the rotation which undoes this rotation.
181  inline Rotation3D get_inverse() const {
182  IMP_USAGE_CHECK(v_.get_squared_magnitude() > 0,
183  "Attempting to invert uninitialized rotation");
184  Rotation3D ret(v_[0], -v_[1], -v_[2], -v_[3]);
185  return ret;
186  }
187 
188  //! Return the quaternion so that it can be stored
189  /** Note that there is no guarantee on which of the two
190  equivalent quaternions is returned.
191  */
192  const Vector4D &get_quaternion() const {
193  IMP_USAGE_CHECK(v_.get_squared_magnitude() > 0,
194  "Attempting to access uninitialized rotation");
195  return v_;
196  }
197 
198  //! multiply two rotations
199  Rotation3D operator*(const Rotation3D &q) const {
200  IMP_USAGE_CHECK(v_.get_squared_magnitude() > 0,
201  "Attempting to compose uninitialized rotation");
202  return compose(*this, q);
203  }
204 
205  //! Compute the rotation which when composed with r gives this
206  Rotation3D operator/(const Rotation3D &r) const {
207  IMP_USAGE_CHECK(v_.get_squared_magnitude() > 0,
208  "Attempting to compose uninitialized rotation");
209  return compose(*this, r.get_inverse());
210  }
211 
212  const Rotation3D &operator/=(const Rotation3D &r) {
213  *this = *this / r;
214  return *this;
215  }
216 
217  /** \brief Return the derivative of the position o with respect to
218  the i'th internal quaternion coefficient, for i in [0..3],
219  namely (dx/di, dy/di, dz/di) ??? TODO: is this even true ???
220  */
221  const Vector3D get_derivative(const Vector3D &o, unsigned int i) const;
222 };
223 
225 
226 //! Return a rotation that does not do anything
227 /** See Rotation3D */
228 inline Rotation3D get_identity_rotation_3d() { return Rotation3D(1, 0, 0, 0); }
229 
230 //! Return a distance between the two rotations
231 /** The distance runs between 0 and 1. More precisely,
232  the distance returned is distance between the two
233  quaternion vectors properly normalized, divided
234  by sqrt(2).
235 
236  A vector with distance d from the unit vector
237  represents a rotation of
238 
239  \f$ \theta= \cos^{-1}\left(1-\sqrt{2}d\right)\f$
240  See Rotation3D
241 */
242 inline double get_distance(const Rotation3D &r0, const Rotation3D &r1) {
243  double dot =
244  (r0.get_quaternion() - r1.get_quaternion()).get_squared_magnitude();
245  double odot =
246  (r0.get_quaternion() + r1.get_quaternion()).get_squared_magnitude();
247  double ans = std::min(dot, odot);
248  // TODO: barak - added static for efficieny
249  static const double s2 = std::sqrt(2.0);
250  double ret = ans / s2;
251  return std::max(std::min(ret, 1.0), 0.0);
252 }
253 
254 //! Generate a Rotation3D object from a rotation around an axis
255 //! that is assumed to be normalized
256 /**
257  \param[in] axis_norm the normalized rotation axis passing through (0,0,0)
258  \param[in] angle the rotation angle in radians in the
259  clockwise direction
260  \note http://en.wikipedia.org/wiki/Rotation_matrix
261  \note www.euclideanspace.com/maths/geometry/rotations/conversions/
262  angleToQuaternion/index.htm
263  See Rotation3D
264 */
265 IMPALGEBRAEXPORT Rotation3D
266  get_rotation_about_normalized_axis(const Vector3D &axis_norm, double angle);
267 
268 //! Generate a Rotation3D object from a rotation around an axis
269 /**
270  \param[in] axis the rotation axis passes through (0,0,0)
271  \param[in] angle the rotation angle in radians in the
272  clockwise direction
273  \note http://en.wikipedia.org/wiki/Rotation_matrix
274  \note www.euclideanspace.com/maths/geometry/rotations/conversions/
275  angleToQuaternion/index.htm
276  See Rotation3D
277 */
278 IMPALGEBRAEXPORT Rotation3D
279  get_rotation_about_axis(const Vector3D &axis, double angle);
280 
281 //! Create a rotation from the first vector to the second one.
282 /** See Rotation3D
283  */
284 IMPALGEBRAEXPORT Rotation3D
286 
287 //! Generate a Rotation3D object from a rotation matrix
288 /**
289  See Rotation3D
290 */
291 IMPALGEBRAEXPORT Rotation3D
292  get_rotation_from_matrix(double m00, double m01, double m02, double m10,
293  double m11, double m12, double m20, double m21,
294  double m22);
295 
296 //! Generate a Rotation3D object from a rotation matrix
297 /**
298  See Rotation3D
299 */
300 IMPALGEBRAEXPORT Rotation3D get_rotation_from_matrix(IMP_Eigen::Matrix3d m);
301 
302 //! Pick a rotation at random from all possible rotations
303 /** See Rotation3D */
304 IMPALGEBRAEXPORT Rotation3D get_random_rotation_3d();
305 
306 //! Pick a rotation at random near the provided one
307 /** This method generates a rotation that is within the provided
308  distance of center.
309  \param[in] center The center of the rotational volume
310  \param[in] distance See
311  get_distance(const Rotation3D&,const Rotation3D&)
312  for a full definition.
313 
314  \note The cost of this operation increases as distance goes to 0.
315 
316  See Rotation3D
317 */
318 IMPALGEBRAEXPORT Rotation3D
319  get_random_rotation_3d(const Rotation3D &center, double distance);
320 
321 //! Cover the space of rotations evenly
322 /** If you care about the distance between samples instead of the number
323  of samples, the "surface area" of the set of rotations is pi^2. If
324  you allocate each sample a volume of 4/3 pi d^3 (to space them d apart),
325  Then you want 3/4 pi/d^3 points.
326 
327  Creates at least num_points rotations.
328 */
329 IMPALGEBRAEXPORT Rotation3Ds
330  get_uniform_cover_rotations_3d(unsigned int num_points);
331 
332 //! Generates a nondegenerate set of Euler angles with a delta resolution
333 /**
334 \param[in] delta sample every delta angles in radians.
335  */
337  double delta);
338 
339 //! Compute a rotatation from an unnormalized quaternion
340 /** See Rotation3D */
342  VectorD<4> uv = v.get_unit_vector();
343  return Rotation3D(uv[0], uv[1], uv[2], uv[3]);
344 }
345 
346 /** See Rotation3D
347  */
348 inline Rotation3D compose(const Rotation3D &a, const Rotation3D &b) {
349  return Rotation3D(a.v_[0] * b.v_[0] - a.v_[1] * b.v_[1] - a.v_[2] * b.v_[2] -
350  a.v_[3] * b.v_[3],
351  a.v_[0] * b.v_[1] + a.v_[1] * b.v_[0] + a.v_[2] * b.v_[3] -
352  a.v_[3] * b.v_[2],
353  a.v_[0] * b.v_[2] - a.v_[1] * b.v_[3] + a.v_[2] * b.v_[0] +
354  a.v_[3] * b.v_[1],
355  a.v_[0] * b.v_[3] + a.v_[1] * b.v_[2] - a.v_[2] * b.v_[1] +
356  a.v_[3] * b.v_[0]);
357 }
358 
359 /** \name Euler Angles
360  There are many conventions for how to define Euler angles, based on choices
361  of which of the x,y,z axis to use in what order and whether the rotation
362  axis is in the body frame (and hence affected by previous rotations) or in
363  in a fixed frame. See
364  http://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles
365  for a general description.
366 
367  - All Euler angles are specified in radians.
368  - Only x-y-z order is currently supported.
369  - To convert Euler angles in a different order, one can compose a Rotation3D
370  from three rotations using get_rotation_about_axis function.
371  @{
372 */
373 
374 //! Initialize a rotation in x-y-z order from three angles
375 /** \param[in] xr Rotation around the X axis in radians
376  \param[in] yr Rotation around the Y axis in radians
377  \param[in] zr Rotation around the Z axis in radians
378  \note The three rotations are represented in the original (fixed)
379  coordinate frame.
380  See Rotation3D
381  See FixedXYZ
382 */
383 IMPALGEBRAEXPORT Rotation3D
384  get_rotation_from_fixed_xyz(double xr, double yr, double zr);
385 
386 //! Initialize a rotation from euler angles
387 /**
388  \param[in] phi Rotation around the Z axis in radians
389  \param[in] theta Rotation around the X axis in radians
390  \param[in] psi Rotation around the Z axis in radians
391  \note The first rotation is by an angle phi about the z-axis.
392  The second rotation is by an angle theta in [0,pi] about the
393  former x-axis , and the third rotation is by an angle psi
394  about the former z-axis.
395  See Rotation3D
396 */
397 IMPALGEBRAEXPORT Rotation3D
398  get_rotation_from_fixed_zxz(double phi, double theta, double psi);
399 
400 //! Generate a rotation object from Euler Angles
401 /** \note The first rotation is by an angle about the z-axis.
402  The second rotation is by an angle about the new y-axis.
403  The third rotation is by an angle about the new z-axis.
404  \param[in] Rot First Euler angle (radians) defining the rotation (Z axis)
405  \param[in] Tilt Second Euler angle (radians) defining the rotation (Y axis)
406  \param[in] Psi Third Euler angle (radians) defining the rotation (Z axis)
407  See Rotation3D
408 */
409 IMPALGEBRAEXPORT Rotation3D
410  get_rotation_from_fixed_zyz(double Rot, double Tilt, double Psi);
411 
412 //! A simple class for returning XYZ Euler angles
413 class FixedXYZ : public GeometricPrimitiveD<3> {
414  double v_[3];
415 
416  public:
417  FixedXYZ() {}
418  FixedXYZ(double x, double y, double z) {
419  v_[0] = x;
420  v_[1] = y;
421  v_[2] = z;
422  }
423  double get_x() const { return v_[0]; }
424  double get_y() const { return v_[1]; }
425  double get_z() const { return v_[2]; }
427  { out << v_[0] << " " << v_[1] << " " << v_[2]; });
428 };
429 
431 
432 //! The inverse of rotation_from_fixed_xyz()
433 /**
434  \see rotation_from_fixed_xyz()
435  See Rotation3D
436  See FixesXYZ
437 */
438 IMPALGEBRAEXPORT FixedXYZ get_fixed_xyz_from_rotation(const Rotation3D &r);
439 
440 /** @}*/
441 
442 //! Interpolate between two rotations
443 /** It f ==0, return b, if f==1 return a.
444  See Rotation3D*/
446  double f) {
447  VectorD<4> bq = b.get_quaternion(), aq = a.get_quaternion();
448  if (bq * aq < 0) bq = -bq;
449  return Rotation3D(f * aq + (1 - f) * bq);
450 }
451 
452 /** Return the rotation which takes the native x and y axes to the
453  given x and y axes.
454  The two axis must be perpendicular unit vectors.
455 */
456 IMPALGEBRAEXPORT Rotation3D
457  get_rotation_from_x_y_axes(const Vector3D &x, const Vector3D &y);
458 
459 //! Decompose a Rotation3D object into a rotation around an axis
460 /**
461  Decompose a Rotation3D object into a rotation around an axis. For all identity
462  rotations, returns the axis [1,0,0] and the angle 0.0.
463 
464  \note http://en.wikipedia.org/wiki/Rotation_matrix
465  \note www.euclideanspace.com/maths/geometry/rotations/conversions/
466  angleToQuaternion/index.htm
467  See Rotation3D
468 
469  @return axis direction and rotation about the axis in Radians
470 */
471 IMPALGEBRAEXPORT std::pair<Vector3D, double> get_axis_and_angle(
472  const Rotation3D &rot);
473 
474 typedef std::pair<Vector3D, double> AxisAnglePair;
475 #ifndef IMP_DOXYGEN
476 typedef base::Vector<AxisAnglePair> AxisAnglePairs;
477 #endif
478 
479 IMPALGEBRA_END_NAMESPACE
480 #endif /* IMPALGEBRA_ROTATION_3D_H */
Vector3D get_rotated(const Vector3D &o) const
Rotate a vector around the origin.
Definition: Rotation3D.h:154
An exception for a request for an invalid member of a container.
Rotation3D get_rotation_about_normalized_axis(const Vector3D &axis_norm, double angle)
Basic types used by IMP.
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:86
Rotation2D compose(const Rotation2D &a, const Rotation2D &b)
compose two rotations a and b
Definition: Rotation2D.h:108
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:206
A simple class for returning XYZ Euler angles.
Definition: Rotation3D.h:413
Rotation3D(const VectorD< 4 > &v, bool assume_normalized=false)
Definition: Rotation3D.h:80
#define IMP_VALUES(Name, PluralName)
Define the type for storing sets of values.
Vector3D operator*(const Vector3D &v) const
Rotate a vector around the origin.
Definition: Rotation3D.h:171
Rotation3D compose(const Rotation3D &a, const Rotation3D &b)
Definition: Rotation3D.h:348
#define IMP_SHOWABLE_INLINE(Name, how_to_show)
Declare the methods needed by an object that can be printed.
double get_rotated_one_coordinate(const Vector3D &o, unsigned int coord) const
Gets only the requested rotation coordinate of the vector.
Definition: Rotation3D.h:162
VT get_unit_vector(VT vt)
Definition: VectorBaseD.h:242
#define IMP_USAGE_CHECK_FLOAT_EQUAL(expra, exprb, message)
const Vector4D & get_quaternion() const
Return the quaternion so that it can be stored.
Definition: Rotation3D.h:192
VectorD< 4 > Vector4D
Definition: VectorD.h:399
#define IMP_USAGE_CHECK(expr, message)
A runtime test for incorrect usage of a class or method.
Rotation3D get_rotation_about_axis(const Vector3D &axis, double angle)
Generate a Rotation3D object from a rotation around an axis.
IMP::base::Vector< Rotation3D > Rotation3Ds
Definition: Rotation3D.h:224
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:181
Rotation3D get_rotation_from_fixed_zyz(double Rot, double Tilt, double Psi)
Generate a rotation object from Euler Angles.
#define IMP_NO_SWIG(x)
Hide the line when SWIG is compiled or parses it.
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:242
Rotation3D get_interpolated(const Rotation3D &a, const Rotation3D &b, double f)
Interpolate between two rotations.
Definition: Rotation3D.h:445
Rotation3D get_rotation_from_matrix(IMP_Eigen::Matrix3d m)
Generate a Rotation3D object from a rotation matrix.
Rotation3D get_rotation_from_vector4d(const VectorD< 4 > &v)
Compute a rotatation from an unnormalized quaternion.
Definition: Rotation3D.h:341
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:199
3D rotation class.
Definition: Rotation3D.h:46
Rotation3D(double a, double b, double c, double d)
Create a rotation from a quaternion.
Definition: Rotation3D.h:90
#define IMP_THROW(message, exception_name)
Throw an exception with a message.
Logging and error reporting support.
VectorD< 3 > Vector3D
Definition: VectorD.h:395
Rotation3D get_identity_rotation_3d()
Return a rotation that does not do anything.
Definition: Rotation3D.h:228
Simple 3D vector class.
Rotation3D get_rotation_from_fixed_zxz(double phi, double theta, double psi)
Initialize a rotation from euler angles.