JavaScript
CreateJS
数学
三角関数

三角関数で角度から座標を導くふたつの式の使い途

三角関数の$sin$と$cos$を使うと、角度から座標を求めることができます。おもに用いられるのは、ふたつの方程式です。それぞれがどのようなところで、どのように使われるのかをご説明します。

三角関数で角度から座標を定めるふたつの方程式

まずは、ふたつの方程式を以下に示しましょう。第1は、原点$(0, 0)$からの距離$r$と$x$軸正方向となす角度$\theta$から座標$(x, y)$を求めます。

x = r\cos\theta\\
y = r\sin\theta

第2は、座標$(x, y)$を原点$(0, 0)$から角度$\theta$回して、新たな座標$(x', y')$を導く式です。

x' = x\cos\theta - y\sin\theta\\
y' = x\sin\theta + y\cos\theta

原点からの距離と角度で座標を定める ー 極座標

第1の方程式は、三角関数の定義にもとづきます。半径1の円(単位円)の円周上の点$P(x, y)$と原点$O$を結ぶ$OA$が$x$軸の正方向となす角度を$\theta$としたとき、座標$(x, y)$はつぎのように定められています。

x = \cos\theta\\
y = \sin\theta

三角関数のsinとcos

図001

すると、原点が$(x_o, y_o)$で距離は$r$、角度が$\theta$のときは、座標$(x, y)$はつぎの式で表されます。距離と角度からレーダーのように定める座標は「極座標」と呼ばれます。

x = r\cos\theta + x_o\\
y = r\sin\theta + y_o

座標を原点から一定角回した新たな座標も計算できます。まず、座標の原点からの距離および$x$軸となす角度を求めます。つぎに、距離はそのまま、回す角度を足し込んで導けばよいのです。

JavaScriptコードで書くなら、つぎのとおりです。なお、ECMAScript 2015のMath.hypot()メソッドは、座標の原点からの距離を返します。

const r = Math.hypot(x, y);
const angle = Math.atan2(y, x);
const newX = r * Math.cos(angle + rotation);
const newY = r * Math.sin(angle + rotation);

座標を原点から決められた角度回す

座標を原点から決められた角度回す場合には、第2の方程式を使う方が無駄な手間は省けます。もとの座標の原点からの距離も角度も求めなくて済むからです。とくに、たくさんの座標を同じ角度回すときなら、$sin$と$cos$の値は一度計算すれば使い回せるので、さらにお得になります(「任意の座標を原点から指定した角度回す」参照)。

x' = x\cos\theta - y\sin\theta\\
y' = x\sin\theta + y\cos\theta

原点が$(x_o, y_o)$のときは、それらの値を$(x, y)$座標から差し引いて回し、そのあとで原点座標を足し込みます。

x' = (x - x_o)\cos\theta - (y - y_o)\sin\theta + x_o\\
y' = (x - x_o)\sin\theta + (y - y_o)\cos\theta + y_o

三角関数のふたつの式を使った作例

つぎのjudo.itの作例はふたつの方程式を使ってみました。CreateJSを用いたアニメーションです。ウィンドウ内をクリックするたびに、円がランダムに置かれて、中心から回ります。

ランダムに置いた円を回す

1804002_001.png
>> jsdo.itへ

円の配置は、中心からの距離と角度をランダムに決めて、第1の方程式で定めました。距離には範囲を定めて、円は中心近くには置かず、真ん中は空白にしています。

function getPolar(r, angle, center) {
    const x = r * Math.cos(angle) + center.x;
    const y = r * Math.sin(angle) + center.y;
    return {x: x, y: y};
}

多くの座標を同じ角度回すときは、第2の方程式がお得でした。$cos$と$sin$の値ははじめに求め、それをすべての座標計算に使い回しています。引数に受け取る複数の座標は、配列に納められている前提です。

function rotatePoints(points, angle, center) {
    const cos = Math.cos(angle);
    const sin = Math.sin(angle);
    points.forEach((point) => {
        const x = point.x - center.x;
        const y = point.y - center.y;
        point.x = x * cos - y * sin + center.x;
        point.y = x * sin + y * cos + center.y;
    });
}