Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get Nearest Point on Linestring #190

Closed
chivasblue opened this issue Oct 18, 2014 · 3 comments
Closed

Get Nearest Point on Linestring #190

chivasblue opened this issue Oct 18, 2014 · 3 comments

Comments

@chivasblue
Copy link

Hello,
Given a point, I am trying to get the nearest point on a linestring. It seems to work fine for a simple linestring, e.g
Python 3.4.0 (default, Apr 11 2014, 13:05:11)
[GCC 4.8.2] on linux
Type "help", "copyright", "credits" or "license" for more information.

from shapely.geometry import Point, LineString
line = LineString([(0,0),(5,7),(12,6)])
p = Point(4,8)
np = line.interpolate(line.project(p))
print(np)
POINT (5 7)

However, for a complex linestring I am not getting the intended results.e.g.

route=LineString([(19.119318,72.902800),(19.119660,72.901455),(19.119673,72.901401),(19.119848,72.900553),(19.119975,72.899972),(19.120129,72.899675),(19.120308,72.899385),(19.120589,72.899162),(19.121131,72.898909),(19.121597,72.898739),(19.122330,72.898471),(19.122696,72.898429),(19.123296,72.897991),(19.123680,72.897623),(19.124095,72.897035),(19.124402,72.896411),(19.124483,72.896177),(19.124573,72.895796),(19.124585,72.895470),(19.124603,72.895014),(19.124652,72.894291),(19.124686,72.894067),(19.124929,72.893177),(19.124971,72.893049),(19.125097,72.892666),(19.125214,72.892323),(19.125450,72.891802),(19.125757,72.891281),(19.125951,72.890874),(19.126170,72.890413),(19.126833,72.889417),(19.127319,72.888873),(19.128909,72.886714),(19.129060,72.886402),(19.129109,72.886299),(19.129238,72.885913),(19.129302,72.885370),(19.129372,72.881686),(19.129396,72.880652),(19.129413,72.880540),(19.129366,72.880167),(19.129382,72.880070),(19.129419,72.879849),(19.129509,72.879205),(19.129709,72.877766),(19.129969,72.876684),(19.130029,72.876511),(19.128367,72.875341),(19.127365,72.874602),(19.125882,72.873536),(19.125160,72.873014),(19.124815,72.872761),(19.124413,72.872457),(19.123149,72.871568),(19.122517,72.871091),(19.122162,72.870822),(19.121981,72.870749),(19.121736,72.870651),(19.121013,72.870576),(19.119933,72.870464),(19.119596,72.870432)])

list(route.coords)
[(19.119318, 72.9028), (19.11966, 72.901455), (19.119673, 72.901401), (19.119848, 72.900553), (19.119975, 72.899972), (19.120129, 72.899675), (19.120308, 72.899385), (19.120589, 72.899162), (19.121131, 72.898909), (19.121597, 72.898739), (19.12233, 72.898471), (19.122696, 72.898429), (19.123296, 72.897991), (19.12368, 72.897623), (19.124095, 72.897035), (19.124402, 72.896411), (19.124483, 72.896177), (19.124573, 72.895796), (19.124585, 72.89547), (19.124603, 72.895014), (19.124652, 72.894291), (19.124686, 72.894067), (19.124929, 72.893177), (19.124971, 72.893049), (19.125097, 72.892666), (19.125214, 72.892323), (19.12545, 72.891802), (19.125757, 72.891281), (19.125951, 72.890874), (19.12617, 72.890413), (19.126833, 72.889417), (19.127319, 72.888873), (19.128909, 72.886714), (19.12906, 72.886402), (19.129109, 72.886299), (19.129238, 72.885913), (19.129302, 72.88537), (19.129372, 72.881686), (19.129396, 72.880652), (19.129413, 72.88054), (19.129366, 72.880167), (19.129382, 72.88007), (19.129419, 72.879849), (19.129509, 72.879205), (19.129709, 72.877766), (19.129969, 72.876684), (19.130029, 72.876511), (19.128367, 72.875341), (19.127365, 72.874602), (19.125882, 72.873536), (19.12516, 72.873014), (19.124815, 72.872761), (19.124413, 72.872457), (19.123149, 72.871568), (19.122517, 72.871091), (19.122162, 72.870822), (19.121981, 72.870749), (19.121736, 72.870651), (19.121013, 72.870576), (19.119933, 72.870464), (19.119596, 72.870432)]

end=Point(19.125150,72.893218)

np = route.interpolate(route.project(end))

print(np)
POINT (19.12493833590478 72.89314854771877)

I was expecting the result to be 19.124929, 72.893177. Is it something which I am doing wrong? Any help appreciated.

Thanks!

@snorfalorpagus
Copy link
Member

The point returned is the nearest point on the line to the original point. The nearest point is not necessarily an existing vertex in the LineString, and in this case it isn't.

end = Point(19.125150,72.893218)
np = Point(19.12493833590478, 72.89314854771877)
expected = Point(19.124929, 72.893177)

print end.distance(np) # 0.000222767386696
print end.distance(expected) # 0.000224770994572

If you want to find the nearest vertex you should first convert the LineString to a MultiPoint geometry, then use the nearest_points operation (note the minor floating point error):

from shapely.ops import nearest_points
from shapely.geometry import MultiPoint
mp = MultiPoint(route)
print nearest_points(mp, end)[0] # POINT (19.124929 72.89317699999999)

This query requires calculating the distance between the original point and each vertex in the original linestring. For very complex routes this could be rather slow. If this is the case you should consider using the rtree module, which uses spatial indexing to make this kind of query very fast:

http://toblerity.org/rtree/tutorial.html

@chivasblue
Copy link
Author

Oh ok Thanks for your response.

@Sudeepa14
Copy link

@snorfalorpagus . I was searching for something like this. any smart suggestions to get rid of the floating point error? Same issue is there with this tool also.

jorisvandenbossche pushed a commit to jorisvandenbossche/shapely that referenced this issue Nov 6, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants