Skip to content

rotation

hamilton_product_array

hamilton_product_array(
    quaternion0: ndarray, quaternion1: ndarray
) -> ndarray

Hamilton product for array of quaternions. Product is not commutative, order of quaternions is important.

Parameters:

Name Type Description Default

quaternion0

ndarray

[[w0_0, x0_0, y0_0, z0_0], [w0_1, x0_1, y0_1, z0_1],...]

required

quaternion1

ndarray

[[w1_0, x1_0, y1_0, z1_0], [w1_1, x1_1, y1_1, z1_1],...]

required
Source code in src/mechaphlowers/core/geometry/rotation.py
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
def hamilton_product_array(
    quaternion0: np.ndarray, quaternion1: np.ndarray
) -> np.ndarray:
    """Hamilton product for array of quaternions. Product is not commutative, order of quaternions is important.

    Args:
            quaternion0 (np.ndarray): [[w0_0, x0_0, y0_0, z0_0], [w0_1, x0_1, y0_1, z0_1],...]
            quaternion1 (np.ndarray): [[w1_0, x1_0, y1_0, z1_0], [w1_1, x1_1, y1_1, z1_1],...]
    """
    w0, x0, y0, z0 = np.split(quaternion0, 4, axis=-1)
    w1, x1, y1, z1 = np.split(quaternion1, 4, axis=-1)
    return np.concatenate(
        (
            w0 * w1 - x0 * x1 - y0 * y1 - z0 * z1,
            w0 * x1 + x0 * w1 + y0 * z1 - z0 * y1,
            w0 * y1 + y0 * w1 + z0 * x1 - x0 * z1,
            w0 * z1 + z0 * w1 + x0 * y1 - y0 * x1,
        ),
        axis=-1,
    )

rotation_matrix_to_quaternion

rotation_matrix_to_quaternion(
    beta: ndarray, rotation_axes: ndarray
) -> ndarray

Create rotation matrix for quaternion rotation. One rotation vector equals to: [cos(beta/2), sin(beta/2)u_x, sin(beta/2)u_y, sin(beta/2)*u_z] where unit_vector = [u_x, u_y, u_z]. unit_vector is rotation_axes that has been normalized

Parameters:

Name Type Description Default

beta

ndarray

array of angles in radians [beta_0, beta_1]

required

rotation_axes

ndarray

array of axes of rotation in 3D (will be normalized) [[r_x0, r_y0, r_z0], [r_x1, r_y1, r_z1], ...]

required

Returns:

Type Description
ndarray

np.ndarray: [[w0, x0, y0, z0], [w1, x1, y1, z1],...]

Examples:

Create two quaternions that serve as rotation matrix: rotation of \(\frac{\pi}{2} rad\) around the axis \(\vec{x}\), and rotation of \(\pi rad\) around the axis \(\vec{z}\)

1
2
3
4
>>> beta = np.array([np.pi / 2, np.pi])
>>> rotation_axes = np.array([[1, 0, 0], [0, 0, 1]])
>>> rotation_matrix_to_quaternion(beta, rotation_axes)
array([[0.707106781, 0.707106781, 0, 0], [0, 0, 0, 1]])
Source code in src/mechaphlowers/core/geometry/rotation.py
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
def rotation_matrix_to_quaternion(
    beta: np.ndarray, rotation_axes: np.ndarray
) -> np.ndarray:
    """Create rotation matrix for quaternion rotation.
    One rotation vector equals to: [cos(beta/2), sin(beta/2)*u_x, sin(beta/2)*u_y, sin(beta/2)*u_z]
    where unit_vector = [u_x, u_y, u_z].
    unit_vector is rotation_axes that has been normalized

    Args:
            beta (np.ndarray): array of angles in radians [beta_0, beta_1]
            rotation_axes (np.ndarray): array of axes of rotation in 3D (will be normalized) [[r_x0, r_y0, r_z0], [r_x1, r_y1, r_z1], ...]

    Returns:
            np.ndarray: [[w0, x0, y0, z0], [w1, x1, y1, z1],...]

    Examples:
            Create two quaternions that serve as rotation matrix:
            rotation of $\\frac{\\pi}{2} rad$ around the axis $\\vec{x}$, and rotation of $\\pi rad$ around the axis $\\vec{z}$

            >>> beta = np.array([np.pi / 2, np.pi])
            >>> rotation_axes = np.array([[1, 0, 0], [0, 0, 1]])
            >>> rotation_matrix_to_quaternion(beta, rotation_axes)
            array([[0.707106781, 0.707106781, 0, 0], [0, 0, 0, 1]])
    """
    # normalize the rotation axis
    unit_vector = (
        rotation_axes / np.linalg.norm(rotation_axes, axis=1)[:, np.newaxis]
    )

    # C equals to: [[cos(beta_0/2)], [cos(beta_1/2)],...]
    C = np.cos(beta / 2)[:, np.newaxis]
    S = np.sin(beta / 2)[:, np.newaxis]
    x, y, z = np.split(unit_vector, 3, axis=-1)

    quat = np.concatenate((C, S * x, S * y, S * z), axis=-1)
    return quat

