826220679@qq.com
2 天以前 48ee74129bb09a817a0bbbabe860c4007b74c66b
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
package publicway;
 
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
 
public class Gpstoxuzuobiao {
    private static final double METERS_PER_DEGREE_LAT = 111320.0d;
    
    // 缓存基准站坐标
    private static double cachedBaseLat = 0.0;
    private static double cachedBaseLon = 0.0;
    private static boolean baseStationLoaded = false;
 
    /**
     * 解析GNGGA数据并转换为XY坐标
     * @param gnggaData $GNGGA数据
     * @return double[]{x, y} 相对坐标,如果解析失败或无基站数据返回null
     */
    public static double[] processGNGGAToXY(String gnggaData) {
        ensureBaseStationLoaded();
        if (!baseStationLoaded) {
            return null;
        }
        return processGNGGAToXY(gnggaData, cachedBaseLat, cachedBaseLon);
    }
 
    /**
     * 解析GNGGA数据并转换为XY坐标
     * @param gnggaData $GNGGA数据
     * @param baseLat 基准站纬度
     * @param baseLon 基准站经度
     * @return double[]{x, y} 相对坐标
     */
    public static double[] processGNGGAToXY(String gnggaData, double baseLat, double baseLon) {
        if (gnggaData == null || !gnggaData.contains("$GNGGA")) {
            return null;
        }
        
        // 简单的解析逻辑,提取经纬度
        // 格式: $GNGGA,hhmmss.ss,lat,latDir,lon,lonDir,quality,sats,hdop,alt,units,sep,units,age,refID*cs
        
        String[] parts = gnggaData.split(",");
        // 找到$GNGGA的位置
        int index = -1;
        for(int i=0; i<parts.length; i++) {
            if (parts[i].contains("$GNGGA")) {
                index = i;
                break;
            }
        }
        
        // 确保有足够的字段: lat(2), latDir(3), lon(4), lonDir(5)
        if (index == -1 || index + 5 >= parts.length) {
            return null;
        }
        
        String latStr = parts[index + 2];
        String latDir = parts[index + 3];
        String lonStr = parts[index + 4];
        String lonDir = parts[index + 5];
        
        if (latStr.isEmpty() || lonStr.isEmpty()) {
            return null;
        }
        
        double lat = parseDMToDecimal(latStr, latDir);
        double lon = parseDMToDecimal(lonStr, lonDir);
        
        return convertLatLonToLocal(lat, lon, baseLat, baseLon);
    }
 
    /**
     * 将度分格式(DMM)转换为十进制格式(DD)
     * @param dmm 度分格式字符串 (e.g. "3015.1234")
     * @param direction 方向 (N/S/E/W)
     * @return 十进制经纬度
     */
    public static double parseDMToDecimal(String dmm, String direction) {
        if (dmm == null || dmm.isEmpty()) {
            return 0.0;
        }
        try {
            double val = Double.parseDouble(dmm);
            int degrees = (int) (val / 100);
            double minutes = val - degrees * 100;
            double decimal = degrees + minutes / 60.0;
            if (direction != null && (direction.equalsIgnoreCase("S") || direction.equalsIgnoreCase("W"))) {
                decimal = -decimal;
            }
            return decimal;
        } catch (NumberFormatException e) {
            return 0.0;
        }
    }
 
    /**
     * 将经纬度转换为相对坐标(XY)
     * @param lat 目标纬度
     * @param lon 目标经度
     * @param baseLat 基准站纬度
     * @param baseLon 基准站经度
     * @return double[]{x, y} (单位: 米)
     */
    public static double[] convertLatLonToLocal(double lat, double lon, double baseLat, double baseLon) {
        double deltaLat = lat - baseLat;
        double deltaLon = lon - baseLon;
        double meanLatRad = Math.toRadians((baseLat + lat) / 2.0);
        double eastMeters = deltaLon * METERS_PER_DEGREE_LAT * Math.cos(meanLatRad);
        double northMeters = deltaLat * METERS_PER_DEGREE_LAT;
        return new double[]{eastMeters, northMeters};
    }
    
    private static void ensureBaseStationLoaded() {
        if (baseStationLoaded) return;
        
        Properties props = new Properties();
        try (FileInputStream input = new FileInputStream("basestation.properties")) {
            props.load(input);
            String coords = props.getProperty("installationCoordinates");
            if (coords != null && !coords.isEmpty() && !"-1".equals(coords)) {
                String[] parts = coords.split(",");
                if (parts.length >= 4) {
                    cachedBaseLat = parseDMToDecimal(parts[0], parts[1]);
                    cachedBaseLon = parseDMToDecimal(parts[2], parts[3]);
                    baseStationLoaded = true;
                }
            }
        } catch (IOException e) {
            // ignore
        }
    }
    
    /**
     * 重新加载基准站信息
     */
    public static void reloadBaseStation() {
        baseStationLoaded = false;
        ensureBaseStationLoaded();
    }
}