Orientations#

This module contains the Orientations class.

class pyfar.Orientations(quat=None, normalize=True, copy=True, **kwargs)[source]#

Bases: Rotation

This class for Orientations in the three-dimensional space, is a subclass of scipy.spatial.transform.Rotation and equally based on quaternions of shape (N, 4). It inherits all methods of the Rotation class and adds the creation from perpendicular view and up vectors through from_view_up and a convenient plot function show.

An orientation can be visualized with the triple of view, up and right vectors and it is tied to the object’s local coordinate system. Alternatively the object’s orientation can be illustrated with help of the right hand: Thumb (view), forefinger (up) and middle finger (right).

Examples

>>> from pyfar import Orientations
>>> views = [[1, 0, 0], [2, 0, 0]]
>>> ups = [[0, 1, 0], [0, -2, 0]]
>>> orientations = Orientations.from_view_up(views, ups)

Visualize orientations at certain positions:

>>> positions = [[0, 0.5, 0], [0, -0.5, 0]]
>>> orientations.show(positions)

Rotate first element of orientations:

>>> from scipy.spatial.transform import Rotation
>>> rot_x45 = Rotation.from_euler('x', 45, degrees=True)
>>> orientations[1] = orientations[1] * rot_x45
>>> orientations.show(positions)

To create Orientations objects use from_... methods. Orientations(...) is not supposed to be instantiated directly.

quat#

Each row is a (possibly non-unit norm) quaternion in scalar-last (x, y, z, w) format. Each quaternion will be normalized to unit norm.

Type:

array_like, shape (N, 4) or (4,)

Methods:

align_vectors(b[, weights, return_sensitivity])

Estimate an orientation to optimally align two sets of vectors.

as_view_up_right()

Get Orientations as a view, up, and right vector.

concatenate(orientations)

Concatenate a sequence of Orientations objects into a single object.

copy()

Return a deep copy of the Orientations object.

from_davenport(axes, order, angles[, degrees])

Initialize from Davenport angles.

from_euler(seq, angles[, degrees])

Initialize from Euler angles.

from_matrix(matrix[, assume_valid])

Initialize from rotation matrix.

from_mrp(mrp)

Initialize from Modified Rodrigues Parameters (MRPs).

from_quat(quat[, scalar_first])

Initialize from quaternions.

from_rotvec(rotvec[, degrees])

Initialize from rotation vectors.

from_view_up(views, ups)

Initialize Orientations from a view an up vector.

identity([num, shape])

Get identity orientation(s).

inv()

Invert this orientation.

mean([weights, axis])

Get the mean of the orientations.

random([num, rng, shape])

Generate orientations that are uniformly distributed on a sphere.

reduce([left, right, return_indices])

Reduce this orientation with the provided orientation groups.

show([positions, show_views, show_ups, ...])

Visualize Orientations as triples of view (red), up (green) and right (blue) vectors in a quiver plot.

align_vectors(b, weights=None, return_sensitivity=False)[source]#

Estimate an orientation to optimally align two sets of vectors.

Find a rotation between frames A and B which best aligns a set of vectors a and b observed in these frames. The following loss function is minimized to solve for the rotation matrix \(C\):

\[\begin{split}L(C) = \\frac{1}{2} \\sum_{i = 1}^{n} w_i \\lVert \\mathbf{a}_i - C \\mathbf{b}_i \\rVert^2 ,\end{split}\]

where \(w_i\)’s are the weights corresponding to each vector.

The rotation is estimated with Kabsch algorithm [1], and solves what is known as the “pointing problem”, or “Wahba’s problem” [2].

Note that the length of each vector in this formulation acts as an implicit weight. So for use cases where all vectors need to be weighted equally, you should normalize them to unit length prior to calling this method.

There are two special cases. The first is if a single vector is given for a and b, in which the shortest distance rotation that aligns b to a is returned.

The second is when one of the weights is infinity. In this case, the shortest distance rotation between the primary infinite weight vectors is calculated as above. Then, the rotation about the aligned primary vectors is calculated such that the secondary vectors are optimally aligned per the above loss function. The result is the composition of these two rotations. The result via this process is the same as the Kabsch algorithm as the corresponding weight approaches infinity in the limit. For a single secondary vector this is known as the “align-constrain” algorithm [3].

For both special cases (single vectors or an infinite weight), the sensitivity matrix does not have physical meaning and an error will be raised if it is requested. For an infinite weight, the primary vectors act as a constraint with perfect alignment, so their contribution to rssd will be forced to 0 even if they are of different lengths.

