地理空间坐标系统-同一椭球基准内的坐标转换-相关代码算法实现C#

围绕上一篇,同一椭球基准内不同坐标系下坐标转换的相关算法,此篇主要分享的是这些算法的实现

采用代码为C#,转换精度都做了验证,都在小数点后两位

大地球面坐标与大地空间直角坐标互转

【坐标正转】 经度、纬度、高程(LBH)转到XYZ

        /// <summary>
        /// 大地坐标转空间直角坐标
        /// </summary>
        /// <param name="geoCoordSystem"></param>
        /// <param name="originalPoint">纬度、经度、大地高。</param>
        /// <param name="reslutPoint"></param>
        public void GeodeticToSpace(GeoCoordSystem geoCoordSystem, 
             GeoPoint originalPoint,out Point3d reslutPoint)
        {
            double B, L, H;    //纬度、经度、大地高“十进制弧度”,大地高单位为:"米"
            double a, b, f;    //长半轴、短半轴、椭球反扁率
            double e, ee, e2;  //第一偏心率、第二偏心率,第一偏心率平方。
            ///参数示例
            {
                //a = 6378245.00;//椭球长半轴,单位米
                //f = 1 / 298.30000000000001;//椭球扁率
                //b = a * (1 - f);//椭球短半轴
                //e = Math.Sqrt(a * a - b * b) / a;//椭球第一偏心率
                //ee = Math.Sqrt(a * a - b * b) / b;//椭球第二偏心率
                //e2 = e * e; //第一偏心率的平方。
            }
            B = UnitConvert.DegreesToRedians(originalPoint.N);
            L = UnitConvert.DegreesToRedians(originalPoint.E);
            H = originalPoint.H;
            a = geoCoordSystem.SpheroidDatum.Semiminor_Axis;
            e = geoCoordSystem.SpheroidDatum.Spheroid_E;
            e2 = e * e;
            double N = a / Math.Sqrt(1 - e2 * Math.Sin(B) * Math.Sin(B)); //子午圈曲率半径
            //double X = (N + H) * Math.Cos(B) * Math.Cos(L);
            //double Y = (N + H) * Math.Cos(B) * Math.Sin(L);
            //double Z = (N * (1 - e2) + H) * Math.Sin(B);
            reslutPoint.X = (N + H) * Math.Cos(B) * Math.Cos(L);
            reslutPoint.Y = (N + H) * Math.Cos(B) * Math.Sin(L);
            reslutPoint.Z = (N * (1 - e2) + H) * Math.Sin(B);
        }

【坐标反转】 XYZ转经度、纬度、高程(LBH),空间直角坐标转经纬度坐标,迭代法的实现

        /// <summary>
        /// 空间直角坐标转大地坐标
        /// </summary>
        /// <param name="geoCoordSystem">参考坐标系</param>
        /// <param name="originalPoint">空间直角坐标</param>
        /// <param name="reslutPoint">返回结果:大地坐标</param>
        public void SpaceRectangularToGeodetic(GeoCoordSystem geoCoordSystem
           , Point3d originalPoint, out GeoPoint reslutPoint)
        {
            double B, L, H;    //经度、纬度单位此处为:“十进制弧度”,大地高单位为:"米"
            double a, b, f;    //长半轴、短半轴、椭球反扁率
            double e, ee, e2;  //第一偏心率、第二偏心率,第一偏心率平方。
            double X, Y, Z;    //空间直角坐标点的,X,Y,Z
            double Rho= 206264.806247096363;
            var Error = 0.00001;
            ///参数示例
            {
                //a = 6378245.00;//椭球长半轴,单位米
                //f = 1 / 298.30000000000001;//椭球扁率
                //b = a * (1 - f);//椭球短半轴
                //e = Math.Sqrt(a * a - b * b) / a;//椭球第一偏心率
                //ee = Math.Sqrt(a * a - b * b) / b;//椭球第二偏心率
                //e2 = e * e; //第一偏心率的平方。
            }
            X = originalPoint.X;
            Y = originalPoint.Y;
            Z = originalPoint.Z;
            a = geoCoordSystem.SpheroidDatum.Semiminor_Axis;
            e = geoCoordSystem.SpheroidDatum.Spheroid_E;
            e2 = e * e;
            double B1 = Math.Atan(Z / Math.Sqrt(X * X + Y * Y));
            double N1, B2;
            while (true)
            {
                N1 = a / Math.Sqrt(1 - e2 * Math.Sin(B1) * Math.Sin(B1));  //子午圈曲率半径
                B2 = Math.Atan((Z + N1 * e2 * Math.Sin(B1)) / Math.Sqrt(X * X + Y * Y));
                if (Math.Abs(B2 - B1) * Rho <= Error)
                    break;
                B1 = B2;
            }
            B = B2;
            L = Math.Acos(X / Math.Sqrt(X * X + Y * Y));
            if (Y < 0)
            {
                L = -L;
            }
            double N = a / Math.Sqrt(1 - e2 * Math.Sin(B) * Math.Sin(B));  //子午圈曲率半径
            H= Math.Sqrt(X * X + Y * Y) / Math.Cos(B) - N;
            reslutPoint.N = UnitConvert.RediansToDegrees(B);
            reslutPoint.E = UnitConvert.RediansToDegrees(L);
            reslutPoint.H =H;
        }

