3D transformations for Python with comprehensive rotation representations, coordinate conversions, and visualization tools
—
Optimized vectorized operations for processing arrays of rotations and transformations. These functions provide significant performance improvements (400-1000x faster) over iterative approaches by operating on entire arrays simultaneously.
Vectorized operations for processing arrays of rotations with optimized algorithms.
def norm_vectors(V):
"""
Normalize batch of vectors to unit length.
Parameters:
- V: array, shape (..., 3) - Batch of vectors
Returns:
- V_norm: array, shape (..., 3) - Normalized vectors
"""
def angles_between_vectors(A, B):
"""Compute angles between batches of vectors."""
def cross_product_matrices(V):
"""Convert batch of vectors to skew-symmetric matrices."""
def norm_axis_angles(A):
"""Normalize batch of axis-angle representations."""Efficient conversions between rotation matrices and other representations.
def matrices_from_quaternions(Q):
"""
Convert batch of quaternions to rotation matrices.
Parameters:
- Q: array, shape (..., 4) - Batch of quaternions
Returns:
- R: array, shape (..., 3, 3) - Batch of rotation matrices
"""
def quaternions_from_matrices(R):
"""Convert batch of rotation matrices to quaternions."""
def matrices_from_compact_axis_angles(A):
"""Convert batch of compact axis-angles to matrices."""
def axis_angles_from_matrices(R):
"""Convert batch of matrices to axis-angles."""
def active_matrices_from_angles(angles):
"""Convert batch of 2D angles to rotation matrices."""
def active_matrices_from_intrinsic_euler_angles(E, axes):
"""Convert batch of intrinsic Euler angles to matrices."""
def active_matrices_from_extrinsic_euler_angles(E, axes):
"""Convert batch of extrinsic Euler angles to matrices."""Optimized operations for arrays of quaternions.
def batch_concatenate_quaternions(Q1, Q2):
"""
Compose batches of quaternions.
Parameters:
- Q1: array, shape (..., 4) - First batch of quaternions
- Q2: array, shape (..., 4) - Second batch of quaternions
Returns:
- Q: array, shape (..., 4) - Composed quaternions (Q2 * Q1)
"""
def batch_q_conj(Q):
"""Compute conjugates of batch of quaternions."""
def smooth_quaternion_trajectory(Q):
"""
Smooth quaternion trajectory by removing sign flips.
Parameters:
- Q: array, shape (n_steps, 4) - Quaternion trajectory
Returns:
- Q_smooth: array, shape (n_steps, 4) - Smoothed trajectory
"""
def quaternion_slerp_batch(start, end, t):
"""Batch SLERP between quaternion arrays."""
def axis_angles_from_quaternions(Q):
"""Convert batch of quaternions to axis-angles."""
def batch_quaternion_wxyz_from_xyzw(Q):
"""Convert batch from [x,y,z,w] to [w,x,y,z] format."""
def batch_quaternion_xyzw_from_wxyz(Q):
"""Convert batch from [w,x,y,z] to [x,y,z,w] format."""Vectorized operations for arrays of 3D transformations.
def invert_transforms(A2B):
"""
Invert batch of transformation matrices.
Parameters:
- A2B: array, shape (..., 4, 4) - Batch of transformations
Returns:
- B2A: array, shape (..., 4, 4) - Inverted transformations
"""
def concat_one_to_many(A2B, B2C):
"""Concatenate one transform with batch of transforms."""
def concat_many_to_one(A2B, B2C):
"""Concatenate batch of transforms with one transform."""
def concat_many_to_many(A2B, B2C):
"""Concatenate two batches of transforms element-wise."""
def concat_dynamic(*args):
"""Dynamically concatenate transforms based on array shapes."""Operations for arrays of position-quaternion representations.
def transforms_from_pqs(pqs):
"""
Convert batch of position-quaternions to transformations.
Parameters:
- pqs: array, shape (..., 7) - Position-quaternions [x,y,z,qw,qx,qy,qz]
Returns:
- A2B: array, shape (..., 4, 4) - Transformation matrices
"""
def pqs_from_transforms(A2B):
"""Extract position-quaternions from batch of transforms."""Vectorized operations for dual quaternion arrays.
def dual_quaternions_from_transforms(A2B):
"""Convert batch of transforms to dual quaternions."""
def transforms_from_dual_quaternions(dqs):
"""Convert batch of dual quaternions to transforms."""
def dual_quaternions_from_pqs(pqs):
"""Convert batch of position-quaternions to dual quaternions."""
def pqs_from_dual_quaternions(dqs):
"""Convert batch of dual quaternions to position-quaternions."""
def batch_concatenate_dual_quaternions(dq1, dq2):
"""Compose batches of dual quaternions."""
def batch_dq_conj(dqs):
"""Conjugate batch of dual quaternions."""
def batch_dq_q_conj(dqs):
"""Quaternion conjugate batch of dual quaternions."""
def batch_dq_prod_vector(dqs, V):
"""Transform batch of vectors using dual quaternions."""
def dual_quaternions_power(dqs, t):
"""Dual quaternion power for batch."""
def dual_quaternions_sclerp(start, end, t):
"""Batch screw LERP between dual quaternion arrays."""Operations for arrays of screw parameters and exponential coordinates.
def transforms_from_exponential_coordinates(Stheta):
"""
Convert batch of exponential coordinates to transforms.
Parameters:
- Stheta: array, shape (..., 6) - Exponential coordinates
Returns:
- A2B: array, shape (..., 4, 4) - Transformation matrices
"""
def exponential_coordinates_from_transforms(A2B):
"""Extract exponential coordinates from batch of transforms."""
def dual_quaternions_from_screw_parameters(S):
"""Convert batch of screw parameters to dual quaternions."""
def screw_parameters_from_dual_quaternions(dqs):
"""Convert batch of dual quaternions to screw parameters."""
def mirror_screw_axis_direction(S):
"""Mirror direction of screw axis."""Functions for generating random batches of transformations.
def random_trajectories(n_steps, random_state=None):
"""
Generate random transformation trajectory.
Parameters:
- n_steps: int - Number of trajectory steps
- random_state: RandomState, optional - Random number generator
Returns:
- trajectory: array, shape (n_steps, 4, 4) - Random trajectory
"""import numpy as np
import pytransform3d.batch_rotations as pbr
# Create batch of random quaternions
n_rotations = 1000
Q = np.random.randn(n_rotations, 4)
Q = Q / np.linalg.norm(Q, axis=1, keepdims=True) # normalize
# Convert all quaternions to matrices at once
R = pbr.matrices_from_quaternions(Q)
print(f"Converted {n_rotations} quaternions to matrices")
print(f"Result shape: {R.shape}")
# Convert back to verify
Q_recovered = pbr.quaternions_from_matrices(R)
# Smooth trajectory by removing sign flips
Q_smooth = pbr.smooth_quaternion_trajectory(Q_recovered)import numpy as np
import pytransform3d.trajectories as ptr
# Create batch of transformations
n_transforms = 500
transforms = np.tile(np.eye(4), (n_transforms, 1, 1))
transforms[:, :3, 3] = np.random.randn(n_transforms, 3) # random translations
# Invert all transformations at once
transforms_inv = ptr.invert_transforms(transforms)
# Extract position-quaternions
pqs = ptr.pqs_from_transforms(transforms)
print(f"Extracted {n_transforms} position-quaternions")
print(f"PQ shape: {pqs.shape}")
# Convert to dual quaternions
dqs = ptr.dual_quaternions_from_pqs(pqs)import pytransform3d.trajectories as ptr
# Create two transformation sequences
T1 = ptr.random_trajectories(100) # 100 random transforms
T2 = ptr.random_trajectories(100) # 100 random transforms
# Compose all pairs element-wise
T_composed = ptr.concat_many_to_many(T1, T2)
print(f"Composed {len(T1)} transformation pairs")
# Apply one transform to many
single_transform = np.eye(4)
single_transform[:3, 3] = [1, 0, 0] # translation
T_offset = ptr.concat_one_to_many(single_transform, T1)import time
import numpy as np
import pytransform3d.rotations as pr
import pytransform3d.batch_rotations as pbr
# Create test data
n = 10000
Q = np.random.randn(n, 4)
Q = Q / np.linalg.norm(Q, axis=1, keepdims=True)
# Batch operation
start = time.time()
R_batch = pbr.matrices_from_quaternions(Q)
batch_time = time.time() - start
# Iterative operation
start = time.time()
R_iter = np.array([pr.matrix_from_quaternion(q) for q in Q])
iter_time = time.time() - start
print(f"Batch operation: {batch_time:.4f}s")
print(f"Iterative operation: {iter_time:.4f}s")
print(f"Speedup: {iter_time/batch_time:.1f}x")import pytransform3d.batch_rotations as pbr
import pytransform3d.trajectories as ptr
# Create trajectory with potential quaternion sign flips
trajectory_pqs = ptr.random_trajectories(200) # 200 transformation steps
pqs = ptr.pqs_from_transforms(trajectory_pqs)
# Extract quaternions and smooth
Q = pqs[:, 3:] # quaternion part [qw, qx, qy, qz]
Q_smooth = pbr.smooth_quaternion_trajectory(Q)
# Reconstruct smooth trajectory
pqs_smooth = pqs.copy()
pqs_smooth[:, 3:] = Q_smooth
trajectory_smooth = ptr.transforms_from_pqs(pqs_smooth)Install with Tessl CLI
npx tessl i tessl/pypi-pytransform3d