1

I have two lines and I need to test that one line's endpoint lies on the interior of another line. I cannot figure out a way to do this, or my geometry is not correct somehow.

I have tried using the spatial predicates directly on the lines, and also getting the endpoints of the line whose endpoint should be on the interior of the other line, and doing the predicates on those, but nothing is getting a True, other than .disjoint()

Here is a standalone example which tests all the predicates:


from shapely.geometry import Point
from shapely.wkt import loads as wkt_loads

line1 = wkt_loads('LINESTRING (-2541327.852614192 1200639.51876279, -2541334.881208359 1200651.320660183, -2541341.737174531 1200665.621295573, -2541352.153298927 1200681.115312071, -2541361.311127506 1200689.640737319, -2541372.488576112 1200702.662111132, -2541380.898505223 1200714.892181718, -2541387.70079183 1200724.264702213, -2541396.446646634 1200731.151712671, -2541410.682807061 1200735.514577996, -2541418.649446443 1200743.231518303, -2541425.810027506 1200749.314348437, -2541434.914176412 1200752.911671434, -2541447.170981444 1200756.47464954, -2541454.694329239 1200759.678469584, -2541459.450155741 1200762.090993515)') line2 = wkt_loads('LINESTRING (-2541400.394516717 1200732.361591246, -2541400.400887049 1200732.340804661)')

Testing with lines directly

print(f"line1.contains(line2): {line1.contains(line2)}") print(f"line1.covers(line2): {line1.covers(line2)}") print(f"line1.crosses(line2): {line1.crosses(line2)}") print(f"line1.disjoint(line2): {line1.disjoint(line2)}") print(f"line1.intersects(line2): {line1.intersects(line2)}") print(f"line1.overlaps(line2): {line1.overlaps(line2)}") print(f"line1.touches(line2): {line1.touches(line2)}") print(f"line1.within(line2): {line1.within(line2)}") print(f"line2.contains(line1): {line2.contains(line1)}") print(f"line2.covers(line1): {line2.covers(line1)}") print(f"line2.crosses(line1): {line2.crosses(line1)}") print(f"line2.disjoint(line1): {line2.disjoint(line1)}") print(f"line2.intersects(line1): {line2.intersects(line1)}") print(f"line2.overlaps(line1): {line2.overlaps(line1)}") print(f"line2.touches(line1): {line2.touches(line1)}") print(f"line2.within(line1): {line2.within(line1)}")

p2_start, p2_end = Point(line2.coords[0]), Point(line2.coords[1]) print(f"line1.contains(p2_start): {line1.contains(p2_start)}") print(f"line1.covers(p2_start): {line1.covers(p2_start)}") print(f"line1.crosses(p2_start): {line1.crosses(p2_start)}") print(f"line1.disjoint(p2_start): {line1.disjoint(p2_start)}") print(f"line1.intersects(p2_start): {line1.intersects(p2_start)}") print(f"line1.overlaps(p2_start): {line1.overlaps(p2_start)}") print(f"line1.touches(p2_start): {line1.touches(p2_start)}") print(f"line1.within(p2_start): {line1.within(p2_start)}") print(f"p2_start.contains(line1): {p2_start.contains(line1)}") print(f"p2_start.covers(line1): {p2_start.covers(line1)}") print(f"p2_start.crosses(line1): {p2_start.crosses(line1)}") print(f"p2_start.disjoint(line1): {p2_start.disjoint(line1)}") print(f"p2_start.intersects(line1): {p2_start.intersects(line1)}") print(f"p2_start.overlaps(line1): {p2_start.overlaps(line1)}") print(f"p2_start.touches(line1): {p2_start.touches(line1)}") print(f"p2_start.within(line1): {p2_start.within(line1)}")

