内容简介:坐标转换,简言之就是讲一个坐标系的坐标通过特定模型转换到另一坐标下;转换中,需要用到不同的转换模型,例如三维空间下的布尔莎七参数、莫洛金斯模型;二维空间下的平面三参、四参、多项式拟合等模型。本文中,主要使用布尔莎七参数模型进行坐标转换。详细见百科:
坐标转换
坐标转换,简言之就是讲一个坐标系的坐标通过特定模型转换到另一坐标下;转换中,需要用到不同的转换模型,例如三维空间下的布尔莎七参数、莫洛金斯模型;二维空间下的平面三参、四参、多项式拟合等模型。本文中,主要使用布尔莎七参数模型进行坐标转换。
坐标转换关系
布尔莎模型(七参数模型)
详细见百科: 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工具,做过七参数转换对比测试,同样参数下转换后坐标差值如下图(数据就不贴出来了)。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 代码分析Python地图坐标转换
- iOS做地图相关需要知道的Tips(一)——坐标系及相互转换方法
- HQChart 1.9334 版本发布,增加等比坐标、黄金分割坐标、等分坐标
- cocos creator教程之世界坐标和局部坐标
- arcgis for jsapi开发:坐标系、经纬度与平面坐标的互换
- iOS坐标系探究
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。