提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
一、程序简介
大地坐标正算是根据给定的地球椭球体参数和起点经纬度、方位角和距离计算出终点的经纬度坐标
二、程序实现逻辑
定义地球椭球体参数
定义WGS84椭球体长半轴a=6378137.0,短半轴b=6356752.3142,第一偏心率e=(a2-b2)/a=0.0818191908426。
输入起点的大地坐标和方位角距离
输入起点的大地坐标(lat1, lon1)和方位角bear和距离s。
计算辅助量
先将起点纬度换算为弧度,计算出扁率f=(a-b)/a,以及纬度圆的半径rho=a*(1-e2)/(1-e2sin2(lat1))1.5,扁率圆的半径nu=a/sqrt(1-e2sin2(lat1)),然后计算出由起点沿方位角bear前进距离s到达的点的纬度lat2和初始子午线弧长度A=0。
迭代计算
根据公式计算纬度lat2、经差dLon、子午线弧曲率半径C、球面距离s和初始子午线弧长A,直到dLon小于1e-12。
计算终点经度lon2
根据公式lon2=lon1+dLon。
三、程序代码
以下是C#代码实现大地坐标正算:
using System;
namespace GeodeticCalculation
{
public class Ellipsoid
{
public const double WGS84_A = 6378137.0;
public const double WGS84_B = 6356752.3142;
public const double WGS84_F = (WGS84_A - WGS84_B) / WGS84_A;
public double a;
public double b;
public double f;
public Ellipsoid(double a, double b)
{
this.a = a;
this.b = b;
f = (a - b) / a;
}
public double GetRho(double lat)
{
double sinLat = Math.Sin(lat);
return a * (1 - f) / Math.Pow(1 - f * sinLat * sinLat, 1.5);
}
public double GetNu(double lat)
{
double sinLat = Math.Sin(lat);
return a / Math.Sqrt(1 - f * sinLat * sinLat);
}
}
public class GeodeticCalculator
{
public static double DEG_TO_RAD = Math.PI / 180.0;
public static double RAD_TO_DEG = 180.0 / Math.PI;
public static double CalculateDistance(double lat1, double lon1, double lat2, double lon2)
{
double earthRadius = Ellipsoid.WGS84_A;
double dLat = DEG_TO_RAD * (lat2 - lat1);
double dLon = DEG_TO_RAD * (lon2 - lon1);
double a = Math.Sin(dLat / 2) * Math.Sin(dLat / 2) + Math.Cos(DEG_TO_RAD * lat1) * Math.Cos(DEG_TO_RAD * lat2) * Math.Sin(dLon / 2) * Math.Sin(dLon / 2);
double c = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a));
double distance = earthRadius * c;
return distance;
}
public static double[] CalculateDestination(double lat1, double lon1, double bearing, double distance)
{
Ellipsoid ellipsoid = new Ellipsoid(Ellipsoid.WGS84_A, Ellipsoid.WGS84_B);
double lat = DEG_TO_RAD * lat1;
double lon = DEG_TO_RAD * lon1;
double s = distance;
double alpha1 = DEG_TO_RAD * bearing;
double sinAlpha1 = Math.Sin(alpha1);
double cosAlpha1 = Math.Cos(alpha1);
double tanU1 = (1 - ellipsoid.f) * Math.Tan(lat);
double cosU1 = 1 / Math.Sqrt(1 + tanU1 * tanU1);
double sinU1 = tanU1 * cosU1;
double sigma1 = Math.Atan2(tanU1, cosAlpha1);
double sinAlpha = cosU1 * sinAlpha1;
double cosSqAlpha = 1 - sinAlpha * sinAlpha;
double uSq = cosSqAlpha * (ellipsoid.a * ellipsoid.a - ellipsoid.b * ellipsoid.b) / (ellipsoid.b * ellipsoid.b);
double A = 1 + uSq / 16384 * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq)));
double B = uSq / 1024 * (256 + uSq * (-128 + uSq * (74 - 47 * uSq)));
double sigma = s / (ellipsoid.b * A);
double sigmaP = 2 * Math.PI;
double cos2SigmaM = 0.0;
double sinSigma = 0.0;
double cosSigma = 0.0;
while (Math.Abs(sigma - sigmaP) > 1e-12)
{
cos2SigmaM = Math.Cos(2 * sigma1 + sigma);
sinSigma = Math.Sin(sigma);
cosSigma = Math.Cos(sigma);
double deltaSigma = B * sinSigma * (cos2SigmaM + B / 4 * (cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM) - B / 6 * cos2SigmaM * (-3 + 4 * sinSigma * sinSigma) * (-3 + 4 * cos2SigmaM * cos2SigmaM)));
sigmaP = sigma;
sigma = s / (ellipsoid.b * A) + deltaSigma;
}
double tmp = sinU1 * sinSigma - cosU1 * cosSigma * cosAlpha1;
double lat2 = Math.Atan2(sinU1 * cosSigma + cosU1 * sinSigma * cosAlpha1, (1 - ellipsoid.f) * Math.Sqrt(sinAlpha * sinAlpha + tmp * tmp));
double lambda = Math.Atan2(sinSigma * sinAlpha1, cosU1 * cosSigma - sinU1 * sinSigma * cosAlpha1);
double C = ellipsoid.f / 16 * cosSqAlpha * (4 + ellipsoid.f * (4 - 3 * cosSqAlpha));
double L = lambda - (1 - C) * ellipsoid.f * sinAlpha * (sigma + C * sinSigma * (cos2SigmaM + C * cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM)));
double lon2 = (lon + L + 3 * Math.PI) % (2 * Math.PI) - Math.PI;
double[] destination = {
lat2 * RAD_TO_DEG, lon2 * RAD_TO_DEG };
return destination;
}
}
class Program
{
static void Main(string[] args)
{
double lat1 = 39.9087;
double lon1 = 116.3974;
double bear = 60.0;
double distance = 100000.0;
double[] destination = GeodeticCalculator.CalculateDestination(lat1, lon1, bear, distance);
Console.WriteLine("Starting point: ({0}, {1})", lat1, lon1);
Console.WriteLine("Bearing: {0}", bear);
Console.WriteLine("Distance: {0}", distance);
Console.WriteLine("Destination point: ({0}, {1})", destination[0], destination[1]);
}
}
}
总结
以上代码可以计算出起点经纬度、方位角和距离给定情况下的终点经纬度。