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();
|
}
|
}
|