Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ENH]: Natural 3D rotation with mouse #28288

Closed
MischaMegens2 opened this issue May 23, 2024 · 1 comment
Closed

[ENH]: Natural 3D rotation with mouse #28288

MischaMegens2 opened this issue May 23, 2024 · 1 comment

Comments

@MischaMegens2
Copy link
Contributor

Problem

In mplot3d, the plot currently reacts differently to dragging the mouse, depending on the orientation of the axes. In the default orientation, moving the mouse left/right or up/down tilts the plot left/right or up/down correspondingly, which is quite natural and intuitive. However, when the plot is rotated so that we are looking down the z-axis, then moving the mouse up/down does not tilt the plot up/down as expected, but rotates it around the z-axis. The situation reminds of gimball lock. It is clumsy and annoying.
Additionally, the 'roll' angle currently cannot be controlled with the mouse (issue #14451 and PR #21426 mention this) - at present, the two degrees of freedom of the mouse (left-right and up-down) correspond directly to two of the rotational degrees of freedom of the plot (azimuth and elevation), whereas there are in fact three (i.e., azimuth, elevation, and roll; or heading, tilt, and bank, if you will). Rotations around three cartesian axes do look essentially different (one can turn up/down, turn left/right, or twist left/right-handed). Controlling only two limits the accessible orientations.

Proposed solution

For a natural interaction with the mouse, it is desirable that the figure reacts in the same way to mouse movements, regardless of orientation: there should be no difference between "poles" and "equator" of the figure, and no 'gimbal lock'.
Of course this problem is not new - satisfying solutions have been devised in the nineties of the last century, e.g., Ken Shoemake's 'arcball' [1]. All that is needed to implement this in mplot3d is a small change to axes3d._onmove(), together with a minimal quaternion class - this avoids an additional dependency on a large package like numpy-quaternion.
The quaternion class can be made internal, to hide it; or it can be exposed since it can be more generally useful.

  1. [Ken Shoemake, "ARCBALL: A user interface for specifying three-dimensional rotation using a mouse." in Proceedings of Graphics Interface '92, 1992, pp. 151-156, https://doi.org/10.20380/GI1992.18]
@MischaMegens2 MischaMegens2 changed the title [ENH]: natural 3D rotation with mouse [ENH]: Natural 3D rotation with mouse May 23, 2024
MischaMegens2 added a commit to MischaMegens2/matplotlib that referenced this issue May 24, 2024
- Addresses Issue matplotlib#28288
- Introduces three-dimensional rotation by mouse using a variation on Ken Shoemake's ARCBALL
- Provides a minimal Quaternion class, to avoid an additional  dependency on a large package like 'numpy-quaternion'
MischaMegens2 added a commit to MischaMegens2/matplotlib that referenced this issue May 24, 2024
- Addresses Issue matplotlib#28288
- Introduces three-dimensional rotation by mouse using a variation on Ken Shoemake's ARCBALL
- Provides a minimal Quaternion class, to avoid an additional  dependency on a large package like 'numpy-quaternion'
@MischaMegens2
Copy link
Contributor Author

This what the mouse rotation looks like on the surface3d.py example, before the pull request #28290
(play the movie):

elev_azim.mov

(you can see the figure sometimes rotates, when you'd think it should tilt; or it moves in the opposite direction as the mouse).
After the patch:

arcball.mov

(Now the movement is much more consistent: the figure tilts up/down, left/right if you move the mouse up/down, left/right near the center; near the edge, the mouse rotates the figure).

MischaMegens2 added a commit to MischaMegens2/matplotlib that referenced this issue Jun 3, 2024
- Addresses Issue matplotlib#28288
- Introduces three-dimensional rotation by mouse using a variation on Ken Shoemake's ARCBALL
- Provides a minimal Quaternion class, to avoid an additional  dependency on a large package like 'numpy-quaternion'
MischaMegens2 added a commit to MischaMegens2/matplotlib that referenced this issue Jun 4, 2024
- Addresses Issue matplotlib#28288
- Introduces three-dimensional rotation by mouse using a variation on Ken Shoemake's ARCBALL
- Provides a minimal Quaternion class, to avoid an additional  dependency on a large package like 'numpy-quaternion'
scottshambaugh pushed a commit that referenced this issue Jun 5, 2024
* Natural 3D rotation with mouse

- Addresses Issue #28288
- Introduces three-dimensional rotation by mouse using a variation on Ken Shoemake's ARCBALL
- Provides a minimal Quaternion class, to avoid an additional  dependency on a large package like 'numpy-quaternion'

* Suggestions from reviewers

- makes axes3d.Quaternion a private _Quaternion class
- shortens as_cardan_angles()
- adds two extra tests to test_axes3d::test_quaternion(): from_cardan_angles() should return a unit quaternion, and as_cardan_angles() should be insensitive to quaternion magnitude
- updates "mplot3d View Angles" documentation (the mouse can control both azimuth, elevation, and roll; and matlab does have a roll angle nowadays)
- put in a reference to quaternion multiplication using scalar and vector parts (wikipedia)
- rename class method that constructs a quaternion from two vectors to `rotate_from_to()`
- clarify docstring: "The quaternion for the shortest rotation from vector r1 to vector r2"
- issue warning when vectors are anti-parallel: "shortest rotation is ambiguous"
- construct a perpendicular vector for generic r2 == -r1
- add test case for anti-parallel vectors
- add test for the warning
- add reference to Ken Shoemake's arcball, in axes3d.py
- point out that angles are in radians, not degrees, in quaternion class docstrings
- in test_axes3d, add an import for axes3d._Quaternion, to avoid repetition
- add Quaternion conjugate(), and tests for it
- add Quaternion norm, and tests
- add Quaternion normalize(), and tests
- add Quaternion reciprocal(), and tests
- add Quaternion division, and tests
- add Quaternion rotate(vector), and a test

* Update axes3d.py's arcball

- change argument  from 2 element numpy array to x, y
- add type hints

* Update doc/api/toolkits/mplot3d/view_angles.rst

---------

Co-authored-by: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com>
@QuLogic QuLogic added this to the v3.10.0 milestone Jun 5, 2024
muchojp pushed a commit to muchojp/matplotlib that referenced this issue Jun 6, 2024
* Natural 3D rotation with mouse

- Addresses Issue matplotlib#28288
- Introduces three-dimensional rotation by mouse using a variation on Ken Shoemake's ARCBALL
- Provides a minimal Quaternion class, to avoid an additional  dependency on a large package like 'numpy-quaternion'

* Suggestions from reviewers

- makes axes3d.Quaternion a private _Quaternion class
- shortens as_cardan_angles()
- adds two extra tests to test_axes3d::test_quaternion(): from_cardan_angles() should return a unit quaternion, and as_cardan_angles() should be insensitive to quaternion magnitude
- updates "mplot3d View Angles" documentation (the mouse can control both azimuth, elevation, and roll; and matlab does have a roll angle nowadays)
- put in a reference to quaternion multiplication using scalar and vector parts (wikipedia)
- rename class method that constructs a quaternion from two vectors to `rotate_from_to()`
- clarify docstring: "The quaternion for the shortest rotation from vector r1 to vector r2"
- issue warning when vectors are anti-parallel: "shortest rotation is ambiguous"
- construct a perpendicular vector for generic r2 == -r1
- add test case for anti-parallel vectors
- add test for the warning
- add reference to Ken Shoemake's arcball, in axes3d.py
- point out that angles are in radians, not degrees, in quaternion class docstrings
- in test_axes3d, add an import for axes3d._Quaternion, to avoid repetition
- add Quaternion conjugate(), and tests for it
- add Quaternion norm, and tests
- add Quaternion normalize(), and tests
- add Quaternion reciprocal(), and tests
- add Quaternion division, and tests
- add Quaternion rotate(vector), and a test

* Update axes3d.py's arcball

- change argument  from 2 element numpy array to x, y
- add type hints

* Update doc/api/toolkits/mplot3d/view_angles.rst

---------

Co-authored-by: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants