Dans un langage de programmation (Python, C #, etc.), je dois déterminer comment calculer l'angle entre une ligne et l'axe horizontal?
Je pense qu'une image décrit le mieux ce que je veux:
Donné (P1x, P1y) et (P2x, P2y) quel est le meilleur moyen de calculer cet angle? L'origine est en haut et seul le quadrant positif est utilisé.
Commencez par trouver la différence entre le point de départ et le point de fin (ici, il s’agit davantage d’un segment de ligne dirigé, et non d’une "ligne", car les lignes s’étendent à l’infini et ne commencent pas à un point particulier).
deltaY = P2_y - P1_y
deltaX = P2_x - P1_x
Calculez ensuite l’angle (qui va de l’axe X positif en P1
à l’axe Y positif en P1
).
angleInDegrees = arctan(deltaY / deltaX) * 180 / PI
Mais arctan
n'est peut-être pas idéal, car diviser les différences de cette manière effacera la distinction nécessaire pour distinguer le quadrant dans lequel l'angle est situé (voir ci-dessous). Utilisez plutôt le code suivant si votre langue comprend une fonction atan2
:
angleInDegrees = atan2(deltaY, deltaX) * 180 / PI
EDIT (22 février 2017): En général, cependant, appeler atan2(deltaY,deltaX)
uniquement pour obtenir le bon angle pour cos
et sin
peut être inélégant. Dans ces cas, vous pouvez souvent effectuer les opérations suivantes:
(deltaX, deltaY)
comme un vecteur.deltaX
et deltaY
par la longueur du vecteur (sqrt(deltaX*deltaX+deltaY*deltaY)
), sauf si la longueur est 0.deltaX
sera maintenant le cosinus de l'angle entre le vecteur et l'axe horizontal (dans la direction allant du X positif à l'axe Y positif à P1
).deltaY
sera maintenant le sinus de cet angle.EDIT (28 février 2017): Même sans normalisation (deltaX, deltaY)
:
deltaX
vous dira si le cosinus décrit à l'étape 3 est positif ou négatif.deltaY
vous dira si le sinus décrit à l'étape 4 est positif ou négatif.deltaX
et deltaY
vous indiqueront le quadrant dans lequel se trouve l'angle, par rapport à l'axe des X positif à P1
: +deltaX
, +deltaY
: 0 à 90 degrés.-deltaX
, +deltaY
: 90 à 180 degrés.-deltaX
, -deltaY
: 180 à 270 degrés (-180 à -90 degrés).+deltaX
, -deltaY
: 270 à 360 degrés (-90 à 0 degrés).Une implémentation en Python utilisant radians (fournie le 19 juillet 2015 par Eric Leschinski, qui a révisé ma réponse):
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)
Tous les tests réussissent. Voir https://en.wikipedia.org/wiki/Unit_circle
Désolé, mais je suis à peu près sûr que la réponse de Peter est fausse. Notez que l'axe y descend en bas de la page (commun dans les graphiques). En tant que tel, le calcul de deltaY doit être inversé, sinon vous obtenez une mauvaise réponse.
Considérer:
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)));
donne
45.0
-45.0
135.0
-135.0
Donc, si dans l'exemple ci-dessus, P1 est (1,1) et P2 (2,2) [parce que Y augmente la page], le code ci-dessus donnera 45,0 degrés pour l'exemple présenté, ce qui est faux. Changer l'ordre du calcul deltaY et cela fonctionne correctement.
J'ai trouvé une solution en Python qui fonctionne bien!
from math import atan2,degrees
def GetAngleOfLineBetweenTwoPoints(p1, p2):
return degrees(atan2(p2 - p1, 1))
print GetAngleOfLineBetweenTwoPoints(1,3)
En considérant la question exacte, en nous plaçant dans un système de coordonnées "spécial" où un axe positif signifie un mouvement VERS LE BAS (comme un écran ou une vue d'interface), vous devez adapter cette fonction de la manière suivante et inverser les coordonnées Y:
Exemple dans 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
}
Cette fonction donne une réponse correcte à la question. La réponse est exprimée en radians. L’utilisation, pour afficher les angles en degrés, est la suivante:
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
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;
Une formule pour un angle de 0 à 2pi.
Il y a x = x2-x1 et y = y2-y1.La formule fonctionne pour
toute valeur de x et y. Pour x = y = 0, le résultat est indéfini.
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)))
Basé sur la référence "Peter O" .. Voici la version 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)); }
fonction 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