4

I have a problem to check if a Linestring contains a Point. I consider the straight line y = 0.1 x , and take by it a segment l='Linestring( 0 0 , 4 0.4 )' and a Point p on segment l, p = 'Point(1.5 0.15)'. If I check ST_Contains(l,p) the result is false and the distance ST_Distance(l,p) is near to zero, but this is wrong because the Point is on the Linestring. If I try with p= 'Point(2 0.2)' the result is right.

What is the problem?

WITH 
     l AS (
           SELECT ST_GeomFromText('Linestring( 0 0 ,  4 0.4 )') AS geom          -- segment of the straight line y = 0.1 x
       ),
     p AS (
       SELECT ST_GeomFromText('Point(1.5 0.15)') AS geom                     -- point on the straight line y = 0.1 x
       )

 SELECT ST_AsText(ST_Intersection(p.geom,l.geom)) as ST_Intersection,
        ST_Distance(p.geom,l.geom),
        ST_Contains(l.geom,p.geom),
        ST_Intersects(p.geom,l.geom),
        ST_AsText(ST_Line_Interpolate_Point(l.geom,1.5/4)) as ST_Substring       -- point in position 1.5/4 of l 
 FROM l,p

Result 1

EDIT: My origin problem was: LineString L1 contains Linestring L2 but if I do ST_SymDifference(l1.geom,l2.geom) the result is incorrect.

WITH 
     l1 AS (
           SELECT ST_GeomFromText('Linestring( 0 0 ,  4 0.4 )') AS geom          -- segment of the straight line y = 0.1 x
       ),
     l2 AS (
       SELECT ST_GeomFromText('LineString(0 0 , 1.5 0.15)') AS geom             -- segment of the straight line y = 0.1 x
       )

 SELECT ST_AsText(ST_SymDifference(l1.geom,l2.geom)) as ST_Intersection     
 FROM l1,l2

Result 2

1
  • 1
    Point on line is always difficult, even when matching a vertex. Use distance to line and then decide if the return distance is small enough to make the point 'on' the line. Commented May 6, 2016 at 0:28

1 Answer 1

8

Overlay operators like Contains, Intersection, SymDifference, etc. require exact noding. This is because there are floating point differences on the order of 1e-14 when interpolations are performed between two lines that are not equal. And while 1e-14 is a tiny number, it is still not zero.

Use ST_Snap to help "snap" vertices from one geometry onto another to get exact noding. For example:

SELECT ST_AsText(ST_Intersection(p, ST_Snap(l, p, 1e-14))) as ST_Intersection,
    ST_Distance(p, ST_Snap(l, p, 1e-14)),
    ST_Contains(ST_Snap(l, p, 1e-14), p),
    ST_Intersects(p, ST_Snap(l, p, 1e-14))
FROM (
    SELECT 'Linestring(0 0, 4 0.4)'::geometry l, 'Point(1.5 0.15)'::geometry p
) f;

 st_intersection | st_distance | st_contains | st_intersects
-----------------+-------------+-------------+---------------
 POINT(1.5 0.15) |           0 | t           | t
(1 row)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.