Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit f059296

Browse files
Fix 3D rotation precession
Fix arcsin domain error Revert to simplified trig Linting tests
1 parent f8592cb commit f059296

File tree

2 files changed

+13
-10
lines changed

2 files changed

+13
-10
lines changed

lib/mpl_toolkits/mplot3d/axes3d.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1568,10 +1568,11 @@ def _on_move(self, event):
15681568
q = _Quaternion.from_cardan_angles(elev, azim, roll)
15691569

15701570
# Update quaternion - a variation on Ken Shoemake's ARCBALL
1571-
current_vec = self._arcball(self._sx/w, self._sy/h)
1572-
new_vec = self._arcball(x/w, y/h)
1571+
scale = np.sqrt(2)/2 # slow down the rate of rotation
1572+
current_vec = self._arcball(self._sx*scale/w, self._sy*scale/h)
1573+
new_vec = self._arcball(x*scale/w, y*scale/h)
15731574
dq = _Quaternion.rotate_from_to(current_vec, new_vec)
1574-
q = dq * q
1575+
q = dq * dq * q
15751576

15761577
# Convert to elev, azim, roll
15771578
elev, azim, roll = q.as_cardan_angles()
@@ -4020,11 +4021,14 @@ def from_cardan_angles(cls, elev, azim, roll):
40204021
def as_cardan_angles(self):
40214022
"""
40224023
The inverse of `from_cardan_angles()`.
4024+
This function acts on the quaternion as if it were unit normed.
40234025
Note that the angles returned are in radians, not degrees.
40244026
"""
40254027
qw = self.scalar
40264028
qx, qy, qz = self.vector[..., :]
40274029
azim = np.arctan2(2*(-qw*qz+qx*qy), qw*qw+qx*qx-qy*qy-qz*qz)
4028-
elev = np.arcsin( 2*( qw*qy+qz*qx)/(qw*qw+qx*qx+qy*qy+qz*qz)) # noqa E201
4030+
# Clip below is to avoid floating point round-off errors
4031+
elev = np.arcsin(np.clip(2*(qw*qy+qz*qx)
4032+
/ (qw*qw+qx*qx+qy*qy+qz*qz), -1, 1))
40294033
roll = np.arctan2(2*( qw*qx-qy*qz), qw*qw-qx*qx-qy*qy+qz*qz) # noqa E201
40304034
return elev, azim, roll

lib/mpl_toolkits/mplot3d/tests/test_axes3d.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1950,10 +1950,10 @@ def test_rotate():
19501950
for roll, dx, dy, new_elev, new_azim, new_roll in [
19511951
[0, 0.5, 0, 0, -90, 0],
19521952
[30, 0.5, 0, 30, -90, 0],
1953-
[0, 0, 0.5, -90, 0, 0],
1953+
[0, 0, 0.5, -90, -180, 180],
19541954
[30, 0, 0.5, -60, -90, 90],
1955-
[0, 0.5, 0.5, -45, -90, 45],
1956-
[30, 0.5, 0.5, -15, -90, 45]]:
1955+
[0, np.sqrt(2)/4, np.sqrt(2)/4, -45, -90, 45],
1956+
[30, np.sqrt(2)/4, np.sqrt(2)/4, -15, -90, 45]]:
19571957
fig = plt.figure()
19581958
ax = fig.add_subplot(1, 1, 1, projection='3d')
19591959
ax.view_init(0, 0, roll)
@@ -1967,9 +1967,8 @@ def test_rotate():
19671967
xdata=dx*ax._pseudo_w, ydata=dy*ax._pseudo_h))
19681968
fig.canvas.draw()
19691969

1970-
assert np.isclose(ax.elev, new_elev)
1971-
assert np.isclose(ax.azim, new_azim)
1972-
assert np.isclose(ax.roll, new_roll)
1970+
np.testing.assert_allclose((ax.elev, ax.azim, ax.roll),
1971+
(new_elev, new_azim, new_roll), atol=1e-6)
19731972

19741973

19751974
def test_pan():

0 commit comments

Comments
 (0)