Skip to content

Commit 486d670

Browse files
committed
Add example showing how to combine rotations (from left to right)
Signed-off-by: Håkon Wiik Ånes <[email protected]>
1 parent e45da36 commit 486d670

File tree

2 files changed

+85
-0
lines changed

2 files changed

+85
-0
lines changed

examples/rotations/README.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Rotations
2+
=========
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
r"""
2+
===================
3+
Combining rotations
4+
===================
5+
6+
This example demonstrates how to combine two rotations :math:`g_A` and
7+
:math:`g_B`, i.e. from left to right like so
8+
9+
.. math::
10+
g_{AB} = g_A \cdot g_B.
11+
12+
This order follows from the convention of passive rotations chosen in
13+
orix which follows :cite:`rowenhorst2015consistent`.
14+
15+
To convince ourselves that this order is correct, we will reproduce the
16+
example given by Rowenhorst and co-workers in section 4.2.2 in the above
17+
mentioned paper. We want to rotate a vector :math:`(0, 0, z)` by two
18+
rotations: rotation :math:`A` by :math:`120^{\circ}` around
19+
:math:`[1 1 1]`, and rotation :math:`B` by :math:`180^{\circ}` around
20+
:math:`[1 1 0]`; rotation :math:`A` will be carried out first, followed
21+
by rotation :math:`B`.
22+
23+
Note that a negative angle when *defining* a rotation in the axis-angle
24+
representation is necessary for consistent transformations between
25+
rotation representations. The rotation still rotates a vector
26+
intuitively.
27+
"""
28+
29+
import matplotlib.pyplot as plt
30+
31+
from orix import plot
32+
from orix.quaternion import Rotation
33+
from orix.vector import Vector3d
34+
35+
plt.rcParams.update({"font.size": 12, "grid.alpha": 0.5})
36+
37+
gA = Rotation.from_axes_angles([1, 1, 1], -120, degrees=True)
38+
gB = Rotation.from_axes_angles([1, 1, 0], -180, degrees=True)
39+
gAB = gA * gB
40+
41+
# Compare with quaternions and orientation matrices from section 4.2.2
42+
# in Rowenhorst et al. (2015)
43+
g_all = Rotation.stack((gA, gB, gAB)).squeeze()
44+
print("gA, gB and gAB:\n* As quaternions:\n", g_all)
45+
print("* As orientation matrices:\n", g_all.to_matrix().squeeze().round(10))
46+
47+
v_start = Vector3d.zvector()
48+
v_end = gAB * v_start
49+
print(
50+
"Point rotated by gAB:\n",
51+
v_start.data.squeeze().tolist(),
52+
"->",
53+
v_end.data.squeeze().round(10).tolist(),
54+
)
55+
56+
# Illustrate the steps of the rotation by plotting the vector before
57+
# (red), during (green) and after (blue) the rotation and the rotation
58+
# paths (first: cyan; second: magenta)
59+
v_intermediate = gB * v_start
60+
61+
v_si_path = Vector3d.from_path_ends(Vector3d.stack((v_start, v_intermediate)))
62+
v_sie_path = Vector3d.from_path_ends(Vector3d.stack((v_intermediate, v_end)))
63+
64+
fig = plt.figure(layout="tight")
65+
ax0 = fig.add_subplot(121, projection="stereographic", hemisphere="upper")
66+
ax1 = fig.add_subplot(122, projection="stereographic", hemisphere="lower")
67+
ax0.stereographic_grid(), ax1.stereographic_grid()
68+
Vector3d.stack((v_start, v_intermediate, v_end)).scatter(
69+
figure=fig,
70+
s=50,
71+
c=["r", "g", "b"],
72+
axes_labels=["e1", "e2"],
73+
)
74+
ax0.plot(v_si_path, color="c"), ax1.plot(v_si_path, color="c")
75+
ax0.plot(v_sie_path, color="m"), ax1.plot(v_sie_path, color="m")
76+
gA.axis.scatter(figure=fig, c="orange")
77+
gB.axis.scatter(figure=fig, c="k")
78+
text_kw = dict(bbox=dict(alpha=0.5, fc="w", boxstyle="round,pad=0.1"), ha="right")
79+
ax0.text(v_start, s="Start", **text_kw)
80+
ax1.text(v_intermediate, s="Intermediate", **text_kw)
81+
ax1.text(v_end, s="End", **text_kw)
82+
ax1.text(gA.axis, s="Axis gA", **text_kw)
83+
ax0.text(gB.axis, s="Axis gB", **text_kw)

0 commit comments

Comments
 (0)