Skip to content

Commit

Permalink
Remove Euler and Quaternion
Browse files Browse the repository at this point in the history
  • Loading branch information
Christdej committed Apr 6, 2022
1 parent 79ec335 commit 14f51ba
Show file tree
Hide file tree
Showing 28 changed files with 441 additions and 724 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,5 @@ This will install package in _editable_ mode. Convenient for local development
### How to use

The tests in this repository can be used as examples
of how to use the different models and functions
of how to use the different models and functions. The
[test_example.py](tests/test_example.py) is a good place to start
4 changes: 2 additions & 2 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
line_length = 88
multi_line_output = 3
include_trailing_comma = True
force_grid_wrap=0
use_parentheses=True
force_grid_wrap = 0
use_parentheses = True

[mypy]
follow_imports = normal
Expand Down
12 changes: 4 additions & 8 deletions src/alitra/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,20 @@
asset coordinate-frame.
>>> import numpy as np
>>> from alitra import align_frames
>>> from alitra.models import Euler, Quaternion, PositionList, Transform, Translation
>>> from alitra.models import Positions, Transform, Translation
Setting up rotations, translations and positions for transformation
>>> robot_frame = Frame("robot")
>>> asset_frame = Frame("asset")
>>> euler = Euler(psi=np.pi / 4, from_=robot_frame, to_=asset_frame).to_array()
>>> euler = np.array([np.pi / 4, 0, 0])
>>> translation = Translation(x=1, y=0, from_=robot_frame, to_=asset_frame)
>>> p_robot = PositionList.from_array(np.array([[1, 1, 0], [10, 1, 0]]), frame=robot_frame)
>>> p_robot = Positions.from_array(np.array([[1, 1, 0], [10, 1, 0]]), frame=robot_frame)
>>> rotation_axes = "z"
Making the transform
>>> transform = Transform.from_euler(
>>> transform = Transform.from_euler_array(
... translation=translation, euler=euler, from_=robot_frame, to_=asset_frame
... )
Expand All @@ -33,14 +32,11 @@
between the two frames.
>>> transform = Transform(p_robot, p_asset, rotation_axes)
"""

from alitra.alignment import align_maps, align_positions
from alitra.transformations import (
transform_euler,
transform_orientation,
transform_pose,
transform_position,
transform_quaternion,
)
10 changes: 5 additions & 5 deletions src/alitra/alignment.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ def align_positions(
fixed coordinate system. Further, let the relationship between the two reference
systems be described as
positions_from = rotation_object.apply(positions_to) + translation
positions_from = rotation.apply(positions_to) + translation
This function finds the rotation_object and translation by matching the two
This function finds the rotation and translation by matching the two
coordinate systems, and represent the transformation through a Transform object.
For robustness it is adviced to use more than 2 positions in alignment and using
positions with some distance to each other.
Expand Down Expand Up @@ -68,13 +68,13 @@ def align_positions(
except Exception as e:
raise ValueError(e)

rotation_object, rmsd_rot, sensitivity = Rotation.align_vectors(
rotation, rmsd_rot, sensitivity = Rotation.align_vectors(
edges_2, edges_1, return_sensitivity=True
)

translations: Translation = Translation.from_array(
np.mean(
positions_to.to_array() - rotation_object.apply(positions_from.to_array()),
positions_to.to_array() - rotation.apply(positions_from.to_array()),
axis=0, # type:ignore
),
from_=positions_from.frame,
Expand All @@ -84,7 +84,7 @@ def align_positions(
from_=positions_from.frame,
to_=positions_to.frame,
translation=translations,
rotation_object=rotation_object,
rotation=rotation,
)

try:
Expand Down
1 change: 0 additions & 1 deletion src/alitra/convert/__init__.py

This file was deleted.

41 changes: 0 additions & 41 deletions src/alitra/convert/convert.py

This file was deleted.

2 changes: 0 additions & 2 deletions src/alitra/models/__init__.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
from .bounds import Bounds
from .euler import Euler
from .frame import Frame
from .map import Map
from .orientation import Orientation
from .pose import Pose
from .position import Position, Positions
from .quaternion import Quaternion
from .transform import Transform
from .translation import Translation
16 changes: 8 additions & 8 deletions src/alitra/models/bounds.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
@dataclass
class Bounds:
"""
Bounds defines the square bounds of which the map should be valid inside.
Position 1 and 2 should be on the diagonal corners of the bounding square.
Bounds defines the cube bounds of which the map should be valid inside.
Position 1 and 2 should be on the diagonal corners of the bounding cube.
"""

position1: Position
Expand All @@ -26,15 +26,15 @@ def __post_init__(self):
self.z_max = max(position.z for position in positions)
self.z_min = min(position.z for position in positions)

def position_within_bounds(self, Position: Position) -> bool:
if not Position.frame == self.frame:
def position_within_bounds(self, position: Position) -> bool:
if not position.frame == self.frame:
raise TypeError(
f"The Position is in {Position.frame} frame and the bounds are in {self.frame} frame"
f"The position is in {position.frame} frame and the bounds are in {self.frame} frame"
)
if Position.x < self.x_min or Position.x > self.x_max:
if position.x < self.x_min or position.x > self.x_max:
return False
if Position.y < self.y_min or Position.y > self.y_max:
if position.y < self.y_min or position.y > self.y_max:
return False
if Position.z < self.z_min or Position.z > self.z_max:
if position.z < self.z_min or position.z > self.z_max:
return False
return True
34 changes: 0 additions & 34 deletions src/alitra/models/euler.py

This file was deleted.

69 changes: 18 additions & 51 deletions src/alitra/models/orientation.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,60 +3,31 @@
from dataclasses import dataclass

import numpy as np
from scipy.spatial.transform.rotation import Rotation
from scipy.spatial.transform import Rotation

from alitra.convert import quaternion_to_euler

from .euler import Euler
from .frame import Frame
from .quaternion import Quaternion


@dataclass
class Orientation:
"""
This class represents an orientation using quaternions. Methods that utilize
Euler angles will all follow the yaw, pitch, roll convention which rotates around
the ZYX axis with intrinsic rotations.
This class represents an orientation scipy rotation object and a frame
"""

x: float
y: float
z: float
w: float
frame: Frame

def __eq__(self, other):
if not isinstance(other, Orientation):
return False
if (
np.allclose(
a=[self.x, self.y, self.z, self.w],
b=[other.x, other.y, other.z, other.w],
atol=1e-10,
)
and self.frame == other.frame
):
return True
return False
rotation: Rotation

def to_euler_array(
self,
degrees: bool = False,
wrap_angles: bool = False,
self, degrees: bool = False, wrap_angles: bool = False, seq: str = "ZYX"
) -> np.ndarray:
"""
Retrieve the orientation as yaw, pitch, roll Euler coordinates. This function uses the ZYX intrinsic rotations
as standard convention.
Retrieve the orientation as yaw, pitch, roll euler coordinates. This function
uses the ZYX intrinsic rotations as default convention.
:param degrees: Set to true to retrieve angles as degrees.
:return: List of euler angles [yaw, pitch, roll]
"""

euler = quaternion_to_euler(
Quaternion(x=self.x, y=self.y, z=self.z, w=self.w, frame=self.frame),
sequence="ZYX",
degrees=degrees,
).to_array()
euler = self.rotation.as_euler(seq=seq, degrees=degrees)

if wrap_angles:
base = 360.0 if degrees else 2 * np.pi
Expand All @@ -66,26 +37,22 @@ def to_euler_array(

return euler

def to_array(self) -> np.ndarray:
return np.array([self.x, self.y, self.z, self.w], dtype=float)
def to_quat_array(self) -> np.ndarray:
return self.rotation.as_quat()

@staticmethod
def from_array(orientation: np.ndarray, frame: Frame) -> Orientation:
if orientation.shape != (4,):
raise ValueError("orientation should have shape (4,)")
def from_quat_array(quat: np.ndarray, frame: Frame) -> Orientation:
if quat.shape != (4,):
raise ValueError("quaternion should have shape (4,)")
return Orientation(
x=orientation[0],
y=orientation[1],
z=orientation[2],
w=orientation[3],
frame=frame,
rotation=Rotation.from_quat(quat),
)

@staticmethod
def from_euler(euler: Euler, frame: Frame, seq="ZYX") -> Orientation:
rotation_object = Rotation.from_euler(seq, euler.to_array())
quaternion: Quaternion = Quaternion.from_array(
rotation_object.as_quat(), frame=frame
)
orientation: Orientation = Orientation.from_array(quaternion.to_array(), frame)
def from_euler_array(
euler: np.ndarray, frame: Frame, degrees: bool = False, seq: str = "ZYX"
) -> Orientation:
rotation = Rotation.from_euler(seq=seq, angles=euler, degrees=degrees)
orientation: Orientation = Orientation(rotation=rotation, frame=frame)
return orientation
4 changes: 2 additions & 2 deletions src/alitra/models/position.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ def to_array(self) -> np.ndarray:

@staticmethod
def from_array(position_array: np.ndarray, frame: Frame) -> Positions:
if position_array.shape[1] != 3:
raise ValueError("position_array should have shape (3,N)")
if len(position_array.shape) < 2 or position_array.shape[1] != 3:
raise ValueError("position_array should have shape (N,3)")
positions: List[Position] = []
for position in position_array:
positions.append(
Expand Down
38 changes: 0 additions & 38 deletions src/alitra/models/quaternion.py

This file was deleted.

Loading

0 comments on commit 14f51ba

Please sign in to comment.