線分ABと点Pの最短距離と交点を求める。
内積を使う。片方のベクトルが正規化されていた場合、内積の値が投影した長さになることを利用する。Aと点Pを結んだベクトルAPと、ベクトルABを正規化したベクトルabの内積はdになる。これによってA+ab*dで交点Cが計算できる。交点Cが分かればPとCの距離(点と直線の最短距離)を求めることができる。
vector ab = normalize(B - A);
float d = dot(P-A, ab);
// 交点座標
vector C = A + ab * d;
実例:ライン
// input0: line
// input1: point
// RunOver: Detail
vector A = point(0, "P", 0);
vector B = point(0, "P", 1);
vector P = point(1, "P", 0);
vector ab = normalize(B - A);
float d = (dot(P-A, ab));
// 直線の範囲内か判別
if(d >= 0 && d < length(A-B))
{
// 交点座標
vector C = A + ab * d;
addpoint(0, C);
}
実例:カーブ
ループで各エッジと比較する。交点座標がエッジ内に収まっているかチェックする。
// input1: point
// input2: polyline
float minDist = 10000;
vector closestCross;
vector P = point(1, "P", 0);
// 各エッジとの交点を比較する
for(int i = 0; i < npoints(2)-1; i++)
{
vector A = point(2, "P", i);
vector B = point(2, "P", i+1);
vector ab = normalize(B - A);
float d = dot(P-A, ab);
// 直線の範囲内か判別
if(d >= 0 && d <= length(A-B))
{
vector C = A + ab * d; // 新しいポイント
float dist = length(C-P);
// 最小の値なら更新
if(dist < minDist)
{
minDist = dist;
closestCross = C;
}
}
// 位置が始点より前の場合
else if(d < 0)
{
float dist = length(P-A);
// 最小の値なら更新
if(dist < minDist)
{
minDist = dist;
closestCross = A;
}
}
// 位置が終点より後ろの場合
else if(d > length(A-B))
{
float dist = length(P-B);
// 最小の値なら更新
if(dist < minDist)
{
minDist = dist;
closestCross = B;
}
}
}
int pt = addpoint(0, closestCross);