Numa linguagem de programação (Python, C#, etc.) preciso de determinar como calcular o ângulo entre uma linha e o eixo horizontal?
Penso que uma imagem descreve melhor o que eu quero:
Dado (P1x,P1y) e (P2x,P2y) qual é a melhor maneira de calcular este ângulo? A origem está no quadrante das pessoas e apenas o quadrante positivo é utilizado.
Primeiro encontrar a diferença entre o ponto inicial e o ponto final (aqui, isto é mais um segmento de linha dirigido, não um "linha" uma vez que as linhas se estendem infinitamente e don't começam num determinado ponto).
deltaY = P2_y - P1_y
deltaX = P2_x - P1_x
Depois calcular o ângulo (que vai do eixo X positivo em P1
até ao eixo Y positivo em P1
).
angleInDegrees = arctan(deltaY / deltaX) * 180 / PI
Mas o arctan' pode não ser o ideal, porque dividindo as diferenças desta forma apagará a distinção necessária para distinguir em que quadrante está o ângulo (ver abaixo). Em vez disso, utilize o seguinte se a sua língua incluir uma função
atan2`:
angleInDegrees = atan2(deltaY, deltaX) * 180 / PI
EDIT (Fev. 22, 2017): Em geral, contudo, chamar atan2(deltaY,deltaX)
somente para obter o ângulo adequado para cos
e sin
pode ser deselegante. Nesses casos, pode, em vez disso, fazer o seguinte:
(deltaX, deltaY)
como um vector.deltaX
e deltaY
pelo vector's length (sqrt(deltaX*deltaX+deltaY*deltaY)
), a menos que o comprimento seja 0.deltaX
será agora o cosseno do ângulo entre o vector e o eixo horizontal (na direcção do X positivo para o eixo Y positivo em P1
).deltaY
será agora o seno desse ângulo.EDIT (Fev. 28, 2017): Mesmo sem normalizar (deltaX, deltaY)
:
deltaX
dir-lhe-á se o co-seno descrito no passo 3 é positivo ou negativo.deltaY
dir-lhe-á se o cosseno descrito no passo 4 é positivo ou negativo.deltaX
e deltaY
dir-lhe-ão em que quadrante está o ângulo, em relação ao eixo X positivo em P1
:+deltaX
, +deltaY
: 0 a 90 graus.-deltaX
, +deltaY
: 90 a 180 graus.-deltaX
, -deltaY
: 180 a 270 graus (-180 a -90 graus).+deltaX
, -deltaY
: 270 a 360 graus (-90 a 0 graus).Uma implementação em Python utilizando radiantes (fornecida em 19 de Julho de 2015 por Eric Leschinski, que editou a minha resposta):
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)
Todos os testes são aprovados. Ver https://en.wikipedia.org/wiki/Unit_circle
Desculpe, mas I'tenho quase a certeza que a resposta de Peter's está errada. Note-se que o eixo y desce a página (comum nos gráficos). Como tal, o cálculo do deltaY tem de ser invertido, ou obtém-se a resposta errada.
Considere:
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)));
dá
45.0
-45.0
135.0
-135.0
Assim, se no exemplo acima, P1 é (1,1) e P2 é (2,2) [porque Y aumenta para baixo na página], o código acima dará 45,0 graus para o exemplo mostrado, o que está errado. Alterar a ordem do cálculo do deltaY e este funciona correctamente.