package home; import java.text.DecimalFormat; public class XyToLatLngConverter { private static final DecimalFormat COORDINATE_FORMAT = new DecimalFormat("0.0000000"); /** * 将局部坐标转换为经纬度坐标 * * @param localX 局部X坐标(厘米) * @param localY 局部Y坐标(厘米) * @param latA 点A的纬度(度分格式) * @param lonA 点A的经度(度分格式) * @param latB 点B的纬度(度分格式) * @param lonB 点B的经度(度分格式) * @param localXA 点A的局部X坐标(厘米) * @param localYA 点A的局部Y坐标(厘米) * @param localXB 点B的局部X坐标(厘米) * @param localYB 点B的局部Y坐标(厘米) * @return 字符串数组: * [0] 十进制度纬度, * [1] 十进制度经度, * [2] 度分格式纬度, * [3] 度分格式经度 */ public static String[] convertLocalToGlobalCoordinates( String localX, String localY, double latA, double lonA, double latB, double lonB, double localXA, double localYA, double localXB, double localYB) { // 1. 计算坐标系转换参数 double[] transformParams = CoordinateTranslator.computeTransformParamsWithTwoPoints( latA, lonA, latB, lonB, localXA, localYA, localXB, localYB); // 2. 解析输入坐标并转换为米 double x = Double.parseDouble(localX) / 100.0; double y = Double.parseDouble(localY) / 100.0; // 3. 从转换参数中提取必要信息 double originEasting = transformParams[0]; // 原点东坐标(米) double originNorthing = transformParams[1]; // 原点北坐标(米) double cosTheta = transformParams[2]; // 旋转矩阵cos分量 double sinTheta = transformParams[3]; // 旋转矩阵sin分量 double zone = transformParams[5]; // UTM带号 // 4. 将局部坐标转换为UTM坐标 double[] utmCoordinates = convertLocalToUtm(x, y, originEasting, originNorthing, cosTheta, sinTheta); // 5. 将UTM坐标转换为经纬度 double[] latLng = convertUtmToWgs84(utmCoordinates[0], utmCoordinates[1], zone); // 6. 准备结果数组 String[] result = new String[4]; result[0] = COORDINATE_FORMAT.format(latLng[0]); // 十进制度纬度 result[1] = COORDINATE_FORMAT.format(latLng[1]); // 十进制度经度 // 7. 转换为度分格式 double latDegMin = convertDecimalToDegMin(latLng[0]); double lngDegMin = convertDecimalToDegMin(latLng[1]); result[2] = COORDINATE_FORMAT.format(latDegMin); // 度分格式纬度 result[3] = COORDINATE_FORMAT.format(lngDegMin); // 度分格式经度 return result; } /** * 将十进制度转换为度分格式 * @param decimalDegrees 十进制度坐标值 * @return 度分格式坐标值 (dddmm.mmmm) */ private static double convertDecimalToDegMin(double decimalDegrees) { double degrees = Math.floor(decimalDegrees); double minutes = (decimalDegrees - degrees) * 60.0; return degrees * 100.0 + minutes; } /** * 将局部坐标转换为UTM坐标 * * @param localX 局部坐标系X值(米) * @param localY 局部坐标系Y值(米) * @param originEasting 原点东坐标(米) * @param originNorthing 原点北坐标(米) * @param cosTheta 旋转矩阵cos分量 * @param sinTheta 旋转矩阵sin分量 * @return UTM坐标数组 [东坐标, 北坐标] */ private static double[] convertLocalToUtm( double localX, double localY, double originEasting, double originNorthing, double cosTheta, double sinTheta) { // 交换XY坐标(局部坐标系通常以Y为前进方向) double rotatedX = localY; double rotatedY = localX; // 应用旋转和平移变换 double dx = cosTheta * rotatedX + sinTheta * rotatedY; double dy = -sinTheta * rotatedX + cosTheta * rotatedY; return new double[] { dx + originEasting, // 东坐标 dy + originNorthing // 北坐标 }; } /** * 将UTM坐标转换为WGS84经纬度 * * @param easting UTM东坐标(米) * @param northing UTM北坐标(米) * @param zone UTM带号 * @return 经纬度数组 [纬度, 经度] (十进制度) */ public static double[] convertUtmToWgs84(double easting, double northing, double zone) { return utm2ll_wgs84(easting, northing, zone); } /** * UTM坐标转WGS84经纬度实现 */ private static double[] utm2ll_wgs84(double x, double y, double f) { double[] latlon = new double[2]; double A1 = 6378137.0; double F1 = 298.257223563; // 常量定义 double D0 = 180 / Math.PI; double maxiter = 100; double eps = 1e-11; double K0 = 0.9996; double X0 = 500000; double Y0 = (f < 0) ? 1e7 : 0; double P0 = 0; double L0 = (6 * Math.abs(f) - 183) / D0; double E1 = Math.sqrt((A1 * A1 - (A1 * (1 - 1 / F1)) * (A1 * (1 - 1 / F1)))) / A1; double N = K0 * A1; double[] C = coef(E1, 0); double YS = Y0 - N * (C[0] * P0 + C[1] * Math.sin(2 * P0) + C[2] * Math.sin(4 * P0) + C[3] * Math.sin(6 * P0) + C[4] * Math.sin(8 * P0)); C = coef(E1, 1); double zta = (y - YS) / (N * C[0]); double ztb = (x - X0) / (N * C[0]); double L = zta; double LS = ztb; for (int i = 2; i < 6; i++) { double zta_temp = zta * (i - 1) * 2; double ztb_temp = ztb * (i - 1) * 2; L = L - C[i - 1] * Math.sin(zta_temp) * Math.cosh(ztb_temp); LS = LS - C[i - 1] * Math.cos(zta_temp) * Math.sinh(ztb_temp); } double l = L0 + Math.atan(Math.sinh(LS) / Math.cos(L)); double p = Math.asin(Math.sin(L) / Math.cosh(LS)); L = Math.log(Math.tan(Math.PI / 4 + p / 2)); p = 2 * Math.atan(Math.exp(L)) - Math.PI / 2; double p0 = 0; double n = 0; while ((p0 == 0 || Math.abs(p - p0) > eps) && n < maxiter) { p0 = p; double es = E1 * Math.sin(p0); p = 2 * Math.atan(Math.pow((1 + es) / (1 - es), E1 / 2) * Math.exp(L)) - Math.PI / 2; n = n + 1; } latlon[0] = p * D0; latlon[1] = l * D0; return latlon; } /** * 计算UTM转换系数 */ private static double[] coef(double e, int m) { double[][] c0; double[] c = new double[5]; if (m == 0) { c0 = new double[][] { {-175.0 / 16384.0, 0.0, -5 / 256.0, 0.0, -3 / 64.0, 0.0, -1 / 4.0, 0.0, 1.0}, {-105 / 4096.0, 0.0, -45 / 1024.0, 0.0, -3 / 32.0, 0.0, -3 / 8.0, 0.0, 0.0}, {525 / 16384.0, 0.0, 45 / 1024.0, 0.0, 15 / 256.0, 0.0, 0.0, 0.0, 0.0}, {-175 / 12288.0, 0.0, -35 / 3072.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {315 / 131072.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0} // 5x9 }; } else { c0 = new double[][] { {-175.0 / 16384.0, 0.0, -5 / 256.0, 0.0, -3 / 64.0, 0.0, -1 / 4.0, 0.0, 1.0}, {1 / 61440.0, 0.0, 7 / 2048.0, 0.0, 1 / 48.0, 0.0, 1 / 8.0, 0.0, 0.0}, {59 / 368640.0, 0.0, 3 / 1280.0, 0.0, 1 / 768.0, 0.0, 0.0, 0.0, 0.0}, {283 / 430080.0, 0.0, 17 / 30720.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {4397 / 41287680.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0} // 5x9 }; } for (int i = 1; i <= 5; i++) { for (int j = 1; j <= 9; j++) { c[i - 1] += c0[i - 1][j - 1] * Math.pow(e, 9 - j); } } return c; } }