Неудивительно, что здесь можно использовать функцию angle
.Требуется сложный аргумент x + y i
:
Преимущество этого метода заключается в том, что относительные углы легко получить.С atan2
это было бы немного сложнее.
def get_angle(a,b,yx=False):
# make sure inputs are contiguous float
# swap x and if requested
a,b = map(np.ascontiguousarray, (a[...,::-1],b[...,::-1]) if yx else (a,b), (float,float))
# view cast to complex, prune excess dimension
A,B = (z.view(complex).reshape(z.shape[:-1]) for z in (a,b))
# to get the relative angle we must either divide
# or (probably cheaper) multiply with the conjugate
return np.angle(A.conj()*B)
a,b,c = np.random.randn(3,20,2)
# let's look at a roundtrip as a test
get_angle(a,b)+get_angle(b,c)+get_angle(c,a)
# array([ 0.00000000e+00, 1.66533454e-16, 4.44089210e-16, -2.22044605e-16,
# 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, -4.44089210e-16,
# 0.00000000e+00, -1.66533454e-16, 2.22044605e-16, 0.00000000e+00,
# 0.00000000e+00, 2.22044605e-16, 6.28318531e+00, 8.32667268e-17,
# 2.22044605e-16, -6.28318531e+00, -2.22044605e-16, 6.28318531e+00])
# some zeros, some 2pi and some -2pi ==> looks ok
# Let's also check the sum of angles of triangles abc:
get_angle(a-c,b-c)+get_angle(b-a,c-a)+get_angle(c-b,a-b)
# array([-3.14159265, -3.14159265, 3.14159265, -3.14159265, -3.14159265,
# 3.14159265, -3.14159265, -3.14159265, 3.14159265, -3.14159265,
# -3.14159265, 3.14159265, -3.14159265, -3.14159265, 3.14159265,
# 3.14159265, -3.14159265, -3.14159265, 3.14159265, 3.14159265])