大地球面坐标与大地投影坐标互转-以高斯投影坐标转换为例

【坐标正算】 经度、纬度(LB)转到x,y

        /// <summary>
        /// 大地坐标转高斯坐标
        /// </summary>
        /// <param name="pGaussKrugerCoordSystem"></param>
        /// <param name="originalCooords"></param>
        /// <param name="targetCooords"></param>
        public void GeodeticToGauss(GaussKrugerCoordSystem pGaussKrugerCoordSystem,
              GeoPoint originalCooords, out GeoPoint targetCooords)
        {
            double B, L, H;    //纬度、经度、大地高。单位为十进制度。
            double a, b, f;  //长半轴、短半轴、椭球反扁率
            double e, ee, e2;  //第一偏心率、第二偏心率,第一偏心率平方。
            double x, y, z;    //高斯坐标X,Y,Z
            double L0;         //中央子午线(中央经线)

            {
                //double x, y;
                //double B = 40.00;   //纬度 单位度
                //double L = 113.00; //经度  单位 度
                //B = B * Math.PI / 180; ///0.0174533; //转换为弧度
                //L = L * Math.PI / 180; //0.0174533; //转换为弧度
                //double a = 6378245.00;//椭球长半轴,单位米
                //double f = 1 / 298.30000000000001;//椭球扁率
                //double b = a * (1 - f);//椭球短半轴
                //double e = Math.Sqrt(a * a - b * b) / a;//椭球第一偏心率
                //double ee = Math.Sqrt(a * a - b * b) / b;//椭球第二偏心率
                //double L0 = 114.00;//中央子午线 单位为度。
                //L0 = L0 * Math.PI / 180; //0.0174533; //转换为弧度
                //double e2 = e * e; //第一偏心率的平方。
            }

            B = UnitConvert.DegreesToRedians(originalCooords.N);
            L = UnitConvert.DegreesToRedians(originalCooords.E);
            H = UnitConvert.DegreesToRedians(originalCooords.H);
            L0 = UnitConvert.DegreesToRedians(pGaussKrugerCoordSystem.Central_Meridian);
            a = pGaussKrugerCoordSystem.GeoCoordSystem.SpheroidDatum.Semiminor_Axis;
            e = pGaussKrugerCoordSystem.GeoCoordSystem.SpheroidDatum.Spheroid_E;
            ee = pGaussKrugerCoordSystem.GeoCoordSystem.SpheroidDatum.Spheroid_EE;
            e2 = e * e;

            double Sin_B = Math.Sin(B);
            double Cos_B = Math.Cos(B);

            //子午圈曲率半径
            double N = a / Math.Sqrt(1 - Math.Pow(e, 2) * Sin_B * Sin_B);  
            double ll = L - L0; //经差,到中央经线的差
            double t2 = Math.Tan(B) * Math.Tan(B);
            double n2 = ee * ee * Cos_B * Cos_B;
            double pp = 1.0;// (180 / Math.PI) * 3600;  //

            double m0 = a * (1 - e * e);
            double m2 = 3 * e2 * m0 / 2.0;
            double m4 = 5 * e2 * m2 / 4.0;
            double m6 = 7 * e2 * m4 / 6.0;
            double m8 = 9 * e2 * m6 / 8.0;

            double a0 = m0 + m2 / 2.0 + 3 * m4 / 8.0 + 5 * m6 / 16.0 + 35 * m8 / 128.0;
            double a2 = m2 / 2.0 + m4 / 2.0 + 15 * m6 / 32.0 + 7 * m8 / 16.0;
            double a4 = m4 / 8.0 + 3 * m6 / 16.0 + 7 * m8 / 32.0;
            double a6 = m6 / 32.0 + m8 / 16.0;
            double a8 = m8 / 128.0;

            //中央子午线弧长。
            double X = a0 * B - Sin_B * Cos_B * ((a2 - a4 + a6) 
                      + (2 * a4 - 16 * a6 / 3.0) * Sin_B * Sin_B 
                      + 16 * a6 * Math.Pow(Sin_B, 4) / 3.0);
            double x1 = N * Sin_B * Cos_B * ll * ll / (2 * pp * pp);
            double x2 = N * Sin_B * Cos_B * Cos_B * Cos_B 
                        *(5 - t2 + 9 * n2 + 4 * n2 * n2) * Math.Pow(ll, 4) 
                        / (24 * Math.Pow(pp, 4));
            double x3 = N * Sin_B * Math.Pow(Cos_B, 5) 
                        * (61 - 58 * t2 + t2 * t2) * Math.Pow(ll, 6) 
                        / (720 * Math.Pow(pp, 6));

            x = X + x1 + x2 + x3;

            double y1 = N * Cos_B * ll / pp;
            double y2 = N * Math.Pow(Cos_B, 3) * (1 - t2 + n2) * Math.Pow(ll, 3) 
                        / (6 * Math.Pow(pp, 3));
            double y3 = N * Math.Pow(Cos_B, 5) 
                        * (5 - 18 * t2 + t2 * t2 + 14 * n2 - 58 * n2 * t2) 
                        * Math.Pow(ll, 5) 
                        / (120 * Math.Pow(pp, 5));

            y = y1 + y2 + y3;
            y = y + 500000;

            targetCooords.N = x;
            targetCooords.E = y;
            targetCooords.H = 0;
        }

