web-dev-qa-db-ja.com

線分が長方形と交差するかどうかを確認する方法は?

2つのポイント(x1、y1)および(x2、y2)が長方形の2つの対角を表し、他の2つのポイント(x3、y3)および(x4、y4)が2つのエンドポイントを表す場合ラインセグメント、ラインセグメントが長方形と交差するかどうかをどのように確認できますか?

(ラインセグメントは、指定されたエンドポイント間に含まれるセグメントです。これらの2点で定義される無限の長さのラインではありません。)

28
omega

非常に簡単なオプションの1つは、 2つのラインセグメントが交差するかどうかをチェックする標準アルゴリズム を使用して、ラインセグメントがボックスのコーナーを構成する4つのラインセグメントのいずれかと交差するかどうかをチェックすることです。 2つのラインセグメントが交差しているかどうかを確認するのは計算上非常に効率的であるため、これは非常に高速に実行できると予想されます。

お役に立てれば!

27
templatetypedef

4つの頂点すべて(長方形の角)のドット積を、線分セグメントの方向ベクトルで取得します。 4つすべてに同じ符号の値がある場合、すべての頂点は線の同じ側(線分ではなく無限の線)にあるため、線は長方形と交差しません。このアプローチは、2D交差点の検出にのみ有効です。これを使用して、それらのほとんどを迅速にフィルタリングできます(乗算と加算のみを使用)。線の代わりに線分をさらにチェックする必要があります。

1
Srinivasan

線分が長方形と交差するかどうかをテストするための式の導出方法を理解するには、 vector dot product のプロパティを覚えておくことが重要です。

線分を単位ベクトルとして表し、線分セグメントの始点と原点の間の距離を表します。 PointF 変数a_ptStartおよびa_ptEndから Vector を使用して計算するC#コードを次に示します。

Vector vecLine = new Vector(a_ptEnd.X - a_ptStart.X, a_ptEnd.Y - a_ptStart.Y);
double dLengthLine = vecLine.Length;
vecLine /= dLengthLine;
double dDistLine = Vector.Multiply(vecLine, new Vector(a_ptStart.X, a_ptStart.Y));

また、ラインセグメントの垂直ベクトルと、原点からの距離を計算する必要があります。単位ベクトルを90°回転させるのは easy です。

Vector vecPerpLine = new Vector(-vecLine.Y, vecLine.X);
double dDistPerpLine = Vector.Multiply(vecPerpLine, new Vector(a_ptStart.X, a_ptStart.Y));

長方形の四隅がvecRect1vecRect2vecRect3、およびvecRect4と呼ばれるVector変数にあると仮定して、 距離 を計算します=線分とターゲットの境界矩形の4つの角すべての間:

double dPerpLineDist1 = Vector.Multiply(vecPerpLine, vecRect1) - dDistPerpLine;
double dPerpLineDist2 = Vector.Multiply(vecPerpLine, vecRect2) - dDistPerpLine;
double dPerpLineDist3 = Vector.Multiply(vecPerpLine, vecRect3) - dDistPerpLine;
double dPerpLineDist4 = Vector.Multiply(vecPerpLine, vecRect4) - dDistPerpLine;
double dMinPerpLineDist = Math.Min(dPerpLineDist1, Math.Min(dPerpLineDist2,
    Math.Min(dPerpLineDist3, dPerpLineDist4)));
double dMaxPerpLineDist = Math.Max(dPerpLineDist1, Math.Max(dPerpLineDist2,
    Math.Max(dPerpLineDist3, dPerpLineDist4)));

すべての距離が正の場合、またはすべての距離が負の場合、長方形は線の片側またはもう一方の側にあるため、交点はありません。 (ゼロ範囲の長方形は、線分と交差しないと見なされます。)

if (dMinPerpLineDist <= 0.0 && dMaxPerpLineDist <= 0.0
        || dMinPerpLineDist >= 0.0 && dMaxPerpLineDist >= 0.0)
    /* no intersection */;

次に、ターゲットの境界矩形の4つの角すべてを線分に投影します。これにより、線の原点とその線上の長方形の角の投影との間の距離がわかります。

double dDistLine1 = Vector.Multiply(vecLine, vecRect1) - dDistLine;
double dDistLine2 = Vector.Multiply(vecLine, vecRect2) - dDistLine;
double dDistLine3 = Vector.Multiply(vecLine, vecRect3) - dDistLine;
double dDistLine4 = Vector.Multiply(vecLine, vecRect4) - dDistLine;
double dMinLineDist = Math.Min(dDistLine1, Math.Min(dDistLine2,
    Math.Min(dDistLine3, dDistLine4)));
double dMaxLineDist = Math.Max(dDistLine1, Math.Max(dDistLine2,
    Math.Max(dDistLine3, dDistLine4)));

四角形のポイントがラインセグメントの範囲内に収まらない場合、交差はありません。

if (dMaxLineDist <= 0.0 || dMinLineDist >= dLengthLine)
    /* no intersection */;

それで十分だと思います。

1
ulatekh