print(f"line1.contains(p2_end): {line1.contains(p2_end)}") print(f"line1.covers(p2_end): {line1.covers(p2_end)}") print(f"line1.crosses(p2_end): {line1.crosses(p2_end)}") print(f"line1.disjoint(p2_end): {line1.disjoint(p2_end)}") print(f"line1.intersects(p2_end): {line1.intersects(p2_end)}") print(f"line1.overlaps(p2_end): {line1.overlaps(p2_end)}") print(f"line1.touches(p2_end): {line1.touches(p2_end)}") print(f"line1.within(p2_end): {line1.within(p2_end)}") print(f"p2_end.contains(line1): {p2_end.contains(line1)}") print(f"p2_end.covers(line1): {p2_end.covers(line1)}") print(f"p2_end.crosses(line1): {p2_end.crosses(line1)}") print(f"p2_end.disjoint(line1): {p2_end.disjoint(line1)}") print(f"p2_end.intersects(line1): {p2_end.intersects(line1)}") print(f"p2_end.overlaps(line1): {p2_end.overlaps(line1)}") print(f"p2_end.touches(line1): {p2_end.touches(line1)}") print(f"p2_end.within(line1): {p2_end.within(line1)}")

And here is a picture of the geometries (red = line1, blue = line2):

enter image description here

How can I determine if line2's endpoint lies on line1's interior?

wfgeo
  • 3,538
  • 2
  • 24
  • 47
  • Lines don't have an interior – Ian Turton Jun 07 '22 at 11:44
  • What about the boundary, is that the proper term for it? – wfgeo Jun 07 '22 at 11:44
  • I'd rather think that the point does not lie exactly on the line geometrically and use miniscule buffering around the line to make sure it will be "caught" by the intersection calculation. – bugmenot123 Jun 07 '22 at 11:47
  • Transform your blue line in 2 points (each extremity) and check if at least 1 point is inside a small (1m?) buffer of the red line – Cupain Jun 07 '22 at 11:49
  • 2
    @IanTurton Topologically, lines do have have an interior (the part of the geometry that isn't the endpoints, as per Clementini, et. al.). But IEEE floating-point representation is unlikely to model "point inside line" correctly for all cases, so a "distance less than a threshold" test should be used instead. – Vince Jun 07 '22 at 12:03

1 Answers1

0

Your problem is that they don't intersect. You can test it with the code below.

from shapely.geometry import Point
from shapely.wkt import loads as wkt_loads

line1 = wkt_loads('LINESTRING (-2541327.852614192 1200639.51876279, -2541334.881208359 1200651.320660183, -2541341.737174531 1200665.621295573, -2541352.153298927 1200681.115312071, -2541361.311127506 1200689.640737319, -2541372.488576112 1200702.662111132, -2541380.898505223 1200714.892181718, -2541387.70079183 1200724.264702213, -2541396.446646634 1200731.151712671, -2541410.682807061 1200735.514577996, -2541418.649446443 1200743.231518303, -2541425.810027506 1200749.314348437, -2541434.914176412 1200752.911671434, -2541447.170981444 1200756.47464954, -2541454.694329239 1200759.678469584, -2541459.450155741 1200762.090993515)') line2 = wkt_loads('LINESTRING (-2541400.394516717 1200732.361591246, -2541400.400887049 1200732.340804661)')

p2_start, p2_end = Point(line2.coords[0]), Point(line2.coords[1]) npstart = line1.interpolate(line1.project(p2_start)) npend = line1.interpolate(line1.project(p2_end)) print(f"p2_start {p2_start}") print(f"p2_end {p2_end}") print(f"npstart {npstart}") print(f"npend {npend}") print(p2_start.distance(npstart)) print(p2_end.distance(npend))

p2_start POINT (-2541400.394516717 1200732.361591246)

p2_end POINT (-2541400.400887049 1200732.340804661)

npstart POINT (-2541400.394516717 1200732.361591246)

npend POINT (-2541400.394516717 1200732.361591246)

2.3283064365386963e-10

0.021740819882111136

ZRab
  • 31
  • 2