使用arctan2

时间:2017-06-07 15:12:28

标签: python numpy vector 3d

我正在使用2个矢量数组(shape =(100,3))和一个切线矢量数组(也就是shape =(100,3))并希望获得最有效的方法来正确获取两者之间的有符号角度给定与两个向量正交的切向量的向量。我已经看到这在stackoverflow上解决了2d,但是使用arctan2没有解决3d问题。由于潜在的小角度,我需要使用arctan2而不是acos。我有一个自定义函数来计算沿正确轴(称为normrow)的交叉乘积的范数,但是在使用范数计算正弦角时,我丢失了符号信息。什么是在正弦角上保持正确符号的最有效方法,所以arctan2在-pi和pi之间返回正确的值?

from numpy import cross, reshape, einsum

def v_angle(v1, v2, tangent):
        cos_ang = einsum('ij, ij -> i', v1, v2).reshape(-1, 1)
        sin_ang  = normrow(cross(v1, v2))
        return arctan2(sin_ang, cos_ang))

是采用叉积和切向量的点积的最佳方法吗?我已经尝试了两种方法,第二种方法稍快一些。

from numpy import cross, reshape, einsum, sign, arctan2
import time

numvec = 10000000

v1 = zeros((numvec, 3), dtype=float64)
v2 = zeros((numvec, 3), dtype=float64)
tangent = zeros((numvec, 3), dtype=float64)
v1[:, 1] = 1.0
v2[:, 1] = 0.5
v2[:, 2] = sqrt(3) / 2.
tangent[:, 0] = 1.0

def v_angle_signed(v1, v2, tangent):
    cos_ang = einsum('ij, ij -> i', v1, v2).reshape(-1, 1)
    sin_ang  = normrow(cross(v1, v2))
    sign_sin = sign(einsum('ij, ij -> i', cross(v1,v2), tangent)).reshape(-1, 1)
    sin_ang *= sign_sin
    return arctan2(sin_ang, cos_ang)

def v_angle_signed_v2(v1, v2, tangent):
    cosang = einsum('ij, ij -> i', v1, v2).reshape(-1, 1)
    cross_p = cross(v1, v2)
    sinang = sign(einsum('ij, ij -> i', cross_p, tangent)).reshape(-1, 1) * normrow(cross_p)
    return arctan2(sinang, cosang)

tick = time.time()
angle = v_angle(v1, v2)
print('wrong sign %.5f' % (time.time()-tick) + 's')
tick = time.time()
angle2 = v_angle_signed(v1, v2, tangent)
print('correct sign v1 %.5f' % (time.time()-tick) + 's')
tick = time.time()
angle3 = v_angle_signed_v2(v1, v2, tangent)
print('correct sign v2 %.5f' % (time.time()-tick) + 's')

样本量为10,000,000:

Output:
wrong sign 1.20736s
correct sign v1 1.97774s
correct sign v2 1.38374s

0 个答案:

没有答案