天天看点

ECEF坐标系转经纬度 wgs84 - 方法提炼ECEF坐标系转经纬度 wgs84 - 方法提炼

ECEF坐标系转经纬度 wgs84 - 方法提炼

本文提供坐标系转换算法,根据某前端算法修改完善为C#语言支持。

最近在项目中遇到空间坐标转换问题,现提供相关算法C#支持。

源代码

相关代码如下:

using System;

namespace ConsoleApp1
{
    /// <summary>
    /// ECEF坐标系转换经纬度 wgs84
    /// 方法提炼
    /// </summary>
    internal class Program
    {
        private static void Main(string[] args)
        {
            double[] ret = XYZ2LLA(new double[]
            {
                3333,4444,1500
            });

            Console.WriteLine(string.Format("LON-:{0}\r\nLAT-:{1}\r\nALT-:{2}\r\n", ret[0], ret[1], ret[2]));
            
            Console.Read();
        }

        private static double EARTH_1 = 6378.137;
        private static double Temp_1 = EARTH_1 * (1.0 - (1.0 / 298.257223563));
        private static double Eccsq = 1 - Math.Pow(Temp_1, 2) / Math.Pow(EARTH_1, 2);
        private static double Dtr = Math.PI / 180.0;

        /// <summary>
        /// ECEF坐标系转经纬度 wgs84
        /// 输入-千米、千米、千米
        /// 输出-经、纬、千米
        /// </summary>
        /// <param name="xvec"></param>
        /// <returns></returns>
        private static double[] XYZ2LLA(double[] xvec)
        {
            double flatgc, flatn, dlat, rp, x, y, z, p, tangd, rn, clat, slat, flat, flon, altkm;
            x = xvec[0];
            y = xvec[1];
            z = xvec[2];

            rp = Math.Sqrt(Math.Pow(x, 2) + Math.Pow(y, 2) + Math.Pow(z, 2));
            flatgc = Math.Asin(z / rp) / Dtr;
            flon = ((Math.Abs(x) + Math.Abs(y)) < 1.0e-10) ? 0.0 : Math.Atan2(y, x) / Dtr;
            flon = (flon < 0.0) ? flon + 360.0 : flon;
            p = Math.Sqrt(Math.Pow(x, 2) + Math.Pow(y, 2));

            if (p < 1.0e-10)
            {
                flat = ((z < 0.0)) ? -90.0 : 90.0;
                altkm = rp - Radcur(flat)[0];
            }
            else
            {
                altkm = rp - Radcur(flatgc)[0];
                flat = Gc2gd(flatgc, altkm);
                rn = Radcur(flat)[1];
                for (double kount = 0; kount < 5; kount++)
                {
                    slat = Math.Sin(Dtr * flat);
                    tangd = (z + rn * Eccsq * slat) / p;
                    flatn = Math.Atan(tangd) / Dtr;
                    dlat = flatn - flat;
                    flat = flatn;
                    clat = Math.Cos(Dtr * flat);
                    rn = Radcur(flat)[1];
                    altkm = (p / clat) - rn;
                    if (Math.Abs(dlat) < 1.0e-12)
                    {
                        break;
                    }
                }
            }
            return new double[] { flat, flon, altkm };
        }

        private static double Gc2gd(double flatgci, double altkmi)
        {
            double[] rrnrm = Radcur(flatgci);
            double ratio = 1 - Math.Pow(Math.Sqrt(Eccsq), 2) * rrnrm[1] / (rrnrm[1] + altkmi);
            double tlat = Math.Tan(Dtr * flatgci) / ratio;
            rrnrm = Radcur((1 / Dtr) * Math.Atan(tlat));
            ratio = 1 - Math.Pow(Math.Sqrt(Eccsq), 2) * rrnrm[1] / (rrnrm[1] + altkmi);
            tlat = Math.Tan(Dtr * flatgci) / ratio;
            return (1 / Dtr) * Math.Atan(tlat);
        }

        private static double[] Radcur(double lati)
        {
            double slat, dsq, rn, rho, z;
            slat = Math.Sin(Dtr * lati);
            dsq = 1.0 - Eccsq * Math.Pow(slat, 2);
            rn = EARTH_1 / Math.Sqrt(dsq);
            rho = rn * Math.Cos(Dtr * lati);
            z = (1.0 - Eccsq) * rn * slat;
            return (new double[] { Math.Sqrt(Math.Pow(rho, 2) + Math.Pow(z, 2)), rn, rn * (1.0 - Eccsq) / dsq });
        }
    }
}
           

2019年11月25日

Dawn