Skip to content

Commit

Permalink
Merge pull request #2470 from mdcutone/mathtools
Browse files Browse the repository at this point in the history
NF: Mathtools
  • Loading branch information
peircej committed May 23, 2019
2 parents 942b6ec + a3c881b commit d924824
Show file tree
Hide file tree
Showing 4 changed files with 515 additions and 0 deletions.
31 changes: 31 additions & 0 deletions docs/source/api/tools/mathtools.rst
@@ -0,0 +1,31 @@

:mod:`psychopy.tools.mathtools`
----------------------------------------

.. automodule:: psychopy.tools.mathtools
.. currentmodule:: psychopy.tools.mathtools

.. autosummary::

normalize
lerp
slerp
multQuat
quatFromAxisAngle
matrixFromQuat
scaleMatrix
rotationMatrix
translationMatrix

Function details
~~~~~~~~~~~~~~~~~~~~~~~

.. autofunction:: normalize
.. autofunction:: lerp
.. autofunction:: slerp
.. autofunction:: multQuat
.. autofunction:: quatFromAxisAngle
.. autofunction:: matrixFromQuat
.. autofunction:: scaleMatrix
.. autofunction:: rotationMatrix
.. autofunction:: translationMatrix
1 change: 1 addition & 0 deletions docs/source/api/visual.rst
Expand Up @@ -65,3 +65,4 @@ Helper functions:
* :mod:`~psychopy.tools.monitorunittools` to convert cm<->pix<->deg etc.
* :mod:`~psychopy.tools.colorspacetools` to convert between supported color spaces
* :mod:`~psychopy.tools.viewtools` to work with view projections
* :mod:`~psychopy.tools.mathtools` to work with vectors, quaternions, and matrices
75 changes: 75 additions & 0 deletions psychopy/tests/test_tools/test_mathtools.py
@@ -0,0 +1,75 @@
# -*- coding: utf-8 -*-
"""Tests for psychopy.tools.mathtools
"""

from psychopy.tools.mathtools import *
import numpy as np
import pytest


@pytest.mark.mathtools
def test_rotationMatrix():
"""Test rotation matrix composition."""
# identity check
R = rotationMatrix(0., [0., 0., -1.], dtype=np.float64)
assert np.allclose(R, np.identity(4))


@pytest.mark.mathtools
def test_quatFromAxisAngle():
"""Test creating a quaternion from `axis` and `angle`."""
# identity check
axis = [0., 0., -1.]
angle = 0.0
q = quatFromAxisAngle(axis, angle, degrees=True, dtype=np.float64)
assert np.allclose(q, np.asarray([0., 0., 0., 1.]))


@pytest.mark.mathtools
def test_multQuat():
"""Test quaternion multiplication.
Create two quaternions, multiply them, and check if the resulting
orientation is as expected.
"""
np.random.seed(123456)
N = 1000
axes = np.random.uniform(-1.0, 1.0, (N, 3,)) # random axes
angles = np.random.uniform(0.0, 360.0, (N, 2,)) # random angles

for i in range(N):
totalAngle = angles[i, 0] + angles[i, 1]
q0 = quatFromAxisAngle(
axes[i, :], angles[i, 0], degrees=True, dtype=np.float64)
q1 = quatFromAxisAngle(
axes[i, :], angles[i, 1], degrees=True, dtype=np.float64)
quatTarget = quatFromAxisAngle(
axes[i, :], totalAngle, degrees=True, dtype=np.float64)

assert np.allclose(multQuat(q0, q1, dtype=np.float64), quatTarget)


@pytest.mark.mathtools
def test_matrixFromQuat():
"""Test if a matrix created using `matrixFromQuat` is equivalent to a
rotation matrix created by `rotationMatrix`.
"""
# test if quaternion conversions give the same rotation matrices
np.random.seed(123456)
N = 1000
axes = np.random.uniform(-1.0, 1.0, (N, 3,)) # random axes
angles = np.random.uniform(0.0, 360.0, (N,)) # random angles

for i in range(N):
# create a quaternion and convert it to a rotation matrix
q = quatFromAxisAngle(axes[i, :], angles[i], degrees=True, dtype=np.float64)
qr = matrixFromQuat(q, dtype=np.float64)
# create a rotation matrix directly
rm = rotationMatrix(angles[i], axes[i, :], dtype=np.float64)
# check if they are close
assert np.allclose(qr, rm)


if __name__ == "__main__":
pytest.main()

0 comments on commit d924824

Please sign in to comment.