如何判断一个点是否靠近某条直线?

9
7个回答

30

您需要计算到直线的直角距离。然后您需要定义"接近"是什么,并测试它是否在该距离范围内。

你想要的方程式是:

d=|v^^·r|=(|(x_2-x_1)(y_1-y_0)-(x_1-x_0)(y_2-y_1)|)/(sqrt((x_2-x_1)^2+(y_2-y_1)^2)).


12
注意:如果你正在处理线段(而不是无限长的直线),这可能会产生错误的结果:该点可能远离线段的端点,但仍具有较小的法向距离... - MartinStettner
还要注意,如果你要比较 d 和 D,将 |(x2 - x1) x (x1 - x0)|^2 与 D^2 |x2 - x1|^2 进行比较会更有效率,这样可以节省两个平方根和一个除法,但需要进行一次乘法。 - Dave
如果您无法访问链接,只想要一个方程式来插入数字,则我提供了所需的公式。 - Alan Jackson
对不起,Alan 先生,公式也没有出现! - Wahid Bitar
“d”是用来确定给定点是否在线段上的最大距离吗? - JarsOfJam-Scheduler
显示剩余3条评论

3

Alan Jackson的答案几乎完美 - 但他的第一个(也是最获赞的)评论表明端点没有得到正确处理。为确保点在线段上,只需创建一个以线段为对角线的框,然后检查点是否包含在内。以下是伪代码:

给定由点a和b组成的线段ab以及待确定的点p:

int buffer = 25;//this is the distance that you would still consider the point nearby
Point topLeft = new Point(minimum(a.x, b.x), minimum(a.y, b.y));
Point bottomRight = new Point(maximum(a.x, b.x), maximum(a.y, b.y));
Rect box = new Rect(topLeft.x - buffer, topLeft.y - buffer, bottomRight.x + buffer, bottomRight.y + buffer);
if (box.contains(p))
{
    //now run the test provided by Alan
    if (test)
        return true;
}
return false;

2

这里有一个Python函数可以解决问题。它适用于2或3维(或更多),并且处理垂直和水平线而不需要特殊情况。如果将clipToSegment设置为true,则返回的点将被剪切到线段端点,如果投影线超出了提供的线段。

def nearestPointOnLine(pt, r0, r1, clipToSegment = True):
    r01 = r1 - r0           # vector from r0 to r1 
    d = np.linalg.norm(r01) # length of r01
    r01u = r01 / d          # unit vector from r0 to r1
    r = pt - r0             # vector from r0 to pt
    rid = np.dot(r, r01u)   # projection (length) of r onto r01u
    ri = r01u * rid         # projection vector
    lpt = r0 + ri           # point on line

    if clipToSegment:       # if projection is not on line segment
        if rid > d:         # clip to endpoints if clipToSegment set
            return r1
        if rid < 0:
            return r0 

    return lpt

用法:(点[4,5]到线段由[2,4]到[4,6]的距离)

r0 = np.array([2,4])
r1 = np.array([4,6])
rpt = np.array([4,5])
pt = nearestPointOnLine(rpt, r0, r1, True)

dist = np.linalg.norm(rpt-pt)
print('dist', dist)

1
可以在最后一个返回语句之前计算rilpt - bb1950328

0

计算你的线上离那个点最近的点。

假设线段为a和b,点为p。

float vAPx = p.x - a.x;
float vAPy = p.y - a.y;
float vABx = b.x - a.x;
float vABy = b.y - a.y;
float sqDistanceAB = a.distanceSq(b);
float ABAPproduct = vABx*vAPx + vABy*vAPy;
float amount = ABAPproduct / sqDistanceAB;
if (amount > 1) amount = 1;
if (amount < 0) amount = 0;

这将给您“量”,以便在A和B之间的线段上确定您所处的位置(正确地被界定)。

    float nx = (amount * (b.x - a.x)) + a.x;
    float ny = (amount * (b.y - a.y)) + a.y;

返回给你点(nx,ny)。

if (p.distance(nx,ny) > threshold) reject;

这将在线段结束后正常工作,因为它将“amount”保持在0和1之间。

如果您不想要一个有界的线段,请摆脱“amount”的限制。代码的其余部分仍将工作,计算A之前和之后以及B之外的位置。

还有另一个问题声称这个问题是重复的,但它要求不同的东西,因此我的解决方案解决了点的位置,然后只解决欧几里得距离(实际上解决了两个问题)。

a.distanceSq(b)也可以表示为vABxvABx + vAByvABy,因为我们已经完成了这些。


0

基本上,你想做的就是找到法线(垂直于你给定的直线的线)与你的点和直线相交,然后计算沿着那条线的距离。


是的先生,但我在数学方面非常薄弱,请帮助我并给我这个方程式。 - Wahid Bitar
1
看最上面的,那里面什么都有。 - Charlie Martin

0

近在何方?

一些几何知识可以帮助你找到答案,你只需要了解以下步骤。

假设你的线段是y=mx+b的形式,那么到达你所需点的最短距离将是垂直于你起始线段(m1=-1/m)的线段,与你所询问的点相交。

然后你可以计算出交点和所询问点之间的距离。


-2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接