给定一个单位向量,找到旋转的两个角度,使该向量与一个轴对齐

6

我对线性代数不是很精通,所以我在这方面遇到了困难。

我有一个单位向量v。 我想找到两个角度(angle1和绕x轴的旋转,angle2和绕z轴的旋转),使得当我通过它们旋转v时,将其与y轴对齐。 从 这个 问题中,我有一个可以找到任意向量之间夹角并返回旋转的函数。 但是,这个函数返回3个角度。基本上有无限数量的三维旋转可以将v与y轴对齐,因此我需要这两个唯一的角度。

这是我现在拥有的代码,需要numpy和scipy:

import numpy as np
import random
from scipy.spatial.transform import Rotation as R

def rotation_from_unit_vectors(a, b):
    v = np.cross(a, b)
    c = np.dot(a, b)
    s = np.linalg.norm(v)
    kmat = np.array([[0, -v[2], v[1]], [v[2], 0, -v[0]], [-v[1], v[0], 0]])
    rotation_matrix = np.eye(3) + kmat + kmat.dot(kmat) * ((1 - c) / (s ** 2))
    return  R.from_matrix(rotation_matrix)


y_axis = np.asarray([0.0, 1.0, 0.0])

alpha = random.uniform(0, 10)
beta = random.uniform(0, 10)
gamma = random.uniform(0, 10)

v = np.asarray([alpha, beta, gamma])
v = v / np.linalg.norm(v)

r = rotation_from_unit_vectors(v, y_axis)
print(r.as_euler('xyz', degrees = True))
print(r.apply(v))

@DavisHerring 嗯,你能举个例子,说明除了角度对称之外不唯一的两个例子吗?我真的无法想象... - user2882307
@DavisHerring 为了更好的理解:我想描述向量的方向(而不是大小)。其中,中性方向应与Y轴对齐。我认为通过两次旋转可以唯一确定这样一个方向。但是从您的评论中,您似乎在说这并不是这种情况。那么我想知道:有什么方法可以用(最好)两个参数唯一地描述三维方向呢? - user2882307
@DavisHerring 我不想越俎代庖。但是有没有一种方法可以“反转”这个旋转。例如,一旦计算出这个旋转,找到将y单位向量与给定向量对齐的旋转? - user2882307
除了绕 z 轴旋转,然后再绕 x 轴旋转以便你可以仅仅否定角度,你是指其他的方法吗? - Davis Herring
@DavisHerring 是的,我的意思是仍然使用欧拉角约定,先绕x轴旋转,然后再绕z轴旋转。 - user2882307
显示剩余5条评论
2个回答

2
利用固定的目标对齐,只需使用三角函数即可轻松完成:
import math

def to_y(x,y,z):
  rx=-math.atan2(z,y)              # or +math.atan2(z,-y)
  y2=y*math.cos(rx)-z*math.sin(rx) # -> (x,y2,0)
  return rx,math.atan2(x,y2)

旋转是指从+x或+z(右手定则)的原点逆时针方向看时定义的;旋转方向始终为较小幅度的方向,但可能会根据注释找到一个物理上更小的旋转。请注意,输入不需要被规范化,并且永远不会产生NaN(除非它出现在输入中)。

2

这是一个非标准问题,需要一些思考。

给定v1v2,您想要将rotate_z(rotate_x(v1, alpha), beta)旋转到与v2相同的方向。

我们知道可以通过简单地缩放v2来获得对齐的向量,这将给出x1,y3,z3 = v3 = v2 * |v1| / |v2|。由于绕z轴的旋转不会影响z坐标,因此我们可以确定alpha,使得rotate_x(v1, alpha)的z坐标等于z3。之后,我们确定角度beta以正确放置X和Y坐标。

import numpy as np
def alignment_angles(v1, v2):
    x1,y1,z1 = v1 # initial vector
    x2,y2,z2 = v2 # reference vector

    # magnitude of the two vectors
    r1 = np.sqrt(x1**2 + y1**2 + z1**2)
    r2 = np.sqrt(x2**2 + y2**2 + z2**2)
    # this will be the result when aligning v1 to v2
    # it has the magnitude of v1 and the direction of v2
    x3,y3,z3 = x2*r1/r2, y2*r1/r2, z2*r1/r2
    # the rotation in x must set the z coordinate to the
    # final value, since the rotation over the z axis will
    # not affect the z coordinate (this have two solutions)
    rho1 = np.sqrt(z1**2 + y1**2)
    if(abs(z3 / rho1) > 1):
        raise ValueError('Cannot align these vectors')
    alpha = np.arcsin(z3 / rho1) - np.arctan2(z1, y1);

    # apply the rotation to make easier to calcualte the next stage
    y1, z1 = (y1 * np.cos(alpha) - z1 * np.sin(alpha), 
              y1 * np.sin(alpha) + z1 * np.cos(alpha))
    np.allclose(rho1, np.sqrt(z1**2 + y1**2))
    #assert(np.allclose(z1, z3))
    # now it is just a matter of aligning (x1, y1) to (x3, y3)
    beta = np.arctan2(y3, x3) - np.arctan2(y1, x1)
    x1, y1 = (x1 * np.cos(beta) - y1 * np.sin(beta), 
              x1 * np.sin(beta) + y1 * np.cos(beta))
    
    # ensure the fotated v1 was correctly aligned
    assert(np.allclose([x1, y1, z1], [x3, y3, z3]))
    
    return alpha, beta

然后你只需要调用:
alignment_angles((1,2,3), (3,4,5))

或者您也可以使用具有3行的numpy数组。

最初,我认为这将是球面坐标的一个应用,如果第二次旋转的轴是绕第一次旋转相应旋转的z轴,则情况就是如此。

编辑

有些向量无法通过在x轴上旋转和在y轴上旋转来对齐。 假设您想将向量v1 =(1,0,0)与向量v2 =(0,0,1)对齐,则在x轴上的旋转不会影响v1,它始终指向x方向,然后当您围绕z轴旋转时,它始终位于XY平面上。

您给出的示例实际上给出了错误答案,因为asin不是单射函数。

我更改了函数,当您无法对齐给定向量时,它会引发值错误。


感谢您的回答。它在许多情况下似乎有效。但是在许多情况下,断言失败:例如:alignemnt_angles((-0.017868310075997075, -0.3998056402886916, -0.008330974849768172), (0,1,0))。我打印了断言值,发现 z 不匹配。 [1.249000902703301e-16, 0.39994466064372136, -0.016658333534559422], [0.0, 0.4002914334001792, 0.0] - user2882307

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接