Cómo mapear atan2 () a grados 0-360


108

atan2(y, x) tiene esa discontinuidad en 180 ° donde cambia a -180 ° ..0 ° en sentido horario.

¿Cómo mapeo el rango de valores a 0 ° ..360 °?

aquí está mi código:

CGSize deltaPoint = CGSizeMake(endPoint.x - startPoint.x, endPoint.y - startPoint.y);
float swipeBearing = atan2f(deltaPoint.height, deltaPoint.width);

Estoy calculando la dirección de un evento táctil de deslizamiento dado el startPointy endPoint, ambas estructuras de puntos XY. El código es para iPhone, pero cualquier idioma que lo admita atan2f()servirá.


Nota: El método de actualización publicado no devolverá cero grados, sino valores justo por encima de 0 a 360,0.
chux - Restablecer a Monica

2
> [Cómo obtener el ángulo desde 2 posiciones] [1] [1]: stackoverflow.com/questions/9457988/…
MAnoj Sarnaik

Esta función funciona muy bien, sin embargo, el cálculo del ángulo de "grados de rumbo" se invierte. por ejemplo, 45 grados serían típicamente en el primer cuadrante, sin embargo, esto en el cuarto cuadrante. 135 grados normalmente estaría en el segundo cuadrante, pero esta función lo devuelve para estar en el tercer cuadrante. simplemente puedo tomar el valor de retorno de la función x y negarlo de 360 ​​para obtener el valor de ángulo correcto, sin embargo, tengo curiosidad por saber por qué está sucediendo esto en primer lugar.
goelv

Respuestas:


66
(x > 0 ? x : (2*PI + x)) * 360 / (2*PI)

6
Probablemente también desee x> = 0 para el caso x = 0.
bpw1621

13
Para aquellos que no se sientan cómodos con esta notación, y sin la conversión a grados incorporada: if (x> 0) {radianes = x;} else {radianes = 2 * PI + x;} entonces solo estamos agregando 2PI al resultado si es menor que 0.
David Doria

1
O (x >= 0 ? x : (2*PI + x)) * 180/PIcomo en(x < 0 ? 2*PI + x : x) * 180/PI
user3342816

97

Solución usando Modulo

Una solución simple que atrapa todos los casos.

degrees = (degrees + 360) % 360;  // +360 for implementations where mod returns negative numbers

Explicación

Positivo: 1 a 180

Si modifica cualquier número positivo entre 1 y 180 por 360, obtendrá exactamente el mismo número que ingresó. Mod aquí solo asegura que estos números positivos se devuelvan con el mismo valor.

Negativo: -180 a -1

El uso de mod aquí devolverá valores en el rango de 180 y 359 grados.

Casos especiales: 0 y 360

El uso de mod significa que se devuelve 0, lo que la convierte en una solución segura de 0 a 359 grados.


3
soluciones increíbles :)
Qadir Hussain

5
No creo que sea necesario agregar 360. -1% 360 sigue siendo 359 :)
pleasemorebacon

11
No creo que esto sea correcto en todos los idiomas. En Javascript-1 % 360 = -1
Startec

Tampoco es un enfoque viable en Java
Hulk

1
@pleasemorebacon Incorrecto. En algunos idiomas, -1% 360 es -1.
Pharap

40

Simplemente agregue 360 ​​° si la respuesta de atan2 es menor que 0 °.


6
Que es lo mismo que "simplemente agregue 2 * PI" si tiene uno de esos días.
Chris O

33

O si no le gusta la ramificación, simplemente niegue los dos parámetros y agregue 180 ° a la respuesta.

(Agregar 180 ° al valor de retorno lo coloca bien en el rango de 0 a 360, pero cambia el ángulo. Negar ambos parámetros de entrada lo invierte).


2
Gracias, esto es justo lo que estaba buscando.
Jeremy Herrman

2
Prefiero modificar mi código para usar ángulos desnormalizados (<0,> = 360) pero siempre parece haber alguien apuntando a esa falsa sensación "optimizada"; por eso quería agregar esto. (¿O fue porque esta era la forma más rápida de evitar un código de depuración temporal que usé?
Hmm

1
Definitivamente no es fácil de asimilar, como puedo estar de acuerdo después de más de 2 años. Entonces: agregar 180 ° al valor de retorno lo coloca muy bien en el rango de 0-360, pero cambia el ángulo. Negar ambos parámetros de entrada lo invierte.
aib

Esto puede tener algunos problemas cuando $ x = 0 $ y $ y> 0 $ iirc
Trinidad

22

@erikkallen está cerca pero no del todo bien.

theta_rad = atan2(y,x);
theta_deg = (theta_rad/M_PI*180) + (theta_rad > 0 ? 0 : 360);

Esto debería funcionar en C ++: (dependiendo de cómo se implemente fmod, puede ser más rápido o más lento que la expresión condicional)

theta_deg = fmod(atan2(y,x)/M_PI*180,360);

Alternativamente, puede hacer esto:

theta_deg = atan2(-y,-x)/M_PI*180 + 180;

ya que (x, y) y (-x, -y) difieren en ángulos 180 grados.


si te entendí correctamente en Fortran es atan2 (-y, -x) * 180 / PI + 180. ¿Es correcto?
gansub

lo siento, no conozco a FORTRAN. Pero tus matemáticas parecen correctas.
Jason S

11

Tengo 2 soluciones que parecen funcionar para todas las combinaciones de x e y positivas y negativas.

1) Abuso de atan2 ()

