如何检查线段是否与矩形相交?

时间:2013-04-24 23:09:01

标签: algorithm language-agnostic geometry computational-geometry

如果你有2个点,(x1,y1)和(x2,y2),它们代表一个矩形的两个相对的角,以及另外两个点,(x3,y3)和(x4,y4),它们代表2线段的端点,如何检查线段是否与矩形相交?

(线段只是给定端点之间包含的段。它不是由这两个点定义的无限长度线。)

3 个答案:

答案 0 :(得分:26)

一个非常简单的选择是使用a standard algorithm for checking whether two line segments intersect来检查线段是否与构成方框角落的四个线段中的任何一个相交。检查两个线段是否相交在计算上是非常有效的,所以我希望这可以非常快地运行。

希望这有帮助!

答案 1 :(得分:1)

要了解如何推导测试线段是否与矩形相交的公式,重要的是要记住vector dot product的属性。

将线段表示为单位矢量以及线段的起点和原点之间的距离。以下是使用PointFVector变量a_ptStarta_ptEnd计算的一些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));

假设矩形的四个角位于名为VectorvecRect1vecRect2vecRect3的{​​{1}}变量中,请计算distance在线段和目标的边界矩形的所有四个角之间:

vecRect4

如果所有距离都是正的,或者所有距离都是负的,则矩形位于线的一侧或另一侧,因此没有交叉点。 (零范围矩形被认为不与任何线段相交。)

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 */;

如果矩形的点不在线段的范围内,则没有交点。

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)));

我相信这已经足够了。

答案 2 :(得分:0)

使用线段的方向向量获取所有4个顶点(矩形的角)的点积。如果所有4个具有相同符号的值,则所有顶点都位于线的同一侧(不是线段,而是无限线),因此该线不与矩形相交。该方法仅适用于2D交叉检测。这可用于快速过滤大部分(仅使用乘法和加法)。您将不得不进一步检查线段而不是线。