package bianjie; import java.io.*; import java.nio.file.Files; import java.nio.file.Paths; public class bianjieguihua { /** * 静态方法:处理边界数据并返回边界点坐标 * * @param filePath GNGGA数据文件路径(从根目录的GNGGA.txt文件获取) * @param baseStation 基准站坐标,格式:"纬度,N/S,经度,E/W" 例如:"2324.194945,N,11330.938547,E" * @param interval 边界点间隔(米) * @param angleThreshold 角度阈值(度) * @return 边界点坐标字符串,格式:"x1,y1;x2,y2;xn,yn" */ public static String processBoundary(String filePath, String baseStation, double interval, double angleThreshold) { try { // 1. 从TXT文件读取GNGGA数据 String gnggaData = readGNGGAFromTxtFile(filePath); if (gnggaData == null || gnggaData.trim().isEmpty()) { throw new RuntimeException("无法从文件读取GNGGA数据或数据为空"); } // 2. 使用BoundaryProcessor处理数据 String boundaryCoordinates = BoundaryProcessor.processBoundaryData( gnggaData, baseStation, interval, angleThreshold); return boundaryCoordinates; } catch (Exception e) { throw new RuntimeException("处理边界数据时发生错误: " + e.getMessage(), e); } } /** * 从TXT文件读取GNGGA数据 * 文件格式:多个$GNGGA数据记录,用$GNGGA分隔 */ private static String readGNGGAFromTxtFile(String filePath) { try { // 首先尝试从当前工作目录(根目录)加载 File file = new File(filePath); // 如果文件不存在,尝试在用户当前目录下查找 if (!file.exists()) { file = new File(System.getProperty("user.dir") + File.separator + filePath); } // 如果还是不存在,尝试在类路径中查找 if (!file.exists()) { InputStream input = bianjieguihua.class.getClassLoader().getResourceAsStream(filePath); if (input != null) { // 从类路径读取 return readFromInputStream(input); } else { throw new RuntimeException("文件未找到: " + filePath + " (搜索路径: " + new File(".").getAbsolutePath() + ")"); } } // 从文件系统读取 String content = new String(Files.readAllBytes(Paths.get(file.getAbsolutePath()))); // 清理数据:移除多余的空格和换行,确保格式正确 content = content.replaceAll("\\r\\n|\\r|\\n", ""); // 移除换行符 content = content.replaceAll("\\s+", ""); // 移除空白字符 content = content.trim(); // 确保数据以$GNGGA开头(如果不是,可能文件格式不对) if (!content.startsWith("$GNGGA") && content.contains("$GNGGA")) { // 如果包含$GNGGA但不以它开头,可能需要处理 System.out.println("警告: GNGGA数据格式可能需要调整"); } return content; } catch (Exception e) { throw new RuntimeException("读取GNGGA TXT文件时发生错误: " + e.getMessage(), e); } } /** * 从输入流读取数据(用于类路径资源) */ private static String readFromInputStream(InputStream inputStream) throws IOException { StringBuilder resultStringBuilder = new StringBuilder(); try (BufferedReader br = new BufferedReader(new InputStreamReader(inputStream))) { String line; while ((line = br.readLine()) != null) { resultStringBuilder.append(line.trim()); } } return resultStringBuilder.toString(); } /** * 计算坐标点数量 */ private static int countCoordinates(String coordinates) { if (coordinates == null || coordinates.trim().isEmpty()) { return 0; } // 按分号分割坐标点 String[] points = coordinates.split(";"); return points.length; } /** * 高级处理方法 - 允许使用自定义参数 * * @param filePath GNGGA数据文件路径 * @param baseStation 基准站坐标 * @param params 边界参数对象 * @return 边界点坐标字符串 */ public static String processBoundaryAdvanced(String filePath, String baseStation, BoundaryAlgorithm.BoundaryParameters params) { try { // 从文件读取GNGGA数据 String gnggaData = readGNGGAFromTxtFile(filePath); if (gnggaData == null || gnggaData.trim().isEmpty()) { throw new RuntimeException("无法从文件读取GNGGA数据或数据为空"); } // 使用BoundaryProcessor的高级处理方法 String boundaryCoordinates = BoundaryProcessor.processBoundaryDataAdvanced( gnggaData, baseStation, params); return boundaryCoordinates; } catch (Exception e) { throw new RuntimeException("处理边界数据时发生错误: " + e.getMessage(), e); } } /** * 仅进行场景分析,不生成边界 * * @param filePath GNGGA数据文件路径 * @param baseStation 基准站坐标 * @return 场景分析结果 */ public static BoundaryAlgorithm.SceneAnalysis analyzeScene(String filePath, String baseStation) { try { // 从文件读取GNGGA数据 String gnggaData = readGNGGAFromTxtFile(filePath); if (gnggaData == null || gnggaData.trim().isEmpty()) { throw new RuntimeException("无法从文件读取GNGGA数据或数据为空"); } // 使用BoundaryProcessor进行场景分析 return BoundaryProcessor.analyzeScene(gnggaData, baseStation); } catch (Exception e) { throw new RuntimeException("场景分析时发生错误: " + e.getMessage(), e); } } /** * 完整处理流程:场景分析 + 自动参数选择 + 边界生成 * * @param filePath GNGGA数据文件路径 * @param baseStation 基准站坐标 * @return 边界点坐标字符串 */ public static String processBoundaryAuto(String filePath, String baseStation) { try { // 1. 场景分析 BoundaryAlgorithm.SceneAnalysis analysis = analyzeScene(filePath, baseStation); // 2. 根据场景分析结果获取参数 BoundaryAlgorithm algorithm = new BoundaryAlgorithm(); BoundaryAlgorithm.BoundaryParameters params = algorithm.getParametersForPreset(analysis.suggestedPreset); // 3. 使用高级处理方法生成边界 return processBoundaryAdvanced(filePath, baseStation, params); } catch (Exception e) { throw new RuntimeException("自动边界处理时发生错误: " + e.getMessage(), e); } } /** * 解析GNGGA数据并提取有效的经纬度点集合(度分格式保存) * * @param gnggaData 包含多条GNGGA记录的字符串 * @return 有效的经纬度点集合,格式为"纬度方向,经度方向;纬度方向,经度方向;..." */ public static String parseGNGGAToCoordinates(String gnggaData) { try { if (gnggaData == null || gnggaData.trim().isEmpty()) { return ""; } StringBuilder coordinatesBuilder = new StringBuilder(); // 按$GNGGA分割记录 String[] records = gnggaData.split("\\$GNGGA"); for (String record : records) { try { String trimmedRecord = record.trim(); if (trimmedRecord.isEmpty()) continue; // 确保记录以逗号开头以便正确分割字段 if (!trimmedRecord.startsWith(",")) { trimmedRecord = "," + trimmedRecord; } String[] fields = trimmedRecord.split(","); if (fields.length < 7) { continue; // 字段不足,跳过 } // 检查定位质量 (第7个字段,索引6) String fixQualityStr = fields[6]; if (fixQualityStr.isEmpty()) { continue; } int fixQuality; try { fixQuality = Integer.parseInt(fixQualityStr); } catch (NumberFormatException e) { continue; // 定位质量格式错误,跳过 } // 只采用高精度定位点 (4 = RTK固定解) if (fixQuality != 4) { continue; } // 提取纬度度分格式 (第3个字段,索引2) 和方向 (第4个字段,索引3) String latitudeStr = fields[2]; String latDirection = fields[3]; // 提取经度度分格式 (第5个字段,索引4) 和方向 (第6个字段,索引5) String longitudeStr = fields[4]; String lonDirection = fields[5]; if (latitudeStr.isEmpty() || longitudeStr.isEmpty() || latDirection.isEmpty() || lonDirection.isEmpty()) { continue; // 坐标数据不完整,跳过 } // 直接保存度分格式和方向 if (coordinatesBuilder.length() > 0) { coordinatesBuilder.append(";"); } coordinatesBuilder.append(latitudeStr) .append(",") .append(latDirection) .append(",") .append(longitudeStr) .append(",") .append(lonDirection); } catch (Exception e) { // 单条记录解析失败,继续处理下一条 System.err.println("解析GNGGA记录失败: " + record + ", 错误: " + e.getMessage()); } } return coordinatesBuilder.toString(); } catch (Exception e) { throw new RuntimeException("解析GNGGA数据时发生错误: " + e.getMessage(), e); } } /** * 将度分格式坐标转换为十进制度格式 * * @param dmCoord 度分格式坐标 (DDMM.MMMMM) * @param direction 方向 (N/S/E/W) * @return 十进制度格式坐标 */ private static double parseDMToDecimal(String dmCoord, String direction) { try { if (dmCoord == null || dmCoord.isEmpty()) { return 0; } int dotIndex = dmCoord.indexOf('.'); if (dotIndex < 2) { return 0; } // 提取度部分和分部分 int degrees = Integer.parseInt(dmCoord.substring(0, dotIndex - 2)); double minutes = Double.parseDouble(dmCoord.substring(dotIndex - 2)); // 转换为十进制度 double decimal = degrees + minutes / 60.0; // 根据方向调整正负 if ("S".equals(direction) || "W".equals(direction)) { decimal = -decimal; } return decimal; } catch (Exception e) { throw new IllegalArgumentException("度分坐标解析错误: " + dmCoord, e); } } /** * 测试方法 */ public static void main(String[] args) { try { // 创建示例文件(如果不存在) File testFile = new File("GNGGA.txt"); // 测试数据 String filePath = "GNGGA.txt"; String baseStation = "3949.91202005,N,11616.85440851,E"; // 方法2: 自动处理(推荐) String result2 = processBoundaryAuto(filePath, baseStation); System.out.println("自动处理方法结果: " + result2); } catch (Exception e) { System.err.println("测试失败: " + e.getMessage()); e.printStackTrace(); } } }