In my project there are two use-cases. The red and blue shapes are not overlapping in the first case, but they do in the second.
In my test code I tried various predicates from Shapely but could not find anyway to tell them apart.
from shapely import LinearRing
# first use-case
blue_sq = LinearRing([(1, 1), (1, 2), (2, 2), (2, 1), (1, 1)])
red_one = LinearRing([(0, 0), (0, 3), (3, 3), (3, 2), (1, 2), (1, 0), (0, 0)])
print(blue_sq.overlaps(red_one))
print(blue_sq.intersects(red_one))
print(blue_sq.crosses(red_one))
print(blue_sq.contains(red_one))
print(blue_sq.touches(red_one))
print(blue_sq.within(red_one))
# second use-case
blue_ln = LinearRing([(2, 1), (2, 2), (7, 2), (7, 1), (2, 1)])
red_two = LinearRing([(1, 0), (1, 1), (2, 1), (2, 2), (3, 2), (3, 0), (1, 0)])
print(blue_ln.overlaps(red_two))
print(blue_ln.intersects(red_two))
print(blue_ln.crosses(red_two))
print(blue_ln.contains(red_two))
print(blue_ln.touches(red_two))
print(blue_ln.within(red_two))
The results are summarised in the table below.
Shapely predicate | case 1 | case 2 |
---|---|---|
overlaps | True | True |
intersects | True | True |
crosses | False | False |
contains | False | False |
touches | False | False |
within | False | False |
Both cases appear to intersect and overlap, but neither case crosses, contains, touches or lies within the other. I feel sure that I am missing something obvious :-)
A LinearRing is still just a line... so considering that both cases are indeed very similar and there are no differences in the results of the predicates.
A difference appears when you consider the coordinates as the outer border of a surface. To use the lines like that you need to use them to create Polygons in shapely. If you do that, you get the expected different results.
Code sample:
from shapely import Polygon
# first use-case
blue_sq = Polygon([(1, 1), (1, 2), (2, 2), (2, 1), (1, 1)])
red_one = Polygon([(0, 0), (0, 3), (3, 3), (3, 2), (1, 2), (1, 0), (0, 0)])
print(f"{blue_sq.overlaps(red_one)=}")
print(f"{blue_sq.intersects(red_one)=}")
print(f"{blue_sq.crosses(red_one)=}")
print(f"{blue_sq.contains(red_one)=}")
print(f"{blue_sq.touches(red_one)=}")
print(f"{blue_sq.within(red_one)=}")
# second use-case
blue_ln = Polygon([(2, 1), (2, 2), (7, 2), (7, 1), (2, 1)])
red_two = Polygon([(1, 0), (1, 1), (2, 1), (2, 2), (3, 2), (3, 0), (1, 0)])
print(f"{blue_ln.overlaps(red_two)=}")
print(f"{blue_ln.intersects(red_two)=}")
print(f"{blue_ln.crosses(red_two)=}")
print(f"{blue_ln.contains(red_two)=}")
print(f"{blue_ln.touches(red_two)=}")
print(f"{blue_ln.within(red_two)=}")
Output:
blue_sq.overlaps(red_one)=False
blue_sq.intersects(red_one)=True
blue_sq.crosses(red_one)=False
blue_sq.contains(red_one)=False
blue_sq.touches(red_one)=True
blue_sq.within(red_one)=False
blue_ln.overlaps(red_two)=True
blue_ln.intersects(red_two)=True
blue_ln.crosses(red_two)=False
blue_ln.contains(red_two)=False
blue_ln.touches(red_two)=False
blue_ln.within(red_two)=False