2

I am using postgis's ST_LineLocatePoint to find out the closest point on a LineString to the given Point, and using ST_LineInterpolatePoint to extract a Point from the returned float number.(as referred here)

This is my ST_LineLocatePoint Query:

SELECT ST_AsText(ST_LineInterpolatePoint(foo.the_line,
         ST_LineLocatePoint(foo.the_line,ST_GeomFromText('POINT(12.962315 
         77.584841)')))) AS g FROM (SELECT ST_GeomFromText('LINESTRING(12.96145 
         77.58408,12.96219 77.58447,12.96302 77.58489,12.96316 77.58496,12.96348 
         77.58511)') AS the_line) AS foo;

Output:

                  g                     
------------------------------------------
 POINT(12.9624389808159 77.5845959902924)

Which exactly lies on the linestring I have passed. Demonstration is displayed here.

But when I check whether this point lies in the same linestring using ST_Contains it always return false, even though the point lies within.

My ST_Contains Query:

    SELECT ST_Contains(ST_GeomFromText('LINESTRING(12.96145 77.58408,12.96219 
    77.58447,12.96302 77.58489, 12.96316 77.58496, 12.96348 
    77.58511)'),ST_GeomFromText('POINT(12.9624389808159 77.5845959902924)'));

Output:

 st_contains 
-------------
 f

I am not getting where I am doing wrong, why I am getting false. Can anyone help me in this.

Postgresql : 9.4
postgis : 2.1

2 Answers 2

3

Using ST_LineLocatePoint and then ST_LineInterpolatePoint has introduced a rounding error as you can see by this query showing the distance between the point you calculated and the line:

SELECT ST_Distance(
    ST_GeomFromText('LINESTRING(12.96145 77.58408, 12.96219 77.58447, 12.96302 77.58489, 12.96316 77.58496, 12.96348 77.58511)'),
    ST_GeomFromText('POINT(12.9624389808159 77.5845959902924)')
);

     st_distance      
----------------------
 1.58882185807825e-14
(1 row)

This means that ST_Contains won't return t.

To find the closest point on the line, PostGIS actually comes with the function you need: ST_ClosestPoint.

SELECT ST_AsText(ST_ClosestPoint(
    ST_GeomFromText('POINT(12.962315 77.584841)'), 
    ST_GeomFromText('LINESTRING(12.96145 77.58408, 12.96219 77.58447, 12.96302 77.58489, 12.96316 77.58496, 12.96348 77.58511)')
));

         st_astext          
----------------------------
 POINT(12.962315 77.584841)
5
  • you are right that it is about rounding errors, but st_Closestpoint will not help. You get the same error problem. Actually there is many points along a line that cannot be described with a finite number of decimals. So use st_dwithin for exampke with a small tolerance instead of st_contains. Sep 29, 2015 at 19:35
  • @bosth how come the rounded point appear on the same line? It didn't look that much far away from linestring. Look at the live demo mentioned in the question(jsfiddle.net/2p3zekae/2/).
    – Aparichith
    Sep 30, 2015 at 1:46
  • @bosth your ST_ClosestPoint query returns the same given point as output.
    – Aparichith
    Sep 30, 2015 at 1:54
  • tried ST_ClosestPoint example and it is also giving the same point as ST_LineLocatePoint. Query: SELECT ST_AsText(ST_ClosestPoint(pt,line)) AS cp_pt_line,ST_AsText(ST_ClosestPoint(line,pt)) As cp_line_pt FROM (SELECT 'POINT(12.962315 77.584841)'::geometry As pt, 'LINESTRING (12.96145 77.58408,12.96219 77.58447, 12.96302 77.58489, 12.96316 77.58496, 12.96348 77.58511)'::geometry As line) As foo; Output: 12.9624389808159 77.5845959902924)
    – Aparichith
    Sep 30, 2015 at 1:58
  • ST_ClosestPoint(A, B) and ST_ClosestPoint(B, A) are two very different calculations. As for the visual appearance, the difference is so small that you wouldn't see it in the rendered map.
    – bosth
    Sep 30, 2015 at 6:53
1

Copy-paste from the same question somewhere else:

I am not getting where I am doing wrong.

I think you're doing good... I had the same issue some time ago... I used ST_ClosestPoint to locate point on linestring and then cut a linestring with this point, but I can't.

Following the documentation:

ST_ClosestPoint — Returns the 2-dimensional point on g1 that is closest to g2. This is the first point of the shortest line.

So I get situation where one function says - this point is on a line, and other functions says - ok, but I can't cut cause your point is not on a line... I was confused like you're now...

In my case resolution was to draw another line which will intersect first line 'exactly' in given point and after that first line was cutted...

After some research I found issue was about rounding of coordinates counted and writen. I explain it to myself that, according to the definitions line is infinitely thin and point is infinitely small (they do not have the area), so they can easily miss each other - but it's my reasoning and I'm not sure whether it is good. I advice you to use st_intersects, but with very low st_buffer or ST_DWithin function also with very low distance.

To be sure that your point lies on a line it have to be a part of this line (e.g. LINESTRING(0 0, 5 5) points (0 0) and (5 5). Example with point(3 3) works because it's coordinates are counted without any roundings.

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.