Find minimum distance from point to complicated curve

前端 未结 3 1813
执笔经年
执笔经年 2020-12-23 22:37

I have a complicated curve defined as a set of points in a table like so (the full table is here):

#  x   y
1.0577  12.0914
1.0501  11.9946
1.0465  11.9338
.         


        
相关标签:
3条回答
  • 2020-12-23 23:14

    The curve is by nature parametric, i.e. for each x there isn't necessary a unique y and vice versa. So you shouldn't interpolate a function of the form y(x) or x(y). Instead, you should do two interpolations, x(t) and y(t) where t is, say, the index of the corresponding point.

    Then you use scipy.optimize.fminbound to find the optimal t such that (x(t) - x0)^2 + (y(t) - y0)^2 is the smallest, where (x0, y0) are the red dots in your first figure. For fminsearch, you could specify the min/max bound for t to be 1 and len(x_data)

    0 讨论(0)
  • 2020-12-23 23:25

    If you're open to using a library for this, have a look at shapely: https://github.com/Toblerity/Shapely

    As a quick example (points.txt contains the data you linked to in your question):

    import shapely.geometry as geom
    import numpy as np
    
    coords = np.loadtxt('points.txt')
    
    line = geom.LineString(coords)
    point = geom.Point(0.8, 10.5)
    
    # Note that "line.distance(point)" would be identical
    print point.distance(line)
    

    As an interactive example (this also draws the line segments you wanted):

    import numpy as np
    import shapely.geometry as geom
    import matplotlib.pyplot as plt
    
    class NearestPoint(object):
        def __init__(self, line, ax):
            self.line = line
            self.ax = ax
            ax.figure.canvas.mpl_connect('button_press_event', self)
    
        def __call__(self, event):
            x, y = event.xdata, event.ydata
            point = geom.Point(x, y)
            distance = self.line.distance(point)
            self.draw_segment(point)
            print 'Distance to line:', distance
    
        def draw_segment(self, point):
            point_on_line = line.interpolate(line.project(point))
            self.ax.plot([point.x, point_on_line.x], [point.y, point_on_line.y], 
                         color='red', marker='o', scalex=False, scaley=False)
            fig.canvas.draw()
    
    if __name__ == '__main__':
        coords = np.loadtxt('points.txt')
    
        line = geom.LineString(coords)
    
        fig, ax = plt.subplots()
        ax.plot(*coords.T)
        ax.axis('equal')
        NearestPoint(line, ax)
        plt.show()
    

    enter image description here

    Note that I've added ax.axis('equal'). shapely operates in the coordinate system that the data is in. Without the equal axis plot, the view will be distorted, and while shapely will still find the nearest point, it won't look quite right in the display:

    enter image description here

    0 讨论(0)
  • 2020-12-23 23:30

    You could try implementing a calculation of distance from point to line on incremental pairs of points on the curve and finding that minimum. This will introduce a small bit of error from the curve as drawn, but it should be very small, as the points are relatively close together.

    http://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line

    0 讨论(0)
提交回复
热议问题