Skip to content

Commit

Permalink
Merge pull request #777 from jabooth/3drots
Browse files Browse the repository at this point in the history
convienience constructors for 3D rotations
  • Loading branch information
jabooth committed May 6, 2017
2 parents 376d223 + d1e232f commit 4ed81f7
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 7 deletions.
4 changes: 2 additions & 2 deletions menpo/transform/homogeneous/affine.py
Expand Up @@ -62,8 +62,8 @@ def init_from_2d_shear(cls, phi, psi, degrees=True):
A 2D shear transform.
"""
if degrees:
phi = phi * np.pi / 180.
psi = psi * np.pi / 180.
phi = np.deg2rad(phi)
psi = np.deg2rad(psi)
# Create shear matrix
h_matrix = np.eye(3)
h_matrix[0, 1] = np.tan(phi)
Expand Down
84 changes: 79 additions & 5 deletions menpo/transform/homogeneous/rotation.py
Expand Up @@ -127,8 +127,7 @@ def init_from_2d_ccw_angle(cls, theta, degrees=True):
A 2D rotation transform.
"""
if degrees:
# convert to radians
theta = theta * np.pi / 180.0
theta = np.deg2rad(theta)
return Rotation(np.array([[np.cos(theta), -np.sin(theta)],
[np.sin(theta), np.cos(theta)]]),
skip_checks=True)
Expand All @@ -151,6 +150,81 @@ def init_3d_from_quaternion(cls, q):
r = cls.init_identity(n_dims=3)
return r.from_vector(q)

@classmethod
def init_from_3d_ccw_angle_around_x(cls, theta, degrees=True):
r"""
Convenience constructor for 3D CCW rotations around the x axis
Parameters
----------
theta : `float`
The angle of rotation about the origin
degrees : `bool`, optional
If ``True`` theta is interpreted as a degree. If ``False``, theta is
interpreted as radians.
Returns
-------
rotation : :map:`Rotation`
A 3D rotation transform.
"""
if degrees:
theta = np.deg2rad(theta)
return Rotation(np.array([[ 1, 0, 0],
[ 0, np.cos(theta), -np.sin(theta)],
[ 0, np.sin(theta), np.cos(theta)]]),
skip_checks=True)

@classmethod
def init_from_3d_ccw_angle_around_y(cls, theta, degrees=True):
r"""
Convenience constructor for 3D CCW rotations around the y axis
Parameters
----------
theta : `float`
The angle of rotation about the origin
degrees : `bool`, optional
If ``True`` theta is interpreted as a degree. If ``False``, theta is
interpreted as radians.
Returns
-------
rotation : :map:`Rotation`
A 3D rotation transform.
"""
if degrees:
theta = np.deg2rad(theta)
return Rotation(np.array([[ np.cos(theta), 0, np.sin(theta)],
[ 0, 1, 0],
[-np.sin(theta), 0, np.cos(theta)]]),
skip_checks=True)

@classmethod
def init_from_3d_ccw_angle_around_z(cls, theta, degrees=True):
r"""
Convenience constructor for 3D CCW rotations around the z axis
Parameters
----------
theta : `float`
The angle of rotation about the origin
degrees : `bool`, optional
If ``True`` theta is interpreted as a degree. If ``False``, theta is
interpreted as radians.
Returns
-------
rotation : :map:`Rotation`
A 3D rotation transform.
"""
if degrees:
theta = np.deg2rad(theta)
return Rotation(np.array([[ np.cos(theta), -np.sin(theta), 0],
[ np.sin(theta), np.cos(theta), 0],
[ 0, 0, 1]]),
skip_checks=True)

@property
def rotation_matrix(self):
r"""
Expand Down Expand Up @@ -184,12 +258,12 @@ def set_rotation_matrix(self, value, skip_checks=False):
self._h_matrix[:-1, :-1] = value

def _transform_str(self):
axis, rad_angle_of_rotation = self.axis_and_angle_of_rotation()
axis, radians_of_rotation = self.axis_and_angle_of_rotation()
if axis is None:
return "NO OP"
angle_of_rot = (rad_angle_of_rotation * 180.0) / np.pi
degrees_of_rotation = np.rad2deg(radians_of_rotation)
message = ('CCW Rotation of {:.1f} degrees '
'about {}'.format(angle_of_rot,axis))
'about {}'.format(degrees_of_rotation, axis))
return message

def axis_and_angle_of_rotation(self):
Expand Down
18 changes: 18 additions & 0 deletions menpo/transform/test/h_rotation_test.py
Expand Up @@ -105,3 +105,21 @@ def test_rotation2d_identity():

def test_rotation3d_identity():
assert_allclose(Rotation.init_identity(3).h_matrix, np.eye(4))


def test_rotation3d_init_from_3d_ccw_angle_around_x():
assert_allclose(
Rotation.init_from_3d_ccw_angle_around_x(90).apply(np.array([0, 0, 1])),
np.array([0, -1, 0]), atol=1e-6)


def test_rotation3d_init_from_3d_ccw_angle_around_y():
assert_allclose(
Rotation.init_from_3d_ccw_angle_around_y(90).apply(np.array([0, 0, 1])),
np.array([1, 0, 0]), atol=1e-6)


def test_rotation3d_init_from_3d_ccw_angle_around_z():
assert_allclose(
Rotation.init_from_3d_ccw_angle_around_z(90).apply(np.array([0, 1, 0])),
np.array([-1, 0, 0]), atol=1e-6)

0 comments on commit 4ed81f7

Please sign in to comment.