download as script · edit page

A reference frame is the coordinate system in which data are expressed. A rotation moves a geometric object within a fixed reference frame. In MTEX, rot * v is the active rotation that moves the direction v. This is different from a frame change, which describes the same object in another reference frame without moving it. Orientations use rotations as coordinate mappings, as explained in Crystal Orientation as Coordinate Transformation.

This page assumes the three-dimensional directions introduced in Defining Three-Dimensional Vectors and basic matrix algebra.

MTEX can build a rotation from Euler angles, an axis and angle, a matrix, or the action on directions. Every constructor returns a rotation array. MTEX stores its proper part internally as a unit quaternion.

import numpy as np
from mtex import *
plottingConvention.default('y↑→x')

Euler Angles

Euler angles describe a rotation by three successive angular steps. The axes, their order, and the direction of the mapping belong to the convention. Three numbers without that convention are therefore ambiguous.

Texture analysis commonly uses the following names:

  • Bunge \((\varphi_1,\Phi,\varphi_2)\), with the ZXZ axis sequence
  • Matthies \((\alpha,\beta,\gamma)\), with the ZYZ axis sequence
  • Roe \((\Psi,\Theta,\Phi)\)
  • Kocks \((\Psi,\Theta,\varphi)\)
  • Canova \((\omega,\Theta,\varphi)\)

A new MTEX installation uses Bunge as its preference. Reusable code should name the convention so that a user’s preference cannot change the input.

rotBunge = rotation.byEuler(30 * degree, 50 * degree, 10 * degree, 'Bunge')
rotRoe = rotation.byEuler(30 * degree, 50 * degree, 10 * degree, 'Roe')
angle(rotBunge, rotRoe) / degree
69.5509

The nonzero angle confirms that equal triplets in different conventions need not describe the same rotation. Angles are radians throughout MTEX, which is why values in degrees are multiplied by degree.

The convention used to read an existing rotation can also be named. Euler returns the three angles in radians; the rotation constructed with the Roe triplet above reads, in degrees,

np.array(Euler(rotRoe, 'Roe')) / degree
array([30., 50., 10.])

np.array(Euler(rotRoe, 'Bunge')) / degree
array([120.,  50., 280.])

These are two descriptions of the same rotation. The separate question of which way an orientation maps coordinates is covered in MTEX vs. Bunge Convention.

For interactive work, setMTEXpref changes the session’s default Euler convention. Explicit conventions remain safer in files that must be reproducible.

Euler Angles Are Not Unique

Even after the convention is fixed, Euler angles are not always unique. In the Bunge convention, when the middle angle \(\Phi\) is zero, only the sum of the first and third angles is determined. These two triplets therefore describe the same rotation.

rotA = rotation.byEuler(10 * degree, 0, 20 * degree, 'Bunge')
rotB = rotation.byEuler(15 * degree, 0, 15 * degree, 'Bunge')
angle(rotA, rotB) / degree
1.2722e-14

The zero angular difference is the Euler-angle singularity. It is a property of the representation, not an additional physical freedom of the rotation.

Axis and Angle

Every non-identity proper rotation in three dimensions turns about an axis. MTEX reports an angle between \(0\) and \(180^\circ\). The identity has no unique axis. At \(180^\circ\), the two signs of the axis describe the same rotation.

rot = rotation.byAxisAngle(vector3d.X, 30 * degree)

The axis and angle can be read from any rotation, however it was defined.

rot.axis()
vector3d (y↑→x)
  x  y  z
  1  0  0

rot.angle() / degree
30.0000

The following figure draws the axis in blue, a direction before the rotation in grey, and the rotated direction in red.

v = normalize(vector3d(0.2, 0.3, 1))
arrow3d(1.5 * rot.axis(), faceColor='blue')
hold(True)
arrow3d(1.2 * v, faceColor=[.45, .45, .45])
arrow3d(1.2 * (rot * v), faceColor='red')
hold(False)

Notice that the blue axis stays fixed while the red direction has turned around it. This fixed direction is the defining axis of the rotation.

Rodrigues–Frank Vector

The Rodrigues–Frank vector packs axis and angle into one vector. It is the rotation axis scaled by \(\tan(\omega/2)\).

R = rot.Rodrigues()
R
vector3d (y↑→x)
      x  y  z
  0.268  0  0

Its length recovers the rotation angle.

2 * np.arctan(norm(R)) / degree
30.0000

Constructing a rotation from the vector returns the original rotation, as shown by their zero angular difference.

rotFromR = rotation.byRodrigues(R)
angle(rot, rotFromR) / degree
0

Rotation Matrix

A proper rotation is also represented by an orthogonal \(3 \times 3\) matrix with determinant \(+1\).

M = rot.matrix()
M
array([[ 1.   ,  0.   ,  0.   ],
       [ 0.   ,  0.866, -0.5  ],
       [ 0.   ,  0.5  ,  0.866]])

Its columns are the rotated basis directions X, Y, and Z. Rotating Y gives the second column of M.

rot * vector3d.Y
vector3d (y↑→x)
  x      y    z
  0  0.866  0.5

rotation.byMatrix reconstructs the rotation.

rotFromM = rotation.byMatrix(M)
angle(rot, rotFromM) / degree
0

