点与线段之间的最短距离
我需要一个基本函数来找到点和线段之间的最短距离。 随意用您想要的任何语言编写解决方案; 我可以将其翻译成我正在使用的(Javascript)。
编辑:我的线段由两个端点定义。 因此,我的线段 AB 是由两点 A (x1,y1) 和 B (x2,y2) 定义的。 我试图找到该线段和点 C (x3,y3)
之间的距离。 我很遗憾地承认,我的几何技能很生疏,所以我看到的例子很令人困惑。
I need a basic function to find the shortest distance between a point and a line segment. Feel free to write the solution in any language you want; I can translate it into what I'm using (Javascript).
EDIT: My line segment is defined by two endpoints. So my line segment AB
is defined by the two points A (x1,y1)
and B (x2,y2)
. I'm trying to find the distance between this line segment and a point C (x3,y3)
. My geometry skills are rusty, so the examples I've seen are confusing, I'm sorry to admit.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(30)
WPF版本:
WPF version:
无法抗拒用 python 进行编码:)
Fortran 也是如此:)
Couldn't resist coding it in python :)
Ditto for fortran :)
这是 Grumdrig 解决方案的更完整拼写。 此版本还返回最近的点本身。
Here is a more complete spelling out of Grumdrig's solution. This version also returns the closest point itself.
我假设您想找到点和线段之间的最短距离; 为此,您需要找到与穿过您的点的线段(lineB)垂直的线(lineA),确定该线(lineA)与穿过您的线段(lineB)的线之间的交点; 如果该点位于线段的两点之间,则该距离是您的点与刚刚找到的点(即 lineA 和 lineB 的交点)之间的距离; 如果该点不在线段两点之间,则需要获取该点与线段两端较近的点之间的距离; 这可以通过取该点和线段两点之间的平方距离(以避免平方根)来轻松完成; 以更接近的为准,取其平方根。
I'm assuming you want to find the shortest distance between the point and a line segment; to do this, you need to find the line (lineA) which is perpendicular to your line segment (lineB) which goes through your point, determine the intersection between that line (lineA) and your line which goes through your line segment (lineB); if that point is between the two points of your line segment, then the distance is the distance between your point and the point you just found which is the intersection of lineA and lineB; if the point is not between the two points of your line segment, you need to get the distance between your point and the closer of two ends of the line segment; this can be done easily by taking the square distance (to avoid a square root) between the point and the two points of the line segment; whichever is closer, take the square root of that one.
考虑对上面格鲁姆德里格的答案的修改。 很多时候,您会发现浮点不精确会导致问题。 我在下面的版本中使用双精度数,但您可以轻松更改为浮点数。 重要的部分是它使用 epsilon 来处理“slop”。 此外,您很多时候想知道交叉点发生在哪里,或者是否发生过。 如果返回的t是< 0.0或> 1.0,没有发生碰撞。 然而,即使没有发生碰撞,很多时候你也会想知道线段上距离 P 最近的点在哪里,因此我使用 qx 和 qy 来返回该位置。
Consider this modification to Grumdrig's answer above. Many times you'll find that floating point imprecision can cause problems. I'm using doubles in the version below, but you can easily change to floats. The important part is that it uses an epsilon to handle the "slop". In addition, you'll many times want to know WHERE the intersection happened, or if it happened at all. If the returned t is < 0.0 or > 1.0, no collision occurred. However, even if no collision occurred, many times you'll want to know where the closest point on the segment to P is, and thus I use qx and qy to return this location.
Grumdrig 的 C++/JavaScript 实现对我来说非常有用,因此我提供了我正在使用的 Python 直接端口。 完整的代码位于此处。
Grumdrig's C++/JavaScript implementation was very useful to me, so I have provided a Python direct port that I am using. The complete code is here.
这里使用的是 Swift
Here it is using Swift
现在我的解决方案也是......
(Javascript)
它非常快,因为我试图避免任何 Math.pow 函数。
正如你所看到的,在函数的末尾我有直线的距离。
代码来自lib http://www.draw2d.org/graphiti/ jsdoc/#!/example
And now my solution as well......
(Javascript)
It is very fast because I try to avoid any Math.pow functions.
As you can see, at the end of the function I have the distance of the line.
code is from the lib http://www.draw2d.org/graphiti/jsdoc/#!/example
C#
改编自@Grumdrig
C#
Adapted from @Grumdrig
Matlab 代码,如果调用不带参数的函数,则具有内置的“自测试”:
Matlab code, with built-in "self test" if they call the function with no arguments:
用t-sql编码,
点是(@px,@py),线段从(@ax,@ay)到(@bx,@by)
coded in t-sql
the point is (@px, @py) and the line segment runs from (@ax, @ay) to (@bx, @by)
看起来 StackOverflow 上的几乎所有其他人都贡献了答案(到目前为止有 23 个答案),所以这是我对 C# 的贡献。 这主要基于 M. Katz 的答案,而 M. Katz 的答案又基于 Grumdrig 的答案。
这是一个小测试程序。
正如您所看到的,我尝试测量使用避免 Sqrt() 方法的版本和普通版本之间的差异。 我的测试表明您也许可以节省大约 2.5%,但我什至不确定 - 各种测试运行中的变化具有相同的数量级。 我还尝试测量 Matti 发布的版本(加上明显的优化),该版本似乎比基于 Katz/Grumdrig 代码的版本慢约 4%。
编辑:顺便说一句,我还尝试过测量一种使用叉积(和 Sqrt())找到到无限直线(不是线段)的距离的方法,速度大约快 32%。
Looks like just about everyone else on StackOverflow has contributed an answer (23 answers so far), so here's my contribution for C#. This is mostly based on the answer by M. Katz, which in turn is based on the answer by Grumdrig.
And here's a little test program.
As you can see, I tried to measure the difference between using the version that avoids the Sqrt() method and the normal version. My tests indicate you can maybe save about 2.5%, but I'm not even sure of that - the variations within the various test runs were of the same order of magnitude. I also tried measuring the version posted by Matti (plus an obvious optimization), and that version seems to be about 4% slower than the version based on Katz/Grumdrig code.
Edit: Incidentally, I've also tried measuring a method that finds the distance to an infinite line (not a line segment) using a cross product (and a Sqrt()), and it's about 32% faster.
这是 devnullicus 的 C++ 版本转换为 C#。 对于我的实施,我需要知道交叉点并发现他的解决方案运行良好。
Here is devnullicus's C++ version converted to C#. For my implementation I needed to know the point of intersection and found his solution to work well.
2D 和 3D 解决方案
考虑更改基础,使线段变为
(0, 0, 0)-(d, 0, 0)
且点变为>(u,v,0)
。 最短距离出现在该平面中,由下式给出(到端点之一或到支撑线的距离,具体取决于线的投影。等距轨迹由两个半圆和两条线段组成。 )
在上面的表达式中,d是线段AB的长度,u、v分别是AB/d(方向上的单位向量)的标量积和叉积(模) AB)和AC。 因此从向量上看,
A 2D and 3D solution
Consider a change of basis such that the line segment becomes
(0, 0, 0)-(d, 0, 0)
and the point(u, v, 0)
. The shortest distance occurs in that plane and is given by(the distance to one of the endpoints or to the supporting line, depending on the projection to the line. The iso-distance locus is made of two half-circles and two line segments.)
In the above expression, d is the length of the segment AB, and u, v are respectivey the scalar product and (modulus of the) cross product of AB/d (unit vector in the direction of AB) and AC. Hence vectorially,
C#版本
C# Version
上述功能不适用于垂直线。 这是一个运行良好的函数!
与点 p1、p2 的直线。 检查点是p;
The above function is not working on vertical lines. Here is a function that is working fine!
Line with points p1, p2. and CheckPoint is p;
请参阅以下网站中的 Matlab GEOMETRY 工具箱:
http://people.sc.fsu.edu/~jburkardt/m_src /geometry/geometry.html
ctrl+f 输入“segment”即可查找线段相关函数。 您需要函数“segment_point_dist_2d.m”和“segment_point_dist_3d.m”。
GEOMETRY 代码有 C 版本和 C++ 版本、FORTRAN77 版本、FORTRAN90 版本和 MATLAB 版本。
see the Matlab GEOMETRY toolbox in the following website:
http://people.sc.fsu.edu/~jburkardt/m_src/geometry/geometry.html
ctrl+f and type "segment" to find line segment related functions. the functions "segment_point_dist_2d.m" and "segment_point_dist_3d.m" are what you need.
The GEOMETRY codes are available in a C version and a C++ version and a FORTRAN77 version and a FORTRAN90 version and a MATLAB version.
基于 Joshua Javascript 的 AutoHotkeys 版本:
AutoHotkeys version based on Joshua's Javascript:
接受的答案不起作用
(例如,0,0 和 (-10,2,10,2) 之间的距离应为 2)。
这是有效的代码:
the accepted answer does not work
(e.g. distance between 0,0 and (-10,2,10,2) should be 2).
here's code that works:
这里没有看到 Java 实现,所以我将 Javascript 函数从已接受的答案翻译为 Java 代码:
Didn't see a Java implementation here, so I translated the Javascript function from the accepted answer to Java code:
Eli,您选择的代码不正确。 靠近线段所在线但远离线段一端的点将被错误地判断为靠近线段。更新:提到的错误答案不再被接受。这是一些正确的 C++ 代码。 它假定一个 2D 向量类
class vec2 {float x,y;}
,本质上,具有加、减、缩放等运算符,以及距离和点积函数(即x1 x2 + y1 y2)。
编辑:我需要一个 Javascript 实现,所以就在这里,没有依赖项(或注释,但它是上面的直接端口)。 点表示为具有
x
和y
属性的对象。编辑2:我需要一个Java版本,但更重要的是,我需要3d而不是2d。
这里,在函数参数中,
是有问题的点,线段的端点
和
。 函数dist_sq
(假设存在)计算两点之间距离的平方。Eli, the code you've settled on is incorrect. A point near the line on which the segment lies but far off one end of the segment would be incorrectly judged near the segment.Update: The incorrect answer mentioned is no longer the accepted one.Here's some correct code, in C++. It presumes a class 2D-vector
class vec2 {float x,y;}
, essentially, with operators to add, subract, scale, etc, and a distance and dot product function (i.e.x1 x2 + y1 y2
).EDIT: I needed a Javascript implementation, so here it is, with no dependencies (or comments, but it's a direct port of the above). Points are represented as objects with
x
andy
attributes.EDIT 2: I needed a Java version, but more important, I needed it in 3d instead of 2d.
Here, in the function parameters,
<px,py,pz>
is the point in question and the line segment has the endpoints<lx1,ly1,lz1>
and<lx2,ly2,lz2>
. The functiondist_sq
(which is assumed to exist) finds the square of the distance between two points.这是最简单的完整 JavaScript 代码。
x, y 是您的目标点,x1, y1 到 x2, y2 是您的线段。
更新:修复评论中的 0 长度行问题。
更新:Kotlin 版本
Here is the simplest complete code in Javascript.
x, y is your target point and x1, y1 to x2, y2 is your line segment.
UPDATED: fix for 0 length line problem from comments.
UPDATED: Kotlin version
这是针对有限线段的实现,而不是像这里大多数其他函数那样的无限线(这就是我这样做的原因)。
Paul Bourke 理论的实现。
Python:
AS3:
Java
This is an implementation made for FINITE LINE SEGMENTS, not infinite lines like most other functions here seem to be (that's why I made this).
Implementation of theory by Paul Bourke.
Python:
AS3:
Java
在我自己的问题线程如何在 C、C# / .NET 2.0 或 Java 中计算所有情况下点和线段之间的最短 2D 距离? 当我找到一个答案时,有人要求我在此处放置一个 C# 答案:所以这里是从 http://www.topcoder 修改的。 com/tc?d1=tutorials&d2=geometry1&module=Static :
我 @SO 不是为了回答而是提出问题,所以我希望我不会因为某些原因而获得百万票反对,而是构建评论家。 我只是想(并且受到鼓励)分享其他人的想法,因为该线程中的解决方案要么使用某种外来语言(Fortran、Mathematica),要么被某人标记为错误。 对我来说唯一有用的一个(由 Grumdrig 编写)是用 C++ 编写的,没有人标记它有错误。 但它缺少被调用的方法(点等)。
In my own question thread how to calculate shortest 2D distance between a point and a line segment in all cases in C, C# / .NET 2.0 or Java? I was asked to put a C# answer here when I find one: so here it is, modified from http://www.topcoder.com/tc?d1=tutorials&d2=geometry1&module=Static :
I'm @SO not to answer but ask questions so I hope I don't get million down votes for some reasons but constructing critic. I just wanted (and was encouraged) to share somebody else's ideas since the solutions in this thread are either with some exotic language (Fortran, Mathematica) or tagged as faulty by somebody. The only useful one (by Grumdrig) for me is written with C++ and nobody tagged it faulty. But it's missing the methods (dot etc.) that are called.
对于任何感兴趣的人,这里有一个 Joshua 的 Javascript 代码到 Objective-C 的简单转换:
我需要这个解决方案与
MKMapPoint
一起使用,所以我将分享它,以防其他人需要它。 只需进行一些细微的更改,这将返回以米为单位的距离:For anyone interested, here's a trivial conversion of Joshua's Javascript code to Objective-C:
I needed this solution to work with
MKMapPoint
so I will share it in case someone else needs it. Just some minor change and this will return the distance in meters :在 F# 中,从点
c
到a
和b
之间的线段的距离由以下公式给出:向量
d 沿着线段从
a
指向b
。d/s
与ca
的点积给出了无限直线与点c
之间最接近点的参数。min
和max
函数用于将此参数限制在0..s
范围内,以便该点位于a< 之间/code> 和
b
。 最后,a+pc
的长度就是c
到线段上最近点的距离。使用示例:
In F#, the distance from the point
c
to the line segment betweena
andb
is given by:The vector
d
points froma
tob
along the line segment. The dot product ofd/s
withc-a
gives the parameter of the point of closest approach between the infinite line and the pointc
. Themin
andmax
function are used to clamp this parameter to the range0..s
so that the point lies betweena
andb
. Finally, the length ofa+p-c
is the distance fromc
to the closest point on the line segment.Example use:
在 Mathematica 中,
它使用线段的参数化描述,并将点投影到线段定义的线上。 当参数在线段中从 0 变为 1 时,如果投影超出此范围,我们将计算到相应端点的距离,而不是与线段垂直的直线。
绘制结果:
绘制那些比截止距离更近的点:
等值线图:
In Mathematica
It uses a parametric description of the segment, and projects the point into the line defined by the segment. As the parameter goes from 0 to 1 in the segment, if the projection is outside this bounds, we compute the distance to the corresponding enpoint, instead of the straight line normal to the segment.
Plotting result:
Plot those points nearer than a cutoff distance:
Contour Plot:
嘿,这是我昨天刚写的。 它位于 Actionscript 3.0 中,基本上是 Javascript,尽管您可能没有相同的 Point 类。
另外,这里对这个问题有一个非常完整且可读的讨论: notejot.com
Hey, I just wrote this yesterday. It's in Actionscript 3.0, which is basically Javascript, though you might not have the same Point class.
Also, there's a pretty complete and readable discussion of the problem here: notejot.com
使用反正切线的直线解决方案:
其想法是将A移动到(0, 0)并顺时针旋转三角形以使C位于X轴上,
当发生这种情况时,By 将是距离。
C#
一行 C#(要转换为 SQL)
One line solution using arctangents:
The idea is to move A to (0, 0) and rotate triangle clockwise to make C lay on X axis,
when this happen, By will be the distance.
C#
One line C# (to be converted to SQL)
对于懒惰的人来说,这是我上面 @Grumdrig 解决方案的 Objective-C 端口:
For the lazy, here's my Objective-C port of @Grumdrig's solution above: