Minimum distance between a point and a line in latitude, longitude

后端 未结 5 1861
感情败类
感情败类 2020-12-28 09:45

I have a line with two points in latitude and longitude
A: 3.222895, 101.719751
B: 3.227511, 101.724318

and 1 point
C: 3.224972, 101.722932

Ho

相关标签:
5条回答
  • 2020-12-28 10:05

    See post here: https://stackoverflow.com/a/33343505/4083623

    For distance up to a few thousands meters I would simplify the issue from sphere to plane. Then, the issue is pretty simply as a easy triangle calculation can be used:

    We have points A and B and look for a distance X to line AB. Then:

    Location a;
    Location b;
    Location x;
    
    double ax = a.distanceTo(x);
    double alfa = (Math.abs(a.bearingTo(b) - a.bearingTo(x))) / 180
                * Math.PI;
    double distance = Math.sin(alfa) * ax;
    
    0 讨论(0)
  • 2020-12-28 10:08

    Thanks to mimi and this great article http://www.movable-type.co.uk/scripts/latlong.html but they don't give the whole picture. Here is a detail one. All this points are collected using Google Earth using Placemark to mark the locations. Make sure lat/long are set to decimal degrees in Preferences.

    lat A = 3.222895  
    lon A = 101.719751  
    lat B = 3.222895  
    lon B = 101.719751  
    lat C = 3.224972  
    lon C = 101.722932  
    Earth radius, R = 6371
    

    1. First you have to find the bearing from A to C and A to B.
    Bearing formula

    bearingAC = atan2( sin(Δλ)*cos(φ₂), cos(φ₁)*sin(φ₂) − sin(φ₁)*cos(φ₂)*cos(Δλ) )  
    bearingAB = atan2( sin(Δλ)*cos(φ₂), cos(φ₁)*sin(φ₂) − sin(φ₁)*cos(φ₂)*cos(Δλ) ) 
    

    φ is latitude, λ is longitude, R is earth radius

    2. Find A to C distance using spherical law of cosines

    distanceAC = acos( sin(φ₁)*sin(φ₂) + cos(φ₁)*cos(φ₂)*cos(Δλ) )*R
    

    3. Find cross-track distance

    distance = asin(sin(distanceAC/ R) * sin(bearingAC − bearing AB)) * R
    

    Objective-C code

    double lat1 = 3.227511;
    double lon1 = 101.724318;
    double lat2 = 3.222895;
    double lon2 = 101.719751;
    double lat3 = 3.224972;
    double lon3 = 101.722932;
    
    double y = sin(lon3 - lon1) * cos(lat3);
    double x = cos(lat1) * sin(lat3) - sin(lat1) * cos(lat3) * cos(lat3 - lat1);
    double bearing1 = radiansToDegrees(atan2(y, x));
    bearing1 = 360 - ((bearing1 + 360) % 360);
    
    double y2 = sin(lon2 - lon1) * cos(lat2);
    double x2 = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(lat2 - lat1);
    double bearing2 = radiansToDegrees(atan2(y2, x2));
    bearing2 = 360 - ((bearing2 + 360) % 360);
    
    double lat1Rads = degreesToRadians(lat1);
    double lat3Rads = degreesToRadians(lat3);
    double dLon = degreesToRadians(lon3 - lon1);
    
    double distanceAC = acos(sin(lat1Rads) * sin(lat3Rads)+cos(lat1Rads)*cos(lat3Rads)*cos(dLon)) * 6371;  
    double min_distance = fabs(asin(sin(distanceAC/6371)*sin(degreesToRadians(bearing1)-degreesToRadians(bearing2))) * 6371);
    
    NSLog(@"bearing 1: %g", bearing1);  
    NSLog(@"bearing 2: %g", bearing2);  
    NSLog(@"distance AC: %g", distanceAC);  
    NSLog(@"min distance: %g", min_distance);
    

    Actually there's a library for this. You can find it here https://github.com/100grams/CoreLocationUtils

    0 讨论(0)
  • 2020-12-28 10:15

    Calculate bearing for each: C to A , and C to B:

    var y = Math.sin(dLon) * Math.cos(lat2);
    var x = Math.cos(lat1)*Math.sin(lat2) -
            Math.sin(lat1)*Math.cos(lat2)*Math.cos(dLon);
    var brng = Math.atan2(y, x).toDeg();
    

    dLon= lon2-lon1;

    Calculate cross-track distance:

    var dXt = Math.asin(Math.sin(distance_CB/R)*Math.sin(bearing_CA-bearing_CB)) * R;
    

    R is the radius of earth, dXt is the minimum distance you wanted to calculate.

    0 讨论(0)
  • 2020-12-28 10:21

    Code to carry out this calculation is posted at here. This implements an accurate solution in terms of ellipsoidal geodesics. For the basic geodesic calculations, you can use GeographicLib or the port of these algorithms to C which are included in version 4.9.0 of PROJ.4. This C interface is documented here.

    Here's the result of compiling and running intercept.cpp:

    $ echo 3.222895 101.719751 3.227511 101.724318 3.224972 101.722932 | ./intercept 
    Initial guess 3.225203 101.7220345
    Increment 0.0003349040566247297 0.0003313413822354505
    Increment -4.440892098500626e-16 0
    Increment 0 0
    ...
    Final result 3.225537904056624 101.7223658413822
    Azimuth to A1 -135.1593040635131
    Azimuth to A2 44.84069593652217
    Azimuth to B1 134.8406959363608
    

    Distance to line is 88.743m:

    $ echo 3.224972 101.722932 3.225537904056624 101.7223658413822 | GeodSolve -i
    -45.15927221 -45.15930407 88.743
    
    0 讨论(0)
  • 2020-12-28 10:29

    If you know how to calculate the distance of two points, get the distances between each two points, you get AB, AC, and BC. You want to know the closest distance between point C and line AB.

    First get the value of P

    P=(AB+BC+AC)/2
    

    Using P, you need to get S

    S=SQRT((P(P-AC)(P-AB)(P-AC)) 
    

    SQRT means square root. Then you get what you want by

    2*S/AB
    
    0 讨论(0)
提交回复
热议问题