rotation_quaternion

rotation_quaternion(
    vector: ndarray,
    beta: ndarray,
    rotation_axes: ndarray,
    degrees: bool = False,
) -> ndarray

Compute rotation of vector using quaternion rotation.

Parameters:

Name Type Description Default

vector

ndarray

array of 3D points to rotate [[x0, y0, z0], [x1, y1, z1],...]

required

beta

ndarray

array of angles in radians [beta_0, beta_1, ...]

required

rotation_axes

ndarray

array of axes of rotation in 3D. Doesn't need to be normalized beforehand [[r_x0, r_y0, r_z0], [r_x1, r_y1, r_z1], ...]

required

degrees

bool

set to True if input angles are in degree. False if in radians

False

Returns:

Type Description
ndarray

np.ndarray: array of new points that have been rotated by angles beta around rotation_axes

Examples:

Rotation of vector \(2\vec{z}\) by angle of \(\frac{\pi}{2} rad\) around the axis \(\vec{x}\), and rotation of vector \(\vec{y}\) by angle of \(- \frac{\pi}{2} rad\) around the axis \(\vec{z}\)

The rotated vectors are: \(-2\vec{y}\) and \(\vec{x}\)

1
2
3
4
5
>>> vector = np.array([[0, 0, 2], [0, 1, 0]])
>>> beta = np.array([np.pi / 2, -np.pi / 2])
>>> rotation_axes = np.array([[1, 0, 0], [0, 0, 1]])
>>> rotation_quaternion(vector, beta, rotation_axes)
array([[ 0,  -2,  0], [1,  0,  0]])
Source code in src/mechaphlowers/core/geometry/rotation.py
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
def rotation_quaternion(
    vector: np.ndarray,
    beta: np.ndarray,
    rotation_axes: np.ndarray,
    degrees: bool = False,
) -> np.ndarray:
    """Compute rotation of vector using quaternion rotation.

    Args:
            vector (np.ndarray): array of 3D points to rotate [[x0, y0, z0], [x1, y1, z1],...]
            beta (np.ndarray): array of angles in radians [beta_0, beta_1, ...]
            rotation_axes (np.ndarray): array of axes of rotation in 3D. Doesn't need to be normalized beforehand [[r_x0, r_y0, r_z0], [r_x1, r_y1, r_z1], ...]
            degrees (bool): set to True if input angles are in degree. False if in radians

    Returns:
            np.ndarray: array of new points that have been rotated by angles beta around rotation_axes

    Examples:
            Rotation of vector $2\\vec{z}$ by angle of  $\\frac{\\pi}{2} rad$ around the axis $\\vec{x}$, and rotation of vector $\\vec{y}$ by angle of $- \\frac{\\pi}{2} rad$ around the axis $\\vec{z}$

            The rotated vectors are: $-2\\vec{y}$ and $\\vec{x}$
            >>> vector = np.array([[0, 0, 2], [0, 1, 0]])
            >>> beta = np.array([np.pi / 2, -np.pi / 2])
            >>> rotation_axes = np.array([[1, 0, 0], [0, 0, 1]])
            >>> rotation_quaternion(vector, beta, rotation_axes)
            array([[ 0,  -2,  0], [1,  0,  0]])
    """

    if degrees:
        np.radians(beta, out=beta)
    # compute the rotation matrix as quaternion
    rotation_quaternion = rotation_matrix_to_quaternion(beta, rotation_axes)
    # compute the conjugate of the rotation matrix
    conj = np.full(rotation_quaternion.shape, [1, -1, -1, -1])
    rotation_quaternion_conj = rotation_quaternion * conj

    # add a zero w coordinate to vector to make it a quaternion
    w_coord = np.zeros((vector.shape[0], 1))
    purequat = np.concat((w_coord, vector), axis=1)

    # compute the new rotated quaternion:
    # vector_rotated = R * vector * R_conj
    vector_rotated = hamilton_product_array(
        rotation_quaternion,
        hamilton_product_array(purequat, rotation_quaternion_conj),
    )

    # remove w coordinate to be back in 3D
    vector_rotated_3d = vector_rotated[:, 1:]
    return vector_rotated_3d

