Skip to content

Commit

Permalink
rotations
Browse files Browse the repository at this point in the history
  • Loading branch information
0x00b1 committed Apr 5, 2024
1 parent 3e4ffd0 commit 615212b
Show file tree
Hide file tree
Showing 75 changed files with 4,446 additions and 1 deletion.
23 changes: 22 additions & 1 deletion .github/workflows/push.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,27 @@ jobs:
with:
name: "python-package-distributions"
path: "dist/"
pytest:
strategy:
matrix:
platform:
- "macos-latest"
- "ubuntu-latest"
- "windows-latest"
python:
- "3.10"
- "3.11"
runs-on: ${{ matrix.platform }}
steps:
- uses: "actions/checkout@v4"
- uses: "actions/setup-python@v5"
with:
python-version: ${{ matrix.python }}
- run: "python -m pip install --editable '.[test]'"
- run: "python -m pytest"
- env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
uses: "codecov/codecov-action@v3"
pypi:
environment:
name: "pypi.org"
Expand Down Expand Up @@ -58,7 +79,7 @@ jobs:
- uses: "chartboost/ruff-action@v1"
with:
args: "format --check"
test-pypi:
testpypi:
environment:
name: "test.pypi.org"
url: "https://test.pypi.org/project/beignet"
Expand Down
13 changes: 13 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
repos:
- hooks:
- id: "check-toml"
- id: "check-yaml"
repo: "https://github.com/pre-commit/pre-commit-hooks"
rev: "v4.5.0"
- hooks:
- args:
- "--fix"
id: "ruff"
- id: "ruff-format"
repo: "https://github.com/astral-sh/ruff-pre-commit"
rev: "v0.3.5"
7 changes: 7 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ name = "beignet"
readme = "README.md"
requires-python = ">=3.10"

[project.optional-dependencies]
test = [
"hypothesis",
"pytest",
"scipy",
]

[tool.ruff.format]
docstring-code-format = true

Expand Down
91 changes: 91 additions & 0 deletions src/beignet/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,96 @@
import importlib.metadata
from importlib.metadata import PackageNotFoundError
from ._apply_euler_angle import apply_euler_angle
from ._apply_rotation_matrix import apply_rotation_matrix
from ._apply_rotation_quaternion import (
apply_rotation_quaternion,
)
from ._apply_rotation_vector import apply_rotation_vector
from ._compose_rotation_quaternion import compose_rotation_quaternion
from ._euler_angle_identity import euler_angle_identity
from ._euler_angle_magnitude import euler_angle_magnitude
from ._euler_angle_to_rotation_matrix import euler_angle_to_rotation_matrix
from ._euler_angle_to_rotation_quaternion import (
euler_angle_to_rotation_quaternion,
)
from ._euler_angle_to_rotation_vector import euler_angle_to_rotation_vector
from ._invert_euler_angle import invert_euler_angle
from ._invert_rotation_matrix import invert_rotation_matrix
from ._invert_rotation_quaternion import invert_rotation_quaternion
from ._invert_rotation_vector import invert_rotation_vector
from ._mean_rotation_quaternion import mean_rotation_quaternion
from ._random_euler_angle import random_euler_angle
from ._random_rotation_matrix import random_rotation_matrix
from ._random_rotation_quaternion import random_rotation_quaternion
from ._random_rotation_vector import random_rotation_vector
from ._rotation_matrix_identity import rotation_matrix_identity
from ._rotation_matrix_magnitude import rotation_matrix_magnitude
from ._rotation_matrix_to_euler_angle import rotation_matrix_to_euler_angle
from ._rotation_matrix_to_rotation_quaternion import (
rotation_matrix_to_rotation_quaternion,
)
from ._rotation_matrix_to_rotation_vector import (
rotation_matrix_to_rotation_vector,
)
from ._rotation_quaternion_identity import rotation_quaternion_identity
from ._rotation_quaternion_magnitude import rotation_quaternion_magnitude
from ._rotation_quaternion_to_euler_angle import (
rotation_quaternion_to_euler_angle,
)
from ._rotation_quaternion_to_rotation_matrix import (
rotation_quaternion_to_rotation_matrix,
)
from ._rotation_quaternion_to_rotation_vector import (
rotation_quaternion_to_rotation_vector,
)
from ._rotation_vector_identity import rotation_vector_identity
from ._rotation_vector_magnitude import rotation_vector_magnitude
from ._rotation_vector_to_euler_angle import rotation_vector_to_euler_angle
from ._rotation_vector_to_rotation_matrix import (
rotation_vector_to_rotation_matrix,
)
from ._rotation_vector_to_rotation_quaternion import (
rotation_vector_to_rotation_quaternion,
)
from ._slerp import slerp

