坐标转换(c#) 原 荐

栏目: ASP.NET · 发布时间: 6年前

内容简介:坐标转换,简言之就是讲一个坐标系的坐标通过特定模型转换到另一坐标下;转换中,需要用到不同的转换模型,例如三维空间下的布尔莎七参数、莫洛金斯模型;二维空间下的平面三参、四参、多项式拟合等模型。本文中,主要使用布尔莎七参数模型进行坐标转换。详细见百科:

坐标转换  

坐标转换,简言之就是讲一个坐标系的坐标通过特定模型转换到另一坐标下;转换中,需要用到不同的转换模型,例如三维空间下的布尔莎七参数、莫洛金斯模型;二维空间下的平面三参、四参、多项式拟合等模型。本文中,主要使用布尔莎七参数模型进行坐标转换。

坐标转换关系

坐标转换(c#) 原 荐

布尔莎模型(七参数模型)

详细见百科: https://baike.baidu.com/item/%E4%B8%83%E5%8F%82%E6%95%B0

程序实现

1.编写数据转换类

把各种格式表示的度分秒转换为弧度形式进行计算,最后一个方法把弧度转为度分秒连写的格式。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Text.RegularExpressions;
namespace CoordTF
{ 
    class DataCnversion
    {
        #region 
        /// <summary>
        /// 数据格式化,全转为度分秒(x.xxxx)连写格式
        /// </summary>
        /// <param name="oldCoord">大地坐标</param>
        /// <param name="dataFormat">数据格式</param>
        /// <returns></returns>
        public double DataFormatting(string oldCoord,string dataFormat)
        {
            double newCoord = 0.00;
            switch (dataFormat)
            {
                case "度°分'秒″":
                    newCoord = DMSA_RAD(oldCoord);
                    break;
                case "度:分:秒":
                    newCoord = DMSB_RAD(oldCoord);
                    break;
                case "度:分":

                    break;
                case "度":
                    newCoord = D_RAD(oldCoord); 
                    break;
                case "度分秒连写":
                    newCoord = DMSLX_RAD(oldCoord);
                    break;
            }
            return newCoord;
        }
        #endregion
        #region 各形式角度转弧度
        double d, m, s;     //度分秒
        /// <summary>
        /// 度°分'秒"格式转弧度
        /// </summary>
        /// <param name="dms">格式为XX ° XX ' XX.XX " </param>
        /// <returns></returns>
        public double DMSA_RAD(string dms)
        {
            double rad;
            var newD = dms.Substring(0, dms.IndexOf("°"));
            var newM = dms.Substring(dms.IndexOf("°")+1,dms.IndexOf("′")-3);
            var newS = dms.Substring(dms.IndexOf("′")+1,dms.Length-dms.IndexOf("′")-2);
            rad = (double.Parse(newD) + double.Parse(newM)/ 60 + double.Parse(newS) / 3600) * 
            Math.PI / 180;
            return rad;
        }
        /// <summary>
        /// 度:分:秒 格式转弧度
        /// </summary>
        /// <param name="dms">格式为度:分:秒</param>
        /// <returns></returns>
        public double DMSB_RAD(string dms)
        {
            double rad;
            string[] newDms = dms.Split(':');
            rad = (double.Parse(newDms[0].ToString()) + double.Parse(newDms[1].ToString()) / 60 + 
            double.Parse(newDms[2].ToString()) / 3600) * Math.PI / 180;
            return rad;
        }
        /// <summary>
        /// 度分秒连写(x.xxxx)转弧度
        /// </summary>
        /// <param name="dms">格式为x.xxxx</param>
        /// <returns></returns>
        public double DMSLX_RAD(string dms)
        {
            double rad;
            var newDms = double.Parse(dms);
            d = Math.Floor(newDms); //度
            var x = (newDms - d) * 100;
            x = double.Parse(x.ToString("N8"));
            m = Math.Floor(x);  //分
            s = (x - m) * 100;
            m /= 60; //秒
            s /= 3600;
            rad = (d + m + s) / 180 * (Math.PI);    //弧度
            return rad;
        }
        /// <summary>
        /// xx.xxxx° 格式转弧度
        /// </summary>
        /// <param name="dms">角度,格式为XX.XXXX°</param>
        /// <returns></returns>
        public double D_RAD(string dms)
        {
            double rad;
            rad = (double.Parse(dms) * Math.PI / 180);
            return rad;
        }
        #endregion
        /// <summary>
        /// 弧度转角度(结果为xx.xxxxxx连写格式)
        /// </summary>
        /// <param name="rad">弧度值</param>
        /// <returns></returns>
        public double RAD_DMS(string rad)
        {
            double dms;
            var newRad = double.Parse(rad);
            var d = newRad / Math.PI * 180; //度
            var dStr = d.ToString("N8");
            d = double.Parse(dStr);
            var x = Math.Floor(d);
            var m = (d - x) * 60;   //分
            var mStr = m.ToString("N8");
            m = double.Parse(mStr);
            var f = Math.Floor(m);
            var s = (m - f) * 60;   //秒
            var sStr = s.ToString("N8");
            s = double.Parse(sStr);
            dms = x + f / 100 + s / 10000;
            return dms;
        }
    }
}

2.编写坐标转换类

          包含空间与大地互转、高斯正反算、同一坐标系下换带计算、布尔莎七参数转换计算。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using MathNet.Numerics.LinearAlgebra.Double;
namespace CoordTF
{
    class CoordTransform
    {
        /// <summary>
        /// 大地坐标转空间直角
        /// </summary>
        /// <param name="B">纬度</param>
        /// <param name="L">经度</param>
        /// <param name="H">高度</param>
        /// <param name="a">椭球长半轴</param>
        /// <param name="fl">扁率倒数</param>
        /// <returns></returns>
        public double[] BLH_XYZ(double B, double L, double H, double a, double fl,string 
        dataFormat)
        {
            var f = 1 / fl;
            var e2 = 2 * f - f * f;
            DataCnversion dataCnversion = new DataCnversion();
            B = dataCnversion.DataFormatting(B.ToString(), dataFormat);
            L = dataCnversion.DataFormatting(L.ToString(), dataFormat);
            var W = Math.Sqrt(1 - e2 * (Math.Sin(B) * Math.Sin(B)));
            var N = a / W;
            var X = (N + H) * Math.Cos(B) * Math.Cos(L);
            var Y = (N + H) * Math.Cos(B) * Math.Sin(L);
            var Z = (N * (1 - e2) + H) * Math.Sin(B);
            double[] XYZ = new double[3];
            XYZ[0] = X;
            XYZ[1] = Y;
            XYZ[2] = Z;
            return XYZ;
        }
        /// <summary>
        /// 空间直角转大地坐标
        /// </summary>
        /// <param name="X">空间X</param>
        /// <param name="Y">空间Y</param>
        /// <param name="Z">空间Z</param>
        /// <param name="a">椭球长半轴</param>
        /// <param name="fl">扁率倒数</param>
        /// <returns></returns>
        public double[] XYZ_BLH(double X, double Y, double Z, double a, double fl)
        {
            var f = 1 / fl;
            var e2 = 2 * f - f * f;
            var S = Math.Sqrt(X * X + Y * Y);
            var L = Math.Acos(X / S);
            if (Y < 0)
                L = -L;
            var Rho = 206264.806247096363;
            var Error = 0.00001;
            var B1 = Math.Atan(Z / S);
            double B2;
            while (true)
            {
                var W1 = Math.Sqrt(1 - e2 * (Math.Sin(B1) * Math.Sin(B1)));
                var N1 = a / W1;
                B2 = Math.Atan((Z + N1 * e2 * Math.Sin(B1)) / S);
                if (Math.Abs(B2 - B1) * Rho <= Error)
                    break;
                B1 = B2;
            }
            var B = B2;
            var W = Math.Sqrt(1 - e2 * (Math.Sin(B) * Math.Sin(B)));
            var N = a / W;
            var H = S / Math.Cos(B) - N;
            DataCnversion dataCnversion = new DataCnversion();
            B = dataCnversion.RAD_DMS(B.ToString("N8"));
            L = dataCnversion.RAD_DMS(L.ToString("N8"));
            double[] BLH = new double[3];
            BLH[0] = B;
            BLH[1] = L;
            BLH[2] = H;
            return BLH;
        }
        /// <summary>
        /// 布尔莎七参转换
        /// </summary>
        /// <param name="X">空间直角X</param>
        /// <param name="Y">空间直角Y</param>
        /// <param name="Z">空间直角Z</param>
        /// <param name="dx">平移参数x</param>
        /// <param name="dy">平移参数y</param>
        /// <param name="dz">平移参数z</param>
        /// <param name="rpx">旋转参数x</param>
        /// <param name="rpy">旋转参数y</param>
        /// <param name="rpz">旋转参数z</param>
        /// <param name="k">尺度参数k</param>
        /// <returns></returns>
        public double[] BursaTF(double X, double Y, double Z, double dx, double dy, double dz, 
        double rpx, double rpy, double rpz, double k)
        {
            var Rho = 206264.806247096355;//常数          
            double A15, A16, A17, A24, A26, A27, A34, A35, A37;
            A15 = Z / Rho;  A16 = Y / Rho;  A17 = X / 1000000;
            A24 = Z / Rho;  A26 = X / Rho;  A27 = Y/ 1000000;
            A34 = Y / Rho;  A35 = X / Rho;  A37 = Z / 1000000;
            var newX = X + dx - A15 * rpy + A16 * rpz + A17 * k;
            var newY = Y + dy + A24 * rpx - A26 * rpz + A27 * k;
            var newZ = Z + dz - A34 * rpx + A35 * rpy + A37 * k;
            double[] result = { newX, newY, newZ };

            return result;
        }
        /// <summary>
        /// 高斯正算
        /// </summary>
        /// <param name="B">大地纬度</param>
        /// <param name="L">大地经度</param>
        /// <param name="L0">中央子午线经度(度°分′秒″格式)</param>
        /// <param name="a">椭球长半径</param>
        /// <param name="f1">扁率倒数</param>
        /// <param name="xCon">x常参</param>
        /// <param name="yCon">y常参</param>
        /// <returns></returns>
        public double[] BL_xy(double B, double L, double L0, double a, double f1, double xCon, 
        double yCon)
        {
            DataCnversion dataCnversion = new DataCnversion();
            var f = 1 / f1;
            var e2 = 2 * f - f * f;
            var e12 = e2 / (1 - e2);
            B = dataCnversion.DMSLX_RAD(B.ToString("N8"));
            L = dataCnversion.DMSLX_RAD(L.ToString("N8"));
            L0 = dataCnversion.DMSLX_RAD(L0.ToString("N8"));
            var l = L - L0;
            var A0 = 1 + 3 * e2 / 4 + 45 * Math.Pow(e2, 2) / 64 + 350 * Math.Pow(e2, 3) / 512 + 
            11025 * Math.Pow(e2, 4) / 16384;
            var A2 = -(3 * e2 / 4 + 60 * Math.Pow(e2, 2) / 64 + 525 * Math.Pow(e2, 3) / 512 + 17640 
            * Math.Pow(e2, 4) / 16384) / 2;
            var A4 = (15 * Math.Pow(e2, 2) / 64 + 210 * Math.Pow(e2, 3) / 512 + 8820 * Math.Pow(e2, 
            4) / 16384) / 4;
            var A6 = -(35 * Math.Pow(e2, 3) / 512 + 2520 * Math.Pow(e2, 4) / 16384) / 6;
            var A8 = (315 * Math.Pow(e2, 4) / 16384) / 8;
            var X = a * (1 - e2) * (A0 * B + A2 * Math.Sin(2 * B) + A4 * Math.Sin(4 * B) + A6 * 
            Math.Sin(6 * B) + A8 * Math.Sin(8 * B));
            var m0 = l * Math.Cos(B);
            var t = Math.Tan(B);
            var n2 = e12 * Math.Pow(Math.Cos(B), 2);
            var W = Math.Sqrt(1 - e2 * Math.Pow(Math.Sin(B), 2));
            var N = a / W;
            var Nt = N * t;
            double x = X + (Nt * Math.Pow(m0, 2) / 2) + (Nt * (5 - Math.Pow(t, 2) + (9 * n2) + (4 * 
            Math.Pow(n2, 2))) * Math.Pow(m0, 4) / 24) + (Nt * (61 - (58 * Math.Pow(t, 2)) + 
            Math.Pow(t, 4) + (270 * n2) - (330 * n2 * Math.Pow(t, 2))) * Math.Pow(m0, 6) / 720);
            double y = (N * m0) + (N * (1 - Math.Pow(t, 2) + n2) * Math.Pow(m0, 3) / 6) + (N * (5 - 
            (18 * Math.Pow(t, 2)) + Math.Pow(t, 4) + (14 * n2) - (58 * n2 * Math.Pow(t, 2))) * 
            Math.Pow(m0, 5) / 120);
            x += xCon;
            y += yCon;
            double[] point = new double[2];
            point[0] = x;
            point[1] = y;
            return point;
        }
        /// <summary>
        /// 高斯反算
        /// </summary>
        /// <param name="x">平面坐标x</param>
        /// <param name="y">平面坐标y</param>
        /// <param name="L0">中央子午线经度</param>
        /// <param name="a">椭球长半轴</param>
        /// <param name="f1">扁率倒数</param>
        /// <param name="xCon">x常参数</param>
        /// <param name="yCon">y常参数</param>
        /// <returns></returns>
        public double[] Xy_BL(double x, double y, double L0, double a, double f1, double xCon, 
        double yCon)
        {
            var k = 1000000;
            x -= xCon;
            if (Math.Abs(y) >= k)
            {
                var zoneNumber = Math.Floor(y / k);
                y -= zoneNumber;
            }
            y -= yCon;
            var f = 1 / f1;
            var e2 = 2 * f - f * f;
            var e12 = e2 / (1 - e2);
            DataCnversion dataCnversion = new DataCnversion();
            L0 = dataCnversion.DMSLX_RAD(L0.ToString("N8"));
            var A0 = 1 + 3 * e2 / 4 + 45 * Math.Pow(e2, 2) / 64 + 350 * Math.Pow(e2, 3) / 512 + 
            11025 * Math.Pow(e2, 4) / 16384;
            var B0 = x / (a * (1 - e2) * A0);
            var K0 = (3 * e2 / 4 + 45 * Math.Pow(e2, 2) / 64 + 350 * Math.Pow(e2, 3) / 512 + 11025 
            * Math.Pow(e2, 4) / 16384) / 2;
            var K2 = -(63 * Math.Pow(e2, 2) / 64 + 1108 * Math.Pow(e2, 3) / 512 + 58239 * 
            Math.Pow(e2, 4) / 16384) / 3;
            var K4 = (604 * Math.Pow(e2, 3) / 512 + 68484 * Math.Pow(e2, 4) / 16384) / 3;
            var K6 = -(26328 * Math.Pow(e2, 4) / 16384) / 3;
            var sB0 = Math.Pow(Math.Sin(B0), 2);
            var Bf = B0 + Math.Sin(2 * B0) * (K0 + sB0 * (K2 + sB0 * (K4 + K6 * sB0)));
            var nf2 = e12 * Math.Pow(Math.Cos(Bf), 2);
            var tf = Math.Tan(Bf);
            var tf2 = tf * tf;
            var tf4 = Math.Pow(tf, 4);
            var Wf = Math.Sqrt(1 - e2 * (Math.Pow(Math.Sin(Bf), 2)));
            var Nf = a / Wf;
            var yNf = y / Nf;
            var Vf2 = 1 + nf2;
            var B = Bf - 0.5 * Vf2 * tf * (Math.Pow(yNf, 2) - (5 + 3 * tf2 + nf2 - 9 * nf2 * tf2) * 
            Math.Pow(yNf, 4) / 12 + (61 + 90 * tf2 + 45 * tf4) * Math.Pow(yNf, 6) / 360);
            var l = (yNf - (1 + 2 * tf2 + nf2) * Math.Pow(yNf, 3) / 6 + (5 + 28 * tf2 + 24 * tf4 + 
            6 * nf2 + 8 * nf2 * tf2) * Math.Pow(yNf, 5) / 120) / Math.Cos(Bf);
            var L = L0 + l;
            B = dataCnversion.RAD_DMS(B.ToString("N8"));
            L = dataCnversion.RAD_DMS(L.ToString("N8"));
            double[] point = new double[2];
            point[0] = B;
            point[1] = L;
            return point;
        }
        /// <summary>
        /// 同一坐标系下坐标换带
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="l1">换带前经度</param>
        /// <param name="l2">换带后经度</param>
        /// <param name="a"></param>
        /// <param name="f1"></param>
        /// <param name="xCon"></param>
        /// <param name="yCon"></param>
        /// <returns></returns>
        public double[] CoordChangeBelt(double x, double y, double l1, double l2, double a, double 
        f1, double xCon, double yCon)
        {
            double[] xy2BL = Xy_BL(x, y, l1, a, f1, xCon, yCon);
            var B = xy2BL[0];
            var L = xy2BL[1];
            double[] BL2xy = BL_xy(B, L, l2, a, f1, xCon, yCon);
            return BL2xy;
        }
    }
}

到此,所有的基础转换类完成,使用时依据坐标转换关系,依次调用类中的方法即可。

本人仅与中海达 HGO 数据处理软件包中CoordTool工具,做过七参数转换对比测试,同样参数下转换后坐标差值如下图(数据就不贴出来了)。

坐标转换(c#) 原 荐


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Practice of Programming

The Practice of Programming

Brian W. Kernighan、Rob Pike / Addison-Wesley / 1999-2-14 / USD 49.99

With the same insight and authority that made their book The Unix Programming Environment a classic, Brian Kernighan and Rob Pike have written The Practice of Programming to help make individual progr......一起来看看 《The Practice of Programming》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器