zsh_root
2025-12-10 8d662de2fd262b3a485f16e197cb4d0ca2a61cdf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
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;
    }
}