c#求大地坐标正算

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


一、程序简介

大地坐标正算是根据给定的地球椭球体参数和起点经纬度、方位角和距离计算出终点的经纬度坐标

二、程序实现逻辑

定义地球椭球体参数
定义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]);
        }
    }
}

总结

以上代码可以计算出起点经纬度、方位角和距离给定情况下的终点经纬度。

猜你喜欢

转载自blog.csdn.net/2302_77270563/article/details/129999880
今日推荐