Într-un limbaj de programare (Python, C#, etc) am nevoie pentru a determina cum să calculeze unghiul dintre o linie și axa orizontală?
Cred că o imagine descrie cel mai bine ceea ce vreau:
Dat (P1x,P1y) și (P2x,P2y) care este cel mai bun mod de a calcula acest unghi? Originea este în topleft și numai pozitiv cadranul este folosit.
În primul rând a afla diferența între punctul de pornire și punctul final (aici, acest lucru este mai mult de un segment de linie îndreptate, nu este un "linia", deoarece liniile prelungi la infinit și don't începe de la un anumit punct).
deltaY = P2_y - P1_y
deltaX = P2_x - P1_x
Apoi se calculează unghiul (care ruleaza de la partea pozitivă a axei X de la " P1 "pozitiv pe axa Y la "P1").
angleInDegrees = arctan(deltaY / deltaX) * 180 / PI
Dar arctan
nu poate fi ideal, pentru că împărțirea diferențelor în acest fel va șterge distincția este necesar să se facă distincția care cvadrantul unghiului este în (a se vedea mai jos). Utilizați următoarele loc dacă limba dvs. include un atan2 funcția:
angleInDegrees = atan2(deltaY, deltaX) * 180 / PI
EDIT (Feb. 22, 2017): În general, cu toate acestea, numindu atan2(deltaY,deltaX)
doar pentru a obține unghiul corect pentru că " și " sin` poate fi neelegant. În aceste cazuri, de multe ori puteți face următoarele:
(deltaX, deltaY)
ca un vector.deltaX " și " deltaY de vector's lungime (
sqrt(deltaXdeltaX+deltaYdeltaY)`), cu excepția cazului în care lungimea este de 0.deltaY
va fi acum sinusul acelui unghi.EDIT (Feb. 28, 2017): Chiar și fără normalizarea (deltaX, deltaY)
:
deltaX
va spune dacă cosinus este descris în pasul 3 este pozitiv sau negativ.deltaY
va spune dacă sinusul este descris în pasul 4 este pozitiv sau negativ.deltaX " și "deltaY
va spune care cvadrantul unghiului este, în ceea ce privește partea pozitivă a axei X de la "P1":+deltaX
, +deltaY
: 0 la 90 de grade.-deltaX
, +deltaY
: de la 90 la 180 de grade.-deltaX
, -deltaY
: de la 180 la 270 de grade (-180 la -90 de grade).+deltaX
, -deltaY
: 270 la 360 de grade (-90 la 0 grade).O punere în aplicare în Python folosind radiani (furnizate pe iulie 19, 2015 de Eric Leschinski, care a editat raspunsul meu):
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)
Trece toate testele. Vezi https://en.wikipedia.org/wiki/Unit_circle
Ne pare rau, dar nu'm destul de sigur că Peter's în care răspunsul este greșit. Rețineți că axa y se duce în jos a paginii (frecvente în grafică). Ca atare, deltaY de calcul trebuie să fie inversată, sau veți obține răspunsul greșit.
Ia în considerare:
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
Deci, dacă în exemplul de mai sus, P1 este (1,1) și P2 este (2,2) [deoarece Y crește în josul paginii], codul de mai sus va da 45.0 grade pentru exemplul prezentat, care este greșit. Schimba ordinea de deltaY calcul și funcționează în mod corespunzător.
Având în vedere exact întrebare, punându-ne într-o "speciale" sistem de coordonate unde pozitivă a axei înseamnă mișcare în JOS (cum ar fi un ecran sau o interfață de vedere), trebuie să se adapteze această funcție astfel, negative și Y coordonatele:
Exemplu în 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
}
Această funcție oferă un răspuns corect la întrebare. Răspunsul este exprimat în radiani, astfel încât utilizare, pentru a putea vizualiza și unghiuri în grade, este:
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
Baza de referință "Petru O".. Aici este versiunea 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)); }
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;
O formulă pentru un unghi de la 0 la 2pi.
Acolo este x=x2-x1 și y=y2-y1.Formula este de lucru pentru
orice valoare a lui x și y. Pentru x=y=0 rezultatul este nedefinit.
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)))