80、54、84坐标系七参数转换算法及Java代码

原创 2016年10月04日 12:56:45

一、为什么要进行坐标转换

   我们所在地球是一个不规则的椭球,地表凹凸不平,地底密度不均,因此很难用一个简单模型来概括。国际上根据建模坐标系的原点不同分为参心坐标系和地心坐标系,其中参心坐标系是指参考椭球的几何中心坐标基准,地心,通常分为:参心空间直角坐标系(以xyz为其坐标元素)和参心大地坐标系(以BLH为其坐标元素),比如我国的北京54坐标系和西安80坐标系;坐标系是用地球质心作为原点,通常分为地心空间直角坐标系(xyz为其坐标元素)地心大地坐标系(BLH为其坐标元素),比如GPS采用的WGS84坐标系

   除了原点以外,任何一个椭球的模型还会有长轴、短轴和扁率三个参数,我整理了下54,80,84三个坐标的椭球模型如下表:

坐标系

长轴(单位:米)

短轴(单位:米)

扁率

北京54坐标系

6378245

6356863

1/298.3

西安80坐标系

6378140

6356755

1/298.25722101

WGS84坐标系

6378137

6356752.314

1/298.25722356

 

        所以,我们可见这三个坐标系是原点不一,椭球模型不一的坐标系,就如同三个达芬奇的鸡蛋,虽然都是椭球状,但是形状还是不一样的。所以如果直接做两个坐标系之间的转换是明显不行的。

   那么有没有办法进行转换呢?答案是肯定的。在数学上,任何两个空间直角坐标系都可以通过七个参数,即XYZ三个轴的平移,绕XYZ三个轴的旋转角以及两个坐标系的大小比例因子的转换后重叠在一起。因此,我们在做着三个坐标系的转换基本思路就是在空间直角坐标系里,通过七参数的偏移校正,实现坐标系之间参数的转换。

 二、怎样坐标转换

        好了,那我们如何转换呢。首先,我再区分一下地理上的空间直角坐标系、大地坐标系和平面坐标系的区别。

   空间直角坐标系和数学的空间直角坐标系基本相同,是以一个点为原点,三个互相垂直的直线作为三个轴延伸出来一个坐标系,通常表示为(x,y,z);

   大地坐标系是其地面上一点的大地经度L为大地起始子午面与该点所在的子午面所构成的二面角,由起始子午面起算,向东为正,称为东经(0~180),向西为负,称为西经0~180);大地纬度B是经过该点作椭球面的法线与赤道面的夹角,由赤道面起算,向北为正,称为北纬(0~90),向南为负,称为南纬0~90);大地高H是地面点沿椭球的法线到椭球面的距离,通常表示为(B,L,H);

   平面坐标系主要是我国测绘领域里使用的坐标系,属于参心大地坐标系,有一个坐标原点(54位原苏联的普尔科沃,80位我们陕西省泾阳县永乐镇),Z轴平行于地球质心指向地极原点方向,大地起始子午面平行于格林尼治平均天文台子午面,X轴在大地起始子午面内与 Z轴垂直指向经度 0方向,Y轴与 ZX轴成右手坐标系。因为大地高程以1956年青岛验潮站求出的黄海平均水面为基准,一般情况默认为0,所以通常表示为(X,Y)。

 

下面我以一个例子说明下如何进行WGS84坐标系转西安80坐标系

   WGS84坐标系是大地坐标系,首先要转换到空间直角坐标系,公式如图所示:

  其中a,b是WGS84椭球长短轴。代码为:

//第一步转换,大地坐标系换换成空间直角坐标系
private void BLHtoXYZ(double B, double L, double H, double aAxis, double bAxis) {
    double dblD2R = Math.PI / 180;
    double e1 = Math.sqrt(Math.pow(aAxis, 2) - Math.pow(bAxis, 2)) / aAxis;

    double N = aAxis / Math.sqrt(1.0 - Math.pow(e1, 2) * Math.pow(Math.sin(B * dblD2R), 2));
    targetX = (N + H) * Math.cos(B * dblD2R) * Math.cos(L * dblD2R);
    targetY = (N + H) * Math.cos(B * dblD2R) * Math.sin(L * dblD2R);
    targetZ = (N * (1.0 - Math.pow(e1, 2)) + H) * Math.sin(B * dblD2R);
}

 

      第二步是进行空间直角坐标系里七参数转换,公式如图:


      其中△X,△Y,△Z是坐标平移量,R(ω)是旋转矩阵,(1+m)是比例因子,代码如下:

