高斯坐标和经纬度之间的转化

最近项目需要做工程项目在地图的标注,项目的数据是高斯投影坐标,而地图的标注需要用到的是经纬度,因此需要做处理。在网上查找了各种帖子,掉了不少坑,最终完善出了一个工具类,亲测可用,有问题可以提出探讨。

首先是常用坐标系的参数:

(1)北京54坐标系

长半轴(米):6378245.0; 短半轴(米):6356863 ;扁率之倒数:298.3;中央子午线比例系数:1;北向偏离(米):0;东向偏离(米):500000

(2)国家80坐标系

长半轴(米):6378140.0; 短半轴(米):6356755;扁率之倒数:298.25722101;中央子午线比例系数:1;北向偏离(米):0;东向偏离(米):500000

(3)WGS84坐标系

长半轴(米):6378137.0; 短半轴(米):6356755;扁率之倒数:298.257223563;中央子午线比例系数:1;北向偏离(米):0;东向偏离(米):500000

(4)92坐标系(来源于北京54坐标系)

长半轴(米):6378245.0; 短半轴(米):6356863 ;扁率之倒数:298.3;中央子午线比例系数:1;北向偏离(米):2700000;东向偏离(米):400000

@Slf4j
public class GaussBLUtil {

    public static void main(String[] args) {
        // 以北京54坐标系为例,其中中央子午线(第3个参数)和偏离参数(第4、5个参数)可根据实际情况调整。第6个参数是长半轴,第7个参数是系数除于扁率
        GaussBLUtil.gaussToBL(2720076.481,  454802.918,118.5,0, 500000,6378245.0,1/ 298.3);
    }

    /**
     * @description 高斯投影坐标(平面坐标)转化成经纬度(大地坐标) tip:不带号,直接指定中央经度
     * @param X 平面坐标x
     * @param Y 平面坐标y
     * @param centerL   中央子午线(度)
     * @param X0    北向偏离【米】(X向加常数)
     * @param Y0    东向偏离【米】(Y向加常数)
     * @param factor    卫星椭球坐标投影到平面地图坐标系的投影因子
     * @param param 坐标系参数
     * @date 2023/4/12 15:25
     * @author lyb
     * @return double[]
     */
    public static double[] gaussToBL(double X, double Y, double centerL, double X0, double Y0, double factor, double param){
        int ProjNo;
        // 带宽
        int ZoneWide;
        double[] output = new double[2];
        // latitude0,
        double longitude1, latitude1, longitude0, yval, xval;
        double e1, e2, f, a, ee, NN, T, C, M, D, R, u, fai, iPI;
        //3.1415926535898/180.0;
        iPI = 0.0174532925199433;
        a = factor;// 卫星椭球坐标投影到平面地图坐标系的投影因子
        f = param;// 54年北京坐标系参数
        ZoneWide = 6;

        // 中央经线
        longitude0 = centerL * iPI;
        // 带内大地坐标
        log.info("带内大地坐标(偏移前) x={},y={}", X, Y);
        yval = Y-Y0;
        xval = X-X0;
        e2 = 2 * f - f * f;
        e1 = (1.0 - Math.sqrt(1 - e2)) / (1.0 + Math.sqrt(1 - e2));
        ee = e2 / (1 - e2);
        M = xval;
        u = M / (a * (1 - e2 / 4 - 3 * e2 * e2 / 64 - 5 * e2 * e2 * e2 / 256));
        fai = u + (3 * e1 / 2 - 27 * e1 * e1 * e1 / 32) * Math.sin(2 * u) + (21 * e1 * e1 / 16 - 55 * e1 * e1 * e1 * e1 / 32)
                * Math.sin(4 * u) + (151 * e1 * e1 * e1 / 96) * Math.sin(6 * u) + (1097 * e1 * e1 * e1 * e1 / 512) * Math.sin(8 * u);
        C = ee * Math.cos(fai) * Math.cos(fai);
        T = Math.tan(fai) * Math.tan(fai);
        NN = a / Math.sqrt(1.0 - e2 * Math.sin(fai) * Math.sin(fai));
        R = a * (1 - e2) / Math.sqrt((1 - e2 * Math.sin(fai) * Math.sin(fai)) * (1 - e2 * Math.sin
                (fai) * Math.sin(fai)) * (1 - e2 * Math.sin(fai) * Math.sin(fai)));
        D = yval / NN;
        // 计算经度(Longitude) 纬度(Latitude)
        longitude1 = longitude0 + (D - (1 + 2 * T + C) * D * D * D / 6 + (5 - 2 * C + 28 * T - 3 * C * C + 8 * ee + 24 * T * T) * D
                * D * D * D * D / 120) / Math.cos(fai);
        latitude1 = fai - (NN * Math.tan(fai) / R) * (D * D / 2 - (5 + 3 * T + 10 * C - 4 * C * C - 9 * ee) * D * D * D * D / 24
                + (61 + 90 * T + 298 * C + 45 * T * T - 256 * ee - 3 * C * C) * D * D * D * D * D * D / 720);
        // 转换为度 DD
        output[0] = longitude1 / iPI;
        output[1] = latitude1 / iPI;
        log.info("大地坐标L={}度, B={}度", output[0], output[1]);
        return output;
    }

