代码之家  ›  专栏  ›  技术社区  ›  Jihan Yin

如何有效地计算二维点的三个矢量之间的全(2pi)角

  •  0
  • Jihan Yin  · 技术社区  · 6 年前

    我有三个numpy形状数组[n,2]包含一个点列表。我们称之为a,b,和c,我想找出ab和bc之间的全角。使用acos网络我只有pi弧度,但我想要完整的2pi刻度。我考虑过使用atan2,但不确定如何计算atan2所需的y和x向量-我尝试过使用向量范数,但它们本质上是正的。有没有什么方法可以让我完全使用numpy函数来提高效率?

    2 回复  |  直到 6 年前
        1
  •  2
  •   Tom Holmes    6 年前

    使用 arccos 方法本身只给出向量之间的绝对角度,而不是它是顺时针还是逆时针。你可以通过检查 a 垂直于 b 是负的,表示逆时针的角度。

    import numpy as np
    
    def dot(a, b):
      return np.sum(a * b, axis=-1)
    
    def mag(a):
      return np.sqrt(np.sum(a*a, axis=-1))
    
    def angle(a, b):
      cosab = dot(a, b) / (mag(a) * mag(b)) # cosine of angle between vectors
      angle = np.arccos(cosab) # what you currently have (absolute angle)
    
      b_t = b[:,[1,0]] * [1, -1] # perpendicular of b
    
      is_cc = dot(a, b_t) < 0
    
      # invert the angles for counter-clockwise rotations
      angle[is_cc] = 2*np.pi - angle[is_cc]
      return angle
    
    print(angle(
      np.array([[1, 0], [1, 0]]),
      np.array([[0, 1], [0, -1]])
    ))
    

    将打印的浮点值 [pi/2, 3pi/2] 是的。

    此函数在范围内输出 [0, 2*pi] 是的。

        2
  •  0
  •   Paul Panzer    6 年前

    不出所料, 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])