//第二步转换,空间直角坐标系里七参数转换
Ex = transParaSeven.m_dbXRotate / 180 * Math.PI;
Ey = transParaSeven.m_dbYRotate / 180 * Math.PI;
Ez = transParaSeven.m_dbZRotate / 180 * Math.PI;

double newX = transParaSeven.m_dbXOffset + transParaSeven.m_dbScale * targetX + targetY * Ez - targetZ * Ey + targetX;
double newY = transParaSeven.m_dbYOffset + transParaSeven.m_dbScale * targetY - targetX * Ez + targetZ * Ex + targetY;
double newZ = transParaSeven.m_dbZOffset + transParaSeven.m_dbScale * targetZ + targetX * Ey - targetY * Ex + targetZ;

      注意单位为弧度。

      第三步是空间直角坐标系转大地坐标系,转后的大地坐标系为80的大地坐标系,如图:

      

     其中a,b是西安80椭球长短轴,代码如下:

//第三步转换,空间直接坐标系转换为大地坐标系
private  void XYZtoBLH(double X, double Y, double Z, double aAxis, double bAxis) {
    double e1 = (Math.pow(aAxis, 2) - Math.pow(bAxis, 2)) / Math.pow(aAxis, 2);
    double e2 = (Math.pow(aAxis, 2) - Math.pow(bAxis, 2)) / Math.pow(bAxis, 2);

    double S = Math.sqrt(Math.pow(X, 2) + Math.pow(Y, 2));
    double cosL = X / S;
    double B = 0;
    double L = 0;

    L = Math.acos(cosL);
    L = Math.abs(L);

    double tanB = Z / S;
    B = Math.atan(tanB);
    double c = aAxis * aAxis / bAxis;
    double preB0 = 0.0;
    double ll = 0.0;
    double N = 0.0;
    //迭代计算纬度
    do {
        preB0 = B;
        ll = Math.pow(Math.cos(B), 2) * e2;
        N = c / Math.sqrt(1 + ll);

        tanB = (Z + N * e1 * Math.sin(B)) / S;
        B = Math.atan(tanB);
    }
    while (Math.abs(preB0 - B) >= 0.0000000001);

    ll = Math.pow(Math.cos(B), 2) * e2;
    N = c / Math.sqrt(1 + ll);

    targetZ = Z / Math.sin(B) - N * (1 - e1);
    targetB = B * 180 / Math.PI;
    targetL = L * 180 / Math.PI;
}
   第四步是进行高斯变换,将大地坐标转为平面坐标,公式如图:


    有点复杂,也一时说不清,具体可以查查高斯变换,这个还是很多的。代码如下:

