如何检测两条线段相交的位置?
如何确定两条线是否相交,如果相交,则在什么 x,y 点相交?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
如何确定两条线是否相交,如果相交,则在什么 x,y 点相交?
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
接受
或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
发布评论
评论(27)
我尝试实现上面 Jason 优雅描述的算法; 不幸的是,在调试过程中进行数学计算时,我发现很多情况下它不起作用。
例如,考虑点 A(10,10) B(20,20) C(10,1) D(1,10) 给出 h=.5,但通过检查可以清楚地看出,这些线段并不靠近每个线段其他。
绘制该图可以清楚地看出 0 < h< 1 标准仅表明截取点如果存在则位于 CD 上,但没有告诉我们该点是否位于 AB 上。
为了确保存在交叉点,必须对变量g进行对称计算,截取要求为:
0< g< 1 和 0 < h< 1
I have tried to implement the algorithm so elegantly described by Jason above; unfortunately while working though the mathematics in the debugging I found many cases for which it doesn't work.
For example consider the points A(10,10) B(20,20) C(10,1) D(1,10) gives h=.5 and yet it is clear by examination that these segments are no-where near each other.
Graphing this makes it clear that 0 < h < 1 criteria only indicates that the intercept point would lie on CD if it existed but tells one nothing of whether that point lies on AB.
To ensure that there is a cross point you must do the symmetrical calculation for the variable g and the requirement for interception is:
0 < g < 1 AND 0 < h < 1
这是对加文答案的改进。 marcp的解决方案也类似,但都不推迟划分。
这实际上也是 Gareth Rees 答案的实际应用,因为叉积在 2D 中的等价物是 perp-dot-product,这就是这段代码使用的三个。 切换到 3D 并使用叉积,在末尾对 s 和 t 进行插值,得到 3D 中线条之间最接近的两个点。
无论如何,2D 解决方案:
基本上它将除法推迟到最后一刻,并将大部分测试移至某些计算完成之前,从而添加提前退出。 最后,它还避免了线平行时发生的被零除的情况。
您可能还需要考虑使用 epsilon 测试而不是与零进行比较。 极其接近平行的线可能会产生稍微偏离的结果。 这不是一个错误,而是浮点数学的限制。
Here's an improvement to Gavin's answer. marcp's solution is similar also, but neither postpone the division.
This actually turns out to be a practical application of Gareth Rees' answer as well, because the cross-product's equivalent in 2D is the perp-dot-product, which is what this code uses three of. Switching to 3D and using the cross-product, interpolating both s and t at the end, results in the two closest points between the lines in 3D.
Anyway, the 2D solution:
Basically it postpones the division until the last moment, and moves most of the tests until before certain calculations are done, thereby adding early-outs. Finally, it also avoids the division by zero case which occurs when the lines are parallel.
You also might want to consider using an epsilon test rather than comparison against zero. Lines that are extremely close to parallel can produce results that are slightly off. This is not a bug, it is a limitation with floating point math.
问题C:如何检测两条线段是否相交?
我搜索过相同的主题,但对答案不满意。 所以我写了一篇文章,非常详细地解释了如何检查两条线段是否与大量图像相交。 有完整的(并且经过测试的)Java 代码。
这是本文,裁剪为最重要的部分:
检查线段 a 是否与线段 b 相交的算法如下所示:
什么是边界框? 以下是两条线段的两个边界框:
如果两个边界框都有交点,则移动线段a 使得一个点位于 (0|0)。 现在你有了一条穿过 a 定义的原点的线。 现在以同样的方式移动线段 b,并检查线段 b 的新点是否位于线 a 的不同侧。 如果是这种情况,请反过来检查。 如果也是这种情况,则线段相交。 如果不是,它们就不相交。
问题A:两条线段在哪里相交?
您知道两条线段 a 和 b 相交。 如果您不知道,请使用我在“问题 C”中给您的工具进行检查。
现在您可以通过一些案例并使用七年级数学得出解决方案(请参阅代码和交互式示例)。
问题B:如何检测两条线是否相交?
假设您的点
A = (x1, y1)
、点B = (x2, y2)
、C = (x_3, y_3)
,D = (x_4, y_4)
。第一行由 AB 定义(A != B),第二行由 CD 定义(C != D)。
问题D:两条线相交在哪里?
检查问题 B 是否有交叉。
线 a 和 b 由每条线的两个点定义。
您基本上可以应用问题 A 中使用的相同逻辑。
Question C: How do you detect whether or not two line segments intersect?
I have searched for the same topic, and I wasn't happy with the answers. So I have written an article that explains very detailed how to check if two line segments intersect with a lot of images. There is complete (and tested) Java-code.
Here is the article, cropped to the most important parts:
The algorithm, that checks if line segment a intersects with line segment b, looks like this:
What are bounding boxes? Here are two bounding boxes of two line segments:
If both bounding boxes have an intersection, you move line segment a so that one point is at (0|0). Now you have a line through the origin defined by a. Now move line segment b the same way and check if the new points of line segment b are on different sides of line a. If this is the case, check it the other way around. If this is also the case, the line segments intersect. If not, they don't intersect.
Question A: Where do two line segments intersect?
You know that two line segments a and b intersect. If you don't know that, check it with the tools I gave you in "Question C".
Now you can go through some cases and get the solution with 7th grade math (see code and interactive example).
Question B: How do you detect whether or not two lines intersect?
Let's say your point
A = (x1, y1)
, pointB = (x2, y2)
,C = (x_3, y_3)
,D = (x_4, y_4)
.Your first line is defined by AB (with A != B), and your second one by CD (with C != D).
Question D: Where do two lines intersect?
Check with Question B if they intersect at all.
The lines a and b are defined by two points for each line.
You can basically apply the same logic was used in Question A.
此处一旦接受的答案是不正确的(此后已未被接受,所以万岁!)。 它不能正确消除所有非交叉点。 简单地说,它可能看起来有效,但也可能失败,特别是在 0 和 1 被认为对 h 有效的情况下。
考虑以下情况:
(4,1)-(5,1) 和 (0,0)-(0,2) 处的线
这些是显然不重叠的垂直线。
A=(4,1)
B=(5,1)
C=(0,0)
D=(0,2)
E=(5,1)-(4,1)=(-1,0)
F=(0,2)-(0,0)=(0,-2)
P=(0,1)
h=((4,1)-(0,0)) 点 (0,1) / ((0,-2) 点 (0,1)) = 0
根据上面的答案,这两条线段在一个端点处相交(值为 0 和 1)。 该端点将是:
(0,0)+(0,-2)*0=(0,0)
因此,显然两条线段在 (0,0) 处相交,该线段位于 CD 线上,但不在线上AB。 那么出了什么问题呢? 答案是 0 和 1 的值无效,仅有时会正确预测端点相交。 当一条线(而不是另一条线)的延长线与线段相交时,算法会预测线段的交点,但这并不正确。 我想,通过从 AB 与 CD 开始测试,然后再用 CD 与 AB 进行测试,这个问题将会被消除。 只有当两者都落在 0 和 1 之间(含 0 和 1)时,才可以说它们相交。
如果您必须预测端点,我建议使用向量叉积方法。
-担
The answer once accepted here is incorrect (it has since been unaccepted, so hooray!). It does not correctly eliminate all non-intersections. Trivially it may appear to work but it can fail, especially in the case that 0 and 1 are considered valid for h.
Consider the following case:
Lines at (4,1)-(5,1) and (0,0)-(0,2)
These are perpendicular lines which clearly do not overlap.
A=(4,1)
B=(5,1)
C=(0,0)
D=(0,2)
E=(5,1)-(4,1)=(-1,0)
F=(0,2)-(0,0)=(0,-2)
P=(0,1)
h=((4,1)-(0,0)) dot (0,1) / ((0,-2) dot (0,1)) = 0
According to the above answer, these two line segments meet at an endpoint (values of 0 and 1). That endpoint would be:
(0,0)+(0,-2)*0=(0,0)
So, apparently the two line segments meet at (0,0), which is on line CD, but not on line AB. So what is going wrong? The answer is that the values of 0 and 1 are not valid and only sometimes HAPPEN to correctly predict endpoint intersection. When the extension of one line (but not the other) would meet the line segment, the algorithm predicts an intersection of line segments, but this is not correct. I imagine that by testing starting with AB vs CD and then also testing with CD vs AB, this problem would be eliminated. Only if both fall between 0 and 1 inclusively can they be said to intersect.
I recommend using the vector cross product method if you must predict end-points.
-Dan
iMalc 答案的 Python 版本:
Python version of iMalc's answer:
找到两条线段的正确交点是一项艰巨的任务,有很多边缘情况。 这是一个记录良好、有效且经过测试的 Java 解决方案。
本质上,当找到两条线段的交点时,可能会发生三种情况:
线段不相交
交点是另一段
注意:在代码中,我假设线段 (x1, y1), (x2, y2) 且 x1 = x2 且 y1 = y2 是有效线段。 从数学上来说,线段由不同的点组成,但为了完整性,我允许线段在此实现中成为点。
代码取自我的 github repo
这是一个简单的使用示例:
Finding the correct intersection of two line segments is a non-trivial task with lots of edge cases. Here's a well documented, working and tested solution in Java.
In essence, there are three things that can happen when finding the intersection of two line segments:
The segments do not intersect
There is a unique intersection point
The intersection is another segment
NOTE: In the code, I assume that a line segment (x1, y1), (x2, y2) with x1 = x2 and y1 = y2 is a valid line segment. Mathematically speaking, a line segment consists of distinct points, but I am allowing segments to be points in this implementation for completeness.
Code is taken from my github repo
Here is a simple usage example:
只是想提一下,可以在数字食谱系列中找到很好的解释和明确的解决方案。 我有第三版,答案在第 1117 页,第 21.4 节。 另一种具有不同命名法的解决方案可以在 Marina Gavrilova 可靠线段的论文中找到交叉口测试。 在我看来,她的解决方案稍微简单一些。
我的实现如下:
Just wanted to mention that a good explanation and explicit solution can be found in the Numeric Recipes series. I've got the 3rd edition and the answer is on page 1117, section 21.4. Another solution with a different nomenclature can be found in a paper by Marina Gavrilova Reliable Line Section Intersection Testing. Her solution is, to my mind, a little simpler.
My implementation is below:
上面有很多解决方案,但我认为下面的解决方案非常简单且易于理解。
两条线段向量 AB 和向量 CD 相交当且仅当
更具体地说,当且仅当两个三元组 a,c,d 和 b,c,d 中的一个恰好按逆时针顺序排列时,a 和 b 位于线段 CD 的相对侧。
这里 CCW 代表逆时针方向,它根据点的方向返回真/假。
来源:http://compgeom.cs.uiuc。 edu/~jeffe/teaching/373/notes/x06-sweepline.pdf
第2页
Plenty of solutions are available above, but I think below solution is pretty simple and easy to understand.
Two segments Vector AB and Vector CD intersect if and only if
More specifically a and b are on opposite side of segment CD if and only if exactly one of the two triples a,c,d and b,c,d is in counterclockwise order.
Here CCW represent counterclockwise which returns true/false based on the orientation of the points.
Source : http://compgeom.cs.uiuc.edu/~jeffe/teaching/373/notes/x06-sweepline.pdf
Page 2
C 和 Objective-C
基于 Gareth Rees 的回答
许多函数和结构都是私有的,但您应该很容易知道发生了什么。
这是在此存储库中公开的 https://github.com/hfossli/AGGeometryKit/
C and Objective-C
Based on Gareth Rees' answer
Many of the functions and structs are private, but you should pretty easy be able to know what's going on.
This is public on this repo https://github.com/hfossli/AGGeometryKit/
这对我来说效果很好。 取自此处。
This is working well for me. Taken from here.
我尝试了其中一些答案,但它们对我不起作用(对不起,大家); 经过更多的网络搜索后,我发现了这个。
通过对他的代码进行一些修改,我现在有了这个函数,它将返回交点,或者如果没有找到交点,它将返回 -1,-1。
I tried some of these answers, but they didnt work for me (sorry guys); after some more net searching I found this.
With a little modification to his code I now have this function that will return the point of intersection or if no intersection is found it will return -1,-1.
似乎对 Gavin 的答案< /a> cortijon 在 评论和iMalc提供了一个稍微更少的计算。 一些人指出了各种代码提案的缺点,另一些人则对某些代码提案的效率发表了评论。
iMalc 通过 Gavin 的答案提供的算法是我目前在 javascript 项目中使用的算法,我只是想在这里提供一个清理版本(如果它可以帮助任何人)。
There seems to be some interest in Gavin's answer for which cortijon proposed a javascript version in the comments and iMalc provided a version with slightly fewer computations. Some have pointed out shortcomings with various code proposals and others have commented on the efficiency of some code proposals.
The algorithm provided by iMalc via Gavin's answer is the one that I am currently using in a javascript project and I just wanted to provide a cleaned up version here if it may help anyone.
我认为这个问题有一个更简单的解决方案。 我今天想出了另一个想法,它似乎工作得很好(至少目前在 2D 中)。 您所要做的就是计算两条线之间的交点,然后检查计算出的交点是否在两条线段的边界框中。 如果是,则线段相交。 就是这样。
编辑:
这就是我计算交集的方式(我不知道我在哪里找到这个代码片段)
来自
,这是我的(为了答案的目的而简化)BoundingBox 类:
I think there is a much much simpler solution for this problem. I came up with another idea today and it seems to work just fine (at least in 2D for now). All you have to do, is to calculate the intersection between two lines, then check if the calculated intersection point is within the boundig boxes of both line segments. If it is, the line segments intersect. That's it.
EDIT:
This is how I calculate the intersection (I don't know anymore where I found this code snippet)
comes from
and this is my (simplified for the purpose of the answer) BoundingBox class:
这个解决方案可能会有所帮助
This solution may help
我将 Kris 的上述答案移植到 JavaScript 中。 在尝试了无数不同的答案后,他提供了正确的观点。 我以为我要疯了,因为我没有得到我需要的分数。
I ported Kris's above answer to JavaScript. After trying numerous different answers, his provided the correct points. I thought I was going crazy that I wasn't getting the points I needed.
我尝试了很多方法,然后我决定自己写。 所以这里是:
基于这两个公式:(我从直线方程和其他公式简化了它们)
I tried lot of ways and then I decided to write my own. So here it is:
Based on these two formulas: (I simplified them from equation of lines and other formulas)
这是基于 Gareth Ree 的回答。 如果线段重叠,它也会返回它们。 V 是用 C++ 编写的,是一个简单的向量类。 其中二维向量的叉积返回单个标量。 经我校自动测试系统测试通过。
This based on Gareth Ree's answer. It also returns the overlap of the line segments if they do. Coded in C++, V is a simple vector class. Where the cross product of two vectors in 2D returns a single scalar. It was tested and passed by my schools automatic testing system.
下面是 C# 中线段的基本实现,以及相应的相交检测代码。 它需要一个名为
Vector2f
的 2D 矢量/点结构,但您可以将其替换为具有 X/Y 属性的任何其他类型。 如果更适合您的需求,您也可以将float
替换为double
。此代码用于我的 .NET 物理库 Boing。
Here's a basic implementation of a line segment in C#, with corresponding intersection detection code. It requires a 2D vector/point struct called
Vector2f
, though you can replace this with any other type that has X/Y properties. You could also replacefloat
withdouble
if that suits your needs better.This code is used in my .NET physics library, Boing.
用于检查两个给定线段是否相交的 C++ 程序
A C++ program to check if two given line segments intersect
基于 @Gareth Rees 的回答,Python 版本:
Based on @Gareth Rees answer, version for Python:
如果矩形的每条边都是一条线段,并且用户绘制的部分是一条线段,那么您只需检查用户绘制的线段是否与四个边线段相交。 考虑到每个段的起点和终点,这应该是一个相当简单的练习。
If each side of the rectangle is a line segment, and the user drawn portion is a line segment, then you need to just check the user drawn segment for intersection with the four side line segments. This should be a fairly simple exercise given the start and end points of each segment.
基于 t3chb0t 的回答:
Based on t3chb0t's answer:
我从《多视图几何》一书中读到了这些算法,
下面的文本使用
' 作为转置符号
* 作为点积
x 作为叉积,当使用 as 运算符
1 时,线定义
点 x_vec = (x, y)' 位于线上ax + by + c = 0
我们表示 L = (a, b, c)',点为 (x, y, 1)' 作为齐次坐标,
直线方程可以写为
(x, y, 1)(a , b, c)' = 0 或 x' * L = 0
2. 直线的交点
我们有两条直线 L1=(a1, b1, c1)', L2=(a2, b2, c2)'
假设 x 是一个点,一个向量,并且 x = L1 x L2(L1 叉积 L2)。
请注意,x 始终是 2D 点,如果您对 (L1xL2) 是三元素向量而 x 是 2D 坐标感到困惑,请阅读齐次坐标。
根据三重积,我们知道
L1 * ( L1 x L2 ) = 0,并且L2 * (L1 x L2) = 0,因为L1,L2共面,
我们用向量x替换(L1xL2),则我们有L1 *x=0,L2*x=0,即x同时位于L1和L2上,x为交点。
注意,这里x是齐次坐标,如果x的最后一个元素为零,则意味着L1和L2平行。
I read these algorithm from the book "multiple view geometry"
following text using
' as transpose sign
* as dot product
x as cross product, when using as operator
1. line definition
a point x_vec = (x, y)' lies on the line ax + by + c = 0
we denote L = (a, b, c)', the point as (x, y, 1)' as homogeneous coordinates
the line equation can be written as
(x, y, 1)(a, b, c)' = 0 or x' * L = 0
2. intersection of lines
we have two lines L1=(a1, b1, c1)', L2=(a2, b2, c2)'
assume x is a point, a vector, and x = L1 x L2 (L1 cross product L2).
be careful, x is always a 2D point, please read homogeneous coordinates if you are confused about (L1xL2) is a three elements vector, and x is a 2D coordinates.
according to triple product, we know that
L1 * ( L1 x L2 ) = 0, and L2 * (L1 x L2) = 0, because of L1,L2 co-plane
we substitute (L1xL2) with vector x, then we have L1*x=0, L2*x=0, which means x lie on both L1 and L2, x is the intersection point.
be careful, here x is homogeneous coordinates, if the last element of x is zero, it means L1 and L2 are parallel.
许多答案将所有计算包装到一个函数中。 如果您需要计算线斜率、y 轴截距或 x 轴截距以在代码中的其他位置使用,那么您将进行多余的计算。 我已经分离出了各自的函数,使用了明显的变量名称,并对我的代码进行了注释,以使其更易于理解。 我需要知道线条是否无限相交超出其端点,因此在 JavaScript 中:
http://jsfiddle.net/skibulk/ evmqq00u/
Many answers have wrapped up all the calculations into a single function. If you need to calculate the line slopes, y-intercepts, or x-intercepts for use elsewhere in your code, you'll be making those calculations redundantly. I have separated out the respective functions, used obvious variable names, and commented my code to make it easier to follow. I needed to know if lines intersect infinitely beyond their endpoints, so in JavaScript:
http://jsfiddle.net/skibulk/evmqq00u/
有一个很好的方法可以使用向量叉积来解决这个问题。 定义二维向量叉积v × w为vx <强>wy − vy wx 。
假设两条线段从 p 到 p + r 以及从 q 到 >q+ s。 那么第一行上的任何点都可以表示为 p + t r(对于标量参数 t),第二行上的任意点为 q+ u s(对于标量参数) ;u)。
如果我们能找到 t 和 u<,则两条线相交/em> 这样:
两边与s交叉,得到
自从 s × s = 0,这意味着
因此,求解 t:
以同样的方式,我们可以求解u:
为了减少计算步骤数,将其重写如下很方便(记住s × r = - r × s):
现在有四种情况:
如果r × s = 0 且(q − p) × r = 0,则两条直线共线。
在这种情况下,用以下形式表示第二段的端点(q 和 q+ s)第一条线段的方程 (p + t r):
<块引用>
t0 = (q − p) · r / (r · r)
t1 = (q + s − p) · r / (r · r) = t0 + s · r / (r · r)
如果 t0 和 t1 之间的区间与区间 [0, 1] 相交,则线段共线且重叠; 否则它们是共线且不相交的。
请注意,如果 s 和 r 指向相反的方向,则 s · r < 0,因此要检查的间隔是 [t1, t0] 而不是 [ t0,t1]。
如果r × s = 0 且 (q − p ) × r ≠ 0,则两条直线平行且不相交。
如果r × s ≠ 0且0 ≤ t ≤ 1 和 0 ≤ u ≤ 1,两条线段交于点 p + t < strong>r = q + u s。
否则,两条线段不平行但不相交。
图片来源:此方法是 3D 线相交算法的 2 维特化,摘自 Ronald Goldman 发表在 Graphics Gems 第 304 页上的文章“三空间中两条线的相交”。对于尺寸,通常的情况是线是倾斜的(既不平行也不相交),在这种情况下,该方法给出两条线最接近的点。
There’s a nice approach to this problem that uses vector cross products. Define the 2-dimensional vector cross product v × w to be vx wy − vy wx.
Suppose the two line segments run from p to p + r and from q to q + s. Then any point on the first line is representable as p + t r (for a scalar parameter t) and any point on the second line as q + u s (for a scalar parameter u).
The two lines intersect if we can find t and u such that:
Cross both sides with s, getting
And since s × s = 0, this means
And therefore, solving for t:
In the same way, we can solve for u:
To reduce the number of computation steps, it's convenient to rewrite this as follows (remembering that s × r = − r × s):
Now there are four cases:
If r × s = 0 and (q − p) × r = 0, then the two lines are collinear.
In this case, express the endpoints of the second segment (q and q + s) in terms of the equation of the first line segment (p + t r):
If the interval between t0 and t1 intersects the interval [0, 1] then the line segments are collinear and overlapping; otherwise they are collinear and disjoint.
Note that if s and r point in opposite directions, then s · r < 0 and so the interval to be checked is [t1, t0] rather than [t0, t1].
If r × s = 0 and (q − p) × r ≠ 0, then the two lines are parallel and non-intersecting.
If r × s ≠ 0 and 0 ≤ t ≤ 1 and 0 ≤ u ≤ 1, the two line segments meet at the point p + t r = q + u s.
Otherwise, the two line segments are not parallel but do not intersect.
Credit: this method is the 2-dimensional specialization of the 3D line intersection algorithm from the article "Intersection of two lines in three-space" by Ronald Goldman, published in Graphics Gems, page 304. In three dimensions, the usual case is that the lines are skew (neither parallel nor intersecting) in which case the method gives the points of closest approach of the two lines.
FWIW,以下函数(在 C 中)既检测线相交又确定相交点。 它基于 Andre LeMothe 的“Windows 游戏编程大师的技巧”中的算法”。 它与其他答案(例如 Gareth 的)中的某些算法没有什么不同。 然后 LeMothe 使用克莱默法则(不要问我)来求解方程本身。
我可以证明它在我微弱的小行星克隆中有效,并且似乎可以正确处理 Elemental、Dan 和 Wodzu 其他答案中描述的边缘情况。 它也可能比 KingNestor 发布的代码更快,因为它都是乘法和除法,没有平方根!
我猜想那里有可能被零除,尽管在我的例子中这不是问题。 无论如何,很容易修改以避免崩溃。
顺便说一句,我必须说,在 LeMothe 的书中,虽然他显然得到了正确的算法,但他展示的具体示例插入了错误的数字并进行了错误的计算。 例如:
这让我困惑了几个小时。 :(
FWIW, the following function (in C) both detects line intersections and determines the intersection point. It is based on an algorithm in Andre LeMothe's "Tricks of the Windows Game Programming Gurus". It's not dissimilar to some of the algorithm's in other answers (e.g. Gareth's). LeMothe then uses Cramer's Rule (don't ask me) to solve the equations themselves.
I can attest that it works in my feeble asteroids clone, and seems to deal correctly with the edge cases described in other answers by Elemental, Dan and Wodzu. It's also probably faster than the code posted by KingNestor because it's all multiplication and division, no square roots!
I guess there's some potential for divide by zero in there, though it hasn't been an issue in my case. Easy enough to modify to avoid the crash anyway.
BTW, I must say that in LeMothe's book, though he apparently gets the algorithm right, the concrete example he shows plugs in the wrong numbers and does calculations wrong. For example:
That confused me for hours. :(
问题归结为这个问题:从 A 到 B 和从 C 到 D 的两条线是否相交? 然后你可以问它四次(在线和矩形四个边之间)。
这是执行此操作的向量数学。 我假设从 A 到 B 的线是有问题的线,从 C 到 D 的线是矩形线之一。 我的符号是,
Ax
是“A 的 x 坐标”,Cy
是“C 的 y 坐标”。 而“*
”表示点积,例如A*B = Ax*Bx + Ay*By
。这个
h
数字是关键。 如果h
位于0
和1
之间,则两条线相交,否则不相交。 如果 F*P 为零,当然您无法进行计算,但在这种情况下,直线是平行的,因此仅在明显的情况下相交。确切的交点是
C + F*h
。更多乐趣:
如果
h
恰好为0
或1
,则线条在终点。 您可以根据自己的需要将其视为“交叉点”或不视为“交叉点”。具体来说,
h
是您必须将线的长度乘以多少才能准确接触另一条线。因此,如果
h<0
,则表示矩形线位于给定线“后面”(“方向”为“从A到B”),如果h>1
code> 矩形线位于给定线的“前面”。推导:
A和C是指向线段起点的向量; E 和 F 是构成直线的 A 和 C 两端的向量。
对于平面上的任何两条不平行的线,必须恰好存在一对标量
g
和h
使得以下方程成立:为什么? 因为两条不平行的线必须相交,这意味着您可以将两条线分别缩放一定的量并相互接触。
(乍一看,这看起来像是一个带有两个未知数的单个方程!但当您认为这是一个二维向量方程时,情况并非如此,这意味着这实际上是
x 中的一对方程
和y
。)我们必须消除这些变量之一。 一个简单的方法是将
E
项设为零。 为此,请使用一个向量对方程两边进行点积,该向量将与 E 点为零。我在上面将该向量称为P
,并且我对 E 进行了明显的变换。现在有:
The problem reduces to this question: Do two lines from A to B and from C to D intersect? Then you can ask it four times (between the line and each of the four sides of the rectangle).
Here's the vector math for doing it. I'm assuming the line from A to B is the line in question and the line from C to D is one of the rectangle lines. My notation is that
Ax
is the "x-coordinate of A" andCy
is the "y-coordinate of C." And "*
" means dot-product, so e.g.A*B = Ax*Bx + Ay*By
.This
h
number is the key. Ifh
is between0
and1
, the lines intersect, otherwise they don't. IfF*P
is zero, of course you cannot make the calculation, but in this case the lines are parallel and therefore only intersect in the obvious cases.The exact point of intersection is
C + F*h
.More Fun:
If
h
is exactly0
or1
the lines touch at an end-point. You can consider this an "intersection" or not as you see fit.Specifically,
h
is how much you have to multiply the length of the line in order to exactly touch the other line.Therefore, If
h<0
, it means the rectangle line is "behind" the given line (with "direction" being "from A to B"), and ifh>1
the rectangle line is "in front" of the given line.Derivation:
A and C are vectors that point to the start of the line; E and F are the vectors from the ends of A and C that form the line.
For any two non-parallel lines in the plane, there must be exactly one pair of scalar
g
andh
such that this equation holds:Why? Because two non-parallel lines must intersect, which means you can scale both lines by some amount each and touch each other.
(At first this looks like a single equation with two unknowns! But it isn't when you consider that this is a 2D vector equation, which means this is really a pair of equations in
x
andy
.)We have to eliminate one of these variables. An easy way is to make the
E
term zero. To do that, take the dot-product of both sides of the equation using a vector that will dot to zero with E. That vector I calledP
above, and I did the obvious transformation of E.You now have: