円と線分の交点

計算

直線の式は
P1 = P0 + V*t

それぞれの成分に分割すると
X = P.x + V.x * t
Y = P.y + V.y * t

円の式は
X^2 + Y^2 = R^2

それぞれの成分を円の式に代入してtで整理する

(P.x + V.x * t)^2 + (P.y + V.y * t)^2 = R^2

(V.x^2 + V.y^2) t^2 + 2(P.x * V.x + P.y * V.y) t + (P.x^2 + P.y^2 – R^2)

解の公式を使う

ax^2 + bx + c = 0 のとき
x = (-b ± sqrt(b^2 – 4ac)) / 2a
※b^2 – 4acがマイナスのときは解なし

a = (V.x^2 + V.y^2)
b = 2(P.x * V.x + P.y * V.y)
c = (P.x^2 + P.y^2 – R^2)

コード

// 中心座標の入力
float centerx = `chs("../transform1/tx")`;
float centerz = `chs("../transform1/tz")`;

// 半径
float r = `chs("../circle1/scale")`;

// 円が原点になるようにオフセット
vector offset = set(centerx, 0, centerz);

vector p0 = point(1,"P", 0) - offset;
vector p1 = point(1,"P", 1) - offset;

vector v = normalize(p1 - p0);

float a = v.x * v.x + v.z * v.z;
float b = 2 * (p0.x * v.x + p0.z * v.z);
float c = p0.x * p0.x + p0.z * p0.z - r * r;

if(b * b - 4 * a * c >= 0)
{
    float t = (-b + sqrt(b * b - 4 * a * c)) / 2 * a;
    vector cross = p0 + v * t;
    
    // 内積で線分上にあるか判定
    if(dot(p1 - cross, p0 - cross) < 0)
    {
        cross += offset;
        int pt = addpoint(0, cross);
    }
    
    t = (-b - sqrt(b * b - 4 * a * c)) / 2 * a;
    cross = p0 + v * t;
    if(dot(p1 - cross, p0 - cross) < 0)
    {
        cross += offset;
        int pt = addpoint(0, cross);
    }
}
タイトルとURLをコピーしました