c# - log10 - ¿Cómo calcular el ángulo entre una línea y el eje horizontal?
pi python (8)
¡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)
En un lenguaje de programació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:
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.
Basado en la referencia "Peter O" .. Aquí está la versión de 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)); }
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.
Primero encuentre la diferencia entre el punto inicial 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:
- Tratar
(deltaX, deltaY)
como un vector. - Normaliza ese vector a un vector unitario. Para hacerlo, divida
deltaX
ydeltaY
por la longitud del vector (sqrt(deltaX*deltaX+deltaY*deltaY)
), a menos que la longitud sea 0. - 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 enP1
). - Y
deltaY
ahora será el seno de ese ángulo. - 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 dirá 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
ydeltaY
te dirán en qué cuadrante está el ángulo, en relación con el eje X positivo enP1
:-
+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
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 ángulos 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
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)))
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
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;