Question

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

How can I calculate minimum distance between point C and a line consists of point A and B? It will be convenient if you can provide the calculation and objective-c code too. The distance is around 89 meters (using ruler in Google Earth).

Was it helpful?

Solution

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

OTHER TIPS

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.

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

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;

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
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top