直線同士の距離を求める

2本の直線を最短で結ぶ直線の交点を求めて距離を計算する。

計算

直線ABとCDを最短で結ぶ直線(ベクトル)はどちらの直線とも90度で交差する関係で存在している。つまり、どちらの直線とも内積が0で交わる、と考えて方程式を立てて解いていく。

正規化したベクトルABをab
正規化したベクトルCDをcd
AからP1までの距離をd1
CからP2までの距離をd2
とすると

P1 = A + d1 * ab
P2 = C + d2 * cd

ベクトルP1P2

P2 – P1 = C + d2 * cd – (A + d1 * ab) = C – A + d2 * cd – d1 * ab

ベクトルACをac(※正規化はしてない)としてまとめると

P1P2 = ac + d2 * cd – d1 * ab

ベクトルAB、ベクトルCDとの内積の式を立てると

ab・(ac + d2 * cd – d1 * ab) = 0
cd・(ac + d2 * cd – d1 * ab) = 0

式を展開すると

ab・ac + d2(ab・cd) – d1(ab・ab) = 0

abは正規化ベクトルなのでab・abは1になる

d1 = ab・ac + d2(ab・cd)

同じように

cd・(ac + d2 * cd – d1 * ab) = 0

cd・ac + d2(cd・cd) – d1(cd・ab) = 0

d2 = d1(ab・cd) – cd・ac

この2つの式をそれぞれ代入してまとめる

d1 = ab・ac + (d1(ab・cd) – cd・ac)(ab・cd)

d1 = (ab・ac) + d1(cd・ab)(ab・cd) – (cd・ac)(ab・cd)

d1 – d1(ab・cd)(ab・cd) = (ab・ac) – (cd・ac)(ab・cd)

d1( 1 – (ab・cd)(ab・cd) ) = (ab・ac) – (cd・ac)(ab・cd)

d1 = ( (ab・ac) – (cd・ac)(ab・cd) ) / ( 1 – (ab・cd)(ab・cd) )

同じようにd2をまとめると

d2 = ( ab・ac + d2(ab・cd) )(cd・ab) – cd・ac

d2 = (ab・ac)(ab・cd) + d2(ab・cd)(ab・cd) – (cd・ac)

d2 – d2(ab・cd)(ab・cd) = (ab・ac)(ab・cd) – (cd・ac)

d2 ( 1 – (ab・cd)(ab・cd) ) = (ab・ac)(ab・cd) – (cd・ac)

d2 = ( (ab・ac)(ab・cd) – (cd・ac) ) / ( 1 – (ab・cd)(ab・cd) )

となる

コード

// RunOver: Detail

vector a = point(1, "P", 0);
vector b = point(1, "P", 1);
vector ab = normalize(b - a);

vector c = point(2, "P", 0);
vector d = point(2, "P", 1);
vector cd = normalize(d - c);

vector ac = c - a; // ベクトルACは正規化しない

float d1 = (dot(ab, ac) - dot(ac, cd) * dot(ab, cd)) / (1 - dot(ab, cd) * dot(ab, cd));

vector p1 = a + ab * d1;
int pt1 = addpoint(0, p1);

float d2 = (dot(ab, ac) * dot(ab, cd) - dot(cd, ac)) / (1 - dot(ab, cd) * dot(ab, cd));

vector p2 = c + cd * d2;
int pt2 = addpoint(0, p2);

// ポリラインを生成
int prim = addprim(0, "polyline");
addvertex(0, prim, pt1);
addvertex(0, prim, pt2);

setpointattrib(0, "Cd", pt1, set(1,0.5,0));
setpointattrib(0, "Cd", pt2, set(1,0.5,0));

//printf('d1:' + sprintf('%g', d1) + '\n');
タイトルとURLをコピーしました