简体   繁体   English

如何找到线段上最近的点到任意点?

[英]How to find the closest point on a line segment to an arbitrary point?

This function is supposed to take in a point parameter which will be used to find the closest point to it that lies on the line segment object. 该函数应该接受一个点参数,该参数将用于找到位于线段对象上的最接近点。 In the example assertion code the function getClosestPoint(Point()) takes Point(10, 0) as parameters and should return Point(5,5) as the closest point to Point(10, 0) that is on the line of l1 = Line(Point(5,5), Point(20,35)) With the endpoints being A Point(5,5), B Point(20,35) I'm not sure how to go about solving this problem. 在示例断言代码中,函数getClosestPoint(Point())Point(10, 0) getClosestPoint(Point()) Point(10, 0)作为参数,并且应返回Point(5,5)作为最靠近Point(5,5)的点,该Point(10, 0)位于l1 = Line(Point(5,5), Point(20,35))端点为A Point(5,5), B Point(20,35)我不知道如何解决这个问题。 My current solution will return (4,3) and that is not on the line segment but is on the line. 我当前的解决方案将返回(4,3)并且不在线段上但是在线上。

 from point import Point
 import math
 class Line:
    def __init__(self,aPoint=Point(), bPoint=Point()):
        self.firstPoint = aPoint
        self.secondPoint = bPoint

    def getClosestPoint(self,point=Point()):

        m1 = self.getSlope()
        m2 = -1 / float(m1)
        b1 = self.p1.y - m1 * self.p1.x
        b2 = point.y - m2 * point.x
        x = float(b2 - b1) / float(m1 - m2)
        y = m1 * x + b1
        return Point(x, y)

    if __name__ == "__main__":
         p1 = Point(5,5)
         p2 = Point(20,35)
         l1 = Line(p1,p2)
         assert l1.getClosestPoint(Point(10,0)) == Point(5,5)
         assert l2.getClosestPoint(Point(25/2,25/2)


 class Point: 
    def __init__(self,x=0,y=0):
       self.x = x
       self.y = y

The general answer is to project the point onto the line. 一般的答案是将点投射到线上。 One way to see it is to transform the point into the reference frame defined by your segment ( p1 is the new origin (0, 0) , p2 the new (1, 0) ). 查看它的一种方法是将点转换为由段定义的参考帧( p1是新原点(0, 0)p2是新的(1, 0) )。 Then, you get rid of the new y coordinate (that's where the actual projection occurs) and transform the new point (x, 0) back into the original frame. 然后,您将摆脱新的y坐标(即实际投影发生的位置)并将新点(x, 0)回原始帧。

Concretely, you'll have to find the transformations. 具体而言,您必须找到转换。 The second one, from the new space into the original space is easy to write (just draw it on paper, you'll see): 第二个,从新空间到原始空间很容易写(只需在纸上绘制,你会看到):

x = (x2 - x1) * nx + (y2 - y1) * ny + x1
y = (y1 - y2) * nx + (x2 - x1) * ny + y1

But you can invert these equations to find (nx, ny) that correspond to a point (x, y) . 但是你可以将这些方程反转以找到对应于点(x, y) (nx, ny) (x, y)

When you do that, and assuming neither of us has made any mistakes nor typo, you should get something like: 当你这样做,并假设我们都没有犯过任何错误或错字,你应该得到类似的东西:

dx = x2 - x1
dy = y2 - y1
d2 = dx*dx + dy*dy
nx = ((x3-x1)*dx + (y3-y1)*dy) / d2
return (dx*nx + x1, dy*nx + y1)

edit: If you actually have to find the closest point on the segment instead of the line, it is easy to find because if the projection falls within the segment, you have 0 <= nx <= 1 (it's a necessary and sufficient condition). 编辑:如果你实际上必须找到上最近的点而不是线,很容易找到,因为如果投影属于段,你有0 <= nx <= 1 (这是一个必要和充分的条件) 。 Before the return statement, you can just force nx to stay in this interval: 在return语句之前,您可以强制nx保持在此间隔:

nx = min(1, max(0, nx))

reedit: The statement above is equivalent to: reedit:上述声明相当于:

if nx<0:
    nx = 0
if nx>1:
    nx = 1

This way, the projection of the point on the line (which can be outside the segment) gets pushed back inside the segment (defined by 0 <= nx <= 1 ) at the closest point. 这样,线上点(可以在线段外)的投影在最近点处被推回到线段内(由0 <= nx <= 1 )。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM