はじめに
こんにちは。takenakadxです。
私は、趣味でゲーム開発をしているため、高校数学レベルの線形代数学に触れることがあります。しかし、数学があまり得意ではないので、ネットから数式をコピペしてくることがほとんどです。
今日もゲームの実装に「3次元で点と直線の距離を求める関数」を実装する必要に迫られた為、ネットからコピペしようと探してました。
しかし、2次元での点と直線の距離を求める公式などは見つかるのですが、3次元バージョンが見つからなかったので、自分で実装しました。
備忘録としてここに残しておこうと思います。
直線と点の距離を求める場合は次の2つの方法があります。
- 直線の媒介変数表示を利用して解く方法
- 三角形を仮定して解く方法
それぞれについて説明していきます。
直線の媒介変数表示を利用して解く方法
はじめに、問題設定を行っておきます。
ある点 P(座標$\vec{p}$)と直線Lが3次元ユークリッド空間上にあるとして、直線Lは点$X_0$(座標$\vec{x_0}$)を通り、$\vec{v}$に平行な直線とします。
この時、点Pと直線Lの距離を求めていこうと思います。
まず、直線L上の点の座標を求めておきます。直線L上の任意の点は媒介変数tを用いて
L : t \vec{v} + \vec{x_0}
と表せます。
次に、点Pと直線Lが最も近くなる点をC(座標は直線状の点であるので$t_c \vec{v} + \vec{x_0}$で表せる)とします。
すると、ベクトル$\vec{PC}$とベクトル$\vec{v}$は直交するので次式が成り立ちます。
\vec{v} \cdot \vec{PC} = 0 \tag{1}
ここで、ベクトル$\vec{PC}$は点Pの座標と点Cの座標の差であるので
\vec{PC} = \vec{p} - (t_c \vec{v} + \vec{x_0})
となり、これを(1)に代入して$t_c$について整理すると
t_c = \frac{1}{|\vec{v}|^2} \vec{v} \cdot (\vec{p} - \vec{x_0})
これによって点Cの座標が導出できたので、点Cと点Pの距離は
|(\vec{p} - \vec{x_0}) - \frac{1}{|\vec{v}|^2} \vec{v} \cdot (\vec{p} - \vec{x_0}) \vec{v}| \tag{2}
で求まる。
三角形を仮定して解く方法
図のように、直線状に任意の点A,Bを作り、三角形を仮定して解く。
内積の定義より、$\cos \theta $は
\cos \theta = \frac{\vec{a} \cdot \vec{b}}{|\vec{a}||\vec{b}|} \tag{3}
また、三角関数の定義より次が成り立つ。
\sin \theta = \frac{|\vec{c}|}{|\vec{b}|} \tag{4}
三角関数の法則 $\cos^2 \theta + \sin^2 \theta = 1$と(3)、(4)により、
\frac{(\vec{a} \cdot \vec{b})^2}{(|\vec{a}||\vec{b}|)^2} + \frac{|\vec{c}|^2}{|\vec{b}|^2} = 1
となるので、これを$|\vec{c}|$について解けば
|\vec{c}| = |\vec{b}| \sqrt{1-\frac{(\vec{a}\cdot\vec{b})^2}{(|\vec{a}||\vec{b}|)^2}} \tag{5}
それぞれのやり方が同じかどうかを確かめる。
図を見比べれば分かるが、
- $\vec{v} = \vec{a}$
- $\vec{p} - \vec{x_0} = \vec{b}$
である。
(2)式にそれらを代入してみると、
|\vec{c}| = | \vec{b} - \frac{\vec{a} \cdot \vec{b}}{|\vec{a}|^2} \vec{a} | = ||\vec{b}|\vec{e_b} - \vec{e_a}\cdot(|\vec{b}|\vec{e_b}) \vec{e_a}| = |\vec{b}| |\vec{e_b}-(\vec{e_a}\cdot\vec{e_b})\vec{e_a}| \tag{6}
であることが分かる。ここで、各ベクトルの大きさが1になったベクトルを$\vec{e_a},\vec{e_b}$で表している
($\vec{v} = |\vec{v}|\vec{e_v}$)
ここで、ベクトルの大きさの公式($|\vec{v}| = \sqrt{\vec{v}\cdot\vec{v}}$)を思い出すと、(6)式は
|\vec{b}||\vec{e_b}-(\vec{e_a}\cdot\vec{e_b})\vec{e_a}| = |\vec{b}|\sqrt{(\vec{e_b}-(\vec{e_a}\cdot\vec{e_b})\vec{e_a})\cdot(\vec{e_b}-(\vec{e_a}\cdot\vec{e_b})\vec{e_a})} = |\vec{b}| \sqrt{X}
ここで、平方根の中身$X$は
X = \vec{e_b}\cdot\vec{e_b} + \vec{e_a}\cdot\vec{e_a} (\vec{e_a}\cdot\vec{e_b})^2 - 2(\vec{e_a}\cdot\vec{e_b})^2 = 1 - (\vec{e_a}\cdot\vec{e_b})^2
これより、
|\vec{c}| = |\vec{b}|\sqrt{1-(\vec{e_a}\cdot\vec{e_b})^2 } = |\vec{b}|\sqrt{1-\frac{(\vec{a}\cdot\vec{b})^2}{(|\vec{a}||\vec{b}|)^2} }
となり、(5)式と(2)式が等価であると分かる。
まとめ
色々、数式が出てきて分かりにくかったと思うが、まとめると次のようになる。
点$\vec{x_0} $を通り、$\vec{v}$に平行な直線と点$\vec{p}$との距離は、(2)式によって与えられ、
それと等価な式として(5)式も利用できる。