package com.mosty.base.utils;

import org.locationtech.jts.geom.Coordinate;
import org.osgeo.proj4j.BasicCoordinateTransform;
import org.osgeo.proj4j.CRSFactory;
import org.osgeo.proj4j.CoordinateReferenceSystem;
import org.osgeo.proj4j.ProjCoordinate;

import java.math.BigDecimal;
import java.text.DecimalFormat;

/**
 * @author zhangzhao
 * @description 坐标扩展工具类
 * @modifier zhangzhao
 * @modifiedTime 2024/12/17 19:32
 * @since 2024/12/17 19:32
 */
public class CoordinateUtils {

    /**
     * GIS坐标系代码-WGS84坐标系（国际通用坐标系-"EPSG:4326"）
     */
    public static final String GIS_COORDINATE_SYSTEM_CODE_WGS84 = "EPSG:4326";

    /**
     * GIS坐标系代码-CGCS2000坐标系（中国2000大地坐标系-"EPSG:4490"）
     */
    public static final String GIS_COORDINATE_SYSTEM_CODE_CGCS2000 = "EPSG:4490";

    /**
     * GIS坐标系代码-Pseudo Mercator坐标系（伪墨卡托投影坐标系，又称为Web Mercator坐标系-"EPSG:3857"）
     */
    public static final String GIS_COORDINATE_SYSTEM_CODE_PSEUDO_MERCATOR = "EPSG:3857";

    /**
     * 赤道半径
     */
    public static final double EARTH_RADIUS = 6378137.0;

    /**
     * 地球周长
     */
    public static final double EARTH_PERIMETER = 2 * Math.PI * EARTH_RADIUS;

    /**
     * 坐标原点
     */
    public static final Coordinate ORIGIN = new Coordinate(-EARTH_PERIMETER / 2.0, EARTH_PERIMETER / 2.0);

    /**
     * 坐标系创建工具
     */
    public static final CRSFactory CRS_FACTORY = new CRSFactory();

    /**
     * WGS84坐标系
     */
    public static CoordinateReferenceSystem WGS84_CRS = CRS_FACTORY.createFromName(GIS_COORDINATE_SYSTEM_CODE_WGS84);

    /**
     * 中国2000大地坐标系
     */
    public static CoordinateReferenceSystem CGCS2000_CRS = CRS_FACTORY.createFromName(GIS_COORDINATE_SYSTEM_CODE_CGCS2000);

    /**
     * 伪墨卡托投影坐标系
     */
    public static CoordinateReferenceSystem WEB_MERCATOR_CRS = CRS_FACTORY.createFromName(GIS_COORDINATE_SYSTEM_CODE_PSEUDO_MERCATOR);

    /**
     * 坐标系转换器（WGS84转伪墨卡托投影）
     */
    public static BasicCoordinateTransform TRANSFORM_WGS84_TO_WEB_MERCATOR = new BasicCoordinateTransform(WGS84_CRS, WEB_MERCATOR_CRS);

    /**
     * 坐标系转换器（WGS84转中国2000大地坐标系）
     */
    public static BasicCoordinateTransform TRANSFORM_WGS84_TO_CGCS2000 = new BasicCoordinateTransform(WGS84_CRS, CGCS2000_CRS);

    /**
     * 坐标系转换器（中国2000大地坐标系转伪墨卡托投影）
     */
    public static BasicCoordinateTransform TRANSFORM_CGCS2000_TO_WEB_MERCATOR = new BasicCoordinateTransform(CGCS2000_CRS, WEB_MERCATOR_CRS);

    /**
     * 坐标系转换器（伪墨卡托投影转WGS84）
     */
    public static BasicCoordinateTransform TRANSFORM_WEB_MERCATOR_TO_WGS84 = new BasicCoordinateTransform(WEB_MERCATOR_CRS, WGS84_CRS);

    /**
     * 坐标系转换器（伪墨卡托投影转中国2000大地坐标系）
     */
    public static BasicCoordinateTransform TRANSFORM_WEB_MERCATOR_TO_CGCS2000 = new BasicCoordinateTransform(WEB_MERCATOR_CRS, CGCS2000_CRS);


    /**
     * 经纬度转墨卡托
     *
     * @param pt 经纬度坐标
     * @return 墨卡托坐标
     */
    public static Coordinate wgs842Mercator(Coordinate pt) {
        ProjCoordinate pt1 = new ProjCoordinate(pt.x, pt.y);
        ProjCoordinate pt2 = new ProjCoordinate();
        TRANSFORM_WGS84_TO_WEB_MERCATOR.transform(pt1, pt2);
        return CoordinateUtils.coordinateFormat(new Coordinate(pt2.x, pt2.y));
    }

    /**
     * 经纬度转墨卡托
     *
     * @param longitude 经度
     * @param latitude 纬度
     * @return 墨卡托坐标
     */
    public static Coordinate wgs842Mercator(Double longitude, Double latitude) {
        Coordinate pt = new Coordinate(longitude, latitude);
        return CoordinateUtils.wgs842Mercator(pt);
    }

    /**
     * 经纬度转中国2000大地坐标系
     *
     * @param pt 经纬度坐标
     * @return 中国2000大地坐标
     */
    public static Coordinate wgs842Cgcs2000(Coordinate pt) {
        ProjCoordinate pt1 = new ProjCoordinate(pt.x, pt.y);
        ProjCoordinate pt2 = new ProjCoordinate();
        TRANSFORM_WGS84_TO_CGCS2000.transform(pt1, pt2);
        return CoordinateUtils.coordinateFormat(new Coordinate(pt2.x, pt2.y));
    }

