Chapter 26

回転

miku
miku
2021.11.12に更新

まずは三角関数のおさらいをしよう。(cos(angle) * r, sin(angle) * r) により、原点から angle 方向に r だけ進んだ座標を計算できる。ここで r を固定して angle の値を増やし続けると、半径 r の円周上をぐるぐる回る現象が起こり、このことを円運動と呼んだ。

それに対して今回は別の形で円運動を行う方法について扱いたい。

まず、座標 (x, y) を用意する。そして原点を軸に θ だけ回転させたとき、(x, y)(x', y') の座標に移動するが、その移動後の座標を求めたい。

利用するパラメータは x, y, θ の3つだけである。

移動前の点がx軸上にあるとき

まずは単純化のために移動前の座標がx軸上にあると固定する。つまり (x, 0) だ。

原点から (x, 0) までの距離は x で、(x, 0)(x', y') は同一円周上にあるので、原点から (x', y') までの距離(半径)も x になる。

θ 方向に x だけ進むとき、原点からみて横に移動する量は cosθ * x, 縦は sinθ * x になるので、(x', y') = (cosθ * x, sinθ * x) となる。

移動前の点がy軸上にあるとき

次に、移動前の点がy軸上にあるときについて考える。

図を右に90°回転させれば、先程の「移動前の点がx軸上にあるとき」と同じ形になる。つまり、もともとの 0° / 90° / 180° / 270° の方向を 270° / 0° / 90° / 180° だと思うようにすればいい。

θ(度) 0 90 180 270
cosθ 1 0 -1 0
sinθ 0 1 0 -1

もともとの cosθ, sinθ の値は上記のようになるが、90°回転させた場合の新たな cosθ, sinθ である (x, y) は下記のようになる。

θ(度) 0 90 180 270
x 0 -1 0 1
y 1 0 -1 0

-1~1の範囲を繰り返すのは cosθ, sinθ と一緒なので、cosθ, sinθ を利用した式で表現できそうである。2つの表を見比べるため、結合したものが下記の通りになる。

θ(度) 0 90 180 270
x 0 -1 0 1
y 1 0 -1 0
cosθ 1 0 -1 0
sinθ 0 1 0 -1

ycosθ は一致しており、xsinθ に -1 を掛けたものと一致する。なので (x, y)cosθ, sinθ で表現すると、

(x, y) = (-sinθ, cosθ)

円の半径が r のときは

(x, y) = (-sinθ * r, cosθ * r)

原点から (0, y) までの距離(半径)は y なので、(0, y) にある点を、原点を軸に θ だけ回転したとき、移動後の座標 (x', y')(-sinθ * y, cosθ * y) となる。

長方形で考える

原点から (x, y) までを長方形として捉えて、原点を軸に θ だけ回転させると上記のようになる。(x, 0), (0, y) までをベクトルとして捉えると、(x, y)(x, 0) + (0, y) で求まる。

(x, 0) の回転後の位置は、x軸上に点があるので (cosθ * x, sinθ * x)
(0, y) の回転後の位置は、y軸上に点があるので (-sinθ * y, cosθ * y)

ベクトルの和は (cosθ * x - sinθ * y, sinθ * x + cosθ * y) になる。

ここまでをまとめると、原点を軸に θ だけ回転させると、(x, y) にある点は (cosθ * x - sinθ * y, sinθ * x + cosθ * y) に移動する。

const r = 100;
let x, y, angle;

function setup() {
  createCanvas(windowWidth, windowHeight);

  x = r;
  y = 0;
  angle = 0.03;
}

function draw() {
  const tx = x * cos(angle) - y * sin(angle);
  const ty = x * sin(angle) + y * cos(angle);

  clear();
  translate(width / 2, height / 2);
  circle(tx, ty, 10);

  x = tx;
  y = ty;
}

初期位置を (r, 0) にし、angle ラジアンずつ回転を行う作例。

螺旋

円運動をする際、半径を少しずつ大きくすると螺旋のように回転を行う。

let angle, r;
function setup() {
  createCanvas(windowWidth, windowHeight);

  angle = 0;
  r = 0;

  translate(width / 2, height / 2);
  for (let i = 0; i < 300; i++) {
    const x = cos(angle) * r;
    const y = sin(angle) * r;
    circle(x, y, 10);

    angle += 0.1;
    r++;
  }
}