2012年4月25日水曜日

度数と弧度(ラジアン)との変換

通常、度(度数)とラジアン(弧度)の変換には以下のような式を使います。

ラジアン = 度数 * (π / 180)
度数 = ラジアン * (180 / π)

以下のような式も同じです。
ラジアン = 度数 / 180 * π
度数 = ラジアン / π * 180

当たり前のように書いてしまっているため、復習です。
独学のため、以下、誤りがありましたらご報告いただけるとありがたいです。


そもそもπとは何か

πとは「円周の長さを直径で割った率」のことです。図1だと、「円周率(π) = 円周の長さ(C) ÷ 直径(d)」となります。そのため、直径1の円の円周の長さは約3.14となります。
また同時に、「円周の長さ(C) = 円周率(π) × 直径(d)」となります。
余談ですが、円周率を求めるためには「円周の長さ」が必要となり、円周の長さを求めるためには「円周率」が必要となります。それでは円周率の3.14...とはどのように求められるのでしょうか?実は、別に様々な円周率の計算方式がありそれらを使って円周率の3.14...を近似で求めているのです。
図1: 円周率とは

ラジアンとは何か

OpenGLなどで、sin関数やcos関数への引数に渡すラジアンですが、普段から使っている「度数(°)」とは何が違うのでしょうか?
1ラジアン(rad)とは、「半径と円周の弧の長さと等しくなる角度」とされています。図2では、「半径(r) = 弧(l)となる場合の角度(θ)が1rad」となります。
弧の長さ(l)は、角度(θ)に比例して大きくなるので「弧の長さ(l) = 半径(r) × 角度(θ)」となります。相互変換できるのでどちらでも良いのですが、厳密には、この角度というのは「度(°)」ではなく、「ラジアン(rad)」です。
図2: ラジアンとは
回転させるという行為は円を書くということですが、その角度を求めるのになぜsin関数やcos関数ではラジアンを使うのでしょうか?それは単に、円との相性が良い為です。「半径(r)が1」の単位円で考えてみると、「弧(l) = 角度(θ)」となり「弧(l)は角度(θ)によってのみ決まる」ということになります。つまり、どれだけの距離を移動すれば良いかがラジアンから求められるということです。

度とラジアンの求め方

さて、いよいよタイトルの通り「度数と弧度との変換」ですが、図3の通りの計算式で求められます。上2つよりも長くなってはいますが簡単です。例えば、「角度(θ)が180°の場合」を考えます。
その場合、図1で求めた式を利用して「円周の長さの半分(C/2) = 2πr/2 = πr」となります。そして、図2で求めた式を利用し、「角度(θ) = 弧(l)/半径(r)」に代入すると「角度(θ) = πr/r = π」となります。つまり、「180° = π(rad)」です。
「180°の場合、πrad」なのですから「1°は(π/180)rad」「1radは(180/π)°」となります。つまり、最終的には、最初に書いた式の
ラジアン = 度数 * (π / 180)
度数 = ラジアン * (180 / π)
となります。

図3: 度数とラジアンの求め方

別の計算式

ところが、「iOSで作るシューティングゲーム」では、以下のような計算を行なっています。
// mの左から回転の行列を乗算する
GLfloat rad=r*M_PI*2, c=cosf(rad), s=sinf(rad);

つまり、「ラジアン = 度数 * π * 2」としています。実はこれでも問題なく動作します。むしろ掛け算の分だけ計算が少なくて済みます。

ラジアン = 度数 * (π / 180)
(両辺に360を掛ける)
ラジアン * 360 = 度数 * (π / 180) * 360
ラジアン * 360 = 度数 * π * 2
ですね。つまり、普通に求めた場合よりもラジアンが360倍になっているということです。では、ラジアンが360倍になるとどうなるか。ここでもう一度、角度を求める式です。

度数 = ラジアン * (180 / π)
(両辺に360を掛ける)
度数 * 360 = ラジアン * (180 / π) * 360

そうです、360倍ということは円を一周して同じ所に戻ってくるということです。
これは良いと思ったのですが、間違いでしたらご教示いただけると幸いです。

ちなみに、最新のiOS 5から導入された「GLKit.framework」ですが「GLKMathUtils.h」で以下のように定義されています。
static __inline__ float GLKMathDegreesToRadians(float degrees) { return degrees * (M_PI / 180); };
static __inline__ float GLKMathRadiansToDegrees(float radians) { return radians * (180 / M_PI); };

うーん、普通ですね。もっとも、掛け算も割り算も処理速度にまず違いが出ることはなく、分かりやすさを取れば普通の書き方のほうが良いですね。

0 コメント:

コメントを投稿