Search code examples
javascriptalgorithmgeolocationlatitude-longitude

Projecting a point onto a path


Suppose I have an ordered array containing points (lat, lon) describing a path, and I also have a point (lat, lon) describing my current location.

How can I project the point onto the path (and place the point in the appropriate place in the array)?

What I tried is just simply by searching for the nearest two points and assume it's in the middle of them. It's a good guess, but sometimes fails.

What would be a good way of doing this?


Solution

  • I see it like this:

    line segment overview

    • p0,p1 are path line segment endpoints
    • p is your position
    • q' closest point on line in 3D cartessian
    • q is q' corrected by spherical projection

    So:

    1. convert points to 3D cartessian coordinates
    2. compute perpendicular distance from point and line

      • q'=p0+(dot(p-p0,p1-p0)*(p1-p0)/(|p-p0|*|p1-p0|))
      • perpendicular_distance = |p-q'|
    3. find segment with smallest perpendicular_distance

      and use only it for the rest of bullets

    4. compute q

      If you use sphere instead of ellipsoid then you already know the radius if not then either compute the radius algebraically or use average:

      r=0.5*(|p0-(0,0,0)|+|p1-(0,0,0)|)
      

      assuming (0,0,0) is Earth's center. You can also be more precise if you weight by position:

      w=|q'-p0|/|p1-p0|
      r=(1-w)*|p0-(0,0,0)|+w*|p1-(0,0,0)|
      

      now just correct the position of q'

      q=q'*r/|q'|
      

      set vector q' as q with size r if it is not obvious enough. Also |p0-(0,0,0)|=|p0| obviously but I wanted to be sure you get how I got it ...

    5. convert q from Cartesian to spherical coordinates

    [Notes]

    • |a| is size of vector a done like: |a|=sqrt(ax*ax+ay*ay+az*az)
    • dot(a,b) is dot product of vectors a,b done like: dot(a,b)=(a.b)=ax*bx+ay*by+az*bz

      if your path is not too complex shaped then you can use binary search to find the closest segment. For distance comparison you do not need the sqrt ...