【坐标反算】 x,y转到经度、纬度(LB)

        /// <summary>
        /// 高斯坐标转大地坐标
        /// </summary>
        /// <param name="pGaussKrugerCoordSystem">高斯坐标参考</param>
        /// <param name="originalCooords">高斯平面坐标点</param>
        /// <param name="targetCooords">大地坐标点</param>
        public void GaussToGeodetic(GaussKrugerCoordSystem pGaussKrugerCoordSystem, 
              GeoPoint originalCooord,out GeoPoint targetCooord)
        {
            double B, L, H;    //纬度、经度、大地高。单位为十进制度。
            double a, b, f;  //长半轴、短半轴、椭球反扁率
            double e, ee, e2;  //第一偏心率、第二偏心率,第一偏心率平方。
            double x, y, z;    //高斯坐标X,Y,Z
            double L0;         //中央子午线(中央经线)
            //double x = 4430486.4133464955, y = 414603.95129119331;
            //y = y - 500000;
            //double B = 0;                          //纬度 单位度, 返回结果
            //double L = 0;                           //经度  单位 度,返回结果
            //double a = 6378245.00;                  //椭球长半轴,单位米
            //double f = 1 / 298.30000000000001;      //椭球扁率
            //double b = a * (1 - f);                 //椭球短半轴
            //double e = Math.Sqrt(a * a - b * b) / a;//椭球第一偏心率
            //double ee = Math.Sqrt(a * a - b * b) / b;//椭球第二偏心率
            //double L0 = 114.00;//中央子午线 单位为度。
            //L0 = L0 * Math.PI / 180; //0.0174533; //转换为弧度
            //double e2 = e * e; //第一偏心率的平方。
            x = originalCooord.N- pGaussKrugerCoordSystem.False_Northing;
            y = originalCooord.E- pGaussKrugerCoordSystem.False_Easting;
            z = originalCooord.H;
            L0 = UnitConvert.DegreesToRedians(pGaussKrugerCoordSystem.Central_Meridian);
            a = pGaussKrugerCoordSystem.GeoCoordSystem.SpheroidDatum.Semiminor_Axis;
            e = pGaussKrugerCoordSystem.GeoCoordSystem.SpheroidDatum.Spheroid_E;
            ee = pGaussKrugerCoordSystem.GeoCoordSystem.SpheroidDatum.Spheroid_EE;
            e2 = e * e;

            double m0 = a * (1 - e * e);
            double m2 = 3 * e2 * m0 / 2.0;
            double m4 = 5 * e2 * m2 / 4.0;
            double m6 = 7 * e2 * m4 / 6.0;
            double m8 = 9 * e2 * m6 / 8.0;
            double a0 = m0 + m2 / 2.0 + 3 * m4 / 8.0 + 5 * m6 / 16.0 + 35 * m8 / 128.0;
            double a2 = m2 / 2.0 + m4 / 2.0 + 15 * m6 / 32.0 + 7 * m8 / 16.0;
            double a4 = m4 / 8.0 + 3 * m6 / 16.0 + 7 * m8 / 32.0;
            double a6 = m6 / 32.0 + m8 / 16.0;
            double a8 = m8 / 128.0;

            double Bf = 0;//低点纬度
            double Bfi = x / a0;
            double Bfi1 = Bfi;
            int m = 0;
            do
            {
                Bfi = Bfi1;
                Bfi1 = (x - (-a2 * Math.Sin(2 * Bfi) / 2 
                        + a4 * Math.Sin(4 * Bfi) / 4 - a6 * Math.Sin(6 * Bfi) / 6 
                        + a8 * Math.Sin(8 * Bfi) / 8)) 
                        / a0;
                m++;
            } while (Math.Abs(Bfi1 - Bfi) > 1e-15);
            Bf = Bfi;
            double Nf = a * Math.Pow((1 - Math.Sin(Bf) * Math.Sin(Bf) * e * e), -0.5);
            double Mf = a * (1 - e * e) * Math.Pow(1 - Math.Sin(Bf)
                 * Math.Sin(Bf) * e * e, -1.5);
            double tf = Math.Tan(Bf);
            double nf = ee * Math.Cos(Bf);
            double W = 180 / Math.PI;  //弧度转度。
            B = Bf - tf * y * y / (2 * Mf * Nf) +
                tf * (5 + 3 * tf * tf + nf * nf
                - 9 * nf * nf * tf * tf) * Math.Pow(y, 4) / (24 * Mf * Math.Pow(Nf, 3)) 
                -tf * (61 + 90 * tf * tf + 45 * tf * tf * tf * tf) * Math.Pow(y, 6) 
                / (720 * Mf * Math.Pow(Nf, 5));
            L = L0 
                + y / Nf / Math.Cos(Bf) - Math.Pow(y, 3) 
                * (1 + 2 * tf * tf + nf * nf) / (6 * Math.Pow(Nf, 3) * Math.Cos(Bf)) 
                + Math.Pow(y, 5) * (5 + 28 * tf * tf + 24 * Math.Pow(tf, 4) 
                + 6 * nf * nf + 8 * nf * nf * tf * tf) 
                / (120 * Math.Pow(Nf, 5) * Math.Cos(Bf));
            targetCooord.N = B;
            targetCooord.E = L;
            B = B * 180 / Math.PI;
            L = L * 180 / Math.PI;
            targetCooord.N = B;
            targetCooord.E = L;
            targetCooord.H = 0;
        }
发布了51 篇原创文章 · 获赞 9 · 访问量 16万+

猜你喜欢

转载自blog.csdn.net/mymhj/article/details/103926081