测试两条线是否相交 - JavaScript 函数
我尝试寻找一个 javascript 函数来检测两条线是否相交。
该函数将获取每条线(我们将其称为线 A 和线 B)的两个起点的 x、y 值。
就是如果相交则返回 true,否则返回 false。
函数示例。如果答案使用矢量对象,我很高兴。
Function isIntersect (lineAp1x, lineAp1y, lineAp2x, lineAp2y, lineBp1x, lineBp1y, lineBp2x, lineBp2y)
{
// JavaScript line intersecting test here.
}
一些背景信息:此代码适用于我尝试在 html5 canvas 中制作的游戏,并且是我的碰撞检测的一部分。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
解释:(向量、矩阵和厚颜无耻的行列式)
直线可以通过一些初始向量 v 和方向向量 d 来描述:
我们使用一个点
(a,b)< /code>作为初始向量,它们之间的差
(ca,db)
作为方向向量。我们的第二行也是如此。如果两条线相交,则必须有一个点 X,可以通过沿第一条线行进一段距离 lambda 来到达该点,也可以通过沿第二条线行进 gamma 单位来到达该点。这为我们提供了两个 X 坐标的联立方程:
这些方程可以用矩阵形式表示。我们检查行列式是否非零,以查看交集 X 是否存在。
如果存在交集,那么我们必须检查交集是否确实位于两组点之间。如果 lambda 大于 1,则交点超出第二个点。如果 lambda 小于 0,则交点位于第一个点之前。
因此,0 表示两条线相交!
Explanation: (vectors, a matrix and a cheeky determinant)
Lines can be described by some initial vector, v, and a direction vector, d:
We use one point
(a,b)
as the initial vector and the difference between them(c-a,d-b)
as the direction vector. Likewise for our second line.If our two lines intersect, then there must be a point, X, that is reachable by travelling some distance, lambda, along our first line and also reachable by travelling gamma units along our second line. This gives us two simultaneous equations for the coordinates of X:
These equations can be represented in matrix form. We check that the determinant is non-zero to see if the intersection X even exists.
If there is an intersection, then we must check that the intersection actually lies between both sets of points. If lambda is greater than 1, the intersection is beyond the second point. If lambda is less than 0, the intersection is before the first point.
Hence,
0<lambda<1 && 0<gamma<1
indicates that the two lines intersect!Peter Wone 的答案是一个很好的解决方案,但缺乏解释。我花了大约一个小时来理解它是如何工作的,并且认为我已经足够理解它了。有关详细信息,请参阅他的答案: https://stackoverflow.com/a/16725715/697477
我还提供了一个解决方案对于下面代码中的共线线。
使用旋转方向检查交点
为了解释答案,让我们看一下两条线的每个交点的共同点。根据下图,我们可以看到 P1 到 IP 到 < strong>P4 逆时针旋转。我们可以看到它的互补边顺时针旋转。现在,我们不知道它是否相交,因此我们不知道交点。但我们也可以看到 P1 到 P2< /strong> 到 P4 也逆时针旋转。此外,P1 至 P2 至P3 顺时针旋转。我们可以利用这些知识来确定两条线是否相交。
交叉点示例
您会注意到相交的线创建了四个指向相反方向的面。由于它们面向相反的方向,我们知道 P1 到 P2 到 P3 旋转方向与 P1< 不同/sub> 到P2 至 P4。我们还知道 P1 到 P3 > 到 P4 的旋转方向与 P2< /strong> 至 P3 至P4。
非交叉点示例
在此示例中,您应该注意到,遵循相交测试的相同模式,两个面旋转相同方向。由于它们面向同一方向,因此我们知道它们不相交。
代码示例
因此,我们可以将其实现到 Peter Wone 提供的原始代码中。
Peter Wone's answer is a great solution, but it lacks an explanation. I spent the last hour or so understanding how it works and think I understand enough to explain it as well. See his answer for details: https://stackoverflow.com/a/16725715/697477
I've also included a solution for the co-linear lines in the code below.
Using Rotational Directions to check for intersection
To explain the answer, let's look at something common about every intersection of two lines. Given the picture below, we can see that P1 to IP to P4 rotates counter clockwise. We can see that it's complimentary sides rotate clockwise. Now, we don't know if it intersects, so we don't know the intersection point. But we can also see that P1 to P2 to P4 also rotates counter clockwise. Additionally, P1 to P2 to P3 rotates clock wise. We can use this knowledge to determine whether two lines intersect or not.
Intersection Example
You'll notice that intersecting lines create four faces that point opposite directions. Since they face opposite directions, we know that the direction of P1 to P2 to P3 rotates a direction different than P1 to P2 to P4. We also know that P1 to P3 to P4 rotates a different direction than P2 to P3 to P4.
Non-Intersection Example
In this example, you should notice that following the same pattern for the intersection test, the two faces rotate the same direction. Since they face the same direction, we know that they do not intersect.
Code Sample
So, we can implement this into the original code supplied by Peter Wone.
我从中找到了答案的 wiki 页面。
The wiki page I found the answer from.
虽然能够找到交点很有用,但测试线段是否相交最常用于多边形命中测试,并且考虑到其通常的应用,您需要这样做< em>快。因此我建议你这样做,只使用减法、乘法、比较和AND。
Turn
计算由三个点描述的两条边之间的坡度变化方向:1 表示逆时针,0 表示不转弯,-1 表示顺时针。此代码需要表示为 GLatLng 对象的点,但可以轻松地重写为其他表示系统。斜率比较已标准化为 epsilon 对潮湿浮点误差的容忍度。
Although it is useful to be able to find the intersection point, testing for whether line segments intersect is most often used for polygon hit-testing, and given the usual applications of that, you need to do it fast. Therefore I suggest you do it like this, using only subtraction, multiplication, comparison and AND.
Turn
computes the direction of the change in slope between the two edges described by the three points: 1 means counter-clockwise, 0 means no turn and -1 means clockwise.This code expects points expressed as GLatLng objects but can be trivially rewritten to other systems of representation. The slope comparison has been normalised to epsilon tolerance to damp floating point errors.
我使用 x/y 而不是 lat()/long() 重写了 Peter Wone 对单个函数的回答
I've rewritten Peter Wone's answer to a single function using x/y instead of lat()/long()
这是一个 TypeScript 实现,很大程度上受到 Dan Fox 解决方案的启发。
此实现将为您提供交点(如果有)。否则(平行或无交集),将返回
undefined
。Here comes a TypeScript implementation, heavily inspired by Dan Fox's solution.
This implementation will give you the intersection point, if there is one. Otherwise (parallel or no intersection),
undefined
will be returned.这是一个基于 this gist 的版本,其中包含一些更简洁的变量名称和一些 Coffee。
JavaScript 版本
CoffeeScript 版本
Here's a version based on this gist with some more concise variable names, and some Coffee.
JavaScript version
CoffeeScript version
首先,找到交点坐标 - 这里有详细描述:
http://www.mathopenref.com/coordintersection.html
然后检查 x 坐标是否为交集落在其中一条线的 x 范围内(或者如果您愿意,也可以对 y 坐标执行相同的操作),
即,如果 xIntersection 位于 lineAp1x 和 lineAp2x 之间,则它们相交。
First, find intersection coordinates - here it's described in detail:
http://www.mathopenref.com/coordintersection.html
Then check if the x-coordinate for intersection falls within the x ranges for one of the lines (or do the same with y-coordinate, if you prefer),
i.e. if xIntersection is between lineAp1x and lineAp2x, then they intersect.
对于所有想要准备好冷融合解决方案的人,以下是我改编自http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/7-b147/java/awt/geom/Line2D.java#Line2D.linesIntersect%28double%2Cdouble%2Cdouble %2Cdouble%2Cdouble%2Cdouble%2Cdouble%2Cdouble%29
重要的函数是 ccw 和来自java.awt.geom.Line2D的linesIntersect,我将它们写入coldfusion中,所以我们开始:
我希望这可以帮助适应其他语言?
For all folks who would like to have a solutions ready for coldfusion, here is what I adapted from http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/7-b147/java/awt/geom/Line2D.java#Line2D.linesIntersect%28double%2Cdouble%2Cdouble%2Cdouble%2Cdouble%2Cdouble%2Cdouble%2Cdouble%29
the imporants functions are ccw and linesIntersect from java.awt.geom.Line2D and I wrote them into coldfusion, so here we go:
I hope this can help for adapting to other laguages?
使用毕氏定理求出两个物体之间的距离并加上半径毕氏定理距离公式
Use the pythageorum theorum to find the distance between the 2 objects and add the radius Pythageorum Theorum Distance Formula