如何计算 X 和 Z 上对齐两个向量所需的旋转角度

How to calculate the rotation angles needed on X and Z to align two vectors

我正在尝试旋转 vector1(红色),使其与 3D 中的 vector2(蓝色)对齐 space。但是,只能使用围绕 X 和 Z 轴的旋转。

到目前为止,我已经使用优化算法解决了这个问题,该算法试图最小化向量之间围绕 X 轴和 Z 轴的角度。这在大多数情况下工作得很好,但由于我必须计算很多这些向量,所以它太慢了。

我用于优化方法的代码:

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)))

打印:

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

现在我正在寻找可以解决我的问题的分析方法。例如。由两个旋转角度(围绕 X 和 Z)形成的旋转矩阵,用于将 vector1 与 vector2 对齐。

这是一个相当数学的问题,我不确定如何正确地写数学在这里,但你可以做以下。如果先绕 X 轴旋转,然后绕 Z 轴旋转,则最后一次旋转不会改变 z 投影。如果 (a, b, c) 是起始赋范向量,(x, y, z) 是结束赋范向量,您可以根据围绕 X 轴的旋转矩阵编写 b * sin(f) + c * cos(f) = z,其中 f 是围绕 X 的旋转角度-轴。然后根据equality from wikipedia(好像不太对:sng(c)部分应该去掉)可以求出f的值。所以你可以计算X轴旋转矩阵并得到应用这个旋转后的向量(a', b', c')。再乘以Z轴旋转矩阵,写等式xy就可以得到Z轴旋转角度的sin和cos值。

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