プログラミング言語(Python、C#など)で、私は線と水平軸の間の角度を計算する方法を決定する必要がありますか?
私はイメージが私が欲しいものを最もよく表すと思います:
与えられた(P1バツ、P1よ)と(P2)バツ、P2よ)この角度を計算するための最良の方法は何ですか?原点は最上位にあり、正の象限だけが使用されます。
まず始点と終点の違いを見つけます(ここでは、線は無限に伸びて特定の点から始まらないため、「線」ではなく、より有向線分になります)。
deltaY = P2_y - P1_y
deltaX = P2_x - P1_x
次に角度を計算します(P1
の正のX軸からP1
の正のY軸までの角度)。
angleInDegrees = arctan(deltaY / deltaX) * 180 / PI
しかし、arctan
は理想的ではないかもしれません、違いをこのように分割することは角度がどの四分円にあるかを区別するために必要な区別を消すからです(下記参照)。使用している言語にatan2
関数が含まれている場合は、代わりに次のコードを使用してください。
angleInDegrees = atan2(deltaY, deltaX) * 180 / PI
編集(2017年2月22日):しかし、一般的に、cos
とsin
の適切な角度を取得するためだけにatan2(deltaY,deltaX)
を呼び出すのは巧妙ではないかもしれません。そのような場合は、代わりに次のことを頻繁に実行できます。
(deltaX, deltaY)
をベクトルとして扱います。deltaX
とdeltaY
をベクトルの長さ(sqrt(deltaX*deltaX+deltaY*deltaY)
)で除算します。deltaX
はベクトルと水平軸の間の角度の余弦になります(P1
の正のXから正のY軸の方向)。deltaY
は今やその角度の正弦となるでしょう。編集(2017年2月28日):(deltaX, deltaY)
を正規化しなくても:
deltaX
の符号は、手順3で説明した余弦が正か負かを示します。deltaY
の符号は、ステップ4で説明したサインが正か負かを示します。deltaX
とdeltaY
の記号は、P1
の正のX軸に対して、角度がどの四分円にあるかを示します。+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 を参照してください。
申し訳ありませんが、Peterの答えは間違っていると確信しています。 y軸はページの下に行くことに注意してください(グラフィックでは一般的です)。そのため、deltaYの計算を逆にする必要があります。そうしないと、間違った答えが得られます。
検討してください:
System.out.println (Math.toDegrees(Math.atan2(1,1)));
System.out.println (Math.toDegrees(Math.atan2(-1,1)));
System.out.println (Math.toDegrees(Math.atan2(1,-1)));
System.out.println (Math.toDegrees(Math.atan2(-1,-1)));
与える
45.0
-45.0
135.0
-135.0
したがって、上記の例で、P1が(1,1)でP2が(2,2)の場合(Yがページの下に向かって増加するため)、上のコードは図の例で45.0度になりますが、これは誤りです。 deltaYの計算順序を変更すると正しく動作します。
私はPythonでうまくいっている解決策を見つけました!
from math import atan2,degrees
def GetAngleOfLineBetweenTwoPoints(p1, p2):
return degrees(atan2(p2 - p1, 1))
print GetAngleOfLineBetweenTwoPoints(1,3)
正確な問題を考えて、私たちを正の軸がDOWNを動かすことを意味する(スクリーンやインターフェースビューのような)特別な座標系にして、あなたはこの関数をこのように適応させY座標を負にする必要があります:
Swift 2.0での例
func angle_between_two_points(pa:CGPoint,pb:CGPoint)->Double{
let deltaY:Double = (Double(-pb.y) - Double(-pa.y))
let deltaX:Double = (Double(pb.x) - Double(pa.x))
var a = atan2(deltaY,deltaX)
while a < 0.0 {
a = a + M_PI*2
}
return a
}
この関数は質問に正解します。答えはラジアンであるため、角度で角度を表示するための使用法は次のとおりです。
let p1 = CGPoint(x: 1.5, y: 2) //estimated coords of p1 in question
let p2 = CGPoint(x: 2, y : 3) //estimated coords of p2 in question
print(angle_between_two_points(p1, pb: p2) / (M_PI/180))
//returns 296.56
deltaY = Math.Abs(P2.y - P1.y);
deltaX = Math.Abs(P2.x - P1.x);
angleInDegrees = Math.atan2(deltaY, deltaX) * 180 / PI
if(p2.y > p1.y) // Second point is lower than first, angle goes down (180-360)
{
if(p2.x < p1.x)//Second point is to the left of first (180-270)
angleInDegrees += 180;
else (270-360)
angleInDegrees += 270;
}
else if (p2.x < p1.x) //Second point is top left of first (90-180)
angleInDegrees += 90;
0から2πまでの角度の公式。
X = x 2 - x 1とy = y 2 - y 1があります。
xとyの任意の値x = y = 0の場合、結果は未定義です。
f(x,y)=pi()-pi()/2*(1+sign(x))*(1-sign(y^2))
-pi()/4*(2+sign(x))*sign(y)
-sign(x*y)*atan((abs(x)-abs(y))/(abs(x)+abs(y)))
参照 "Peter O"に基づく..これがJavaバージョンです
private static final float angleBetweenPoints(PointF a, PointF b) {
float deltaY = b.y - a.y;
float deltaX = b.x - a.x;
return (float) (Math.atan2(deltaY, deltaX)); }
matlab関数:
function [lineAngle] = getLineAngle(x1, y1, x2, y2)
deltaY = y2 - y1;
deltaX = x2 - x1;
lineAngle = rad2deg(atan2(deltaY, deltaX));
if deltaY < 0
lineAngle = lineAngle + 360;
end
end