¿Cómo calcular el ángulo entre una línea y el eje horizontal?

En un lenguaje de progtwigción (Python, C #, etc.) ¿Necesito determinar cómo calcular el ángulo entre una línea y el eje horizontal?

Creo que una imagen describe mejor lo que quiero:

no hay palabras que puedan describir esto

Dado (P1 x , P1 y ) y (P2 x , P2 y ) ¿cuál es la mejor manera de calcular este ángulo? El origen está en el topleft y solo se utiliza el cuadrante positivo.

    Primero encuentre la diferencia entre el punto de inicio y el punto final (aquí, esto es más bien un segmento de línea dirigida, no una “línea”, ya que las líneas se extienden infinitamente y no comienzan en un punto en particular).

    deltaY = P2_y - P1_y deltaX = P2_x - P1_x 

    Luego calcule el ángulo (que va desde el eje X positivo en P1 al eje Y positivo en P1 ).

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

    Pero arctan puede no ser ideal, porque dividir las diferencias de esta manera borrará la distinción necesaria para distinguir en qué cuadrante se encuentra el ángulo (ver más abajo). Utilice lo siguiente si su idioma incluye una función atan2 :

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

    EDITAR (22 de febrero de 2017): Sin embargo, en general, llamar a atan2(deltaY,deltaX) solo para obtener el ángulo adecuado para cos y sin puede ser poco elegante. En esos casos, a menudo puedes hacer lo siguiente:

    1. Tratar (deltaX, deltaY) como un vector.
    2. Normaliza ese vector a un vector unitario. Para hacerlo, divida deltaX y deltaY por la longitud del vector ( sqrt(deltaX*deltaX+deltaY*deltaY) ), a menos que la longitud sea 0.
    3. Después de eso, deltaX será ahora el coseno del ángulo entre el vector y el eje horizontal (en la dirección de la X positiva al eje Y positivo en P1 ).
    4. Y deltaY ahora será el seno de ese ángulo.
    5. Si la longitud del vector es 0, no tendrá un ángulo entre él y el eje horizontal (por lo que no tendrá un seno y coseno significativos).

    EDITAR (28 de febrero de 2017): Incluso sin normalizar (deltaX, deltaY) :

    • El signo de deltaX le indicará si el coseno descrito en el paso 3 es positivo o negativo.
    • El signo de deltaY le dirá si el seno descrito en el paso 4 es positivo o negativo.
    • Los signos de deltaX y deltaY te dirán en qué cuadrante está el ángulo, en relación con el eje X positivo en P1 :
      • +deltaX , +deltaY : 0 a 90 grados.
      • -deltaX , +deltaY : 90 a 180 grados.
      • -deltaX , -deltaY : 180 a 270 grados (-180 a -90 grados).
      • +deltaX , -deltaY : 270 a 360 grados (-90 a 0 grados).

    Una implementación en Python usando radianes (proporcionada el 19 de julio de 2015 por Eric Leschinski, quien editó mi respuesta):

     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) 

    Todas las pruebas pasan. Ver https://en.wikipedia.org/wiki/Unit_circle

    Lo siento, pero estoy bastante seguro de que la respuesta de Peter es incorrecta. Tenga en cuenta que el eje y baja la página (común en gráficos). Como tal, el cálculo deltaY debe revertirse, o se obtiene la respuesta incorrecta.

    Considerar:

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

    da

     45.0 -45.0 135.0 -135.0 

    Entonces, si en el ejemplo anterior, P1 es (1,1) y P2 es (2,2) [porque Y aumenta la página], el código anterior dará 45.0 grados para el ejemplo que se muestra, lo cual es incorrecto. Cambia el orden del cálculo deltaY y funciona correctamente.

    ¡He encontrado una solución en Python que funciona bien!

     from math import atan2,degrees def GetAngleOfLineBetweenTwoPoints(p1, p2): return degrees(atan2(p2 - p1, 1)) print GetAngleOfLineBetweenTwoPoints(1,3) 

    Teniendo en cuenta la pregunta exacta, ubicándonos en un sistema de coordenadas “especial” donde el eje positivo significa moverse hacia ABAJO (como una pantalla o una vista de interfaz), necesita adaptar esta función de esta manera, y negar las coordenadas Y:

    Ejemplo en 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 } 

    Esta función da una respuesta correcta a la pregunta. La respuesta está en radianes, por lo que el uso, para ver los angularjs en grados, es:

     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 

    Basado en la referencia “Peter O” .. Aquí está la versión de Java

     private static final float angleBetweenPoints(PointF a, PointF b) { float deltaY = by - ay; float deltaX = bx - ax; return (float) (Math.atan2(deltaY, deltaX)); } 
     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; 

    función 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 

    Una fórmula para un ángulo de 0 a 2pi.

    Hay x = x2-x1 e y = y2-y1.La fórmula está funcionando para

    cualquier valor de x y y. Para x = y = 0, el resultado no está definido.

    f (x, y) = pi () – pi () / 2 * (1 + signo (x)) * (1 signo (y ^ 2))

      -pi()/4*(2+sign(x))*sign(y) -sign(x*y)*atan((abs(x)-abs(y))/(abs(x)+abs(y)))