张世豪
2025-12-05 2144172c7b961d4112850692ed77b46f1ae5d373
src/zhangaiwu/Obstacledge.java
@@ -1,6 +1,7 @@
package zhangaiwu;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
/**
 * 割草机地块障碍物类
@@ -484,6 +485,14 @@
        }
        
        /**
         * 清除基准站坐标
         */
        public void clearBaseStation() {
            this.baseStationLat = null;
            this.baseStationLon = null;
        }
        /**
         * 设置基准站坐标字符串
         * @param baseStationStr 格式如 "2324.200273,N,11330.666730,E"
         */
@@ -824,4 +833,276 @@
        }
    }    
   
    /**
     * 将路径规划使用的障碍物坐标字符串解析为障碍物列表。
     * @param payload 障碍物坐标字符串
     * @param landNumber 地块编号
     * @return 解析得到的障碍物列表
     */
    public static List<Obstacle> parsePlannerPayload(String payload, String landNumber) {
        return ObstaclePayloadConverter.parse(payload, landNumber);
    }
    /**
     * 将障碍物列表转换为路径规划使用的坐标字符串。
     * @param obstacles 障碍物列表
     * @return 坐标字符串,若列表为空返回null
     */
    public static String buildPlannerPayload(List<Obstacle> obstacles) {
        return ObstaclePayloadConverter.build(obstacles);
    }
    /**
     * 障碍物坐标字符串与数据对象之间的转换工具。
     */
    private static final class ObstaclePayloadConverter {
        private ObstaclePayloadConverter() {
        }
        private static List<Obstacle> parse(String payload, String landNumber) {
            List<Obstacle> obstacles = new ArrayList<>();
            if (payload == null) {
                return obstacles;
            }
            String normalizedPayload = stripInlineComment(payload.trim());
            if (normalizedPayload.isEmpty() || "-1".equals(normalizedPayload)) {
                return obstacles;
            }
            String normalizedLand = landNumber != null ? landNumber.trim() : null;
            List<String> entries = splitEntries(normalizedPayload);
            int defaultIndex = 1;
            for (String entry : entries) {
                String trimmedEntry = stripInlineComment(entry);
                if (trimmedEntry.isEmpty()) {
                    continue;
                }
                String nameToken = null;
                String shapeToken = null;
                String coordsSection = trimmedEntry;
                if (trimmedEntry.contains("::")) {
                    String[] parts = trimmedEntry.split("::", 3);
                    if (parts.length == 3) {
                        nameToken = parts[0].trim();
                        shapeToken = parts[1].trim();
                        coordsSection = parts[2].trim();
                    }
                } else if (trimmedEntry.contains("@")) {
                    String[] parts = trimmedEntry.split("@", 3);
                    if (parts.length == 3) {
                        nameToken = parts[0].trim();
                        shapeToken = parts[1].trim();
                        coordsSection = parts[2].trim();
                    } else if (parts.length == 2) {
                        shapeToken = parts[0].trim();
                        coordsSection = parts[1].trim();
                    }
                } else if (trimmedEntry.contains(":")) {
                    String[] parts = trimmedEntry.split(":", 3);
                    if (parts.length == 3) {
                        nameToken = parts[0].trim();
                        shapeToken = parts[1].trim();
                        coordsSection = parts[2].trim();
                    } else if (parts.length == 2) {
                        if (looksLikeShapeToken(parts[0])) {
                            shapeToken = parts[0].trim();
                            coordsSection = parts[1].trim();
                        } else {
                            nameToken = parts[0].trim();
                            coordsSection = parts[1].trim();
                        }
                    }
                }
                List<XYCoordinate> xyCoordinates = parseCoordinates(coordsSection);
                if (xyCoordinates.size() < 2) {
                    continue;
                }
                ObstacleShape shape = resolveShape(shapeToken, xyCoordinates.size());
                if (shape == null) {
                    continue;
                }
                String obstacleName;
                if (nameToken != null && !nameToken.isEmpty()) {
                    obstacleName = nameToken;
                } else {
                    obstacleName = "障碍物" + defaultIndex++;
                }
                Obstacle obstacle = new Obstacle(normalizedLand, obstacleName, shape);
                obstacle.setPlotId(normalizedLand);
                obstacle.setObstacleName(obstacleName);
                obstacle.setShape(shape);
                obstacle.setXyCoordinates(new ArrayList<>(xyCoordinates));
                populatePlaceholderOriginalCoords(obstacle, xyCoordinates.size());
                if (obstacle.isValid()) {
                    obstacles.add(obstacle);
                }
            }
            return obstacles;
        }
        private static String build(List<Obstacle> obstacles) {
            if (obstacles == null || obstacles.isEmpty()) {
                return null;
            }
            StringBuilder builder = new StringBuilder();
            for (Obstacle obstacle : obstacles) {
                if (obstacle == null) {
                    continue;
                }
                List<XYCoordinate> coords = obstacle.getXyCoordinates();
                if (coords == null || coords.isEmpty()) {
                    continue;
                }
                if (builder.length() > 0) {
                    builder.append(' ');
                }
                builder.append('(');
                for (int i = 0; i < coords.size(); i++) {
                    XYCoordinate coord = coords.get(i);
                    if (coord == null) {
                        continue;
                    }
                    if (i > 0) {
                        builder.append(';');
                    }
                    builder.append(formatDouble(coord.getX())).append(',').append(formatDouble(coord.getY()));
                }
                builder.append(')');
            }
            return builder.length() == 0 ? null : builder.toString();
        }
        private static boolean looksLikeShapeToken(String token) {
            if (token == null) {
                return false;
            }
            String normalized = token.trim().toLowerCase(Locale.ROOT);
            return "circle".equals(normalized)
                || "polygon".equals(normalized)
                || "圆形".equals(normalized)
                || "多边形".equals(normalized)
                || "0".equals(normalized)
                || "1".equals(normalized);
        }
        private static List<XYCoordinate> parseCoordinates(String coordsSection) {
            List<XYCoordinate> coords = new ArrayList<>();
            if (coordsSection == null) {
                return coords;
            }
            String sanitized = stripInlineComment(coordsSection.trim());
            if (sanitized.isEmpty() || "-1".equals(sanitized)) {
                return coords;
            }
            // Remove wrapper characters like parentheses that surround persisted payloads
            sanitized = sanitized.replace("(", "").replace(")", "");
            String[] pairs = sanitized.split(";");
            for (String pair : pairs) {
                if (pair == null) {
                    continue;
                }
                String trimmed = stripInlineComment(pair.trim());
                if (trimmed.isEmpty()) {
                    continue;
                }
                trimmed = trimmed.replace("(", "").replace(")", "");
                if (trimmed.isEmpty()) {
                    continue;
                }
                String[] parts = trimmed.split(",");
                if (parts.length < 2) {
                    continue;
                }
                try {
                    double x = Double.parseDouble(parts[0].trim());
                    double y = Double.parseDouble(parts[1].trim());
                    coords.add(new XYCoordinate(x, y));
                } catch (NumberFormatException ignored) {
                    // 忽略格式错误的坐标点
                }
            }
            return coords;
        }
        private static ObstacleShape resolveShape(String shapeToken, int coordinateCount) {
            if (shapeToken != null && !shapeToken.trim().isEmpty()) {
                String normalized = shapeToken.trim().toLowerCase(Locale.ROOT);
                if ("circle".equals(normalized) || "圆形".equals(normalized) || "0".equals(normalized)) {
                    return ObstacleShape.CIRCLE;
                }
                if ("polygon".equals(normalized) || "多边形".equals(normalized) || "1".equals(normalized)) {
                    return ObstacleShape.POLYGON;
                }
            }
            if (coordinateCount == 2) {
                return ObstacleShape.CIRCLE;
            }
            if (coordinateCount >= 3) {
                return ObstacleShape.POLYGON;
            }
            return null;
        }
        private static void populatePlaceholderOriginalCoords(Obstacle obstacle, int xyCount) {
            List<DMCoordinate> dmCoordinates = new ArrayList<>();
            int points = Math.max(1, xyCount);
            for (int i = 0; i < points; i++) {
                dmCoordinates.add(new DMCoordinate(0.0, 'N'));
                dmCoordinates.add(new DMCoordinate(0.0, 'E'));
            }
            obstacle.setOriginalCoordinates(dmCoordinates);
        }
        private static String stripInlineComment(String text) {
            if (text == null) {
                return "";
            }
            int hashIndex = text.indexOf('#');
            if (hashIndex >= 0) {
                return text.substring(0, hashIndex).trim();
            }
            return text.trim();
        }
        private static List<String> splitEntries(String data) {
            List<String> entries = new ArrayList<>();
            if (data.indexOf('|') >= 0) {
                String[] parts = data.split("\\|");
                for (String part : parts) {
                    if (part != null && !part.trim().isEmpty()) {
                        entries.add(part.trim());
                    }
                }
            } else if (data.contains("\n")) {
                String[] lines = data.split("\r?\n");
                for (String line : lines) {
                    if (line != null && !line.trim().isEmpty()) {
                        entries.add(line.trim());
                    }
                }
            } else {
                entries.add(data);
            }
            return entries;
        }
        private static String formatDouble(double value) {
            return String.format(Locale.ROOT, "%.2f", value);
        }
    }
}