グラフィックプログラミングの公式とか概念について -『JavaScript』
ラジアン
普段よく使う度数法でなく弧度法のラジアン(radian)を使います。直感的ではないけど、計算量を節約するメリットがあります。ラジアンは半径が1の円の円周の長さを基準とした角度の表現で、度数法の360度は 2π です。
JavaScript で角度(degree)をラジアンに変換する関数は次のようにかけます。
const deg2Rad = (deg) => deg * Math.PI / 180
三平方の定理
直角三角形において、「直角」をはさむ2つの辺の長さを a,b、斜辺の長さを c としたとき。
a2+b2=c2
加法定理
sin(α+β) = sinαcosβ + cosαsinβ
cos(α+β) = cosαcosβ − sinαsinβ
tan(α+β) = (tanα + tanβ) / (1 - tanαtanβ)
等符号を反転させても成り立つ。
加法定理の覚え方。図形でわかる公式の考え方 | アタリマエ!
余弦定理 Law of cosines
[image:9CB0D869-EB7D-4DAE-8698-5EB558222F77-4423-0003BF7C6DB114C7/Addition theorem.png]
a2 = b2 + c2 - 2bc * cosA
b2 = a2 + c2 - 2ac * cosB
c2 = b2 + a2 - 2ab * cosC
『2辺の長さとその間の角度』から『残り1辺の長さ』を求めたり、『3辺の長さ』から『角度』を求めるのに利用する。
余弦定理とは何か?図解でわかるその使い道と公式の証明 | アタリマエ!
ベクトル
- 「大きさ」と「向き」を持った量のことで、2次元や3次元を数式で表現できる
- 矢印がベクトルの「向き」を表し、長さがベクトルの「大きさ」
- 大きさ(長さ)と向き(方向)が同じであれば「位置は関係なく等しい」
ベクトルとは何か。その意味とベクトルの足し算・引き算 | アタリマエ!
ベクトルは「大きさ」と「向き」という概念がありますが、普段扱うような大きさだけの数値で大小を表現する概念をベクトルの世界(線型代数学)では、スカラー(実数)と呼びます。ラジアンの値もスカラーのひとつと言えますが、大きさだけでなく向きの情報も持っているのがベクトルの特性です。始点と終点の2つの座標を矢印て結ぶことで、大きさと向きを同時に表現できます。
ベクトルの大きさ(長さ)
ベクトル a→ = (ax,ay)
のとき、ベクトルの長さは三平方の定理から求めることができます。
|a→| = √(ax2+ay2)
Math.hypot(ax, ay)
(ax,ay)
のように記述されているとき「座標」か「ベクトル」かを判断する必要があります。ベクトルの場合は暗黙的に原点を始点とした矢印をイメージするようにします。
単位ベクトル
単位ベクトルはそのベクトルをその大きさで割って、大きさを1にすることにより、向きだけを持つようにしたベクトルです。向きだけを比較したり計算したい場合に利用します。
(ax / |a→|, ay / |a→|)
ax / Math.hypot(ax, ay)
ay / Math.hypot(ax, ay)
また大きさが1のベクトルは半径1の円の外周に重なる性質を持ちます。ので、逆説すると、半径1の円で sin cos を利用すると単位ベクトルを求めることができます。あるベクトルを単位化してから、アークサイン Math.asin()
やアークコサイン Math.acos()
に与えると、ベクトルが成す角度を得られます。
ベクトルの和と差
X や Y の次元ごとに計算します。
a→ + b→ = (ax + bx, ay + by)
AB→ + BC→ = AC→
a→ - b→ = (ax - by, ay - by)
AC→ − AB→ = BC→
ベクトルとは何か。その意味とベクトルの足し算・引き算 | アタリマエ!
ベクトルの積(スカラー倍)
ベクトルを拡縮したい場合は、ベクトルにスカラー値を掛けます。JavaScript の Math.sin()
や、Math.cos()
は、常に半径1の円を基準にした値を返します。これをベクトルに見立てると、ある向きに移動するための、縦横の移動量の比を得ることができるので、これにスカラーを掛け合わせてあるオブジェクトの速度をコントロールできます。
ベクトルの内積 dot
ベクトルの内積はどの次元のベクトルでも同じように求めることができますが、異なる次元のベクトル同士では計算することはできません。ベクトル同士を掛け合わせて、そのすべてを合算します。計算結果はスカラー値になります。
const dot = (a, b) => a.x * b.x + a.y * b.y
a→ ・ b→ = ax * bx + ay * by // 1
a→ ・ b→ = |a→||b→|cosθ // 2
a→ ・ b→ = cosθ // 単位ベクトルの場合 (長さが1)
2の式から内積を求め、余弦定理から導かれる 2 = 1 で cosθ
を求めるような使い方をよくすることがあります。また、|a→||b→|
が単位ベクトルであれば、単位ベクトル同士の内積は cosθ
と等しいので角度がわかる。
ベクトルそれぞれを単位化し、内積を求め、それに Math.acos()
で、ベクトル同士がなす角度θを計算できます。
const dot = (a, b) => a.x * b.x + a.y * b.y
function normalize(x, y) {
const vLen = Math.hypot(x, y)
return { x: x / vLen, y: y / vLen }
}
// 内積
const dotVal = dot(normalize(ax, ay), normalize(bx, by))
// 角度
const rad = Math.acos(dotVal)
ベクトルの外積 cross
外積 a→ x b→
はベクトルの掛け算で、次の性質のベクトルを求めることができます。
- 向きが a→ と b→ に直角で交わる(右ネジの法則)
- 長さが a→ と b→ を2辺とする原点からの平行四辺形OACBの面積に等しい
a→ x b→ = (ay * bz - az * by, az * bx - ax * bz, ax * by - ay * bx)
a→ x b→ = |a→||b→|sinθ
a→ x b→ = sinθ
内積と同様の特徴として、単位化されたベクトルの外積は sinθ と等しくなります。
外積の性質を利用するとできることとして、ある面と水平なベクトルを2つを定義すると、そこからまっすぐに上に伸びるベクトルを求められ、そのベクトルの向きに応じて明るさを計算したりします。それを法線ベクトル呼び、法線ベクトルは面に対して直角のベクトルなので、面の向きを表します。
ベクトルの内積と外積の単位円での振舞
- 単位ベクトルの内積は cosθ
- 単位ベクトルの外積は sinθ
- 内積 = 0 のとき、ベクトル同士は垂直
- 内積 > 0 のとき、cosθ < 90 の鋭角
- 内積 < 0のとき、cosθ > 90 の鈍角
- 外積 = 0のとき、ベクトル同士は水平
- 外積 > 0 のとき、ベクトルAの左側にベクトルBがある
- 外積 > 0 のとき、ベクトルAの右側にベクトルBがある
行列
行列は、数字や式(成分)を横(行)と縦(列)に並べたもので、m行n列の行列と呼びます。行列はベクトルを変形したり、変換したりする際に使います。
行列の積は次のように求めます。
[ cosΘ -sinΘ ] x [ X ]
[ sinΘ cosΘ ] x [ Y ]
▼
[ cosΘX + -sinΘY ]
[ sinΘX + cosΘY ]
▼
[ X ]
[ Y ]
行列はベクトルの回転に利用できます。
const rotate2D = (vec, rad) => {
const sin = Math.sin(rad)
const cos = Math.cos(rad)
return [vec[0] * cos + vec[1] * sin, vec[0] * sin + vec[1] * cos]
}