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á.

willc2
fuente
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)
erikkallen
fuente
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.

Liam George Betsworth
fuente
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 °.

dave4420
fuente
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).

aib
fuente
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.

Jason S
fuente
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;
}
Fibbles
fuente
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.

Stephen Canon
fuente
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;
andrés
fuente
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;
Saad Ahmed
fuente
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);
    }
A. Torrez Garay
fuente
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)
Ariane
fuente
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

PhilC
fuente
¿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.

Finallz
fuente
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)))
theodore panagos
fuente
¿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;
escuadra
fuente