web-dev-qa-db-ja.com

atan2()を0〜360度にマップする方法

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()をサポートする言語であればすべて可能です。

一般的な解決策とコードの両方で、助けてくれてありがとう。

更新:erikkallenの答えをニースの長い変数名を持つ関数にしたので、6か月後に理解できます。たぶんそれは他の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;
}
89
willc2
(x > 0 ? x : (2*PI + x)) * 360 / (2*PI)
54
erikkallen

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

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

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

説明

Positive:1から180

1から180 x 360までの正の数をmodすると、入力したものとまったく同じ数が得られます。ここでのmodは、これらの正の数が同じ値として返されることを保証します。

負:-180から-1

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

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

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

84

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

34
dave4420

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

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

30
aib

@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度異なるためです。

20
Jason S

正と負の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;
}
8
Fibbles

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

yがゼロ以外の場合、結果はxと同じ符号になります

副<文>この[前述の事実の]結果として、それ故に、従って、だから◆【同】consequently; therefore <文>このような方法で、このようにして、こんなふうに、上に述べたように◆【同】in this manner <文>そのような程度まで<文> AひいてはB◆【用法】A and thus B <文>例えば◆【同】for example; as an example、

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

実際には、次の詳細な書き換えです。

atan2(y,x)/M_PI*180

ただし、3番目の提案はすぐにわかります。

6
Stephen Canon

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

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

私は角度を0から360に向けるための式を作りました

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

別の解決策は、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
A. Torrez Garay

Rパッケージのジオスフィアは、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)
0
Ariane

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)))
0
double degree = fmodf((atan2(x, y) * (180.0 / M_PI)) + 360, 360);

これは、反時計回りに0°〜360°の角度を返します。0°は3時です。

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

0
PhilC