    /**
     * 经纬度转中国2000大地坐标系
     *
     * @param longitude 经度
     * @param latitude 纬度
     * @return 中国2000大地坐标
     */
    public static Coordinate wgs842Cgcs2000(Double longitude, Double latitude) {
        Coordinate pt = new Coordinate(longitude, latitude);
        return CoordinateUtils.wgs842Cgcs2000(pt);
    }

    /**
     * 中国2000大地坐标系转伪墨卡托投影
     *
     * @param pt 中国2000大地坐标
     * @return 墨卡托坐标
     */
    public static Coordinate cgcs20002Mercator(Coordinate pt) {
        ProjCoordinate pt1 = new ProjCoordinate(pt.x, pt.y);
        ProjCoordinate pt2 = new ProjCoordinate();
        TRANSFORM_CGCS2000_TO_WEB_MERCATOR.transform(pt1, pt2);
        return CoordinateUtils.coordinateFormat(new Coordinate(pt2.x, pt2.y));
    }

    /**
     * 墨卡托转经纬度
     *
     * @param pt 墨卡托坐标
     * @return 经纬度坐标
     */
    public static Coordinate mercator2wgs84(Coordinate pt) {
        ProjCoordinate pt1 = new ProjCoordinate(pt.x, pt.y);
        ProjCoordinate pt2 = new ProjCoordinate();
        TRANSFORM_WEB_MERCATOR_TO_WGS84.transform(pt1, pt2);
        return CoordinateUtils.coordinateFormat(new Coordinate(pt2.x, pt2.y));
    }

    /**
     * 墨卡托转经纬度
     *
     * @param pt 墨卡托坐标
     * @return 经纬度坐标
     */
    public static Coordinate mercator2Cgcs2000(Coordinate pt) {
        ProjCoordinate pt1 = new ProjCoordinate(pt.x, pt.y);
        ProjCoordinate pt2 = new ProjCoordinate();
        TRANSFORM_WEB_MERCATOR_TO_CGCS2000.transform(pt1, pt2);
        return CoordinateUtils.coordinateFormat(new Coordinate(pt2.x, pt2.y));
    }

    /**
     * 高斯转经纬度
     *
     * @param pt 高斯坐标
     * @param d  度带号(3度带)
     * @return 经纬度坐标
     */
    public static Coordinate gk2Geographic(Coordinate pt, int d) {
        CoordinateReferenceSystem GKCRS = CRS_FACTORY.createFromParameters("WGS84", String.format("+proj=tmerc +lat_0=0 +lon_0=%d +k=1 +x_0=500000 +y_0=0 +ellps=WGS84 +units=m +no_defs", d * 3));
        BasicCoordinateTransform transform = new BasicCoordinateTransform(GKCRS, WGS84_CRS);
        ProjCoordinate pt1 = new ProjCoordinate(pt.x, pt.y);
        ProjCoordinate pt2 = new ProjCoordinate();
        transform.transform(pt1, pt2);
        return new Coordinate(pt2.x, pt2.y);
    }

    /**
     * 经纬度转高斯
     *
     * @param pt 经纬度坐标
     * @return 高斯坐标
     */
    public static Coordinate geographic2GK(Coordinate pt) {
        int d = (int) Math.floor((pt.y + 1.5) / 3);
        CoordinateReferenceSystem GKCRS = CRS_FACTORY.createFromParameters("WGS84", String.format("+proj=tmerc +lat_0=0 +lon_0=%d +k=1 +x_0=500000 +y_0=0 +ellps=WGS84 +units=m +no_defs", d * 3));
        BasicCoordinateTransform transform = new BasicCoordinateTransform(WGS84_CRS, GKCRS);
        ProjCoordinate pt1 = new ProjCoordinate(pt.x, pt.y);
        ProjCoordinate pt2 = new ProjCoordinate();
        transform.transform(pt1, pt2);
        return new Coordinate(pt2.x, pt2.y);
    }

    /**
     * 高斯转web墨卡托
     *
     * @param pt 高斯坐标
     * @param d  度带好(3度带)
     * @return 墨卡托坐标
     */
    public static Coordinate gk2Mercator(Coordinate pt, int d) {
        CoordinateReferenceSystem GKCRS = CRS_FACTORY.createFromParameters("WGS84", String.format("+proj=tmerc +lat_0=0 +lon_0=%d +k=1 +x_0=500000 +y_0=0 +ellps=WGS84 +units=m +no_defs", d * 3));
        BasicCoordinateTransform transform = new BasicCoordinateTransform(GKCRS, WEB_MERCATOR_CRS);
        ProjCoordinate pt1 = new ProjCoordinate(pt.x, pt.y);
        ProjCoordinate pt2 = new ProjCoordinate();
        transform.transform(pt1, pt2);
        return new Coordinate(pt2.x, pt2.y);
    }

    public static Coordinate coordinateFormat(Coordinate tar){
        BigDecimal x = new BigDecimal(tar.x + "");
        BigDecimal y = new BigDecimal(tar.y + "");
        x = x.setScale(24, BigDecimal.ROUND_HALF_UP);
        y = y.setScale(24, BigDecimal.ROUND_HALF_UP);
        tar.x = x.doubleValue();
        tar.y = y.doubleValue();
        return tar;
    }

    public static void main(String[] args) {
        Coordinate sour = new Coordinate(31.162117343434343434343434, 104.453947121212121212121212);

        Coordinate res = CoordinateUtils.cgcs20002Mercator(sour);

        Coordinate res2 = CoordinateUtils.mercator2Cgcs2000(res);

        System.out.println("x:" + res2.x);
        System.out.println("y:" + res2.y);
    }

}
