Search code examples
pythonintersectioncurveshapely

Create a new curve from existing curve - Shapely


I have written a Python script that parses the coordinates out of a GPX file. The coordinates are stored as a list of tuples: (float lat, float long). I used Shapely's LineString function to create a curve that I can work with for each GPX file.

After parsing through several GPX files, I had some intersecting curves and I wanted to calculate some information based on these intersecting curves. To keep it simple, imagine I have 3 lines (call them line1, line2, line3). In this particular scenario, line1 intersects both line2 and line3 but line2 and line3 do not intersect. Or more visually:

  |
  |
--*--- Line 2 ------
  |
  |
  |
Line 1
  |
  |
  |
--*--- Line 3 ------
  |
  |

What I am trying to do is create a new curve from these existing curves. The start and end points of this curve would be the intersecting points (denoted by * in the visual representation), and the middles points of the curve would be the points of line1 that fall between these intersecting points.

I have no problem getting the intersecting points using Shapely's intersection() method, but I have no idea how to grab the points of line1 that fall between these intersecting points.

I thought about determining if line1 runs east/west or north/south. Based on that result I could compare the latitude or longitude of the intersecting points against every point in the line (line1 in this case) and once I found a point that was inside the latitude or longitude of the intersecting points then I could start a new line with those coordinates that was bounded by the intersecting points.

However, this seems like a crazy amount of work. I feel like there has to be an easier solution. Especially since I have a very basic knowledge of Shapely. Any help would be greatly appreciated.


Solution

  • The following algorithm is for splitting a lineString in 3 segments given two intermediary points (called startPoint and endPoint) The code looks like python but must be treated more as a pseudo-code because I can not test.

    linestring is the line to be splitted

    ## first  find in which pair the startPoint and endPoint exist
    for i,e in enumerate(linestring,1):
        if linestring[i-1,i].contains(startPoint):
            startIdx = i-1
        if linestring[i-1,i].contains(endPoint):
            endIdx = i
    
    # build three list
    # startLine from the beginning of line until start point 
    # middleLine from startPoint until endPoint
    # endLine from endPoint until the last point
    # transform every list to a LineString 
    
    # start the list with coords from Line starting with beginning until startPoint
    startLine = linestring.coords[:startIdx]
    # append startPoint coords
    startLine.append( startPoint.coords)
    # transform from list to LineString
    startLine = LineSting(startLine)
    
    middleLine =  list(startPoint.coords).extend(linestring.coords[startIdx+1:endIdx-1]).extend(endPoint.coord)
    # transform from list to LineString
    middleLine = LineSting(middleLine)
    
    # start list with end point coords
    endLine = endPoint.coords 
    # extend the list with coords from Line starting with endPoint until end
    endLine.extend( linestring.coords[endIdx:])  
    # transform from list to LineString
    endLine = LineSting(endLine)