3D transformations for Python with comprehensive rotation representations, coordinate conversions, and visualization tools
—
Complete system for representing and converting between rotation formats in three dimensions (SO(3)). Supports matrices, quaternions, axis-angles, Euler angles, Modified Rodrigues Parameters, and geometric algebra rotors with comprehensive conversion functions and mathematical operations.
Operations for 3x3 rotation matrices including validation, normalization, and conversions.
def check_matrix(R, tolerance=1e-6, strict_check=True):
"""Validate rotation matrix properties."""
def norm_matrix(R):
"""Normalize rotation matrix using SVD."""
def matrix_from_euler(e, i, j, k, extrinsic):
"""
Convert Euler angles to rotation matrix.
Parameters:
- e: array-like, shape (3,) - Euler angles in radians
- i: int from [0, 1, 2] - First rotation axis (0: x, 1: y, 2: z)
- j: int from [0, 1, 2] - Second rotation axis (0: x, 1: y, 2: z)
- k: int from [0, 1, 2] - Third rotation axis (0: x, 1: y, 2: z)
- extrinsic: bool - Extrinsic (True) or intrinsic (False) rotations
Returns:
- R: array, shape (3, 3) - Rotation matrix
"""
def matrix_from_quaternion(q):
"""Convert quaternion to rotation matrix."""
def matrix_from_axis_angle(a):
"""Convert axis-angle representation to rotation matrix."""
def matrix_from_compact_axis_angle(a):
"""Convert compact axis-angle to rotation matrix."""
def matrix_from_two_vectors(a, b):
"""Compute rotation matrix aligning vector a to vector b."""
def matrix_from_rotor(rotor):
"""Convert geometric algebra rotor to rotation matrix."""Operations for unit quaternions including validation, composition, and interpolation.
def check_quaternion(q, unit=True, tolerance=1e-6, strict_check=True):
"""Validate quaternion properties."""
def quaternion_from_matrix(R):
"""Convert rotation matrix to quaternion."""
def quaternion_from_euler(e, i, j, k, extrinsic):
"""Convert Euler angles to quaternion."""
def quaternion_from_axis_angle(a):
"""Convert axis-angle representation to quaternion."""
def quaternion_from_compact_axis_angle(a):
"""Convert compact axis-angle to quaternion."""
def concatenate_quaternions(q1, q2):
"""Compose two quaternions (q2 * q1)."""
def q_conj(q):
"""Quaternion conjugate."""
def q_prod_vector(q, v):
"""Rotate vector using quaternion."""
def quaternion_slerp(start, end, t):
"""Spherical linear interpolation between quaternions."""
def quaternion_integrate(q, omega, dt):
"""Integrate angular velocity to update quaternion."""
def quaternion_diff(q1, q2):
"""Difference between quaternions."""
def quaternion_dist(q1, q2):
"""Distance between quaternions."""
def quaternion_wxyz_from_xyzw(q):
"""Convert quaternion from [x,y,z,w] to [w,x,y,z] format."""
def quaternion_xyzw_from_wxyz(q):
"""Convert quaternion from [w,x,y,z] to [x,y,z,w] format."""
def quaternion_double(q):
"""
Double quaternion angle (q^2 operation).
Parameters:
- q: array, shape (4,) - Input quaternion
Returns:
- q2: array, shape (4,) - Doubled quaternion
"""
def quaternion_gradient(q, omega):
"""
Compute quaternion time derivative from angular velocity.
Parameters:
- q: array, shape (4,) - Current quaternion
- omega: array, shape (3,) - Angular velocity
Returns:
- dq_dt: array, shape (4,) - Quaternion time derivative
"""
def pick_closest_quaternion(q, quaternions):
"""
Pick closest quaternion from list (handles q/-q ambiguity).
Parameters:
- q: array, shape (4,) - Reference quaternion
- quaternions: array, shape (n, 4) - Candidate quaternions
Returns:
- closest_q: array, shape (4,) - Closest quaternion
"""Operations for axis-angle representations including compact and full forms.
def check_axis_angle(a, tolerance=1e-6, strict_check=True):
"""Validate axis-angle representation."""
def check_compact_axis_angle(a, tolerance=1e-6, strict_check=True):
"""Validate compact axis-angle representation."""
def norm_axis_angle(a):
"""Normalize axis-angle representation."""
def axis_angle_from_matrix(R):
"""Convert rotation matrix to axis-angle."""
def axis_angle_from_quaternion(q):
"""Convert quaternion to axis-angle."""
def axis_angle_from_two_directions(a, b):
"""Compute axis-angle rotation from direction a to b."""
def compact_axis_angle(a):
"""Extract compact axis-angle from full representation."""
def compact_axis_angle_from_matrix(R):
"""Convert rotation matrix to compact axis-angle."""
def compact_axis_angle_from_quaternion(q):
"""Convert quaternion to compact axis-angle."""
def axis_angle_slerp(start, end, t):
"""Spherical linear interpolation between axis-angles."""
def axis_angle_from_compact_axis_angle(a):
"""
Compute axis-angle from compact axis-angle representation.
Parameters:
- a: array, shape (3,) - Compact axis-angle: angle * (x, y, z)
Returns:
- a: array, shape (4,) - Axis-angle: (x, y, z, angle)
"""
def norm_compact_axis_angle(a):
"""
Normalize compact axis-angle representation.
Parameters:
- a: array, shape (3,) - Compact axis-angle
Returns:
- a_norm: array, shape (3,) - Normalized compact axis-angle
"""
def compact_axis_angle_near_pi(a, threshold=1e-4):
"""
Check if compact axis-angle is near pi (singularity).
Parameters:
- a: array, shape (3,) - Compact axis-angle
- threshold: float - Distance threshold for singularity detection
Returns:
- near_pi: bool - True if near singularity
"""Operations for Euler angle representations with support for all 24 conventions.
# Note: No general check_euler function - validation is done per convention
def norm_euler(e, i, j, k):
"""Normalize Euler angles to valid range for given axis sequence."""
def euler_from_matrix(R, i, j, k, extrinsic, strict_check=True):
"""
Convert rotation matrix to Euler angles.
Parameters:
- R: array, shape (3, 3) - Rotation matrix
- i: int from [0, 1, 2] - First rotation axis (0: x, 1: y, 2: z)
- j: int from [0, 1, 2] - Second rotation axis (0: x, 1, y, 2: z)
- k: int from [0, 1, 2] - Third rotation axis (0: x, 1: y, 2: z)
- extrinsic: bool - Extrinsic (True) or intrinsic (False) convention
- strict_check: bool - Enable strict validation
Returns:
- e: array, shape (3,) - Euler angles
"""
def euler_from_quaternion(q, i, j, k, extrinsic):
"""Convert quaternion to Euler angles."""
def euler_near_gimbal_lock(e, i, j, k, threshold=1e-6):
"""Check if Euler angles are near gimbal lock."""Convenience functions for specific Euler angle conventions. Note: These are deprecated in favor of the general matrix_from_euler() and euler_from_matrix() functions.
# Active matrices from Euler angles - Extrinsic rotations
def active_matrix_from_extrinsic_euler_xyz(e):
"""Convert extrinsic XYZ Euler angles to rotation matrix (deprecated)."""
def active_matrix_from_extrinsic_euler_zyx(e):
"""Convert extrinsic ZYX Euler angles to rotation matrix (deprecated)."""
def active_matrix_from_extrinsic_roll_pitch_yaw(rpy):
"""Convert roll-pitch-yaw to rotation matrix (deprecated)."""
# Active matrices from Euler angles - Intrinsic rotations
def active_matrix_from_intrinsic_euler_xyz(e):
"""Convert intrinsic XYZ Euler angles to rotation matrix (deprecated)."""
def active_matrix_from_intrinsic_euler_zyx(e):
"""Convert intrinsic ZYX Euler angles to rotation matrix (deprecated)."""
# Euler angles from matrices - Intrinsic conventions
def intrinsic_euler_xyz_from_active_matrix(R, strict_check=True):
"""Extract intrinsic XYZ Euler angles from rotation matrix (deprecated)."""
def intrinsic_euler_zyx_from_active_matrix(R, strict_check=True):
"""Extract intrinsic ZYX Euler angles from rotation matrix (deprecated)."""
# Euler angles from matrices - Extrinsic conventions
def extrinsic_euler_xyz_from_active_matrix(R, strict_check=True):
"""Extract extrinsic XYZ Euler angles from rotation matrix (deprecated)."""
def extrinsic_euler_zyx_from_active_matrix(R, strict_check=True):
"""Extract extrinsic ZYX Euler angles from rotation matrix (deprecated)."""
# All 24 Euler angle conventions are available as individual functions:
# Extrinsic: active_matrix_from_extrinsic_euler_{xyz,xyx,xzx,xzy,yxy,yxz,yzx,yzy,zxy,zxz,zyx,zyz}
# Intrinsic: active_matrix_from_intrinsic_euler_{xyz,xyx,xzx,xzy,yxy,yxz,yzx,yzy,zxy,zxz,zyx,zyz}
# Matrix to Euler: {intrinsic,extrinsic}_euler_{convention}_from_active_matrix
# Recommended: Use matrix_from_euler(e, i, j, k, extrinsic) instead
def quaternion_from_extrinsic_euler_xyz(e):
"""Convert extrinsic XYZ Euler angles to quaternion (deprecated)."""Utility functions for 3D vector operations.
def norm_vector(v):
"""Normalize vector to unit length."""
def angle_between_vectors(a, b):
"""Compute angle between two vectors."""
def perpendicular_to_vector(a):
"""Find a vector perpendicular to input vector."""
def vector_projection(a, b):
"""Project vector a onto vector b."""
def perpendicular_to_vectors(a, b):
"""Find vector perpendicular to two input vectors."""
def plane_basis_from_normal(n):
"""Generate orthonormal basis vectors for plane from normal."""Operations for Modified Rodrigues Parameters (MRP) representation.
def check_mrp(mrp, tolerance=1e-6, strict_check=True):
"""Validate Modified Rodrigues Parameters."""
def norm_mrp(mrp):
"""Normalize MRP to avoid singularity."""
def mrp_from_quaternion(q):
"""Convert quaternion to MRP."""
def mrp_from_axis_angle(a):
"""Convert axis-angle to MRP."""
def quaternion_from_mrp(mrp):
"""Convert MRP to quaternion."""
def axis_angle_from_mrp(mrp):
"""Convert MRP to axis-angle."""
def concatenate_mrp(mrp1, mrp2):
"""Compose two MRP representations."""
def mrp_prod_vector(mrp, v):
"""Rotate vector using MRP."""
def mrp_double(mrp):
"""
Double MRP rotation angle.
Parameters:
- mrp: array, shape (3,) - Modified Rodrigues Parameters
Returns:
- mrp2: array, shape (3,) - Doubled MRP
"""
def mrp_near_singularity(mrp, threshold=1e-6):
"""
Check if MRP is near singularity (norm close to 1).
Parameters:
- mrp: array, shape (3,) - Modified Rodrigues Parameters
- threshold: float - Distance threshold for singularity
Returns:
- near_singularity: bool - True if near singularity
"""Operations for geometric algebra rotor representation.
def check_rotor(rotor, tolerance=1e-6, strict_check=True):
"""Validate rotor representation."""
def wedge(a, b):
"""Wedge (exterior) product of vectors."""
def geometric_product(a, b):
"""Geometric product of multivectors."""
def rotor_apply(rotor, v):
"""Apply rotor rotation to vector."""
def rotor_reverse(rotor):
"""Reverse (conjugate) of rotor."""
def concatenate_rotors(r1, r2):
"""Compose two rotors."""
def rotor_from_plane_angle(bivector, angle):
"""Create rotor from plane and angle."""
def rotor_from_two_directions(a, b):
"""Create rotor aligning direction a to b."""
def rotor_slerp(start, end, t):
"""Spherical linear interpolation between rotors."""
def plane_normal_from_bivector(bivector):
"""Extract plane normal from bivector."""Functions for visualizing rotation representations and coordinate frames.
def plot_basis(ax, R=None, p=None, s=1.0, strict_check=True, **kwargs):
"""
Plot coordinate frame basis vectors.
Parameters:
- ax: matplotlib axis - 3D plot axis
- R: array, shape (3, 3) - Rotation matrix (default: identity)
- p: array, shape (3,) - Origin position (default: origin)
- s: float - Scale factor for basis vectors
- strict_check: bool - Enable strict validation
- kwargs: Additional plotting arguments
"""
def plot_axis_angle(ax, a, p=None, s=1.0, **kwargs):
"""
Plot axis-angle representation as rotation axis.
Parameters:
- ax: matplotlib axis - 3D plot axis
- a: array, shape (4,) - Axis-angle representation
- p: array, shape (3,) - Origin position (default: origin)
- s: float - Scale factor for axis vector
- kwargs: Additional plotting arguments
"""
def plot_bivector(ax, bivector, p=None, s=1.0, **kwargs):
"""
Plot bivector (oriented plane) in 3D space.
Parameters:
- ax: matplotlib axis - 3D plot axis
- bivector: array, shape (3,) - Bivector representation
- p: array, shape (3,) - Origin position (default: origin)
- s: float - Scale factor for bivector
- kwargs: Additional plotting arguments
"""Spherical linear interpolation (SLERP) operations for smooth rotation interpolation.
def matrix_slerp(start, end, t):
"""Spherical linear interpolation between rotation matrices."""
def matrix_power(R, t):
"""Matrix power operation for rotations."""
def slerp_weights(t):
"""Compute SLERP interpolation weights."""
def quaternion_slerp(start, end, t):
"""Spherical linear interpolation between quaternions."""
def axis_angle_slerp(start, end, t):
"""Spherical linear interpolation between axis-angles."""
def rotor_slerp(start, end, t):
"""Spherical linear interpolation between rotors."""Functions for generating random rotations with uniform distribution.
def random_matrix(random_state=None):
"""Generate random rotation matrix."""
def random_quaternion(random_state=None):
"""Generate random unit quaternion."""
def random_axis_angle(random_state=None):
"""Generate random axis-angle representation."""
def random_compact_axis_angle(random_state=None):
"""Generate random compact axis-angle."""
def random_vector(random_state=None):
"""Generate random unit vector."""Validation and assertion functions for verifying rotation representations.
def assert_rotation_matrix(R, *args, **kwargs):
"""
Raise an assertion if a matrix is not a rotation matrix.
Checks that R @ R.T = I and det(R) = 1.
Parameters:
- R: array, shape (3, 3) - Matrix to validate
- args: Positional arguments passed to assert_array_almost_equal
- kwargs: Keyword arguments passed to assert_array_almost_equal
"""
def assert_quaternion_equal(q1, q2, *args, **kwargs):
"""Assert that two quaternions are equal (considering q and -q equivalence)."""
def assert_axis_angle_equal(a1, a2, *args, **kwargs):
"""Assert that two axis-angle representations are equal."""
def assert_compact_axis_angle_equal(a1, a2, *args, **kwargs):
"""Assert that two compact axis-angle representations are equal."""
def assert_euler_equal(e1, e2, i, j, k, *args, **kwargs):
"""Assert that two Euler angle representations are equal."""
def assert_mrp_equal(mrp1, mrp2, *args, **kwargs):
"""Assert that two MRP representations are equal."""
def check_quaternions(Q, unit=True):
"""
Input validation for multiple quaternions.
Parameters:
- Q: array, shape (n_steps, 4) - Multiple quaternions
- unit: bool - Normalize quaternions to unit length
Returns:
- Q: array, shape (n_steps, 4) - Validated quaternions
"""
def check_skew_symmetric_matrix(S):
"""Validate that matrix is skew-symmetric (S = -S.T)."""
def check_rot_log(S):
"""Validate rotation logarithm representation."""
def quaternion_requires_renormalization(q, tolerance=1e-3):
"""Check if quaternion needs renormalization."""
def matrix_requires_renormalization(R, tolerance=1e-3):
"""Check if rotation matrix needs renormalization."""Functions for creating rotations from simple angle rotations around coordinate axes.
def norm_angle(a):
"""
Normalize angle to (-pi, pi] range.
Parameters:
- a: float or array - Angle(s) in radians
Returns:
- a_norm: float or array - Normalized angle(s)
"""
def active_matrix_from_angle(basis, angle):
"""
Compute active rotation matrix from rotation about basis vector.
Parameters:
- basis: int from [0, 1, 2] - Rotation axis (0: x, 1: y, 2: z)
- angle: float - Rotation angle in radians
Returns:
- R: array, shape (3, 3) - Active rotation matrix
"""
def passive_matrix_from_angle(basis, angle):
"""
Compute passive rotation matrix from rotation about basis vector.
Parameters:
- basis: int from [0, 1, 2] - Rotation axis (0: x, 1: y, 2: z)
- angle: float - Rotation angle in radians
Returns:
- R: array, shape (3, 3) - Passive rotation matrix
"""
def quaternion_from_angle(basis, angle):
"""
Compute quaternion from rotation about basis vector.
Parameters:
- basis: int from [0, 1, 2] - Rotation axis (0: x, 1: y, 2: z)
- angle: float - Rotation angle in radians
Returns:
- q: array, shape (4,) - Unit quaternion (w, x, y, z)
"""Advanced mathematical operations for rotation analysis.
def cross_product_matrix(v):
"""Convert vector to skew-symmetric matrix."""
def rot_log_from_compact_axis_angle(a):
"""Convert compact axis-angle to rotation logarithm."""
def left_jacobian_SO3(omega):
"""Left Jacobian for SO(3) group."""
def left_jacobian_SO3_inv(omega):
"""Inverse left Jacobian for SO(3)."""
def left_jacobian_SO3_series(omega):
"""Left Jacobian for SO(3) using series expansion."""
def left_jacobian_SO3_inv_series(omega):
"""Inverse left Jacobian for SO(3) using series expansion."""
def robust_polar_decomposition(A):
"""Robust polar decomposition of matrix."""Mathematical constants for rotation operations.
eps: float # Small epsilon value for numerical computations
unitx: np.ndarray # Unit vector [1, 0, 0]
unity: np.ndarray # Unit vector [0, 1, 0]
unitz: np.ndarray # Unit vector [0, 0, 1]
q_i: np.ndarray # Quaternion i basis element
q_j: np.ndarray # Quaternion j basis element
q_k: np.ndarray # Quaternion k basis element
q_id: np.ndarray # Identity quaternion [1, 0, 0, 0]
a_id: np.ndarray # Zero axis-angle representation
R_id: np.ndarray # 3x3 identity rotation matrix
p0: np.ndarray # Origin point [0, 0, 0]import numpy as np
import pytransform3d.rotations as pr
# Convert Euler angles to rotation matrix (XYZ convention)
euler = [0.1, 0.2, 0.3] # roll, pitch, yaw
R = pr.matrix_from_euler(euler, 0, 1, 2, True) # XYZ extrinsic
# Convert to quaternion
q = pr.quaternion_from_matrix(R)
# Convert to axis-angle
a = pr.axis_angle_from_quaternion(q)
# Verify round-trip conversion
R_reconstructed = pr.matrix_from_axis_angle(a)
assert np.allclose(R, R_reconstructed)import pytransform3d.rotations as pr
# Create two rotations
q1 = pr.quaternion_from_euler([0.1, 0, 0], 0, 1, 2, True) # X rotation
q2 = pr.quaternion_from_euler([0, 0.2, 0], 0, 1, 2, True) # Y rotation
# Compose rotations (q2 applied after q1)
q_composed = pr.concatenate_quaternions(q1, q2)
# Interpolate between rotations
t = 0.5 # halfway
q_interp = pr.quaternion_slerp(q1, q2, t)import numpy as np
import pytransform3d.rotations as pr
# Define rotation and vector
q = pr.quaternion_from_euler([0, 0, np.pi/4], 0, 1, 2, True) # Z rotation
v = np.array([1, 0, 0])
# Rotate vector
v_rotated = pr.q_prod_vector(q, v)
print(f"Original: {v}")
print(f"Rotated: {v_rotated}")Install with Tessl CLI
npx tessl i tessl/pypi-pytransform3d