Taking your original example:
from shapely.geometry import Point,LineString
g = LineString(coordinates=[(0, 0), (6.656423206909781, 4.437570291332059)])
p =wkt.loads('POINT (4.160264504318614 2.773481432082537)')
g.contains(p)
my first thought was that the string representation of a floating point number can be something that can not be represented exactly by a computer as a floating-point number in 8 bytes. For a trivial example, if I type 1.2222 and keep typing 2s, eventually python can't keep that precision and shows the last digit as a 3:
>>> 1.22222222222222222
1.2222222222222223
[ There's a nice intro to floating point here: https://docs.python.org/3/tutorial/floatingpoint.html ]
So a better test is to take the number from Python's calculation itself rather than typing them into a text string in a WKT. So I tried:
>>> g.interpolate(0.5, True).xy
(array('d', [3.3282116034548905]), array('d', [2.2187851456660295]))
Now that return value is stored in Python in whatever precision it is using. That point looks reasonably as half-way along the line, so lets try it:
>>> g.contains(g.interpolate(0.5, True))
True
Okay, that seems fine. But maybe halfway is somehow special because computers work with binary numbers and division by two is easy in binary? Anyway, always a good idea to try some more tests. Lets' try another point, this time a little bit past halfway:
>>> g.contains(g.interpolate(0.50001, True))
False
Now that perhaps is a little surprising. This shows directly that a point interpolated on a line is no longer thought to be contained by that line.
I wondered if numeric precision was having this effect. So I tried computing the distance from these interpolated points to the line:
>>> g.distance(g.interpolate(0.5, True))
0.0
>>> g.distance(g.interpolate(0.50001, True))
0.0
And these zeroes are identical zeroes.
I suspect floating point arithmetic rounding errors in the contains
method are occurring here. If you want to detect if a point is on a line then you should perhaps use the distance
method and then test the result is less than some small threshold to account for any precision problems.
g
contains its half-way point:g.contains(g.interpolate(0.5, True))
- is True, so lines can contain points. Note it doesn't contain its 0.25-way point.