Parameters:
  • a (array_like, shape (3,) or (N, 3)) – Vector components observed in initial frame A. Each row of a denotes a vector.

  • b (array_like, shape (3,) or (N, 3)) – Vector components observed in another frame B. Each row of b denotes a vector.

  • weights (array_like shape (N,), optional) – Weights describing the relative importance of the vector observations. If None (default), then all values in weights are assumed to be 1. One and only one weight may be infinity, and weights must be positive.

  • return_sensitivity (bool, optional) – Whether to return the sensitivity matrix. See Notes for details. Default is False.

Returns:

  • orientation (Orientations) – Best estimate of the rotation that transforms b to a.

  • rssd (float) – Stands for “root sum squared distance”. Square root of the weighted sum of the squared distances between the given sets of vectors after alignment. It is equal to sqrt(2 * minimum_loss), where minimum_loss is the loss function evaluated for the found optimal rotation. Note that the result will also be weighted by the vectors’ magnitudes, so perfectly aligned vector pairs will have nonzero rssd if they are not of the same length. This can be avoided by normalizing them to unit length prior to calling this method, though note that doing this will change the resulting rotation.

  • sensitivity_matrix (ndarray, shape (3, 3)) – Sensitivity matrix of the estimated rotation estimate as explained in Notes. Returned only when return_sensitivity is True. Not valid if aligning a single pair of vectors or if there is an infinite weight, in which cases an error will be raised.

Notes

The sensitivity matrix gives the sensitivity of the estimated rotation to small perturbations of the vector measurements. Specifically we consider the rotation estimate error as a small rotation vector of frame A. The sensitivity matrix is proportional to the covariance of this rotation vector assuming that the vectors in a was measured with errors significantly less than their lengths. To get the true covariance matrix, the returned sensitivity matrix must be multiplied by harmonic mean [4] of variance in each observation. Note that weights are supposed to be inversely proportional to the observation variances to get consistent results. For example, if all vectors are measured with the same accuracy of 0.01 (weights must be all equal), then you should multiple the sensitivity matrix by 0.01**2 to get the covariance.

Refer to [5] for more rigorous discussion of the covariance estimation. See [6] for more discussion of the pointing problem and minimal proper pointing.

This function does not support broadcasting or ND arrays with N > 2.

References

as_view_up_right()[source]#

Get Orientations as a view, up, and right vector.

Orientations are internally stored as quaternions for better spherical linear interpolation (SLERP) and spherical harmonics operations. More intuitionally, they can be expressed as view and and up of vectors which cannot be collinear. In this case are restricted to be perpendicular to minimize rounding errors.

Returns:

vector_triple

Return type:

ndarray, shape (N, 3), normalized vectors

classmethod concatenate(orientations)[source]#

Concatenate a sequence of Orientations objects into a single object.

This is useful if you want to, for example, take the mean of a set of orientations and need to pack them into a single object to do so.

Parameters:

orientations (sequence of Orientations objects) – The orientations to concatenate. If a single Orientations object is passed in, a copy is returned.

Returns:

concatenated – The concatenated orientations.

Return type:

Orientations

copy()[source]#

Return a deep copy of the Orientations object.

classmethod from_davenport(axes, order, angles, degrees=False)[source]#

Initialize from Davenport angles.

Rotations in 3-D can be represented by a sequence of 3 rotations around a sequence of axes.

The three rotations can either be in a global frame of reference (extrinsic) or in a body centred frame of reference (intrinsic), which is attached to, and moves with, the object under rotation [7].

For both Euler angles and Davenport angles, consecutive axes must be are orthogonal (axis2 is orthogonal to both axis1 and axis3). For Euler angles, there is an additional relationship between axis1 or axis3, with two possibilities:

  • axis1 and axis3 are also orthogonal (asymmetric sequence)

  • axis1 == axis3 (symmetric sequence)

For Davenport angles, this last relationship is relaxed [8], and only the consecutive orthogonal axes requirement is maintained.

Parameters:
  • axes (array_like, shape (3,) or (..., [1 or 2 or 3], 3)) – Axis of rotation, if one dimensional. If two or more dimensional, describes the sequence of axes for rotations, where each axes[…, i, :] is the ith axis. If more than one axis is given, then the second axis must be orthogonal to both the first and third axes.

  • order (string) – If it is equal to ‘e’ or ‘extrinsic’, the sequence will be extrinsic. If it is equal to ‘i’ or ‘intrinsic’, sequence will be treated as intrinsic.

  • angles (float or array_like, shape (..., [1 or 2 or 3])) – Angles specified in radians (degrees is False) or degrees (degrees is True). Each angle i in the last dimension of angles turns around the corresponding axis axis[…, i, :]. The resulting rotation has the shape np.broadcast_shapes(np.atleast_2d(axes).shape[:-2], np.atleast_1d(angles).shape[:-1]) Dimensionless angles are thus only valid for a single axis.

  • degrees (bool, optional) – If True, then the given angles are assumed to be in degrees. Default is False.

References

classmethod from_euler(seq, angles, degrees=False)[source]#

Initialize from Euler angles.

Rotations in 3-D can be represented by a sequence of 3 rotations around a sequence of axes. In theory, any three axes spanning the 3-D Euclidean space are enough. In practice, the axes of rotation are chosen to be the basis vectors.

The three rotations can either be in a global frame of reference (extrinsic) or in a body centred frame of reference (intrinsic), which is attached to, and moves with, the object under rotation [9].

Parameters:
  • seq (string) – Specifies sequence of axes for rotations. Up to 3 characters belonging to the set {‘X’, ‘Y’, ‘Z’} for intrinsic rotations, or {‘x’, ‘y’, ‘z’} for extrinsic rotations. Extrinsic and intrinsic rotations cannot be mixed in one function call.

  • angles (float or array_like, shape (..., [1 or 2 or 3])) – Euler angles specified in radians (degrees is False) or degrees (degrees is True). Each character in seq defines one axis around which angles turns. The resulting rotation has the shape np.atleast_1d(angles).shape[:-1]. Dimensionless angles are thus only valid for single character seq.

  • degrees (bool, optional) – If True, then the given angles are assumed to be in degrees. Default is False.

References

classmethod from_matrix(matrix, assume_valid=False)[source]#

Initialize from rotation matrix.

Rotations in 3 dimensions can be represented with 3 x 3 orthogonal matrices [10]. If the input is not orthogonal, an approximation is created by orthogonalizing the input matrix using the method described in [11], and then converting the orthogonal rotation matrices to quaternions using the algorithm described in [12]. Matrices must be right-handed.

Parameters:
  • matrix (array_like, shape (..., 3, 3)) – A single matrix or an ND array of matrices, where the last two dimensions contain the rotation matrices.

  • assume_valid (bool, optional) – Must be False unless users can guarantee the input is a valid rotation matrix, i.e. it is orthogonal, rows and columns have unit norm and the determinant is 1. Setting this to True without ensuring these properties is unsafe and will silently lead to incorrect results. If True, normalization steps are skipped, which can improve runtime performance.

References

classmethod from_mrp(mrp)[source]#

Initialize from Modified Rodrigues Parameters (MRPs).

MRPs are a 3 dimensional vector co-directional to the axis of rotation and whose magnitude is equal to tan(theta / 4), where theta is the angle of rotation (in radians) [13].

MRPs have a singularity at 360 degrees which can be avoided by ensuring the angle of rotation does not exceed 180 degrees, i.e. switching the direction of the rotation when it is past 180 degrees.

Parameters:

mrp (array_like, shape (..., 3)) – A single vector or an ND array of vectors, where the last dimension contains the rotation parameters.

References

classmethod from_quat(quat, scalar_first=False)[source]#

Initialize from quaternions.

Rotations in 3 dimensions can be represented using unit norm quaternions [14].

The 4 components of a quaternion are divided into a scalar part w and a vector part (x, y, z) and can be expressed from the angle theta and the axis n of a rotation as follows:

w = cos(theta / 2)
x = sin(theta / 2) * n_x
y = sin(theta / 2) * n_y
z = sin(theta / 2) * n_z

There are 2 conventions to order the components in a quaternion:

  • scalar-first order – (w, x, y, z)

  • scalar-last order – (x, y, z, w)

The choice is controlled by scalar_first argument. By default, it is False and the scalar-last order is assumed.

Advanced users may be interested in the “double cover” of 3D space by the quaternion representation [15]. As of version 1.11.0, the following subset (and only this subset) of operations on a Rotation r corresponding to a quaternion q are guaranteed to preserve the double cover property: r = Rotation.from_quat(q), r.as_quat(canonical=False), r.inv(), and composition using the * operator such as r*r.

Parameters:
  • quat (array_like, shape (..., 4)) – Each row is a (possibly non-unit norm) quaternion representing an active rotation. Each quaternion will be normalized to unit norm.

  • scalar_first (bool, optional) – Whether the scalar component goes first or last. Default is False, i.e. the scalar-last order is assumed.

References

classmethod from_rotvec(rotvec, degrees=False)[source]#

Initialize from rotation vectors.

A rotation vector is a 3 dimensional vector which is co-directional to the axis of rotation and whose norm gives the angle of rotation [16].

Parameters:
  • rotvec (array_like, shape (..., 3)) – A single vector or an ND array of vectors, where the last dimension contains the rotation vectors.

  • degrees (bool, optional) – If True, then the given magnitudes are assumed to be in degrees. Default is False.

References

classmethod from_view_up(views, ups)[source]#

Initialize Orientations from a view an up vector.

Orientations are internally stored as quaternions for better spherical linear interpolation (SLERP) and spherical harmonics operations. More intuitionally, they can be expressed as view and up vectors which cannot be collinear. In this case, they are restricted to be perpendicular to minimize rounding errors.

