0

I am trying to code a java methods which returns a Boolean true if a point(x,y) is on a line segment and false if not.

I tried this:

public static boolean OnDistance(MyLocation a, MyLocation b, MyLocation queryPoint) {

    double value = java.lang.Math.signum((a.mLongitude - b.mLongitude) * (queryPoint.mLatitude - a.mLatitude)
            - (b.mLatitude - a.mLatitude) * (queryPoint.mLongitude - a.mLongitude));
    double compare = 1;
    if (value == compare) {
        return true;
    }

    return false;
}

but it doesn't work.

Jason Aller
  • 3,541
  • 28
  • 38
  • 38
Dennis
  • 90
  • 12

1 Answers1

2

I am not JAVA coder so I stick to math behind ... For starters let assume you are on plane (not sphere surface)

  1. I would use Vector math so let:


    a,b - be the line endpoints
    q - queried point
    c=q-a - queried line direction vector
    d=b-a - line direction vector

  2. use dot product for parameter extraction

    t=dot(c,d)/(|c|*|d|)
    


    t is line parameter <0,1> if out of range q is not inside line
    |c|=sqrt(c.x*c.x+c.y*c.y) size of vector
    dot(c,d)=c.x*d.x+c.y*d.y scalar vector multiply

  3. now compute corresponding point on line

    e=a+(t*d)
    


    e is the closest point to q on the line ab

  4. compute perpendicular distance of q and ab

    l=|q-e|;
    

    if (l>treshold) then q is not on line ab else it is on the line ab. The threshold is the max distance from line you are still accepting as inside line. No need to have l sqrt-ed the threshold constant can be powered by 2 instead for speed.

  5. if you add all this to single equation

    then some things will simplify itself (hope did not make some silly math mistake)

    l=|(q-a)-(b-a)*(dot(q-a,b-a)/|b-a|^2)|;
    return (l<=treshold);
    

    or

    l=|c-(d*dot(c,d)/|d|^2)|;
    return (l<=treshold);
    

    As you can see we do not even need sqrt for this :)

[Notes]

If you need spherical or ellipsoidal surface instead then you need to specify it closer which it is what are the semi axises. The line become arc/curve and need some corrections which depends on the shape of surface see

but can be done also by approximation and may be also by binary search of point e see:

The vector math used can be found here at the end:

Here 3D C++ implementation (with different names):

overview

double distance_point_axis(double *p,double *p0,double *dp)
    {
    int i;
    double l,d,q[3];
    for (i=0;i<3;i++) q[i]=p[i]-p0[i];                  // q = p-p0
    for (l=0.0,i=0;i<3;i++) l+=dp[i]*dp[i];             // l = |dp|^2
    for (d=0.0,i=0;i<3;i++) d+=q[i]*dp[i];              // d = dot(q,dp)
    if (l<1e-10) d=0.0; else d/=l;                      // d = dot(q,dp)/|dp|^2
    for (i=0;i<3;i++) q[i]-=dp[i]*d;                    // q=q-dp*dot(q,dp)/|dp|^2
    for (l=0.0,i=0;i<3;i++) l+=q[i]*q[i]; l=sqrt(l);    // l = |q|
    return l;
    }

Where p0[3] is any point on axis and dp[3] is direction vector of axis. The p[3] is the queried point you want the distance to axis for.

Spektre
  • 49,595
  • 11
  • 110
  • 380