.. only:: html
.. note::
:class: sphx-glr-download-link-note
Click :ref:`here ` to download the full example code
.. rst-class:: sphx-glr-example-title
.. _sphx_glr_examples_rotation3d.py:
Rotation in 3D Space
====================
This tutorial demonstrates how rotate a group of points in 3D space.
To begin with, we must understand that rotation is a linear transformation.
The set of all rotations forms the group SO(3). It is a Lie group that each
group element is described by an orthogonal 3x3 matrix.
That is, if you have two points :math:`\vec{r}_1` and :math:`\vec{r}_2`, and
you want to rotate the two points along the same axis for the same number of
degrees, then there is a single orthogonal matrix :math:`R` that no matter
the value of :math:`\vec{r}_1` and :math:`\vec{r}_2`, their rotation is always
:math:`R\cdot\vec{r}_1` and :math:`R\cdot\vec{r}_2`.
Let's import libraries first
.. code-block:: default
import math
import torch
import pytest
import sys
import nnp.so3 as so3
Let's first take a look at a special case: rotating the three unit vectors
``(1, 0, 0)``, ``(0, 1, 0)`` and ``(0, 0, 1)`` along the diagonal for 120
degree, this should permute these points:
.. code-block:: default
rx = torch.tensor([1, 0, 0])
ry = torch.tensor([0, 1, 0])
rz = torch.tensor([0, 0, 1])
points = torch.stack([rx, ry, rz])
Now let's compute the rotation matrix
.. code-block:: default
axis = torch.ones(3) / math.sqrt(3) * (math.pi * 2 / 3)
R = so3.rotate_along(axis)
Note that we need to do matrix-vector product for all these unit vectors
so we need to do a transpose in order to use ``@`` operator.
.. code-block:: default
rotated = (R @ points.float().t()).t()
print(rotated)
.. rst-class:: sphx-glr-script-out
Out:
.. code-block:: none
tensor([[ 0.0000e+00, 1.0000e+00, -2.1865e-08],
[ 0.0000e+00, 0.0000e+00, 1.0000e+00],
[ 1.0000e+00, 0.0000e+00, 0.0000e+00]])
After this rotation, the three vector permutes: rx->ry, ry->rz, rz->rx. Let's
programmically check that. This check will be run by pytest later.
.. code-block:: default
def test_rotated_unit_vectors():
expected = torch.stack([ry, rz, rx]).float()
assert torch.allclose(rotated, expected, atol=1e-5)
Now let's run all the tests
.. code-block:: default
if __name__ == '__main__':
pytest.main([sys.argv[0], '-v'])
.. rst-class:: sphx-glr-script-out
Out:
.. code-block:: none
============================= test session starts ==============================
platform linux -- Python 3.7.7, pytest-5.4.3, py-1.8.2, pluggy-0.13.1 -- /opt/hostedtoolcache/Python/3.7.7/x64/bin/python
cachedir: .pytest_cache
rootdir: /home/runner/work/nnp/nnp, inifile: setup.cfg
collecting ... collected 1 item
rotation3d.py::test_rotated_unit_vectors PASSED [100%]
============================== 1 passed in 0.01s ===============================
.. rst-class:: sphx-glr-timing
**Total running time of the script:** ( 0 minutes 0.643 seconds)
.. _sphx_glr_download_examples_rotation3d.py:
.. only :: html
.. container:: sphx-glr-footer
:class: sphx-glr-footer-example
.. container:: sphx-glr-download sphx-glr-download-python
:download:`Download Python source code: rotation3d.py `
.. container:: sphx-glr-download sphx-glr-download-jupyter
:download:`Download Jupyter notebook: rotation3d.ipynb `
.. only:: html
.. rst-class:: sphx-glr-signature
`Gallery generated by Sphinx-Gallery `_