坐标系计算工具类

This commit is contained in:
attiya 2025-10-17 10:12:37 +08:00
parent 1c5a0bc5c0
commit 3e90541057

View File

@ -4,8 +4,7 @@ package com.cdzy.common.utils;
* 坐标转换工具类
*
* @author dingchao
* @date 2025/4/2
* @modified by:
* @since 2025/4/2
*/
public class CoordinateUtil {
// 克拉索夫斯基椭球参数
@ -13,6 +12,11 @@ public class CoordinateUtil {
private static final double A = 6378245.0; // 长半轴
private static final double EE = 0.00669342162296594323; // 第一偏心率平方
// 坐标系常量
public static final String EPSG_4326 = "EPSG:4326"; // WGS84
public static final String GCJ02 = "GCJ02"; // 火星坐标系
public static final String BD09 = "BD09"; // 百度坐标系
/**
* WGS84 --> GCJ02
* @param wgsLon 经度
@ -39,6 +43,131 @@ public class CoordinateUtil {
return new double[]{gcjLon, gcjLat};
}
/**
* GCJ02 --> WGS84
* @param gcjLon 经度
* @param gcjLat 纬度
* @return WGS84坐标数组 [经度, 纬度]
*/
public static double[] GCJ02ToWGS84(double gcjLon, double gcjLat) {
if (outOfChina(gcjLon, gcjLat)) {
return new double[]{gcjLon, gcjLat};
}
// 使用迭代法进行逆向转换
double[] wgs84 = WGS84ToGCJ02(gcjLon, gcjLat);
double deltaLon = wgs84[0] - gcjLon;
double deltaLat = wgs84[1] - gcjLat;
return new double[]{gcjLon - deltaLon, gcjLat - deltaLat};
}
/**
* 通用坐标转换方法
* @param lon 经度
* @param lat 纬度
* @param from 源坐标系
* @param to 目标坐标系
* @return 转换后的坐标数组 [经度, 纬度]
* @throws IllegalArgumentException 当不支持的坐标系转换时抛出异常
*/
public static double[] convert(double lon, double lat, String from, String to) {
if (from == null || to == null) {
throw new IllegalArgumentException("源坐标系和目标坐标系不能为null");
}
// 相同坐标系直接返回
if (from.equals(to)) {
return new double[]{lon, lat};
}
// WGS84转GCJ02
if (EPSG_4326.equals(from) && GCJ02.equals(to)) {
return WGS84ToGCJ02(lon, lat);
}
// GCJ02转WGS84
if (GCJ02.equals(from) && EPSG_4326.equals(to)) {
return GCJ02ToWGS84(lon, lat);
}
// WGS84转BD09
if (EPSG_4326.equals(from) && BD09.equals(to)) {
return WGS84ToDB09(lon, lat);
}
// GCJ02转BD09
if (GCJ02.equals(from) && BD09.equals(to)) {
return GCJ02ToBD(new double[]{lon, lat});
}
// BD09转GCJ02
if (BD09.equals(from) && GCJ02.equals(to)) {
return BD09ToGCJ02(new double[]{lon, lat});
}
// 其他转换组合可以通过已有方法组合实现
if (BD09.equals(from) && EPSG_4326.equals(to)) {
// BD09 -> GCJ02 -> WGS84
double[] gcj02 = BD09ToGCJ02(new double[]{lon, lat});
return GCJ02ToWGS84(gcj02[0], gcj02[1]);
}
throw new IllegalArgumentException("不支持的坐标系转换: " + from + " -> " + to);
}
/**
* 判断坐标是否为WGS84坐标系通过检查是否在国内且未加密
* @param lon 经度
* @param lat 纬度
* @return true-可能是WGS84坐标, false-可能是GCJ02坐标
*/
public static boolean isWGS84Coordinate(double lon, double lat) {
if (outOfChina(lon, lat)) {
return true; // 国外坐标WGS84和GCJ02相同
}
// 计算该坐标如果从WGS84转GCJ02的偏移量
double[] gcj02 = WGS84ToGCJ02(lon, lat);
double deltaLon = Math.abs(gcj02[0] - lon);
double deltaLat = Math.abs(gcj02[1] - lat);
// 如果偏移量很小说明可能是GCJ02坐标
// 如果偏移量较大说明可能是WGS84坐标
return deltaLon > 0.0001 || deltaLat > 0.0001;
}
/**
* 计算两个坐标系之间的偏移距离
* @param lon 经度
* @param lat 纬度
* @param from 源坐标系
* @param to 目标坐标系
* @return 偏移距离
*/
public static double calculateOffsetDistance(double lon, double lat, String from, String to) {
double[] converted = convert(lon, lat, from, to);
return calculateDistance(lon, lat, converted[0], converted[1]);
}
/**
* 计算两个坐标点之间的距离
* @param lon1 点1经度
* @param lat1 点1纬度
* @param lon2 点2经度
* @param lat2 点2纬度
* @return 距离
*/
public static double calculateDistance(double lon1, double lat1, double lon2, double lat2) {
double radLat1 = Math.toRadians(lat1);
double radLat2 = Math.toRadians(lat2);
double a = radLat1 - radLat2;
double b = Math.toRadians(lon1) - Math.toRadians(lon2);
double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) +
Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)));
s = s * A; // 使用椭球长半轴
s = Math.round(s * 10000) / 10000.0;
return s;
}
// 纬度偏移计算
private static double transformLat(double x, double y) {
double ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y;
@ -92,8 +221,8 @@ public class CoordinateUtil {
return new double[]{tempLon, tempLat};
}
/*
* wgs84 --> baidu
/**
* WGS84 --> BD09
*
* @param lng 经度
* @param lat 纬度
@ -103,5 +232,4 @@ public class CoordinateUtil {
double[] gcj02 = WGS84ToGCJ02(lng,lat);
return GCJ02ToBD(gcj02);
}
}
}