Per prima cosa trova la differenza tra il punto iniziale e il punto finale (qui, si tratta più di un segmento di linea diretta, non di una "linea", poiché le linee si estendono all'infinito e non iniziano in un punto particolare).
deltaY = P2_y - P1_y
deltaX = P2_x - P1_x
Quindi calcola l'angolo (che corre dall'asse X P1
positivo all'asse Y positivo a P1
).
angleInDegrees = arctan(deltaY / deltaX) * 180 / PI
Ma arctan
potrebbe non essere l'ideale, perché dividere le differenze in questo modo cancellerà la distinzione necessaria per distinguere in quale quadrante si trova l'angolo (vedi sotto). Utilizzare invece quanto segue se la propria lingua include una atan2
funzione:
angleInDegrees = atan2(deltaY, deltaX) * 180 / PI
EDIT (22 febbraio 2017): in generale, tuttavia, chiamare atan2(deltaY,deltaX)
solo per ottenere l'angolazione corretta cos
e sin
potrebbe non essere elegante. In questi casi, è spesso possibile invece procedere come segue:
- Tratta
(deltaX, deltaY)
come un vettore.
- Normalizza quel vettore su un vettore unitario. Per fare ciò, dividi
deltaX
e deltaY
per la lunghezza del vettore ( sqrt(deltaX*deltaX+deltaY*deltaY)
), a meno che la lunghezza sia 0.
- Successivamente,
deltaX
sarà ora il coseno dell'angolo tra il vettore e l'asse orizzontale (nella direzione dall'asse X positivo all'asse Y positivo a P1
).
- E
deltaY
ora sarà il seno di quell'angolo.
- Se la lunghezza del vettore è 0, non avrà un angolo tra esso e l'asse orizzontale (quindi non avrà un seno e un coseno significativi).
EDIT (28 febbraio 2017): Anche senza normalizzare (deltaX, deltaY)
:
- Il segno di
deltaX
ti dirà se il coseno descritto nel passaggio 3 è positivo o negativo.
- Il segno di
deltaY
ti dirà se il seno descritto al punto 4 è positivo o negativo.
- I segni di
deltaX
e deltaY
ti diranno in quale quadrante si trova l'angolo, in relazione all'asse X positivo a P1
:
+deltaX
, +deltaY
: Da 0 a 90 gradi.
-deltaX
, +deltaY
: Da 90 a 180 gradi.
-deltaX
, -deltaY
: Da 180 a 270 gradi (da -180 a -90 gradi).
+deltaX
, -deltaY
: Da 270 a 360 gradi (da -90 a 0 gradi).
Un'implementazione in Python usando i radianti (fornita il 19 luglio 2015 da Eric Leschinski, che ha modificato la mia risposta):
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)
Tutti i test passano. Vedi https://en.wikipedia.org/wiki/Unit_circle