web-dev-qa-db-ja.com

2つの光線が交差するかどうかの判断

2D平面上に無限に伸びる2つの光線がありますが、どちらにも開始点があります。それらは両方とも、開始点と無限に伸びる光線の方向のベクトルによって記述されます。 2つの光線が交差するかどうかを確認したいのですが、交差する場所を知る必要はありません(衝突検出アルゴリズムの一部です)。

これまで見てきたことはすべて、2本の線または線分の交点を見つけることを説明しています。これを解決するための高速アルゴリズムはありますか?

22
Faken

与えられた:2つの光線a、b、開始点(原点ベクトル)as、bs、および方向ベクトルad、bd。

交点pがある場合、2本の線は交差します。

p = as + ad * u
p = bs + bd * v

この方程式系にu> = 0およびv> = 0の解がある場合(正の方向が光線になる)、光線は交差します。

2Dベクトルのx/y座標の場合、これは次のことを意味します。

p.x = as.x + ad.x * u
p.y = as.y + ad.y * u
p.x = bs.x + bd.x * v
p.y = bs.y + bd.y * v

さらなるステップ:

as.x + ad.x * u = bs.x + bd.x * v
as.y + ad.y * u = bs.y + bd.y * v

Vに対する解決:

v := (as.x + ad.x * u - bs.x) / bd.x

Uに対する挿入と解決:

as.y + ad.y * u = bs.y + bd.y * ((as.x + ad.x * u - bs.x) / bd.x) 
u := (as.y*bd.x + bd.y*bs.x - bs.y*bd.x - bd.y*as.x ) / (ad.x*bd.y - ad.y*bd.x)

Uを計算し、次にvを計算します。両方が正の場合、光線は交差し、そうでない場合は交差しません。

27
Peter Walser

PeterWalserの回答に同意できず申し訳ありません。方程式を解くと私の机になります:

u = ((bs.y - as.y) * bd.x - (bs.x - as.x) * bd.y) / (bd.x * ad.y - bd.y * ad.x)
v = ((bs.y - as.y) * ad.x - (bs.x - as.x) * ad.y) / (bd.x * ad.y - bd.y * ad.x)

一般的な用語を除外すると、これは次のようになります。

dx = bs.x - as.x
dy = bs.y - as.y
det = bd.x * ad.y - bd.y * ad.x
u = (dy * bd.x - dx * bd.y) / det
v = (dy * ad.x - dx * ad.y) / det

5つの減算、6つの乗算、2つの除算。

光線が交差するかどうかだけを知る必要がある場合は、uとvの符号で十分であり、これら2つの除算は、何に応じてnum * denom <0または(sign(num)!= sign(denom))に置き換えることができます。ターゲットマシンでより効率的です。

Det == 0のまれなケースは、光線が交差しないことを意味することに注意してください(1つの追加の比較)。

29
Gunter Blache

光線は点のセットで表すことができますA + Vt、ここでAは開始点、Vは光線の方向を示すベクトル、t >= 0はパラメータです。したがって、2つの光線が交差するかどうかを判断するには、次のようにします。

bool DoRaysIntersect(Ray r1, Ray r2)
{
    // Solve the following equations for t1 and t2:
    //   r1.A.x + r1.V.x * t1 == r2.A.x + r2.V.x * t2
    //   r1.A.y + r1.V.y * t1 == r2.A.y + r2.V.y * t2
    if(no solution)  // (e.g. parallel lines)
    {
        if(r1 == r2)  // same ray?
            return true;
        else
            return false;  // parallel, non-intersecting
    }
    else  // unique solution
    {
        if(t1 >= 0 && t2 >= 0)
            return true;
        else
            return false;  // they would intersect if they are lines, but they are not lines
    }
}
3
Adam Rosenfield

線は点pとベクトルvで表されます。

line = p + a * v(すべてのa)

光線はその線の(正の)半分です:

ray = p + a * v(すべてのa> = 0)

2つの線が交差するかどうかを判断するには、それらを等しく設定して解決します。

交差が発生する場所p1 + a1 * v1 = p2 + a2 * v2
(2つの未知数があることに注意してください。12pvは多次元であるため、、および2つの方程式)

解決する12 -両方が負でない場合、それらは交差します。 1つが負の場合、それらは交差しません。

GeomAlgorithms.com には、3Dの線を処理する非常に優れたアルゴリズムがいくつかあります...しかし、一般的に言えば、2本の線が3D空間で交差する確率は非常に低いです。

2Dでは、勾配を確認する必要があります。勾配が等しくない場合、それらは交差します。勾配が等しい場合、それらの点が同じx座標または同じy座標を持っていれば、それらは交差します。

1
vicatcu

2つの光線が交差するかどうかだけを確認したい。 2つの光線から作成された2つの「三角形」の回転方向を計算することによってそれについて説明します。それらは実際には三角形ではありませんが、数学的な観点から、三角形の回転を計算したいだけの場合、共通の開始点を持つ2つのベクトルのみが必要であり、残りは重要ではありません。

最初の三角形は、2つのベクトルと開始点によって形成されます。開始点は、最初の光線の開始点になります。最初のベクトルは、最初の光線の方向ベクトルになります。 2番目のベクトルは、最初の光線の開始点から2番目の光線の開始点までのベクトルになります。ここから、2つのベクトルの外積を取り、符号に注意します。

2番目の三角形に対してこれを再度実行します。この場合も、開始点は2番目の光線の開始点です。最初のベクトルは2番目の光線の方向であり、2番目のベクトルは2番目の光線の開始点から最初の光線の開始点までです。ベクトルの外積を再度取り、符号に注意します。

ここで、2つの記号を取得して、それらが同じであるかどうかを確認します。それらが同じである場合、交差点はありません。それらが異なる場合、交差点があります。それでおしまい!

これがいくつかの疑似コードです:

sign1 = cross(vector1, point1 - point2)
sign2 = cross(vector2, point2 - point1)

if (sign1 * sign2 < 0) // If signs are mismatched, they will multiply to be negative
    return intersection

これは、5回の乗算、6回の減算、および1回の比較であることがわかります。

0
Faken