Search code examples
pythonshapely

How to get equally spaced points on a line in Shapely


I'm trying to (roughly) equally space the points of a line to a predefined distance.

It's ok to have some tolerance between the distances but as close as possible would be desirable.

I know I could manually iterate through each point in my line and check the p1 distance vs p2 and add more points if needed.

But I wondered if anyone knows if there is a way to achieve this with shapely as I already have the coords in a LineString.

enter image description here


Solution

  • One way to do that is to use interpolate method that returns points at specified distances along the line. You just have to generate a list of the distances somehow first. Taking the input line example from Roy2012's answer:

    import numpy as np
    from shapely.geometry import LineString
    from shapely.ops import unary_union
    
    line = LineString(([0, 0], [2, 1], [3, 2], [3.5, 1], [5, 2]))
    

    enter image description here

    Splitting at a specified distance:

    distance_delta = 0.9
    distances = np.arange(0, line.length, distance_delta)
    # or alternatively without NumPy:
    # points_count = int(line.length // distance_delta) + 1
    # distances = (distance_delta * i for i in range(points_count))
    points = [line.interpolate(distance) for distance in distances] + [line.boundary[1]]
    multipoint = unary_union(points)  # or new_line = LineString(points)
    

    enter image description here
    Note that since the distance is fixed you can have problems at the end of the line as shown in the image. Depending on what you want you can include/exclude the [line.boundary[1]] part which adds the line's endpoint or use distances = np.arange(0, line.length, distance_delta)[:-1] to exclude the penultimate point.

    Also, note that the unary_union I'm using should be more efficient than calling object.union(other) inside a loop, as shown in another answer.

    Splitting to a fixed number of points:

    n = 7
    # or to get the distances closest to the desired one:
    # n = round(line.length / desired_distance_delta)
    distances = np.linspace(0, line.length, n)
    # or alternatively without NumPy:
    # distances = (line.length * i / (n - 1) for i in range(n))
    points = [line.interpolate(distance) for distance in distances]
    multipoint = unary_union(points)  # or new_line = LineString(points)
    

    enter image description here