web-dev-qa-db-de.com

Wie berechnet man den Winkel zwischen einer Linie und der horizontalen Achse?

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:

no words can describe this

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.

243
orlp

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:

  1. Behandle (deltaX, deltaY) als Vektor.
  2. Normalisieren Sie diesen Vektor in einen Einheitsvektor. Teilen Sie dazu deltaX und deltaY durch die Vektorlänge (sqrt(deltaX*deltaX+deltaY*deltaY)), sofern die Länge nicht 0 ist.
  3. Danach 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).
  4. Und deltaY wird jetzt der Sinus dieses Winkels sein.
  5. Wenn die Länge des Vektors 0 ist, hat er keinen Winkel zwischen ihm und der horizontalen Achse (also keinen sinnvollen Sinus und Cosinus).

EDIT (28. Februar 2017): Auch ohne Normalisierung von (deltaX, deltaY):

  • Das Vorzeichen von deltaX zeigt an, ob der in Schritt 3 beschriebene Cosinus positiv oder negativ ist.
  • Das Vorzeichen von deltaY zeigt an, ob der in Schritt 4 beschriebene Sinus positiv oder negativ ist.
  • Die Vorzeichen von 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

379
Peter O.

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äß.

49
user1641082

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)
1
dctremblay

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
1
philippe
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
mamashare

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)))
0

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)); }
0

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
0
Benas