In einer Programmiersprache (Python, C # usw.) muss ich ermitteln, wie der Winkel zwischen einer Linie und der horizontalen Achse berechnet wird.
Ich denke, ein Bild beschreibt am besten, was ich will:
Gegeben (P1xP1y) und (P2x, P2y) Wie lässt sich dieser Winkel am besten berechnen? Der Ursprung ist in der obersten Zeile und nur der positive Quadrant wird verwendet.
Finden Sie zuerst die Differenz zwischen dem Startpunkt und dem Endpunkt (hier handelt es sich eher um ein gerades Liniensegment als um eine "Linie", da sich die Linien unendlich erstrecken und nicht an einem bestimmten Punkt beginnen).
deltaY = P2_y - P1_y
deltaX = P2_x - P1_x
Berechnen Sie dann den Winkel (der von der positiven X-Achse bei P1
zur positiven Y-Achse bei P1
verläuft).
angleInDegrees = arctan(deltaY / deltaX) * 180 / PI
arctan
ist jedoch möglicherweise nicht ideal, da durch das Teilen der Unterschiede die Unterscheidung gelöscht wird, die erforderlich ist, um zu unterscheiden, in welchem Quadranten sich der Winkel befindet (siehe unten). Verwenden Sie stattdessen Folgendes, wenn Ihre Sprache eine atan2
-Funktion enthält:
angleInDegrees = atan2(deltaY, deltaX) * 180 / PI
BEARBEITEN (22. Februar 2017): Im Allgemeinen kann das Aufrufen von atan2(deltaY,deltaX)
nur zum Ermitteln des richtigen Winkels für cos
und sin
unelegant sein. In diesen Fällen können Sie stattdessen häufig Folgendes tun:
(deltaX, deltaY)
als Vektor.deltaX
und deltaY
durch die Vektorlänge (sqrt(deltaX*deltaX+deltaY*deltaY)
), sofern die Länge nicht 0 ist.deltaX
nun der Cosinus des Winkels zwischen dem Vektor und der horizontalen Achse (in der Richtung vom positiven X zur positiven Y-Achse bei P1
).deltaY
wird jetzt der Sinus dieses Winkels sein.EDIT (28. Februar 2017): Auch ohne Normalisierung von (deltaX, deltaY)
:
deltaX
zeigt an, ob der in Schritt 3 beschriebene Cosinus positiv oder negativ ist.deltaY
zeigt an, ob der in Schritt 4 beschriebene Sinus positiv oder negativ ist.deltaX
und deltaY
zeigen an, in welchem Quadranten sich der Winkel befindet, bezogen auf die positive X-Achse bei P1
: +deltaX
, +deltaY
: 0 bis 90 Grad.-deltaX
, +deltaY
: 90 bis 180 Grad.-deltaX
, -deltaY
: 180 bis 270 Grad (-180 bis -90 Grad).+deltaX
, -deltaY
: 270 bis 360 Grad (-90 bis 0 Grad).Eine Implementierung in Python mit Radianten (bereitgestellt am 19. Juli 2015 von Eric Leschinski, der meine Antwort bearbeitet hat):
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)
Alle Tests bestehen. Siehe https://en.wikipedia.org/wiki/Unit_circle
Entschuldigung, aber ich bin mir ziemlich sicher, dass Peters Antwort falsch ist. Beachten Sie, dass die y-Achse die Seite nach unten fährt (in der Grafik häufig). Daher muss die DeltaYY-Berechnung umgekehrt werden, oder Sie erhalten die falsche Antwort.
Erwägen:
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)));
gibt
45.0
-45.0
135.0
-135.0
Wenn also im obigen Beispiel P1 (1,1) und P2 (2,2) ist (weil Y die Seite nach unten zieht]), ergibt der obige Code 45,0 Grad für das gezeigte Beispiel, was falsch ist. Ändern Sie die Reihenfolge der DeltaYY-Berechnung und es funktioniert ordnungsgemäß.
Ich habe in Python eine Lösung gefunden, die gut funktioniert!
from math import atan2,degrees
def GetAngleOfLineBetweenTwoPoints(p1, p2):
return degrees(atan2(p2 - p1, 1))
print GetAngleOfLineBetweenTwoPoints(1,3)
In Anbetracht der genauen Frage, die uns in ein "spezielles" Koordinatensystem bringt, in dem positive Achse bedeutet, sich nach unten zu bewegen (wie ein Bildschirm oder eine Schnittstellensicht), müssen Sie diese Funktion wie folgt anpassen und die Y-Koordinaten negieren:
Beispiel in 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
}
Diese Funktion gibt eine korrekte Antwort auf die Frage. Die Antwort ist im Bogenmaß. Die Verwendung von Winkeln in Grad lautet also:
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;
Eine Formel für einen Winkel von 0 bis 2pi.
Es gibt x = x2-x1 und y = y2-y1. Die Formel funktioniert
beliebiger Wert von x und y. Für x = y = 0 ist das Ergebnis undefiniert.
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)))
Basierend auf Referenz "Peter O" .. Hier ist die Java-Version
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-Funktion:
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