0

I am trying to find the intersections of multiple LineStrings that are in a list. Do you know how I could optimize this? I'm not sure on how to make it go faster(provided a small example):

from shapely.geometry import LineString
l1 = LineString([Point(-122.238615,37.78376699999999), Point(-122.237455,37.78220799999999)])
l2 = LineString([Point(-122.236899, 37.77980199999999), Point(-122.232146, 37.77611)])
l3 = LineString([Point(-122.232452, 37.775956), Point(-122.236212, 37.775573)])
l4 = LineString([Point(-122.234843, 37.77336199999999), Point(-122.231641, 37.77664699999999)])
l5 = LineString([Point(-121.908187, 37.67754099999999),Point(-121.908409, 37.67810899999999)])

linestrings = [l1,l2,l3,l4,l5,l1,l2,l3,l4,l5,l1,l2,l3,l4,l5,l1,l2,l3,l4,l5,l1,l2,l3,l4,l5,l1,l2,l3,l4,l5]

import time
the_time = time.time()
[ x.intersection(y) for idx1,x in enumerate(linestrings) for idx2,y in enumerate(linestrings) if idx1<idx2 and x.intersects(y)]
print("TIME:",time.time()-the_time)

Output:

TIME: 0.026987314224243164

This is a small example, but I have way more data, any idea how I can make it go faster?

Barkz
  • 193
  • 1
  • 10
  • Are the lines repeated (like the example above) or distinct? I think there isn't much to do if all pair of segments intersects. – user202729 Jan 20 '18 at 15:54
  • No, they are distinct. – Barkz Jan 20 '18 at 15:56
  • Because the code currently executes in time O(n^2) and, there may be up to n^2 intersections, the code is optimal in terms of asymptotic time complexity. I can only say, the solution would be different depends on the situation. – user202729 Jan 20 '18 at 15:57
  • I understand. Thanks for the answer! – Barkz Jan 20 '18 at 16:00
  • Wouldn't `[x.intersection(y) for x, y in itertools.combinations(linestrings, 2)]` be faster instead of having two iterators in your list comprehesion, which evalute both, `a.intersection(b)` and `b.intersection(a)` and even `a.intersection(a)`? – Mr. T Jan 20 '18 at 16:04
  • I've got intersects() and intersection() which calculate different things. However, I've tested it and unfortunately it doesn't help. Seems like it's just the looping that takes a long time – Barkz Jan 20 '18 at 16:15

1 Answers1

1

It might be useful to employ a spatial index so that the inner loop over the LineStrings can be reduced to loop only over those the bounding box of which intersects with the bounding box of the LineString being iterated over in the outer loop, i.e., to consider only those LineStrings where there is a chance for intersection.

To this end, there is the rtree package:

#!/usr/bin/env python
import time

from shapely.geometry import LineString, Point
import rtree

def main():
    l1 = LineString([Point(-122.238615,37.78376699999999), Point(-122.237455,37.78220799999999)])
    l2 = LineString([Point(-122.236899, 37.77980199999999), Point(-122.232146, 37.77611)])
    l3 = LineString([Point(-122.232452, 37.775956), Point(-122.236212, 37.775573)])
    l4 = LineString([Point(-122.234843, 37.77336199999999), Point(-122.231641, 37.77664699999999)])
    l5 = LineString([Point(-121.908187, 37.67754099999999),Point(-121.908409, 37.67810899999999)])

    linestrings = [l1,l2,l3,l4,l5]

    the_time = time.time()
    L = [ x.intersection(y) for idx1,x in enumerate(linestrings) for idx2,y in enumerate(linestrings) if idx1<idx2 and x.intersects(y) ]
    print("TIME: ", time.time() - the_time)

    the_time = time.time()
    index = rtree.index.Index()
    for idx, l in enumerate(linestrings):
        index.insert(idx, l.bounds)

    K = []
    for i1, l1 in enumerate(linestrings):
        for i2 in index.intersection(l1.bounds):
            if i2 >= i1: continue

            omega = l1.intersection(linestrings[i2])
            if omega.is_empty: continue

            K.append(omega)

    print("TIME: ", time.time() - the_time)

if __name__ == '__main__':
    main()
ewcz
  • 12,819
  • 1
  • 25
  • 47