地理座標和高斯投影座標互相轉換

原文鏈接:https://blog.csdn.net/jianyi7659/article/details/7583339

        前言:原作者提供了js版本的座標轉換函數,和三種橢球體參數(北京54、西安80、WGS84),個人在百度上搜索了CGC2000座標系的橢球參數,添加到函數裏,使用java寫的轉換函數。在ArcMap裏使用同一位置的兩個不同座標系的點進行驗證,誤差還算可以接受。。。

轉換函數代碼:

public class Convertor {
    private double a;//'橢球體長半軸
    private double b;// '橢球體短半軸
    private double f; //'扁率
    private double e;// '第一偏心率
    private double e1; //'第二偏心率
    private double FE;//'東偏移
    private double FN;//'北偏移
    private double L0;//'中央經度
    private double W0;//'原點緯線
    private double k0;//'比例因子
    /**
     * 冪函數
     * @param e
     * @param i
     * @return
     */
    private double MZ(double e, int i) {
        return Math.pow(e,i);
    }

    /**
     * 說明: 用於初始化轉換參數
     *
     * @param TuoqiuCanshu    枚舉類型,提供北京54、西安80和WGS84三個橢球參數
     * @param CentralMeridian 中央經線
     * @param OriginLatitude  原點緯度,如果是標準的分幅,則該參數是0
     * @param EastOffset      東偏移
     * @param NorthOffset     北偏移
     */
    public Convertor(int TuoqiuCanshu, double CentralMeridian, double OriginLatitude, double EastOffset, double NorthOffset) {
        /**
         * 'Krassovsky (北京54採用) 6378245 6356863.0188
         * 'IAG 75(西安80採用) 6378140 6356755.2882
         * 'WGS 84 6378137 6356752.3142
         * 'CGC 2000 6378137 6356752.31414
         */
        if (TuoqiuCanshu == 0)//北京五四
        {
            a = 6378245;
            b = 6356863.0188;
        } else if (TuoqiuCanshu == 1)// '西安八零
        {
            a = 6378140;
            b = 6356755.2882;
        }
        if (TuoqiuCanshu == 2)//'WGS84
        {
            a = 6378137;
            b = 6356752.3142;
        }
        if (TuoqiuCanshu == 3)//'CGC2000座標
        {
            a = 6378137;
            b = 6356752.31414;
        }
        f = (a - b) / a;//扁率
        //e = Math.sqrt(1 - MZ((b / a) ,2));//'第一偏心率
        e = Math.sqrt(2 * f - MZ(f, 2));//'第一偏心率
        //eq = Math.sqrt(MZ((a / b) , 2) - 1);//'第二偏心率
        e1 = e / Math.sqrt(1 - MZ(e, 2));//'第二偏心率
        L0 = CentralMeridian;//中央經
        W0 = OriginLatitude;//原點緯線
        k0 = 1;//'比例因子
        FE = EastOffset;//東偏移
        FN = NorthOffset;//北偏移
    }

    /**
     * 經緯度座標轉高斯投影座標
     * @param J 經度
     * @param W 緯度
     * @return
     */
    public double[] JWgetGK(double J, double W) {
        //'給出經緯度座標,轉換爲高克投影座標
        double[] resultP = new double[2];
        double BR = (W - W0) * Math.PI / 180;//緯度弧長
        double lo = (J - L0) * Math.PI / 180; //經差弧度
        double N = a / Math.sqrt(1 - MZ((e * Math.sin(BR)), 2)); //卯酉圈曲率半徑
        //求解參數s
        double B0;
        double B2;
        double B4;
        double B6;
        double B8;
        double C = MZ(a, 2) / b;
        B0 = 1 - 3 * MZ(e1, 2) / 4 + 45 * MZ(e1, 4) / 64 - 175 * MZ(e1, 6) / 256 + 11025 * MZ(e1, 8) / 16384;
        B2 = B0 - 1;
        B4 = 15 / 32 * MZ(e1, 4) - 175 / 384 * MZ(e1, 6) + 3675 / 8192 * MZ(e1, 8);
        B6 = 0 - 35 / 96 * MZ(e1, 6) + 735 / 2048 * MZ(e1, 8);
        B8 = 315 / 1024 * MZ(e1, 8);
        double s = C * (B0 * BR + Math.sin(BR) * (B2 * Math.cos(BR) + B4 * MZ((Math.cos(BR)), 3) + B6 * MZ((Math.cos(BR)), 5) + B8 * MZ((Math.cos(BR)), 7)));
        double t = Math.tan(BR);
        double g = e1 * Math.cos(BR);
        double XR = s + MZ(lo, 2) / 2 * N * Math.sin(BR) * Math.cos(BR) + MZ(lo, 4) * N * Math.sin(BR) * MZ((Math.cos(BR)), 3) / 24 * (5 - MZ(t, 2) + 9 * MZ(g, 2) + 4 * MZ(g, 4)) + MZ(lo, 6) * N * Math.sin(BR) * MZ((Math.cos(BR)), 5) * (61 - 58 * MZ(t, 2) + MZ(t, 4)) / 720;
        double YR = lo * N * Math.cos(BR) + MZ(lo, 3) * N / 6 * MZ((Math.cos(BR)), 3) * (1 - MZ(t, 2) + MZ(g, 2)) + MZ(lo, 5) * N / 120 * MZ((Math.cos(BR)), 5) * (5 - 18 * MZ(t, 2) + MZ(t, 4) + 14 * MZ(g, 2) - 58 * MZ(g, 2) * MZ(t, 2));
        resultP[0] = YR + FE;
        resultP[1] = XR + FN;
        return resultP;
    }

