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. My current solution will return (4,3) and that is not on the line segment but is on the line.
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
See this nice description by Paul Bourke.
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)
). Then, you get rid of the newy
coordinate (that's where the actual projection occurs) and transform the new point(x, 0)
back into the original frame.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):
But you can invert these equations to find
(nx, ny)
that correspond to a point(x, y)
.When you do that, and assuming neither of us has made any mistakes nor typo, you should get something like:
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). Before the return statement, you can just forcenx
to stay in this interval:reedit: The statement above is equivalent to:
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.