rotation_quaternion_same_axis

rotation_quaternion_same_axis(
    vector: ndarray,
    beta: ndarray,
    rotation_axis: ndarray = array([1, 0, 0]),
    degrees: bool = False,
) -> ndarray

Compute rotation of vector using quaternion rotation. All vectors are rotated around the same axis.

Parameters:

Name Type Description Default

vector

ndarray

array of 3D points to rotate [[x0, y0, z0], [x1, y1, z1],...]

required

beta

ndarray

array of angles [beta_0, beta_1, ...], in radians by default

required

rotation_axis

ndarray

single axis of rotation in 3D. Doesn't need to be normalized beforehand [r_x0, r_y0, r_z0]

array([1, 0, 0])

degrees

bool

set to True if input angles are in degree. False if in radians

False

Returns:

Type Description
ndarray

np.ndarray: array of new points that have been rotated by angles beta around rotation_axis

Examples:

Rotation of vector \(2\vec{z}\) by angle of \(\frac{\pi}{2} rad\) and rotation of vector \(\vec{y}\) by angle of \(\frac{\pi}{4} rad\), both around the axis \(\vec{x}\).

The rotated vectors are: \(-2\vec{y}\) and \(\frac{\sqrt{2}}{2} \vec{y} + \frac{\sqrt{2}}{2} \vec{z} \)

1
2
3
4
5
>>> vector = np.array([[0, 0, 2], [0, 1, 0]])
>>> beta = np.array([np.pi / 2, np.pi / 4])
>>> rotation_axis = np.array([1, 0, 0])
>>> rotation_quaternion_same_axis(vector, beta, rotation_axis)
array([[0,  -2,  0], [0,  0.707106781,  0.707106781]])
Source code in src/mechaphlowers/core/geometry/rotation.py
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
def rotation_quaternion_same_axis(
    vector: np.ndarray,
    beta: np.ndarray,
    rotation_axis: np.ndarray = np.array([1, 0, 0]),
    degrees: bool = False,
) -> np.ndarray:
    """Compute rotation of vector using quaternion rotation.
    All vectors are rotated around the same axis.

    Args:
            vector (np.ndarray): array of 3D points to rotate [[x0, y0, z0], [x1, y1, z1],...]
            beta (np.ndarray): array of angles [beta_0, beta_1, ...], in radians by default
            rotation_axis (np.ndarray): single axis of rotation in 3D. Doesn't need to be normalized beforehand [r_x0, r_y0, r_z0]
            degrees (bool): set to True if input angles are in degree. False if in radians

    Returns:
            np.ndarray: array of new points that have been rotated by angles beta around rotation_axis

    Examples:
            Rotation of vector $2\\vec{z}$ by angle of $\\frac{\\pi}{2} rad$ and rotation of vector $\\vec{y}$ by angle of $\\frac{\\pi}{4} rad$, both around the axis $\\vec{x}$.

            The rotated vectors are: $-2\\vec{y}$ and \\(\\frac{\\sqrt{2}}{2} \\vec{y} + \\frac{\\sqrt{2}}{2} \\vec{z} \\)
            >>> vector = np.array([[0, 0, 2], [0, 1, 0]])
            >>> beta = np.array([np.pi / 2, np.pi / 4])
            >>> rotation_axis = np.array([1, 0, 0])
            >>> rotation_quaternion_same_axis(vector, beta, rotation_axis)
            array([[0,  -2,  0], [0,  0.707106781,  0.707106781]])
    """

    rotation_axes = np.full(vector.shape, rotation_axis)
    return rotation_quaternion(vector, beta, rotation_axes, degrees)