    /**
     * @description 由经纬度(大地坐标)转化成高斯投影坐标(平面坐标) tip:不带号,直接指定中央经度
     * @param longitude 经度
     * @param latitude  纬度
     * @param centerL   中央子午线(度)
     * @param X0    北向偏离【米】(X向加常数)
     * @param Y0    东向偏离【米】(Y向加常数)
     * @param factor    卫星椭球坐标投影到平面地图坐标系的投影因子
     * @param param 坐标系参数
     * @date 2023/4/12 11:02
     * @author lyb
     * @return void
     */
    public static double[] bLToGauss(double longitude, double latitude, double centerL, double X0, double Y0, double factor, double param) {
        int ProjNo = 0;
        int ZoneWide; // //带宽
        double[] output = new double[2];
        double longitude1, latitude1, longitude0, xval, yval;
        double a, f, e2, ee, NN, T, C, A, M, iPI;
        iPI = 0.0174532925199433; // //3.1415926535898/180.0;
        ZoneWide = 6; // 6度带宽
        a = factor;
        f = param;
        longitude0 = centerL;
        longitude0 = longitude0 * iPI; // 中央经线
        longitude1 = longitude * iPI; // 经度转换为弧度
        latitude1 = latitude * iPI; // 纬度转换为弧度
        e2 = 2 * f - f * f;
        ee = e2 * (1.0 - e2);
        NN = a/Math.sqrt(1.0 - e2 * Math.sin(latitude1) * Math.sin(latitude1));
        T = Math.tan(latitude1) * Math.tan(latitude1);
        C = ee * Math.cos(latitude1) * Math.cos(latitude1);
        A = (longitude1 - longitude0) * Math.cos(latitude1);
        M = a * ((1 - e2 / 4 - 3 * e2 * e2 / 64 - 5 * e2 * e2 * e2 / 256) * latitude1
                - (3 * e2 / 8 + 3 * e2 * e2 / 32 + 45 * e2 * e2 * e2
                / 1024) * Math.sin(2 * latitude1)
                + (15 * e2 * e2 / 256 + 45 * e2 * e2 * e2 / 1024)
                * Math.sin(4 * latitude1) - (35 * e2 * e2 * e2 / 3072)
                * Math.sin(6 * latitude1));

        // 因为是以赤道为Y轴的,与我们南北为Y轴是相反的,所以xy与高斯投影的标准xy正好相反;
        yval = NN * (A + (1 - T + C) * A * A * A / 6 + (5 - 18 * T + T * T + 72 * C - 58 * ee)
                * A * A * A * A * A / 120);
        xval = M + NN
                * Math.tan(latitude1)
                * (A * A / 2 + (5 - T + 9 * C + 4 * C * C) * A * A * A * A / 24 + (61
                - 58 * T + T * T + 600 * C - 330 * ee)
                * A * A * A * A * A * A / 720);
        yval = yval+Y0; xval = xval+X0;
        output[0] = xval;
        output[1] = yval;
        log.info("平面坐标 x={},y={}", output[0], output[1]);
        return output;
    }

}

  • 4
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值