//第四部转换,高斯变换,大地坐标系转平面坐标系,84转80
private void gaussBLtoXY(double mX,double mY){
    double m_aAxis = Axis_WGS84_a; //参考椭球长半轴
    double m_bAxis = Axis_WGS84_b; //参考椭球短半轴
    double m_dbMidLongitude = transParaSeven.daihao*3;//中央子午线经度 济南117 威海123 巴州 87
    double m_xOffset = 500000;
    double m_yOffset = 0.0;
    try{
           //角度到弧度的系数
            double dblD2R = Math.PI / 180;
            //代表e的平方
            double e1 = (Math.pow(m_aAxis, 2) - Math.pow(m_bAxis, 2)) / Math.pow(m_aAxis, 2);
            //代表e'的平方
            double e2 = (Math.pow(m_aAxis, 2) - Math.pow(m_bAxis, 2)) / Math.pow(m_bAxis, 2);
            //a0
            double a0 = m_aAxis * (1 - e1) * (1.0 + (3.0 / 4.0) * e1 + (45.0 / 64.0) * Math.pow(e1, 2) + (175.0 / 256.0) * Math.pow(e1, 3) + (11025.0 / 16384.0) * Math.pow(e1, 4));
            //a2                
            double a2 = -0.5 * m_aAxis * (1 - e1) * (3.0 / 4 * e1 + 60.0 / 64 * Math.pow(e1, 2) + 525.0 / 512.0 * Math.pow(e1, 3) + 17640.0 / 16384.0 * Math.pow(e1, 4));
            //a4
            double a4 = 0.25 * m_aAxis * (1 - e1) * (15.0 / 64 * Math.pow(e1, 2) + 210.0 / 512.0 * Math.pow(e1, 3) + 8820.0 / 16384.0 * Math.pow(e1, 4));
            //a6
            double a6 = (-1.0 / 6.0) * m_aAxis * (1 - e1) * (35.0 / 512.0 * Math.pow(e1, 3) + 2520.0 / 16384.0 * Math.pow(e1, 4));
            //a8
            double a8 = 0.125 * m_aAxis * (1 - e1) * (315.0 / 16384.0 * Math.pow(e1, 4));
        ////纬度转换为弧度表示
            //B
            double B = mX * dblD2R;
            //l
            double l = (mY - m_dbMidLongitude) * dblD2R;
            ////X
            double X = a0 * B + a2 * Math.sin(2.0 * B) + a4 * Math.sin(4.0 * B) + a6 * Math.sin(6.0 * B) + a8 * Math.sin(8.0 * B);
            //
            double ll = Math.pow(Math.cos(B), 2) * e2;
            double c = m_aAxis * m_aAxis / m_bAxis;
            //N
            double N = c / Math.sqrt(1 + ll);
            //t
            double t = Math.tan(B);
            double p = Math.cos(B) * l;
            double dby = X + N * t * (1 + ((5.0 - t * t + (9.0 + 4.0 * ll) * ll) + ((61.0 + (t * t - 58.0) * t * t + (9.0 - 11.0 * t * t) * 30.0 * ll) + (1385.0 + (-31111.0 + (543 - t * t) * t * t) * t * t) * p * p / 56.0) * p * p / 30.0) * p * p / 12.0) * p * p / 2.0;
            double dbx;
            dbx = N * (1.0 + ((1.0 - t * t + ll) + ((5.0 + t * t * (t * t - 18.0 - 58.0 * ll) + 14 * ll) + (61.0 + (-479.0 + (179.0 - t * t) * t * t) * t * t) * p * p / 42.0) * p * p / 20.0) * p * p / 6.0) * p;
            mTargetX = dbx + m_xOffset;
            mTargetY = dby + m_yOffset;
    }
     catch (Exception ex) {
     }
}
   OK,也就搞定了。其他的转换也就和这个差不多了,只是步骤相反而已

   

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

7参数求解过程

通过三个或三个以上已知点求解七参数模型中的参数:不同空间直角坐标系之间的变换,其参数有(ΔX0,ΔY0,ΔZ0,ωX,ωY,ωZ,m)七个,其中(ΔX0,ΔY0,ΔZ0)为坐标平移量,(ωX,ωY,ω...

高斯投影正反算的代码

2008-05-28 16:03:29 | 高斯投影正反算的代码 //高斯投影正、反算 //////6度带宽 54年北京坐标系 //高斯投影由经纬度(UnitD)反算大地坐标(含带号,Unit:Met...

利用七参数进行CGCS2000坐标系到西安80坐标系的转换

利用七参数,将CGCS2000坐标系下的大地坐标转换为西安80下的平面坐标。 涉及到的转换有: 1.大地坐标到空间直角坐标的转换 2.利用七参数求解 3.空间直角坐标到大地坐标的转换 4.高斯投影(正...

使用ArcGIS实现WGS84经纬度坐标到北京54高斯投影坐标的转换

【摘 要】 本文针对从事测绘工作者普遍遇到的坐标转换问题,简要介绍ArcGIS实现WGS84经纬度坐标到北京54高斯投影坐标转换原理和步骤。

坐标系统详解

坐标系统详解 sf2gis@163.com 2014年10月23日 2014年11月2日添加EPSG南北分带UTM 2014年12月3日添加Guass-Kruger分带计算 2014年12月...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)