0
# Rotation Conversions
1
2
Convert between quaternions and various rotation representations including rotation matrices, axis-angle vectors, Euler angles, and spherical coordinates. These functions enable seamless integration with other rotation libraries and mathematical frameworks.
3
4
## Capabilities
5
6
### Rotation Matrix Conversions
7
8
Convert between quaternions and 3x3 rotation matrices.
9
10
```python { .api }
11
def as_rotation_matrix(q):
12
"""
13
Convert quaternions to 3x3 rotation matrices.
14
15
Args:
16
q (quaternion or quaternion array): Input quaternions (need not be normalized)
17
18
Returns:
19
ndarray: Rotation matrices with shape q.shape + (3, 3)
20
21
Raises:
22
ZeroDivisionError: If any input quaternion has zero norm
23
24
Notes:
25
For quaternion q and vector v, the rotated vector is:
26
rotated_v = rotation_matrix @ v.vec
27
where v.vec is the 3D vector part of quaternion v.
28
"""
29
30
def from_rotation_matrix(rot, nonorthogonal=True):
31
"""
32
Convert 3x3 rotation matrices to unit quaternions.
33
34
Args:
35
rot (array_like): Rotation matrices with shape (..., 3, 3)
36
nonorthogonal (bool): Use robust algorithm for non-orthogonal matrices (default: True)
37
38
Returns:
39
quaternion array: Unit quaternions with shape rot.shape[:-2]
40
41
Raises:
42
LinAlgError: If eigenvalue solutions do not converge (scipy algorithm)
43
44
Notes:
45
Uses Bar-Itzhack algorithm (scipy.linalg) when nonorthogonal=True for robustness.
46
Falls back to Markley algorithm when scipy unavailable or nonorthogonal=False.
47
"""
48
```
49
50
### Vector Rotation
51
52
Apply quaternion rotations to 3D vectors efficiently.
53
54
```python { .api }
55
def rotate_vectors(R, v, axis=-1):
56
"""
57
Rotate 3D vectors using quaternions.
58
59
Args:
60
R (quaternion array): Rotation quaternions
61
v (array_like): 3D vectors to rotate
62
axis (int): Axis of v containing vector components (must have length 3)
63
64
Returns:
65
ndarray: Rotated vectors with shape R.shape + v.shape
66
67
Notes:
68
More efficient than individual quaternion products when rotating
69
multiple vectors with the same quaternion. Uses matrix multiplication
70
internally for vectorized operations.
71
"""
72
```
73
74
### Axis-Angle Representations
75
76
Convert between quaternions and axis-angle (rotation vector) representations.
77
78
```python { .api }
79
def as_rotation_vector(q):
80
"""
81
Convert quaternions to axis-angle representation.
82
83
Args:
84
q (quaternion or quaternion array): Input quaternions (need not be normalized)
85
86
Returns:
87
ndarray: Rotation vectors with shape q.shape + (3,)
88
89
Notes:
90
Each vector represents rotation axis with magnitude equal to rotation
91
angle in radians. No error for zero-norm quaternions (produces NaN).
92
"""
93
94
def from_rotation_vector(rot):
95
"""
96
Convert axis-angle vectors to unit quaternions.
97
98
Args:
99
rot (array_like): Rotation vectors with shape (..., 3)
100
101
Returns:
102
quaternion array: Unit quaternions with shape rot.shape[:-1]
103
104
Notes:
105
Vector magnitude is rotation angle in radians, direction is rotation axis.
106
Uses quaternion exponential for conversion.
107
"""
108
```
109
110
### Euler Angle Conversions
111
112
Convert between quaternions and Euler angles with caveats about Euler angle limitations.
113
114
```python { .api }
115
def as_euler_angles(q):
116
"""
117
Convert quaternions to Euler angles (ZYZ convention).
118
119
Args:
120
q (quaternion or quaternion array): Input quaternions (need not be normalized)
121
122
Returns:
123
ndarray: Euler angles (alpha, beta, gamma) with shape q.shape + (3,)
124
125
Raises:
126
AllHell: Metaphorically, if you use Euler angles when you shouldn't
127
128
Notes:
129
Uses ZYZ convention: R = exp(alpha*z/2) * exp(beta*y/2) * exp(gamma*z/2)
130
Angles in radians. Euler angles have singularities and are generally
131
discouraged. See package documentation warnings about Euler angles.
132
"""
133
134
def from_euler_angles(alpha_beta_gamma, beta=None, gamma=None):
135
"""
136
Create quaternions from Euler angles (ZYZ convention).
137
138
Args:
139
alpha_beta_gamma (array_like): Euler angles array with last dim 3, or alpha values
140
beta (array_like, optional): Beta angles if alpha_beta_gamma contains only alpha
141
gamma (array_like, optional): Gamma angles if alpha_beta_gamma contains only alpha
142
143
Returns:
144
quaternion array: Quaternions from Euler angle inputs
145
146
Notes:
147
Uses ZYZ convention with angles in radians. Inputs must broadcast together.
148
Strongly consider using other rotation representations instead.
149
"""
150
```
151
152
### Spherical Coordinate Conversions
153
154
Convert between quaternions and spherical coordinates (theta, phi).
155
156
```python { .api }
157
def as_spherical_coords(q):
158
"""
159
Convert quaternions to spherical coordinates.
160
161
Args:
162
q (quaternion or quaternion array): Input quaternions (must be nonzero)
163
164
Returns:
165
ndarray: Spherical coordinates (theta, phi) with shape q.shape + (2,)
166
167
Notes:
168
Returns point on sphere where quaternion rotates z-axis. Loses some
169
information compared to full quaternion representation.
170
"""
171
172
def from_spherical_coords(theta_phi, phi=None):
173
"""
174
Create quaternions from spherical coordinates.
175
176
Args:
177
theta_phi (array_like): Coordinate array with last dim 2, or theta values
178
phi (array_like, optional): Phi coordinates if theta_phi contains only theta
179
180
Returns:
181
quaternion array: Quaternions rotating z-axis to specified coordinates
182
183
Notes:
184
Creates quaternion R = exp(phi*z/2) * exp(theta*y/2). Angles in radians.
185
Rotates z-axis to given spherical coordinates and x,y to local tangent basis.
186
"""
187
```
188
189
## Usage Examples
190
191
```python
192
import quaternion
193
import numpy as np
194
195
# Create sample quaternions
196
q = quaternion.quaternion(1, 0, 0, 0) # Identity
197
q_rot = quaternion.from_euler_angles(0, np.pi/4, 0) # 45° rotation around y
198
199
# Convert to rotation matrix
200
R = quaternion.as_rotation_matrix(q_rot)
201
print(f"Rotation matrix shape: {R.shape}") # (3, 3)
202
203
# Rotate vectors
204
vectors = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) # Identity matrix columns
205
rotated = quaternion.rotate_vectors(q_rot, vectors.T, axis=0)
206
print(f"Rotated vectors shape: {rotated.shape}")
207
208
# Convert to axis-angle representation
209
axis_angle = quaternion.as_rotation_vector(q_rot)
210
print(f"Axis-angle vector: {axis_angle}")
211
212
# Round-trip conversion
213
q_recovered = quaternion.from_rotation_vector(axis_angle)
214
print(f"Original close to recovered: {quaternion.allclose(q_rot, q_recovered)}")
215
216
# Convert to spherical coordinates
217
theta_phi = quaternion.as_spherical_coords(q_rot)
218
print(f"Spherical coords: theta={theta_phi[0]:.3f}, phi={theta_phi[1]:.3f}")
219
220
# Create from rotation matrix
221
R_input = np.array([[0, 1, 0], [-1, 0, 0], [0, 0, 1]]) # 90° rotation around z
222
q_from_matrix = quaternion.from_rotation_matrix(R_input)
223
print(f"Quaternion from matrix: {q_from_matrix}")
224
225
# Demonstrate quaternion-matrix equivalence
226
test_vector = np.array([1, 0, 0])
227
rotated_by_q = quaternion.as_vector_part(q_from_matrix * quaternion.from_vector_part(test_vector) * q_from_matrix.conjugate())
228
rotated_by_matrix = R_input @ test_vector
229
print(f"Quaternion rotation: {rotated_by_q}")
230
print(f"Matrix rotation: {rotated_by_matrix}")
231
print(f"Results match: {np.allclose(rotated_by_q, rotated_by_matrix)}")
232
```