__all__ = [
"apply_euler_angle",
"apply_rotation_matrix",
"apply_rotation_quaternion",
"apply_rotation_vector",
"compose_rotation_quaternion",
"euler_angle_identity",
"euler_angle_magnitude",
"euler_angle_to_rotation_matrix",
"euler_angle_to_rotation_quaternion",
"euler_angle_to_rotation_vector",
"invert_euler_angle",
"invert_rotation_matrix",
"invert_rotation_quaternion",
"invert_rotation_vector",
"mean_rotation_quaternion",
"random_euler_angle",
"random_rotation_matrix",
"random_rotation_quaternion",
"random_rotation_vector",
"rotation_matrix_identity",
"rotation_matrix_magnitude",
"rotation_matrix_to_euler_angle",
"rotation_matrix_to_rotation_quaternion",
"rotation_matrix_to_rotation_vector",
"rotation_quaternion_identity",
"rotation_quaternion_magnitude",
"rotation_quaternion_to_euler_angle",
"rotation_quaternion_to_rotation_matrix",
"rotation_quaternion_to_rotation_vector",
"rotation_vector_identity",
"rotation_vector_magnitude",
"rotation_vector_to_euler_angle",
"rotation_vector_to_rotation_matrix",
"rotation_vector_to_rotation_quaternion",
"slerp",
]

try:
__version__ = importlib.metadata.version("beignet")
Expand Down
63 changes: 63 additions & 0 deletions src/beignet/_apply_euler_angle.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
from torch import Tensor

from ._apply_rotation_matrix import apply_rotation_matrix
from ._euler_angle_to_rotation_matrix import euler_angle_to_rotation_matrix


def apply_euler_angle(
input: Tensor,
rotation: Tensor,
axes: str,
degrees: bool = False,
inverse: bool = False,
) -> Tensor:
r"""
Rotates vectors in three-dimensional space using Euler angles.
Note
----
This function interprets the rotation of the original frame to the final
frame as either a projection, where it maps the components of vectors from
the final frame to the original frame, or as a physical rotation,
integrating the vectors into the original frame during the rotation
process. Consequently, the vector components are maintained in the original
frame’s perspective both before and after the rotation.
Parameters
----------
input : Tensor
Vectors in three-dimensional space with the shape $(\ldots \times 3)$.
Euler angles and vectors must conform to PyTorch broadcasting rules.
rotation : Tensor
Euler angles with the shape $(\ldots \times 3)$, specifying the
rotation in three-dimensional space.
axes : str
Specifies the sequence of axes for the rotations, using one to three
characters from the set ${X, Y, Z}$ for intrinsic rotations, or
${x, y, z}$ for extrinsic rotations. Mixing extrinsic and intrinsic
rotations raises a `ValueError`.
degrees : bool, optional
Indicates whether the Euler angles are provided in degrees. If `False`,
angles are assumed to be in radians. Default, `False`.
inverse : bool, optional
If `True`, applies the inverse rotation using the Euler angles to the
input vectors. Default, `False`.
Returns
-------
rotated_vectors : Tensor
A tensor of the same shape as `input`, containing the rotated vectors.
"""
return apply_rotation_matrix(
input,
euler_angle_to_rotation_matrix(
rotation,
axes,
degrees,
),
inverse,
)
45 changes: 45 additions & 0 deletions src/beignet/_apply_rotation_matrix.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import torch
from torch import Tensor