De acuerdo con los documentos, atan2 toma los parámetros y y x en ese orden. Sin embargo, si los invierte, puede hacer lo siguiente:

double radians = std::atan2(x, y);
double degrees = radians * 180 / M_PI;
if (radians < 0)
{
    degrees += 360; 
}

2) Use atan2 () correctamente y conviértalo después

double degrees = std::atan2(y, x) * 180 / M_PI;
if (degrees > 90)
{
    degrees = 450 - degrees;
}
else
{
    degrees = 90 - degrees;
}

Usted señor, es un salvador de vidas. Acabo de usar este enfoque en Unity y funciona de maravilla.
porfiriopartida

7

@Jason S: su variante "fmod" no funcionará en una implementación que cumpla con los estándares. El estándar C es explícito y claro (7.12.10.1, "las funciones fmod"):

si y es distinto de cero, el resultado tiene el mismo signo que x

así,

fmod(atan2(y,x)/M_PI*180,360)

en realidad es solo una reescritura detallada de:

atan2(y,x)/M_PI*180

Sin embargo, su tercera sugerencia es acertada.


5

Esto es lo que hago normalmente:

float rads = atan2(y, x);
if (y < 0) rads = M_PI*2.f + rads;
float degrees = rads*180.f/M_PI;

2
angle = Math.atan2(x,y)*180/Math.PI;

He hecho una fórmula para orientar el ángulo de 0 a 360

angle + Math.ceil( -angle / 360 ) * 360;

2

Una solución alternativa es utilizar la función mod () definida como:

function mod(a, b) {return a - Math.floor (a / b) * b;}

Luego, con la siguiente función, se obtiene el ángulo entre los puntos ini (x, y) y end (x, y) . El ángulo se expresa en grados normalizados a [0, 360] grados. y Norte haciendo referencia a 360 grados.

    function angleInDegrees(ini, end) {
        var radian = Math.atan2((end.y - ini.y), (end.x - ini.x));//radian [-PI,PI]
        return mod(radian * 180 / Math.PI + 90, 360);
    }

1

La geosfera de los paquetes R calculará el rumbo de rumbo, que es una línea de rumbo constante dado un punto de origen y un este / norte. El este y el norte deben estar en una matriz o vector. El punto de origen de una rosa de los vientos es 0,0. El siguiente código parece resolver fácilmente el problema:

windE<-wind$uasE
windN<-wind$vasN
wind_matrix<-cbind(windE, windN)
wind$wind_dir<-bearingRhumb(c(0,0), wind_matrix)
wind$wind_dir<-round(wind$wind_dir, 0)

1
theta_rad = Math.Atan2(y,x);
if(theta_rad < 0)
  theta_rad = theta_rad + 2 * Math.PI;    //if neg., add 2 PI to it
theta_deg = (theta_rad/M_PI*180) ;        //convert from radian to degree

//or
theta_rad = Math.Atan2(y,x);
theta_rad = (theta_rad < 0) ? theta_rad + 2 * Math.PI : theta_rad;
theta_deg = (theta_rad/M_PI*180) ;

-1 grado se convierte en (-1 + 360) = 359 grados
-179 grados se convierte en (-179 + 360) = 181 grados


¿Qué es Math.PI? ¿Es lo mismo que M_PI?
Pang

1
double degree = fmodf((atan2(x, y) * (180.0 / M_PI)) + 360, 360);

Esto devolverá el grado de 0 ° -360 ° en sentido antihorario, 0 ° es a las 3 en punto.


1

Una fórmula para tener un rango de valores de 0 a 360 grados.

f (x, y) = 180-90 * (1 + signo (x)) * (1-signo (y ^ 2)) - 45 * (2 + signo (x)) * signo (y)

     -(180/pi())*sign(x*y)*atan((abs(x)-abs(y))/(abs(x)+abs(y)))

¿Puede explicar cómo se relaciona esto con la pregunta?
Klaus Gütter

1

Aquí hay algo de javascript. Simplemente ingrese los valores xey.

var angle = (Math.atan2(x,y) * (180/Math.PI) + 360) % 360;
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.