问题
I searched but I could not find a complete answer. In C# if at all possible. I need the shortest distance between a WGS point and a WGS point defined line segment on a sphere (Earth exactly).
float DistanceInKilometres(PointF LineStartA, PointF LineEndB, PointF ThePoint)
EDIT: Perhaps an illustration would help
Please note that this is an ideal example. 'The point' could be anywhere on the surface of the sphere, the segment start-end, too. Obviously, I'm not looking for the distance through the sphere. Math isn't my stronger side, so I don't understand normalize or to cartesian. Maybe I should also note that path AB, is the shortest possible, and Distance?, is the shortest possible too.
回答1:
You can use the spherical law of cosines:
- http://en.wikipedia.org/wiki/Spherical_law_of_cosines
- http://mathworld.wolfram.com/SphericalSegment.html
- http://mathworld.wolfram.com/SphericalTrigonometry.html
You will have to use the earth's radius for calculations:
EARTH_RADIUS_KM = 6371;
Here, from my contributions to OsmMercator.java, from openstreetmap.org:
/**
* Gets the distance using Spherical law of cosines.
*
* @param la1 the Latitude in degrees
* @param lo1 the Longitude in degrees
* @param la2 the Latitude from 2nd coordinate in degrees
* @param lo2 the Longitude from 2nd coordinate in degrees
* @return the distance
*/
public static double getDistance(double la1, double lo1, double la2, double lo2) {
double aStartLat = Math.toRadians(la1);
double aStartLong = Math.toRadians(lo1);
double aEndLat =Math.toRadians(la2);
double aEndLong = Math.toRadians(lo2);
double distance = Math.acos(Math.sin(aStartLat) * Math.sin(aEndLat)
+ Math.cos(aStartLat) * Math.cos(aEndLat)
* Math.cos(aEndLong - aStartLong));
return (EARTH_RADIUS_KM * distance);
}
All you need to do is find the closest point with dot product and use that with the distance equation.
Here's the closest point example:
double[] nearestPointSegment (double[] a, double[] b, double[] c)
{
double[] t= nearestPointGreatCircle(a,b,c);
if (onSegment(a,b,t))
return t;
return (distance(a,c) < distance(b,c)) ? a : c;
}
- How to calculate distance from a point to a line segment, on a sphere?
- http://en.wikipedia.org/wiki/Great-circle_distance
Keep in mind the units haven't been explicitly declared. When dealing with points in space there're are a variety of ways to determine position. The main thing is you have to nail down your units to a consistent type.
When working with position on the earth, I mainly use lat/long coordinates and vectors for magnitude/direction. There're are several known types to use for vectors and earth's position. Among them are the following:
- Earth-centered earth-fixed (ECEF) coordinate system
- North-East-Down (NED)
- Geodetic coordinate system
For your example, I might consider sticking to Geodetic.
Now, bringing this together, you might have some pseudo code which looks like this:
Where a Vector is made up of Geodetic coordinates:
class Vector {
double x=0.0; //latitude
double y=0.0; //longitude
double h=0.0; //height
...
}
public Vector closestPoint(Vector lineStartA, Vector lineEndB, final Vector thePoint ) {
Vector w = thePoint.subtract(lineStartA);
double proj = w.dot(lineEndB);
// endpoint 0 is closest point
if ( proj <= 0.0f )
return lineStartA;
else
{
//Vector square
double vsq = lineEndB.dot(lineEndB);
// endpoint 1 is closest point
if ( proj >= vsq )
return lineStartA.add(lineEndB);
else
return lineStartA.add(lineEndB.multiply(proj/vsq));
}
}
double DistanceInKilometres(Vector lineStartA, Vector lineEndB, Vector thePoint) {
Vector cp=closestPoint(lineStartA, lineEndB, thePoint);
return getDistance(cp.x, cp.y, thePoint.x, thePoint.y);
}
回答2:
If your point lies within a corridor that is defined by the end points of your line segment, and perpendicular to the line, then this answer should do.
If your point lies outside that corridor then compute the distance from your point to each end of the line segment and take the smaller.
来源:https://stackoverflow.com/questions/10045544/distance-of-wgs-point-from-a-wgs-defined-line-segment