atan2()を度0-360にマッピングする方法


108

atan2(y, x) 180°で不連続性があり、時計回りに-180°..0°に切り替わります。

値の範囲を0°..360°にマップするにはどうすればよいですか?

これが私のコードです:

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

両方のXYポイント構造体であるstartPointとを指定して、スワイプタッチイベントの方向を計算していendPointます。コードはiPhone用ですが、サポートatan2f()する言語であれば何でも可能です。


注:ポストされた更新メソッドは、0度ではなく、0から360.0の値を返します。
chux-モニカを2013年

2
> [1] [2つの位置からの角度を取得する方法] [1]:stackoverflow.com/questions/9457988/...
MANOJ Sarnaik

この関数はうまく機能しますが、「bearingDegrees」計算の角度が反転します。たとえば、45度は通常第1象限ですが、これは第4象限です。通常、135度は第2象限にありますが、この関数はそれを第3象限に戻します。私は単純に関数の戻り値xを取り、それを360から否定して正しい角度の値を取得できますが、なぜこれが最初に起こっているのか知りたいのですが?
goelv

回答:


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

6
x = 0の場合、おそらくx> = 0も必要です。
bpw1621 2011年

13
この表記に慣れておらず、組み込みの度数への変換がない場合:if(x> 0){radians = x;} else {radians = 2 * PI + x;}なので、結果に2PIを追加しますifそれが0未満である
デヴィッド・ドリア

1
または(x >= 0 ? x : (2*PI + x)) * 180/PIのように(x < 0 ? 2*PI + x : x) * 180/PI
user3342816

97

Moduloを使用したソリューション

すべてのケースをキャッチするシンプルなソリューション。

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

説明

正:1から180

1から180 x 360までの正の数値をmodすると、入力した数値とまったく同じになります。ここでmodを実行すると、これらの正の数値が同じ値として返されるようになります。

負:-180から-1

ここでmodを使用すると、180〜359度の範囲の値が返されます。

特殊なケース:0および360

modを使用すると0が返されるため、これは0〜359度の安全なソリューションになります。


3
素晴らしいソリューション:)
Qadir Hussain

5
360を追加する必要があるとは思いません。-1%360はまだ359です:)
pleasemorebacon

11
これはすべての言語で正しいとは思いません。Javascriptの場合-1 % 360 = -1
Startec

また、Javaで実行可能なアプローチではありません
ハルク

1
@pleasemorebacon不正解です。一部の言語では-1%360は-1です。
Pharap、2018年

40

atan2からの回答が0°未満の場合は、360°を追加します。


6
これは、その日のいずれかを使用している場合、「2 * PIを追加する」と同じです。
Chris O

33

または、分岐が気に入らない場合は、2つのパラメーターを無効にして、答えに180°を追加します。

(戻り値に180°を追加すると、0〜360の範囲にうまく収まりますが、角度が反転します。両方の入力パラメーターを否定すると、戻り値が反転します。)


2
ありがとう、これは私が探していたものです。
Jeremy Herrman、

2
非正規化された角度(<0、> = 360)を使用するようにコードを変更したいのですが、偽の「最適化された」感覚を狙っている人が常にいるようです。これが私がこれを追加したかった理由です。(それともこれは私がうーん使用されるいくつかの一時的なデバッグコードの周りの迅速な方法だったので、それはでしたか?)
AIB

1
私は2年以上経って同意できるので、間違いなく簡単なことではありません。したがって、戻り値に180°を追加すると、0〜360の範囲にうまく収まりますが、角度が反転します。両方の入力パラメーターを否定すると、元に戻ります。
aib 2014年

$ x = 0 $および$ y> 0 $の場合、これにはいくつかの問題が発生する可能性があります。iirc–
トリニダード

22

@erikkallenは近いですが、正確ではありません。

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

これはC ++で機能するはずです(fmodの実装方法によっては、条件式よりも高速または低速になる場合があります)。

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

あるいは、これを行うことができます:

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

(x、y)と(-x、-y)は角度が180度異なるためです。


Fortranで正しく理解していれば、atan2(-y、-x)* 180 / PI + 180です。
gansub

申し訳ありませんが、FORTRANを知りません。しかし、あなたの数学は正しいようです。
Jason S

11

正と負のxとyのすべての組み合わせで機能するように見える2つのソリューションがあります。

1)虐待atan2()

ドキュメントによると、atan2はパラメータyとxをこの順序で受け取ります。ただし、それらを逆にすると、次のことができます。

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

2)atan2()を正しく使用し、後で変換する

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

あなたはサー、命の救世主です。Unityでこのアプローチを使用しただけで、魅力のように機能します。
porfiriopartida

7

@Jason S: "fmod"バリアントは、標準に準拠した実装では機能しません。C標準は明示的で明確です(7.12.10.1、「fmod関数」):

yがゼロ以外の場合、結果はxと同じ符号を持ちます

したがって、

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

実際には、以下の詳細な書き換えにすぎません。

atan2(y,x)/M_PI*180

ただし、3番目の提案は適切です。


5

これは私が通常行うことです:

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;

角度を0から360に向ける式を作成しました

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

2

別の解決策は、次のように定義されたmod()関数を使用することです。

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

次に、次の関数を使用して、ini(x、y)end(x、y)のポイント間の角度を取得します。角度は、[0、360] degに正規化された度数で表されます。そして北は360度を参照します。

    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

Rパッケージgeosphereは、原点と東/北を指定した一定の方位線であるBearingRhumbを計算します。東座標と北座標は、行列またはベクトルでなければなりません。ウィンドローズの原点は0,0です。次のコードは問題を簡単に解決するようです:

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度は(-1 + 360)になります= 359度
-179度は(-179 + 360)= 181度になります


なにMath.PI?それは同じM_PIですか?
2017

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

これは、反時計回りに0°-360°から次数を返します。0°は3時です。


1

0から360度までの値の範囲を持つ数式。

f(x、y)= 180-90 *(1 + sign(x))*(1-sign(y ^ 2))-45 *(2 + sign(x))* sign(y)

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

これが質問とどのように関連しているか説明していただけますか?
KlausGütter18年

1

ここにいくつかのJavaScriptがあります。xとyの値を入力するだけです。

var angle = (Math.atan2(x,y) * (180/Math.PI) + 360) % 360;
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.