120

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

startPointendPoint、両方のXYポイント構造体を指定して、スワイプタッチイベントの方向を計算しています。コードはiPhone用ですが、サポートしているどの言語でもかまいatan2f()ません。

4

16 に答える 16

114

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

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

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

説明

正:1〜180

1から180x360までの正の数を変更すると、入力したのとまったく同じ数が得られます。ここでの変更は、これらの正の数が同じ値として返されることを保証するだけです。

マイナス:-180から-1

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

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

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

于 2014-09-08T13:06:30.210 に答える
72
(x > 0 ? x : (2*PI + x)) * 360 / (2*PI)
于 2009-08-21T10:20:23.473 に答える
47

atan2からの答えが0°未満の場合は、360°を追加するだけです。

于 2009-08-21T10:17:48.160 に答える
38

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

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

于 2009-08-21T12:08:07.530 に答える
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度異なるためです。

于 2009-08-21T19:14:43.823 に答える
13

正と負の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;
}
于 2014-08-20T06:35:48.140 に答える
8

@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番目の提案は的確です。

于 2009-08-21T20:37:00.833 に答える
5

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

float rads = atan2(y, x);
if (y < 0) rads = M_PI*2.f + rads;
float degrees = rads*180.f/M_PI;
于 2017-02-06T14:59:33.410 に答える
5

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

var angle = (Math.atan2(x,y) * (180/Math.PI) + 360) % 360;
于 2020-04-21T02:24:53.137 に答える
3

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

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

次に、次の関数を使用して、ini(x 、y)ポイントとend(x、y)ポイントの間の角度を取得します。角度は、[0、360]度に正規化された度で表されます。と北は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);
    }
于 2016-02-03T21:47:59.290 に答える
2
angle = Math.atan2(x,y)*180/Math.PI;

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

angle + Math.ceil( -angle / 360 ) * 360;
于 2015-02-04T07:58:00.530 に答える
2

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)))
于 2018-11-25T13:18:30.453 に答える
1

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)
于 2016-05-19T14:32:57.240 に答える
1
double degree = fmodf((atan2(x, y) * (180.0 / M_PI)) + 360, 360);

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

于 2016-10-09T06:49:23.577 に答える
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度になります

于 2017-02-03T03:56:28.357 に答える
0

あなたのアプリケーションでは、正確な角度は必要なく、よりおおよそのコンパス角度、たとえば16方向のうちの1つを好むと思いますか?もしそうなら、このコードはatanの問題を回避し、実際に浮動小数点を完全に回避します。これはビデオゲーム用に作成されているため、8ビットと16ビットの整数を使用します。

/*

                                           349.75d         11.25d, tan=0.2034523
                                              \             /
                                               \   Sector  /      
                                                \    0    /  22.5d tan = ?2 - 1
                                             15      |      1   33.75
                                                     |         /   45d, tan = 1
                                        14           |            2 _56.25
                                                     |             /  67.5d, tan = 1 + ?2
                                     13              |               3
                                                     |                __ 78.75
                                                     |                
                                    12---------------+----------------4 90d tan = infty
                                                     |                __ 101.25
                                                     |                
                                     11              |               5
                                                     |               
                                        10           |            6
                                                     |          
                                             9       |      7
                                                     8



*/

// use signs to map sectors:
static const int8_t map[4][5] = {  /* +n means n >= 0, -n means n < 0 */
  /* 0: +x +y */ {0, 1, 2, 3, 4},
  /* 1: +x -y */ {8, 7, 6, 5, 4},
  /* 2: -x +y */ {0, 15, 14, 13, 12},
  /* 3: -x -y */ {8, 9, 10, 11, 12}
};

int8_t sector(int8_t x, int8_t y) { // x,y signed in range -128:127, result 0:15 from north, clockwise.
  int16_t tangent; // 16 bits
  int8_t quadrant = 0;
  if (x > 0) x = -x; else quadrant |= 2; // make both negative avoids issue with negating -128 
  if (y > 0) y = -y; else quadrant |= 1;
  if (y != 0) {
    // The primary cost of this algorithm is five 16-bit multiplies.
    tangent = (int16_t)x*32;   // worst case y = 1, tangent = 255*32 so fits in 2 bytes.
    /*
       determine base sector using abs(x)/abs(y).
       in segment:
           0 if         0 <= x/y < tan 11.25   -- centered around 0     N
           1 if tan 11.25 <= x/y < tan 33.75   --                 22.5  NxNE
           2 if tan 33.75 <= x/y < tan 56.25   --                 45    NE
           3 if tan 56.25 <= x/y < tan 78.75   --                 67.5  ExNE
           4 if tan 78.75 <= x/y < tan 90      --                 90    E
    */
    if (tangent > y*6  ) return map[quadrant][0]; // tan(11.25)*32
    if (tangent > y*21 ) return map[quadrant][1]; // tan(33.75)*32
    if (tangent > y*47 ) return map[quadrant][2]; // tan(56.25)*32
    if (tangent > y*160) return map[quadrant][3]; // tan(78.75)*32
    // last case is the potentially infinite tan(90) but we don't need to check that limit.
  }
  return map[quadrant][4];
}
于 2021-08-24T19:49:29.250 に答える