Shapely Python: Find where linestring and polygon touch

2.2k Views Asked by At

I'm using shapely to work with geometries. I'm having trouble finding the point where LineString just touches the exterior of a polygon. I have been using the "touches" function, but it does not seem to always work.

According to the Shapely user manual:

object.touches(other)

Returns True if the objects have at least one point in common and their interiors do not intersect with any part of the other.

For reference, consider the following two examples. One works, the other does not.

from shapely.geometry import Polygon
from shapely.speedups._speedups import LineString
from matplotlib import pyplot as plt

examples = {
    "Example 1": {
        "poly_coords": [(-1, -1), (-1, 1), (1, 1), (1, -1), (-1, -1)],
        "line_coords": [(1, 0), (2, 0)]
    },
    "Example 2": {
        "poly_coords": [(336.2, 326.0), (337.65, 338.15), (333.84, 338.8), (333.78, 338.76), (333.14, 338.39),
                        (331.98, 337.77), (331.25, 337.42), (330.05, 336.91), (329.3, 336.63), (328.09, 336.23),
                        (327.27, 335.99), (326.02, 335.69), (325.16, 335.54), (323.92, 335.36), (323.03, 335.28),
                        (321.76, 335.22), (321.19, 335.22), (321.8, 334.9), (322.12, 334.72), (323.64, 333.86),
                        (323.96, 333.68), (325.53, 332.72), (325.84, 332.51), (327.29, 331.53), (327.61, 331.31),
                        (329.01, 330.28), (329.33, 330.04), (330.68, 328.96), (331.0, 328.7), (332.27, 327.58),
                        (332.45, 327.42), (336.2, 326.0)],
        "line_coords": [(336.92499999999995, 332.075), (339.80456651646705, 331.731348028899)]
    }
}
for example_key, ex in examples.items():

    poly = Polygon(ex["poly_coords"])
    line = LineString(ex["line_coords"])
    print("{1} {0} {1}".format(example_key, "#" * 20))
    print(line.touches(poly))
    print(line.intersection(poly))
    print(line.overlaps(poly))

    xpoly, ypoly = poly.exterior.xy
    xline, yline = zip(*ex["line_coords"])
    plt.figure()
    plt.title(example_key)
    plt.fill(xpoly, ypoly, alpha=0.5, fc='r')
    plt.plot(xline, yline)
plt.show()

The output of the example code is below. Why does "touches" return True for example 1, but False for example 2? Shouldn't they be the same?

#################### Example 2 ####################
False
POINT (336.925 332.075)
#################### Example 1 ####################
True
POINT (1 0)

Here are the resulting images:

enter image description here enter image description here

1

There are 1 best solutions below

0
4xle On

I think the answer is in the definition:

object.touches(other)

Returns True if the objects have at least one point in common and their interiors do not intersect with any part of the other.

I suspect you will find with closer inspection that your line_string overlaps with your polygon instead of merely touching it. This would cause it to fail the second clause of the and statement in the definition, as more than one point on the line implicitly intersects with the polygon.