技术背景
做过位置数据处理的小伙伴基本上都会遇到坐标转换,而基于高斯投影原理的大地坐标转平面坐标就是其中一种坐标转换,坐标转换的目的就是方便后面数据的处理工作,大地坐标转高斯平面坐标常用的有两种,即3°带和6°带,具体采用哪种根据实际情况而定。
计算原理
6°带带号n与相应的中央子午线L0经度的关系为:
3°带带号n’与相应的中央子午线L0’经度的关系为:
设参考椭球的长半轴为 a,第一偏心率为 e,并令:
设中央子午线的经度为 L0,再记:
则高斯投影正算公式为:
其中:
没学过测绘的同学对以上原理不是很理解,也很正常,大家可以查阅相关《大地测量学》书籍,具体武大版还是矿大版的,没什么区别。
具体实现
具体实现平台依然是IBM的Eclipse软件,编程语言为Java,下面是以3°带为例,进行高斯投影坐标正算,具体内容请看代码
1 package package1; 2 3 public class BLH_xyh { 4 5 public static double a = 6378137; 6 public static double e = Math.sqrt(0.0066943799013); 7 public static double scale_wide = 3; 8 public static double π = 3.14159265358979323846; 9 10 public static void main(String[] args) { 11 // TODO 自动生成的方法存根 12 Point3d xyh = the_coordinates_are_counting(36.0307523111,120.184664478,9.7065); 13 System.out.println(xyh.getX()+","+xyh.getY()+","+xyh.getZ()); 14 } 15 public static Point3d the_coordinates_are_counting(double B,double L,double H){ 16 double A_ = 1 17 +3*e*e/4 18 +45*e*e*e*e/64 19 +175*e*e*e*e*e*e/256 20 +11025*e*e*e*e*e*e*e*e/16384 21 +43659*e*e*e*e*e*e*e*e*e*e/65536; 22 double B_ = 3*e*e/4+15*e*e*e*e/16 23 +525*e*e*e*e*e*e/512 24 +2205*e*e*e*e*e*e*e*e/2048 25 +72765*e*e*e*e*e*e*e*e*e*e/65536; 26 double C_ = 15*e*e*e*e/64 27 +105*e*e*e*e*e*e/256 28 +2205*e*e*e*e*e*e*e*e/4096 29 +10395*e*e*e*e*e*e*e*e*e*e/16384; 30 double D_ = 35*e*e*e*e*e*e/512 31 +315*e*e*e*e*e*e*e*e/2048 32 +31185*e*e*e*e*e*e*e*e*e*e/13072; 33 /* 34 double E_ = 315*e*e*e*e*e*e*e*e/16384 35 +3465*e*e*e*e*e*e*e*e*e*e/65536; 36 double F_ = 693*e*e*e*e*e*e*e*e*e*e/13072; 37 */ 38 39 double α = A_*a*(1-e*e); 40 double β = -B_*a*(1-e*e)/2; 41 double γ = C_*a*(1-e*e)/4; 42 double δ = -D_*a*(1-e*e)/6; 43 /* 44 double ε = E_*a*(1-e*e)/8; 45 double ζ = -F_*a*(1-e*e)/10; 46 */ 47 48 double C0 = α; 49 double C1 = 2*β+4*γ+6*δ; 50 double C2 = -8*γ-32*δ; 51 double C3 = 32*δ; 52 53 double x,y,sign; 54 double scale_number = Math.floor(L/scale_wide); 55 if(L > (scale_number * scale_wide + scale_wide/2)){ 56 scale_number =scale_number + 1; 57 sign = -1; 58 }else{ 59 sign = 1; 60 } 61 62 double L0 = scale_wide*scale_number; 63 double l = Math.abs(L-L0); 64 B = B*π/180; 65 l = l*π/180; 66 double t = Math.tan(B); 67 double m0 = Math.cos(B)*l; 68 double η = Math.sqrt(e*e*Math.pow(Math.cos(B),2)/(1-e*e)); 69 double N = a/Math.sqrt(1-e*e*Math.pow(Math.sin(B), 2)); 70 71 double X0 = C0*B+Math.cos(B)*(C1*Math.sin(B)+C2*Math.pow(Math.sin(B),3)+C3*Math.pow(Math.sin(B), 5)); 72 73 x = X0 74 +N*t*m0*m0/2 75 +N*t*m0*m0*m0*m0*(5-t*t+9*η*η+4*η*η*η*η)/24 76 +N*t*m0*m0*m0*m0*m0*m0*(61-58*t*t+t*t*t*t)/720; 77 y = N*m0+ 78 N*m0*m0*m0*(1-t*t+η*η)/6+ 79 N*m0*m0*m0*m0*m0*m0*(5-18*t*t+t*t*t*t+14*η*η-58*η*η*t*t)/120; 80 81 y = y*sign+500000; 82 83 double h = H; 84 85 Point3d xyh = new Point3d(x,y,h); 86 return xyh; 87 } 88 }
其中Point3d的定义如下:
1 package package1; 2 3 public class Point3d { 4 private double x; 5 private double y; 6 private double z; 7 public Point3d(double x,double y,double z){ 8 this.x=x; 9 this.y=y; 10 this.z=z; 11 } 12 public double getX() { 13 return x; 14 } 15 public void setX(double x) { 16 this.x = x; 17 } 18 public double getY() { 19 return y; 20 } 21 public void setY(double y) { 22 this.y = y; 23 } 24 public double getZ() { 25 return z; 26 } 27 public void setZ(double z) { 28 this.z = z; 29 } 30 }
测试数据为36.0307523111,120.184664478,9.7065,运行结果如下:
至此结束
致谢
感谢山东科技大学北斗星光创客兴趣学习小组的王老师对于原理文档的整理以及郑** C++代码的技术分享!
参考文档
1、山东科技大学”北斗星光创客”兴趣学习小组GNSS技术文档