826220679@qq.com
2025-08-07 0e0e51fc63a865977d751271be28437e24dd6a99
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 publicsWay;
 
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;
    }
}