1. ホーム
  2. c#

[解決済み】直線と水平軸のなす角の計算方法とは?

2022-04-18 03:35:44

質問

プログラミング言語(Python、C#など)で、直線と横軸の角度を計算する方法を知りたいのですが。

画像は私が欲しいものを最もよく表していると思います。

与えられた(P1 <サブ x ,P1 <サブ y ) と (P2 <サブ x ,P2 <サブ y ) この角度を計算するのに最適な方法は何でしょうか?原点は左上にあり、正の四分円のみ使用します。

解答方法は?

まず、始点と終点の差を求めます(線は無限に伸びていて特定の点から始まらないので、これは線分ではなく、有向線分と言えます)。

deltaY = P2_y - P1_y
deltaX = P2_x - P1_x

次に、角度(X軸の正の部分から P1 にある正のY軸に P1 ).

angleInDegrees = arctan(deltaY / deltaX) * 180 / PI

しかし arctan というのも、この方法で差分を分割すると、角度がどの象限にあるかを区別するのに必要な区別が消えてしまうからです(下記参照)。もしあなたの言語に atan2 関数を使用します。

angleInDegrees = atan2(deltaY, deltaX) * 180 / PI

EDIT(2017年2月22日)。ただし、一般的には atan2(deltaY,deltaX) に対して適切な角度を得るためだけに cossin はエレガントでない場合があります。そのような場合は、代わりに以下のようにすることがよくあります。

  1. 扱う (deltaX, deltaY) をベクトルとして扱います。
  2. そのベクトルを単位ベクトルに正規化する。これを行うには deltaXdeltaY は、ベクトルの長さによって ( sqrt(deltaX*deltaX+deltaY*deltaY) ただし、長さが0である場合を除く。
  3. その後 deltaX は,ベクトルと水平軸(で正の X 軸から正の Y 軸に向かう方向)とのなす角の余弦となります. P1 ).
  4. そして deltaY はその角度の正弦となる。
  5. ベクトルの長さが 0 の場合、水平軸との間に角度はありません(したがって意味のあるサインとコサインが得られません)。

EDIT(2017年2月28日)。正規化しなくても (deltaX, deltaY) :

  • の記号は deltaX は、手順3で記述したコサインが正なのか負なのかを教えてくれる。
  • の符号は deltaY を見れば、手順4で説明した正弦が正なのか負なのかがわかる。
  • の符号は deltaXdeltaY にある正の X 軸に対して、どの象限にあるかがわかります。 P1 :
    • +deltaX , +deltaY : 0~90度
    • -deltaX , +deltaY : 90度から180度
    • -deltaX , -deltaY : 180度~270度(-180度~-90度)。
    • +deltaX , -deltaY : 270度~360度(-90度~0度)です。

ラジアンを使ったPythonでの実装(2015年7月19日提供:Eric Leschinski氏、私の回答を編集してくれた)。

from math import *
def angle_trunc(a):
    while a < 0.0:
        a += pi * 2
    return a

def getAngleBetweenPoints(x_orig, y_orig, x_landmark, y_landmark):
    deltaY = y_landmark - y_orig
    deltaX = x_landmark - x_orig
    return angle_trunc(atan2(deltaY, deltaX))

angle = getAngleBetweenPoints(5, 2, 1,4)
assert angle >= 0, "angle must be >= 0"
angle = getAngleBetweenPoints(1, 1, 2, 1)
assert angle == 0, "expecting angle to be 0"
angle = getAngleBetweenPoints(2, 1, 1, 1)
assert abs(pi - angle) <= 0.01, "expecting angle to be pi, it is: " + str(angle)
angle = getAngleBetweenPoints(2, 1, 2, 3)
assert abs(angle - pi/2) <= 0.01, "expecting angle to be pi/2, it is: " + str(angle)
angle = getAngleBetweenPoints(2, 1, 2, 0)
assert abs(angle - (pi+pi/2)) <= 0.01, "expecting angle to be pi+pi/2, it is: " + str(angle)
angle = getAngleBetweenPoints(1, 1, 2, 2)
assert abs(angle - (pi/4)) <= 0.01, "expecting angle to be pi/4, it is: " + str(angle)
angle = getAngleBetweenPoints(-1, -1, -2, -2)
assert abs(angle - (pi+pi/4)) <= 0.01, "expecting angle to be pi+pi/4, it is: " + str(angle)
angle = getAngleBetweenPoints(-1, -1, -1, 2)
assert abs(angle - (pi/2)) <= 0.01, "expecting angle to be pi/2, it is: " + str(angle)

全てのテストに合格する。参照 https://en.wikipedia.org/wiki/Unit_circle