From 3e905410575cb7444fe57967531b8eeccef79b5715a6cbc1ae86851e6d32a497 Mon Sep 17 00:00:00 2001 From: attiya <2413103649@qq.com> Date: Fri, 17 Oct 2025 10:12:37 +0800 Subject: [PATCH] =?UTF-8?q?=E5=9D=90=E6=A0=87=E7=B3=BB=E8=AE=A1=E7=AE=97?= =?UTF-8?q?=E5=B7=A5=E5=85=B7=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/cdzy/common/utils/CoordinateUtil.java | 140 +++++++++++++++++- 1 file changed, 134 insertions(+), 6 deletions(-) diff --git a/ebike-common/src/main/java/com/cdzy/common/utils/CoordinateUtil.java b/ebike-common/src/main/java/com/cdzy/common/utils/CoordinateUtil.java index 406fdc1..5d2ed28 100644 --- a/ebike-common/src/main/java/com/cdzy/common/utils/CoordinateUtil.java +++ b/ebike-common/src/main/java/com/cdzy/common/utils/CoordinateUtil.java @@ -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); } - -} +} \ No newline at end of file