三角関数の$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
すると、原点が$(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を用いたアニメーションです。ウィンドウ内をクリックするたびに、円がランダムに置かれて、中心から回ります。
####ランダムに置いた円を回す
>> 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;
});
}