線分と点の距離

線分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);
タイトルとURLをコピーしました