1

I am trying to rotate vector1 (red) so that it aligns with vector2 (blue) in 3D space. However, only rotations around the X and Z axis should be used.

vector sample representation

So far, I have solved this using an optimizing algorithm that tries to minimize the angles around the X and Z-Axis between the vectors. This worked in most cases quite well but since I have to compute a lot of those vectors it is too slow.

The code i used for the optimization approach:

vector1 = np.array([0., -1., 0.])
vector2 = np.array([0.2, -0.2, -0.5])

def find_a_c(x, *args):
    vector1, vector2 = args[0], args[1]
    angle_x, angle_z = x[0], x[1]

    # Rotation matrices to rotate around X and Z
    Rx = np.array([[1., 0., 0.],
                  [0., np.cos(angle_x), -np.sin(angle_x)],
                  [0., np.sin(angle_x), np.cos(angle_x)]])

    Rz = np.array([[np.cos(angle_z), -np.sin(angle_z), 0.],
                  [np.sin(angle_z), np.cos(angle_z), 0.],
                  [0., 0., 1.]])

    vector1 = vector1.dot(Rx).dot(Rz)

    # calulate the angle between the vectors around X and Z
    angle_x = angle_between_vectors([vector2[1], vector2[2]], [vector1[1], vector1[2]])
    angle_z = angle_between_vectors([vector2[0], vector2[1]], [vector1[0], vector1[1]])

    return np.abs(angle_x) + np.abs(angle_z)

solution = minimize(fun=find_a_c,
                    x0=[0., 0.],
                    args=(vector1, vector2))

angle_x, angle_z = solution.x[0], solution.x[1]
print("Angle around X: {}°\nAngle around Z: {}°".format(np.rad2deg(angle_x), np.rad2deg(angle_z)))

Prints:

Angle around X: -60.46948402478365°
Angle around Z: -45.0000003467713°

Now I'm looking for an analytical approach that solves my problem. E.g. a rotation matrix formed with the two rotation angles (around X and Z) to align vector1 to vector2.

dschori
  • 13
  • 6
  • 1
    Could you please provide a minimal reproducible example of your code [https://stackoverflow.com/help/minimal-reproducible-example](https://stackoverflow.com/help/minimal-reproducible-example) so that other users can reproduce your problem? Thank you! – mozart_kv467 May 26 '20 at 07:13
  • Does [this](https://stackoverflow.com/questions/14607640/rotating-a-vector-in-3d-space) article about 2D and 3D rotations of vectors help? – AnsFourtyTwo May 26 '20 at 07:57
  • Possibly more helpful is this topic on [math.se]: https://math.stackexchange.com/questions/180418/calculate-rotation-matrix-to-align-vector-a-to-vector-b-in-3d – AnsFourtyTwo May 26 '20 at 08:04
  • @SimonFink , yes, i already succesfully tried this based on [this](https://stackoverflow.com/questions/45142959/calculate-rotation-matrix-to-align-two-vectors-in-3d-space) answer. But this doesn't solve my problem as it does not prevent rotations around the Y Axis (which is physically not possible on my system) – dschori May 26 '20 at 08:14

1 Answers1

1

It's rather mathematical question I am not sure how to write math properly here but you can do following. If you rotate first around X-axis and then around Z-axis your last rotation do not change z projection. If (a, b, c) is the starting normed vector and (x, y, z) is the end normed vector you can write b * sin(f) + c * cos(f) = z based on rotation matrix around X-axis, where f is rotation angle around X-axis. Then based on equality from wikipedia (it seems not quite right: sng(c) part should be dropped) you can find the value of f. So you can calculate X-axis rotation matrix and get the vector after applying this rotation (a', b', c'). Then multiplying it to Z-axis rotation matrix and writing equalities for x and y you can find the values of sin and cos of Z-axis rotation angle.

import numpy as np

vector1 = np.array([0., -1., 0.])
vector2 = np.array([0.2, -0.2, -0.5])
vector2 = vector2 / np.linalg.norm(vector2)
a, b, c = vector1
x, y, z = vector2
def angle(b, c, z):
    return np.arccos(z / np.sqrt(b ** 2 + c ** 2)) - np.arctan2(-b, c)

x_angle = angle(b, c, z)
x_after_x_rotation = a
y_after_x_rotation = b * np.cos(x_angle) - c * np.sin(x_angle)

det = np.sqrt(x_after_x_rotation ** 2 + y_after_x_rotation ** 2)
sin = x_after_x_rotation * y - y_after_x_rotation * x
cos = y_after_x_rotation * y + x_after_x_rotation * x
sin /= det
cos /= det
z_angle = np.arctan2(sin, cos)

print(np.rad2deg(x_angle), np.rad2deg(z_angle))
# 60.50379150343357 45.0
V. Ayrat
  • 2,499
  • 9
  • 10