Parameters:
  • views (array_like, shape (N, 3) or (3,), Coordinates) – A single vector or a stack of vectors, giving the look-direction of an object in three-dimensional space, e.g. from a listener, or the acoustic axis of a loudspeaker, or the direction of a main lobe. Views can also be passed as a Coordinates object.

  • ups (array_like, shape (N, 3) or (3,), Coordinates) – A single vector or a stack of vectors, giving the up-direction of an object, which is usually the up-direction in world-space. Views can also be passed as a Coordinates object.

Returns:

orientations – Object containing the orientations represented by quaternions.

Return type:

Orientations

classmethod identity(num=None, *, shape=None)[source]#

Get identity orientation(s).

Composition with the identity orientation has no effect.

Parameters:
  • num (int or None, optional) – Number of identity orientations to generate. If None (default), then a single rotation is generated.

  • shape (int or tuple of ints, optional) – Shape of identity orientations to generate. If specified, num must be None.

Returns:

identity – The identity rotation.

Return type:

Orientations

inv()[source]#

Invert this orientation.

Composition of an orientation with its inverse results in an identity transformation.

Returns:

inverse – Object containing inverse of the orientations in the current instance.

Return type:

Orientations

mean(weights=None, axis=None)[source]#

Get the mean of the orientations.

The mean used is the chordal L2 mean (also called the projected or induced arithmetic mean) [17]. If A is a set of rotation matrices, then the mean M is the rotation matrix that minimizes the following loss function:

\[\begin{split}L(M) = \\sum_{i = 1}^{n} w_i \\lVert \\mathbf{A}_i - \\mathbf{M} \\rVert^2 ,\end{split}\]

where \(w_i\)’s are the weights corresponding to each matrix.

Parameters:
  • weights (array_like shape (..., N), optional) – Weights describing the relative importance of the orientations. If None (default), then all values in weights are assumed to be equal. If given, the shape of weights must be broadcastable to the rotation shape. Weights must be non-negative.

  • axis (None, int, or tuple of ints, optional) – Axis or axes along which the means are computed. The default is to compute the mean of all orientations.

Returns:

mean – Single orientation containing the mean of the orientations in the current instance.

Return type:

Orientations

References

classmethod random(num=None, rng=None, *, shape=None)[source]#

Generate orientations that are uniformly distributed on a sphere.

Formally, the orientations follow the Haar-uniform distribution over the SO(3) group.

Parameters:
  • num (int or None, optional) – Number of random orientations to generate. If None (default), then a single orientation is generated.

  • rng (numpy.random.Generator, optional) – Pseudorandom number generator state. When rng is None, a new numpy.random.Generator is created using entropy from the operating system. Types other than numpy.random.Generator are passed to numpy.random.default_rng to instantiate a Generator.

  • shape (tuple of ints, optional) – Shape of random orientations to generate. If specified, num must be None.

Returns:

random_orientation – Contains a single orientation if num is None. Otherwise contains a stack of num orientations.

Return type:

Orientaions

Notes

This function is optimized for efficiently sampling random rotation matrices in three dimensions. For generating random rotation matrices in higher dimensions, see scipy.stats.special_ortho_group.

reduce(left=None, right=None, return_indices=False)[source]#

Reduce this orientation with the provided orientation groups.

Reduction of a orientation p is a transformation of the form q = l * p * r, where l and r are chosen from left and right respectively, such that orientation q has the smallest magnitude.

If left and right are orientation groups representing symmetries of two objects rotated by p, then q is the orientation of the smallest magnitude to align these objects considering their symmetries.

Parameters:
  • left (Orientation, optional) – Object containing the left orientation(s). Default value (None) corresponds to the identity orientation.

  • right (Orientation, optional) – Object containing the right orientation(s). Default value (None) corresponds to the identity orientation.

  • return_indices (bool, optional) – Whether to return the indices of the orientations from left and right used for reduction.

Returns:

  • reduced (Orientations) – Object containing reduced orientations.

  • left_best, right_best (integer ndarray) – Indices of elements from left and right used for reduction.

show(positions=None, show_views=True, show_ups=True, show_rights=True, **kwargs)[source]#

Visualize Orientations as triples of view (red), up (green) and right (blue) vectors in a quiver plot.

Parameters:
  • positions (array_like, shape (O, 3), O is len(self)) – These are the positions of each vector triple. If not provided, all triples are positioned in the origin of the coordinate system.

  • show_views (bool) – select wether to show the view vectors or not. The default is True.

  • show_ups (bool) – select wether to show the up vectors or not. The default is True.

  • show_rights (bool) – select wether to show the right vectors or not. The default is True.

  • kwargs (dict) – Additional arguments passed to pyfar.plot.quiver.

Returns:

ax – The axis used for the plot.

Return type:

Axes3D