    /**
     * 高斯投影座標 轉爲 經緯度座標
     * @param X 高斯投影座標X
     * @param Y 高斯投影座標Y
     * @return
     */
    public double[] GKgetJW(double X, double Y) {
        //'給出高克投影座標,轉換爲經緯度座標
        double[] resultP =new double[2];
        double El1 = (1 - Math.sqrt(1 - MZ(e, 2))) / (1 + Math.sqrt(1 - MZ(e, 2)));
        double Mf = (Y - FN) / k0;//真實座標值
        double Q = Mf / (a * (1 - MZ(e, 2) / 4 - 3 * MZ(e, 4) / 64 - 5 * MZ(e, 6) / 256));//角度
        double Bf = Q + (3 * El1 / 2 - 27 * MZ(El1, 3) / 32) * Math.sin(2 * Q) + (21 * MZ(El1, 2) / 16 - 55 * MZ(El1, 4) / 32) * Math.sin(4 * Q) + (151 * MZ(El1, 3) / 96) * Math.sin(6 * Q) + 1097 / 512 * MZ(El1, 4) * Math.sin(8 * Q);
        double Rf = a * (1 - MZ(e, 2)) / Math.sqrt(MZ((1 - MZ((e * Math.sin(Bf)), 2)), 3));
        double Nf = a / Math.sqrt(1 - MZ((e * Math.sin(Bf)), 2));//卯酉圈曲率半徑
        double Tf = MZ((Math.tan(Bf)), 2);
        double D = (X - FE) / (k0 * Nf);
        double Cf = MZ(e1, 2) * MZ((Math.cos(Bf)), 2);
        double B = Bf - Nf * Math.tan(Bf) / Rf * (MZ(D, 2) / 2 - (5 + 3 * Tf + 10 * Cf - 9 * Tf * Cf - 4 * MZ(Cf, 2) - 9 * MZ(e1, 2)) * MZ(D, 4) / 24 + (61 + 90 * Tf + 45 * MZ(Tf, 2) - 256 * MZ(e1, 2) - 3 * MZ(Cf, 2)) * MZ(D, 6) / 720);
        double L = L0 * Math.PI / 180 + 1 / Math.cos(Bf) * (D - (1 + 2 * Tf + Cf) * MZ(D, 3) / 6 + (5 - 2 * Cf + 28 * Tf - 3 * MZ(Cf, 2) + 8 * MZ(e1, 2) + 24 * MZ(Tf, 2)) * MZ(D, 5) / 120);
        double Bangle = B * 180 / Math.PI;
        double Langle = L * 180 / Math.PI;
        resultP[0] = Langle;//RW * 180 / Math.PI;
        resultP[1] = Bangle + W0;//RJ * 180 / Math.PI;
        return resultP;
    }
}

測試代碼:

public class Main {
    public static void main(String[] args) {
        Convertor convertor = new Convertor(1, 120, 0, 500000, 0);
        double[] gk = convertor.JWgetGK(120.101099, 36.010338);
        double[] jw = convertor.GKgetJW(509114.252958,3986696.370605);
        System.out.println(gk[0]+","+gk[1]);
        System.out.println(jw[0]+","+jw[1]);
    }
}

 

 

結果驗證: 

        兩個表示同一位置的不同座標系(西安80地理系,西安80高斯投影系)的,座標值經過上面的代碼轉換後的結果和經過arcmap轉換的座標值的誤差還可以接受。

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章