Pergunta

ATAN2 (y, x) tem que descontinuidade a 180 °, onde ele passa para -180 ° ..0 ° no sentido horário.

Como faço para mapear o intervalo de valores para 0 ° ..360 °?

aqui é o meu código:

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

Eu estou calculando a direção de um evento swiping toque dada a startPoint e endPoint, ambas estruturas ponto XY. O código é para o iPhone, mas qualquer linguagem que suporte atan2f () vai fazer.

Obrigado por sua ajuda caras, tanto com a solução geral e código.

Atualizar : Eu fiz a resposta de erikkallen em uma função com bons nomes longos variáveis, então eu vou compreendê-lo 6 meses a partir de agora. Talvez possa ajudar algum outro Noob iPhone.

float PointPairToBearingDegrees(CGPoint startingPoint, CGPoint endingPoint)
{
    CGPoint originPoint = CGPointMake(endingPoint.x - startingPoint.x, endingPoint.y - startingPoint.y); // get origin point to origin by subtracting end from start
    float bearingRadians = atan2f(originPoint.y, originPoint.x); // get bearing in radians
    float bearingDegrees = bearingRadians * (180.0 / M_PI); // convert to degrees
    bearingDegrees = (bearingDegrees > 0.0 ? bearingDegrees : (360.0 + bearingDegrees)); // correct discontinuity
    return bearingDegrees;
}
Foi útil?

Solução

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

Outras dicas

Solução usando Modulo

Uma solução simples que pega todos os casos.

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

Explicação

Positivo: 1 a 180

Se você mod qualquer número positivo entre 1 e 180 por 360, você terá exatamente o mesmo número que você colocar. Mod aqui apenas garante esses números positivos são retornados como o mesmo valor.

negativo: -180 a -1

Usando mod aqui irá retornar valores na faixa de 180 e 359 graus.

casos especiais: 0 e 360 ??

Usando meios modernos que 0 é retornado, tornando esta uma solução 0-359 graus seguro.

Basta adicionar 360 °, se a resposta de atan2 é inferior a 0 °.

Ou se você não gosta ramificação, apenas negar os dois parâmetros e adicionar 180 ° para a resposta.

(Adição de 180 ° em relação aos coloca o valor de retorno ele bem na gama de 0-360, mas inverte o ângulo. A negação de ambos os parâmetros de entrada vira-o para trás.)

@erikkallen está perto, mas não muito bem.

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

Isso deve funcionar em C ++: (dependendo de como fmod é implementado, pode ser mais rápido ou mais lento do que a expressão condicional)

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

Como alternativa, você poderia fazer isso:

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

desde que (x, y) e (-x, -y) diferem em ângulos de 180 graus.

Eu tenho 2 soluções que parecem trabalhar para todas as combinações de x e y positivo e negativo.

1) Abuso atan2 ()

De acordo com os docs atan2 usa parâmetros Y e X, nessa ordem. No entanto, se você inverter a eles que você pode fazer o seguinte:

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

2) Use atan2 () corretamente e convertido posteriormente

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

@ Jason S: o seu "fmod" variante não funcionará em uma aplicação compatível com os padrões. O padrão C é explícita e clara (7.12.10.1, "as funções FMod"):

Se y é diferente de zero, o resultado tem o mesmo sinal como x

Assim,

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

é realmente apenas um detalhado reescrita de:

atan2(y,x)/M_PI*180

A sua terceira sugestão, no entanto, está no local.

Isto é o que eu faço normalmente:

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

I fez um Fórmula para o ângulo de orientação em 0-360

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

Uma solução alternativa é usar a função mod () definida como:

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

Em seguida, com a seguinte função, o ângulo entre <> fortes ini (x, y) e finais (x, y) pontos é obtido. O ângulo é expressa em graus normalizados de [0, 360] graus. e Norte da referência 360 graus.

    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);
    }

O geosphere pacotes R calculará bearingRhumb, que é uma linha de rolamento constante dado um ponto de origem e easting / northing. O easting e northing deve ser numa matriz ou vector. O ponto de origem para uma rosa dos ventos é 0,0. O código a seguir parece resolver prontamente o 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)
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 ° C torna-se (-1 + 360) = 359 °
-179 ° C torna-se (-179 + 360) = 181 ° C

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

Isso irá retornar grau de 0 ° -360 ° para a esquerda, 0 ° é a 3:00.

Uma fórmula para ter a gama de valores de 0 a 360 graus.

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

     -(180/pi())*sign(x*y)*atan((abs(x)-abs(y))/(abs(x)+abs(y)))
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top