pythonpython-2.7mathtrigonometrysnapping

Snap a point to the closest part of a line?


I have a work order management system that has Python 2.7.


The system has lines and points:

Line Vertex 1: 676561.00, 4860927.00
Line Vertex 2: 676557.00, 4860939.00

Point 100: 676551.00, 4860935.00
Point 200: 676558.00, 4860922.00

I want to snap the points to the nearest part of the line.

Snapping can be defined as:

Moving a point so that it coincides exactly with the closest part of a line.

enter image description here


There appear to be two different mathematical scenarios at play:

A. The closest part of a line is the position along the line where the point is perpendicular to the line.

B. Or, the closest part of the line is simply the closest vertex.

enter image description here


Is it possible to snap a point to the closest part of a line using Python 2.7 (and the standard 2.7 library)?


Solution

  • This is an extremely helpful resource.

    import collections
    import math
    
    Line = collections.namedtuple('Line', 'x1 y1 x2 y2')
    Point = collections.namedtuple('Point', 'x y')
    
    
    def lineLength(line):
      dist = math.sqrt((line.x2 - line.x1)**2 + (line.y2 - line.y1)**2)
      return dist
    
    
    ## See http://paulbourke.net/geometry/pointlineplane/
    ## for helpful formulas
    
    ## Inputs
    line = Line(0.0, 0.0, 100.0, 0.0)
    point = Point(50.0, 1500)
    
    ## Calculations
    print('Inputs:')
    print('Line defined by: ({}, {}) and ({}, {})'.format(line.x1, line.y1, line.x2, line.y2))
    print('Point "P": ({}, {})'.format(point.x, point.y))
    
    len = lineLength(line)
    if (len == 0):
      raise Exception('The points on input line must not be identical')
    
    print('\nResults:')
    print('Length of line (calculated): {}'.format(len))
    
    u = ((point.x - line.x1) * (line.x2 - line.x1) + (point.y - line.y1) * (line.y2 - line.y1)) / (
        len**2)
    
    # restrict to line boundary
    if u > 1:
      u = 1
    elif u < 0:
      u = 0
    
    nearestPointOnLine = Point(line.x1 + u * (line.x2 - line.x1), line.y1 + u * (line.y2 - line.y1))
    shortestLine = Line(nearestPointOnLine.x, nearestPointOnLine.y, point.x, point.y)
    
    print('Nearest point "N" on line: ({}, {})'.format(nearestPointOnLine.x, nearestPointOnLine.y))
    print('Length from "P" to "N": {}'.format(lineLength(shortestLine)))