# Closest point on 5km line

Given a point and a line, I am trying to determine the point on the line that is closest to the given point. The given point is always at least fairly close to the line (3-4 meters max)

Originally I was using the `nearestPointOnLine` function from the turf JS library. However, that gives inaccurate results, especially for long lines: https://github.com/Turfjs/turf/issues/1440

Another approach I tried was using `ST_ClosestPoint` via postgresql:

``````WITH geoms AS (
SELECT
ST_MakeLine(ST_MakePoint (- 86.26725, 34.32582) , ST_MakePoint (- 86.14040, 34.39281)) AS line
, ST_MakePoint (- 86.19219 , 34.36546) AS point
)
select
st_distance(point::geography, line::geography) AS i
, st_distance(st_closestpoint(line, point)::geography, line::geography) AS closest_point_distance
, st_dwithin(st_closestpoint(line, point)::geography, line::geography, 0.1) AS closest_point_is_close_to_line
from
geoms
``````
original_distance closest_point_distance closest_point_is_close_to_line
2.64173838 2.68938954 false

This runs into the rounding issue described here: point returned from ST_LineLocatePoint returns false in ST_Contains

At this point I am considering getting a small line segment close to the point from PostGIS, then getting the closest point on that line with turf. But that seems very involved, and I am wondering if I am missing an easy way (via PostGIS or JavaScript) to get the nearest point (to a close by point) on a long line.

• 5cm is a lot when considering rounding issue... one would expect it more like 10^-6 or smaller – JGH Apr 22 at 14:51

The >0 distance returned by the query is actually correct.

Let's remember that when using the type `geometry`, distances are computed using a straight line while with the type `geography`, the great circle line is used.

So, your data is in `geometry` and you compute the closest point using a straight line (between the start and end point of the line). The closest point is on the line.

Then, you cast to `geography` the computed point and the line. The point doesn't move, but the line is now a great circle and the point is not on the line anymore.

Try running the query using geometries only. The closest point is indeed on the line.

``````WITH geoms AS (
SELECT
ST_MakeLine(ST_MakePoint (- 86.26725, 34.32582) , ST_MakePoint (- 86.14040, 34.39281)) AS line
, ST_MakePoint (- 86.19219 , 34.36546) AS point
)
select
st_distance(point, line) AS i
, st_distance(st_closestpoint(line, point), line) AS closest_point_distance
from
geoms;
i            | closest_point_distance
------------------------+------------------------
4.5032368018051133e-07 |                      0
(1 row)
``````

If you segmentize (or densify) your line then it will work better.

``````SELECT
ST_Segmentize(ST_MakeLine(ST_MakePoint (- 86.26725, 34.32582) , ST_MakePoint (- 86.14040, 34.39281)),.01) AS line
, ST_MakePoint (- 86.19219 , 34.36546) AS point
)
select
st_distance(point::geography, line::geography) AS i
, st_distance(st_closestpoint(line, point)::geography, line::geography) AS closest_point_distance
, st_dwithin(st_closestpoint(line, point)::geography, line::geography, 0.1) AS closest_point_is_close_to_line
from
geoms;
``````

Gives me:

``````     i     | closest_point_distance | closest_point_is_close_to_line
-----------+------------------------+--------------------------------
0.0341319 |             0.01351816 | t
``````