線分の交差判定と交点の求め方

線分の交差判定について。まずは線分同士で判定をして、交差していることが確認できたら、直線同士の交点を計算する、という二段構えです。

交差の判定

//
// 線分が交差しているかチェックする関数
//
int IsIntersectLine(vector p0; vector p1; vector p2; vector p3)
{
    int result = 0;
    
    // まずは線分ABが直線CDと交差しているか判定
    float ta = (p3.x - p2.x) * (p2.z - p0.z) + (p3.z - p2.z) * (p0.x - p2.x);
    float tb = (p3.x - p2.x) * (p2.z - p1.z) + (p3.z - p2.z) * (p1.x - p2.x);
     
    if(ta * tb < 0)
    {
        // 線分CDが直線ABと交差しているか判定
        float tc = (p1.x - p0.x) * (p0.z - p2.z) + (p1.z - p0.z) * (p2.x - p0.x);
        float td = (p1.x - p0.x) * (p0.z - p3.z) + (p1.z - p0.z) * (p3.x - p0.x);
         
        if(tc * td < 0)
        {
            result = 1;
        }
    }
    
    return result;
}

判別式if(ta * tb < 0)の符号を<=にするとギリギリ隣接している場合も交差している判別されます。

解説

線分ABと線分CDの交差を考えます。

直線AB(y = ax + b)にたいして点C、Dがy > ax + bか、y < ax + bのどちら側にあるかで判定する。
点(x1, y1)、点(x2、y2)を通る直線の方程式は
(y2 – y1) / (x2 – x1) * (x – x1) = y – y1

この式を変形する。両辺に(x2 – x1)を掛ける
(x2 – x1) * y = (x2 – x1) * y1 + (y2 – y1) * x – (y2 – y1) * x1
(x2 – x1) * (y1 – y) + (y2 – y1) * (x – x1) = 0

この式のx、yに点C(x3、 y3)または点D(x4、y4)を代入する。解の符号を掛けてマイナスなら交差していると考える。(片方がプラス、片方がマイナスだと掛けてマイナスになる)

tc = (x2 – x1) * (y1 – y3) + (y2 – y1) * (x3 – x1)
td = (x2 – x1) * (y1 – y4) + (y2 – y1) * (x4 – x1)

tc * td < 0 なら交差している

これは直線ABと線分CDの交差なので、直線CDと線分ABの交差も調べる。

ta = (x4 – x3) * (y3 – y1) + (y4 – y3) * (x1 -x3)
tb = (x4 – x3) * (y3 – y2) + (y4 – y3) * (x2 -x3)

ta * tb < 0 なら交差。

ただ交差しているかの判定だけならここまで。

交点の計算

//
// 直線の交点を求める関数
//
vector CrossPoint(vector p0; vector p1; vector p2; vector p3)
{
    // 線分が交差していた場合、直線の交点座標を計算する
    float a1 = p0.z - p1.z;
    float b1 = p1.x - p0.x;
    float c1 = (p1.x - p0.x) * p0.z - (p1.z - p0.z) * p0.x;
     
    float a2 = p2.z - p3.z;
    float b2 = p3.x - p2.x;
    float c2 = (p3.x - p2.x) * p2.z - (p3.z - p2.z) * p2.x;
     
    float x = (c1 * b2 - c2 * b1) / (a1 * b2 - a2 * b1);
    float z = (a1 * c2 - a2 * c1) / (a1 * b2 - a2 * b1);
     
    // 交点座標のポイントを追加
    vector result = set(x, 0, z);
            
    return result;
}

解説

交差しているとわかったら、つぎに直線同士の交点を求める。
連立一次方程式なのでクラメールの公式を使う。

a1 * x + b1 * y = c1
a2 * x + b2 * y = c2

のとき

x = (c1 * b2 – c2 * b1) / (a1 * b2 – a2 * b1)
y = (a1 * c2 – a2 * c1) / (a1 * b2 – a2 * b1)

となる

点A(x1、y1)、点B(x2、y2)の方程式
(y2 – y1) / (x2 – x1) * (x – x1) = (y – y1)

式を変形すると

(y1 – y2) * x + (x2 – x1) * y = (x2 – x1) * y1 – (y2 – y1) * x1

a1 = (y1 – y2)
b1 = (x2 – x1)
c1= (x2 – x1) * y1 – (y2 – y1) * x1

同じように点Cと点Dの式からa2、b2、c2を求める。

タイトルとURLをコピーしました