前言:原作者提供了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轉換的座標值的誤差還可以接受。