web-dev-qa-db-ja.com

2点間の角度(時計回り)を計算する

私は長い間数学を使用していませんでしたが、これは簡単な問題です。

2つのポイントA:(1、0)とB:(1、-1)があるとします。

プログラム(Pythonまたは任意のプログラミング言語)を使用して、A、Origin(0、0)、B間の時計回りの角度を計算します。これは次のようになります。

angle_clockwise(point1, point2)

パラメーターの順序が重要であることに注意してください。角度の計算は時計回りになるため:

  • Angle_clockwise(A、B)を呼び出すと、45が返されます。
  • Angle_clockwise(B、A)を呼び出すと、315が返されます。

つまり、アルゴリズムは次のようになります。

  1. (0、0)で最初のポイントパラメーターの間に線(線1)を描画します。
  2. (0、0)で2番目のポイントパラメーターの間に線(線2)を描画します。
  3. ライン1がライン2に重なるまで時計回りに(0、0)周りに回転します。
  4. angular距離線1が移動した距離が戻り角度になります。

この問題をコーディングする方法はありますか?

15
Eric

2つのベクトルの内積と行列式を使用します。これが実際にどのように機能するかを理解したい場合、これは本当に理解すべきことです。理解するには、ベクトル演算について知っておく必要があります。

参照: https://en.wikipedia.org/wiki/Dot_product および https://en.wikipedia.org/wiki/Determinant

from math import acos
from math import sqrt
from math import pi

def length(v):
    return sqrt(v[0]**2+v[1]**2)
def dot_product(v,w):
   return v[0]*w[0]+v[1]*w[1]
def determinant(v,w):
   return v[0]*w[1]-v[1]*w[0]
def inner_angle(v,w):
   cosx=dot_product(v,w)/(length(v)*length(w))
   rad=acos(cosx) # in radians
   return rad*180/pi # returns degrees
def angle_clockwise(A, B):
    inner=inner_angle(A,B)
    det = determinant(A,B)
    if det<0: #this is a property of the det. If the det < 0 then B is clockwise of A
        return inner
    else: # if the det > 0 then A is immediately clockwise of B
        return 360-inner

行列式の計算では、2つのベクトルを連結して2 x 2行列を形成し、行列式を計算しています。

10
Chris St Pierre

Numpyの arctan2(y, x) は、Originとポイント(x, y)間の反時計回りの角度(-πとπの間のラジアン値)を計算します。

ポイントABに対してこれを実行し、最初の角度から2番目の角度を減算して、時計回りの符号付きangular差を取得します。この差は-2πと2πの間であるため、0から2πの間の正の角度を得るために、2πに対するモジュロを取ることができます。最後に、 np.rad2deg を使用してラジアンを度に変換できます。

import numpy as np

def angle_between(p1, p2):
    ang1 = np.arctan2(*p1[::-1])
    ang2 = np.arctan2(*p2[::-1])
    return np.rad2deg((ang1 - ang2) % (2 * np.pi))

例えば:

A = (1, 0)
B = (1, -1)

print(angle_between(A, B))
# 45.

print(angle_between(B, A))
# 315.

Numpyを使用したくない場合は、math.atan2の代わりに np.arctan2 を使用し、 math.degrees (または単に乗算ラジアンから度に変換するために180 / math.piで)。 numpyバージョンの利点の1つは、ベクトル化された方法でポイントの複数のペア間の角度を計算するために、(2, ...)およびp1に2つのp2配列を渡すこともできることです。

19
ali_m

cmathを必要としないソリューションを次に示します。

import math

class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y

v1 = Vector(0, 1)
v2 = Vector(0, -1)

v1_theta = math.atan2(v1.y, v1.x)
v2_theta = math.atan2(v2.y, v2.x)

r = (v2_theta - v1_theta) * (180.0 / math.pi)

if r < 0:
    r += 360.0

print r
5
Colin Basnett

cmath pythonライブラリ。

>>> import cmath
>>> a_phase = cmath.phase(complex(1,0))
>>> b_phase = cmath.phase(complex(1,-1))
>>> (a_phase - b_phase) * 180 / cmath.pi
45.0
>>> (b_phase - a_phase) * 180 / cmath.pi
-45.0

すべての正の角度が必要な場合は、数値が0より小さいかどうかを確認し、360を追加できます。

2
awmo

Chris St Pierre:関数を以下で使用する場合:

A = (x=1, y=0)
B = (x=0, y=1)

これは、AからBまでの90度の角度になるはずです。関数は270を返します。

あなたがdetのサインを処理する方法にエラーがありますか、何か不足していますか?

1
Antoine

時計回りに角度を計算し、測量で使用される式:

f(E,N)=pi()-pi()/2*(1+sign(N))* (1-sign(E^2))-pi()/4*(2+sign(N))*sign(E)

     -sign(N*E)*atan((abs(N)-abs(E))/(abs(N)+abs(E)))

式は、0から2piまでの角度を与え、北から始まり、

[〜#〜] n [〜#〜]および[〜#〜] e [〜#〜]の任意の値に対して機能します。 (N = N2-N1およびE = E2-E1

N = E =の場合、結果は未定義です。

0