The constructor assumes that its input is orthogonal; it does not validate a matrix imported from another program. A matrix with determinant \(-1\) is accepted by orthogonalTransform.byMatrix and stored as an improper rotation, as discussed in Improper Rotations.

Defined by What It Does

Often the rotation is known only through the directions it must map. Two non-collinear pairs determine exactly one rotation when the angle within the first pair equals the angle within the second pair.

u1, v1 = vector3d.X, vector3d.Y
u2, v2 = vector3d.Z, vector3d.Z
rot = rotation.map(u1, v1, u2, v2)
cat(rot * u1, rot * u2)
vector3d (y↑→x)
  size: 2
  x  y  z
  0  1  0
  0  0  1

The output reproduces the two target directions Y and Z. MTEX raises an error if the angles within the pairs disagree or if the input directions are collinear.

One pair leaves a rotation about the target direction undetermined. rotation.map then returns the smallest-angle rotation taking the first direction to the second.

rot = rotation.map(vector3d.Z, vector3d.Y)
rot * vector3d.Z
vector3d (y↑→x)
  x  y  z
  0  1  0

For opposite directions this smallest angle is \(180^\circ\), but its axis is not unique. Supply a second pair when the particular half turn matters.

Fitting Measured Directions

More than two measured pairs will usually not agree exactly. The least-squares solution from rotation.fit makes rotFit * left as close as possible to right.

left = vector3d.rand(5)
right = rot * left + 0.1 * vector3d.rand(5)
rotFit = rotation.fit(left, right)
angle(rot, rotFit) / degree
2.0085

The nonzero error comes from the added perturbations. By default, rotation.fit uses Horn’s unit-quaternion method. The option method='kabsch' selects the Kabsch matrix method.

Random Rotations

rotation.rand samples the uniform, or Haar, distribution on the rotation group. Its size arguments create an array of rotations, just as size arguments do for NumPy arrays.

rotations = rotation.rand(100)
len(rotations)
100

The output confirms that the array contains 100 rotations. The maxAngle option restricts samples to a ball around the identity. Sampling from a nonuniform distribution is covered in Random Sampling.

Quaternions

A proper rotation is defined by the four coordinates of a unit quaternion. The quaternion and its negative encode the same rotation.

q = quaternion(0.5, 0.5, 0.5, 0.5)
norm(q)
1

The norm is one, so q can be passed to the rotation constructor.

rotQ = rotation(q)
rotMinusQ = rotation(-q)
angle(rotQ, rotMinusQ) / degree
0

The zero difference demonstrates the double representation directly. Rotation Representations explains the geometry and numerical trade-offs of quaternions and rotation vectors.

Constructor Index

The constructors above cover the usual inputs. The complete set also includes generated, imported, and improper rotations.

input constructor
Euler angles rotation.byEuler
axis and angle rotation.byAxisAngle
matrix rotation.byMatrix
Rodrigues–Frank vector rotation.byRodrigues
homochoric vector rotation.byHomochoric
unit quaternion rotation(q)
exact direction pairs rotation.map
noisy direction pairs rotation.fit
identity, random, or missing rotation.id, rotation.rand, rotation.nan
file rotation.load
distribution odf.discreteSample
inversion or reflection rotation.inversion, reflection

References

Next

Representations compares the coordinate descriptions of rotation space. Improper Rotations then treats inversion and reflection, and Operations composes, inverts, and applies rotations. A rotation carrying crystal and specimen symmetry becomes an orientation.

Technical Details

The port stores a rotation as its unit quaternion and derives the axis, the angle, the Rodrigues vector and the matrix on demand; what MATLAB implements as a method is a method with parentheses here, rot.axis(), rot.angle(), rot.matrix(). Euler returns the three angles in radians as a tuple, where MATLAB without an output prints them in degrees; the page divides the array by degree. A matrix of determinant \(-1\) goes through orthogonalTransform.byMatrix, since a rotation is proper here.

Citing this page. This page is part of the documentation of MTEX, a free and open source MATLAB toolbox for analyzing and modeling crystallographic textures. It was written by The MTEX Developers and is published at https://mtex-toolbox.github.io/RotationDefinition_py.html. If you use MTEX, or reuse text or figures from this page, in your research, please cite

F. Bachmann, R. Hielscher, H. Schaeben: Texture Analysis with MTEX - Free and Open Source Software Toolbox, Solid State Phenomena 160 (2010), 63-68. 10.4028/www.scientific.net/SSP.160.63

BibTeX
@article{bachmann2010mtex,
  author  = {F. Bachmann and R. Hielscher and H. Schaeben},
  title   = {Texture Analysis with MTEX - Free and Open Source Software Toolbox},
  journal = {Solid State Phenomena},
  volume  = {160},
  pages   = {63-68},
  year    = {2010},
  doi     = {10.4028/www.scientific.net/SSP.160.63},
  url     = {https://doi.org/10.4028/www.scientific.net/SSP.160.63}
}

Other papers describing specific MTEX methods are listed under Publications — please cite the one that best fits your application. The MTEX source code is licensed under the GNU General Public License v2.0; the text and figures of this documentation are licensed under CC BY 4.0, which permits reuse — including by automated systems — provided The MTEX Developers and this page are credited.