直線同士を結ぶ直線を求める

2本の直線を最短で結ぶ直線と交点の計算方法。

計算

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

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

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

ベクトルP1P2は

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

ベクトルACをacとする

P1P2 = ac + d2 x cd – d1 x ab

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

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

式を展開すると

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

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

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

同じように

cd・(ac + d2 x cd – d1 x 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);

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

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をコピーしました