def apply_rotation_matrix(
input: Tensor,
rotation: Tensor,
inverse: bool | None = False,
) -> Tensor:
r"""
Rotates vectors in three-dimensional space using rotation matrices.
Note
----
This function interprets the rotation of the original frame to the final
frame as either a projection, where it maps the components of vectors from
the final frame to the original frame, or as a physical rotation,
integrating the vectors into the original frame during the rotation
process. Consequently, the vector components are maintained in the original
frame’s perspective both before and after the rotation.
Parameters
----------
input : Tensor, shape (..., 3)
Each vector represents a vector in three-dimensional space. The number
of rotation matrices and number of vectors must follow standard
broadcasting rules: either one of them equals unity or they both equal
each other.
rotation : Tensor, shape (..., 3, 3)
Rotation matrices.
inverse : bool, optional
If `True` the inverse of the rotation matrices are applied to the input
vectors. Default, `False`.
Returns
-------
rotated_vectors : Tensor, shape (..., 3)
Rotated vectors.
"""
if inverse:
return torch.einsum("ikj, ik -> ij", rotation, input)

return torch.einsum("ijk, ik -> ij", rotation, input)
63 changes: 63 additions & 0 deletions src/beignet/_apply_rotation_quaternion.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import torch
from torch import Tensor

from ._rotation_quaternion_to_rotation_matrix import (
rotation_quaternion_to_rotation_matrix,
)


def apply_rotation_quaternion(
input: Tensor,
rotation: Tensor,
inverse: bool | None = False,
) -> Tensor:
r"""
Rotates vectors in three-dimensional space using rotation quaternions.
Note
----
This function interprets the rotation of the original frame to the final
frame as either a projection, where it maps the components of vectors from
the final frame to the original frame, or as a physical rotation,
integrating the vectors into the original frame during the rotation
process. Consequently, the vector components are maintained in the original
frame’s perspective both before and after the rotation.
Parameters
----------
input : Tensor, shape (..., 3)
Each vector represents a vector in three-dimensional space. The number
of rotation quaternions and number of vectors must follow standard
broadcasting rules: either one of them equals unity or they both equal
each other.
rotation : Tensor, shape (..., 4)
Rotation quaternions. Rotation quaternions are normalized to unit norm.
inverse : bool, optional
If `True` the inverse of the rotation quaternions are applied to the
input vectors. Default, `False`.
Returns
-------
output : Tensor, shape (..., 3)
Rotated vectors.
"""
if inverse:
output = torch.einsum(
"ikj, ik -> ij",
rotation_quaternion_to_rotation_matrix(
rotation,
),
input,
)
else:
output = torch.einsum(
"ijk, ik -> ij",
rotation_quaternion_to_rotation_matrix(
rotation,
),
input,
)

return output
58 changes: 58 additions & 0 deletions src/beignet/_apply_rotation_vector.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
from torch import Tensor

from ._apply_rotation_matrix import apply_rotation_matrix
from ._rotation_vector_to_rotation_matrix import (
rotation_vector_to_rotation_matrix,
)


def apply_rotation_vector(
input: Tensor,
rotation: Tensor,
degrees: bool | None = False,
inverse: bool | None = False,
) -> Tensor:
r"""
Rotates vectors in three-dimensional space using rotation vectors.
Note
----
This function interprets the rotation of the original frame to the final
frame as either a projection, where it maps the components of vectors from
the final frame to the original frame, or as a physical rotation,
integrating the vectors into the original frame during the rotation
process. Consequently, the vector components are maintained in the original
frame’s perspective both before and after the rotation.
Parameters
----------
input : Tensor, shape (..., 3)
Each vector represents a vector in three-dimensional space. The number
of rotation vectors and number of vectors must follow standard
broadcasting rules: either one of them equals unity or they both equal
each other.
rotation : Tensor, shape (..., 4)
Rotation vectors.
degrees : bool, optional
If `True`, rotation vector magnitudes are assumed to be in degrees.
Default, `False`.
inverse : bool, optional
If `True` the inverse of the rotation vectors are applied to the input
vectors. Default, `False`.
Returns
-------
rotated_vectors : Tensor, shape (..., 3)
Rotated vectors.
"""
return apply_rotation_matrix(
input,
rotation_vector_to_rotation_matrix(
rotation,
degrees,
),
inverse,
)
Loading

0 comments on commit 615212b

Please sign in to comment.