Wednesday, 17 February 2016

postgresql - PostGIS - Linestring doesn't contain a Point - Problem


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



Answer



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)

No comments:

Post a Comment

arcpy - Changing output name when exporting data driven pages to JPG?

Is there a way to save the output JPG, changing the output file name to the page name, instead of page number? I mean changing the script fo...