张世豪
4 天以前 dc9dce0555beb85d1262893fd5d56747d6a83855
src/lujing/MowingPathGenerationPage.java
@@ -1,6 +1,7 @@
package lujing;
import javax.swing.*;
import javax.swing.SwingUtilities;
import java.awt.*;
import java.math.BigDecimal;
import java.math.RoundingMode;
@@ -143,14 +144,17 @@
        buttonPanel.setBackground(BACKGROUND_COLOR);
        
        JButton generateBtn = createPrimaryFooterButton("生成割草路径");
        JButton previewBtn = createPrimaryFooterButton("预览");
        JButton saveBtn = createPrimaryFooterButton("保存路径");
        JButton cancelBtn = createPrimaryFooterButton("取消");
        
        generateBtn.addActionListener(e -> generatePath(modeValue));
        previewBtn.addActionListener(e -> previewPath());
        saveBtn.addActionListener(e -> savePath());
        cancelBtn.addActionListener(e -> dispose());
        
        buttonPanel.add(generateBtn);
        buttonPanel.add(previewBtn);
        buttonPanel.add(saveBtn);
        buttonPanel.add(cancelBtn);
        add(buttonPanel, BorderLayout.SOUTH);
@@ -187,6 +191,123 @@
    }
    
    /**
     * 预览路径
     */
    private void previewPath() {
        // 先保存当前路径到地块(临时保存,用于预览)
        String pathNormalized = normalizeCoordinateInput(pathArea.getText());
        if (!"-1".equals(pathNormalized)) {
            pathNormalized = pathNormalized
                .replace("\r\n", ";")
                .replace('\r', ';')
                .replace('\n', ';')
                .replaceAll(";+", ";")
                .replaceAll("\\s*;\\s*", ";")
                .trim();
            if (pathNormalized.isEmpty()) {
                pathNormalized = "-1";
            }
        }
        if ("-1".equals(pathNormalized)) {
            JOptionPane.showMessageDialog(this, "请先生成割草路径", "提示", JOptionPane.INFORMATION_MESSAGE);
            return;
        }
        // 临时保存路径到地块对象(不持久化)
        if (saveCallback != null) {
            saveCallback.savePlannedPath(dikuai, pathNormalized);
        }
        // 保存当前页面状态,用于返回时恢复
        String currentBaseStation = baseStationField.getText();
        String currentBoundary = boundaryArea.getText();
        String currentObstacle = obstacleArea.getText();
        String currentWidth = widthField.getText();
        String currentPath = pathArea.getText();
        // 获取地块信息
        String landNumber = dikuai.getLandNumber();
        String landName = dikuai.getLandName();
        // 处理边界坐标,确保变量是 effectively final
        String boundaryInput = normalizeCoordinateInput(boundaryArea.getText());
        final String boundary;
        if (!"-1".equals(boundaryInput)) {
            String processed = boundaryInput.replace("\r\n", ";")
                .replace('\r', ';')
                .replace('\n', ';')
                .replaceAll(";+", ";")
                .replaceAll("\\s*;\\s*", ";")
                .trim();
            if (processed.isEmpty()) {
                boundary = dikuai.getBoundaryCoordinates();
            } else {
                boundary = processed;
            }
        } else {
            boundary = dikuai.getBoundaryCoordinates();
        }
        // 处理障碍物坐标,确保变量是 effectively final
        String obstaclesInput = normalizeCoordinateInput(obstacleArea.getText());
        final String obstacles;
        if (!"-1".equals(obstaclesInput)) {
            String processed = obstaclesInput.replace("\r\n", " ")
                .replace('\r', ' ')
                .replace('\n', ' ')
                .replaceAll("\\s{2,}", " ")
                .trim();
            if (processed.isEmpty()) {
                obstacles = null;
            } else {
                obstacles = processed;
            }
        } else {
            obstacles = null;
        }
        // 保存最终值到 final 变量,以便在 lambda 中使用
        final String finalPathNormalized = pathNormalized;
        final String finalLandNumber = landNumber;
        final String finalLandName = landName;
        // 关闭路径规划页面
        setVisible(false);
        // 打开主页面并显示路径预览
        SwingUtilities.invokeLater(() -> {
            zhuye.Shouye shouye = zhuye.Shouye.getInstance();
            if (shouye != null) {
                // 显示路径预览,并设置返回回调
                shouye.startMowingPathPreview(
                    finalLandNumber,
                    finalLandName,
                    boundary,
                    obstacles,
                    finalPathNormalized,
                    () -> {
                        // 返回回调:重新打开路径规划页面
                        SwingUtilities.invokeLater(() -> {
                            setVisible(true);
                            // 恢复之前的状态
                            baseStationField.setText(currentBaseStation);
                            boundaryArea.setText(currentBoundary);
                            obstacleArea.setText(currentObstacle);
                            widthField.setText(currentWidth);
                            pathArea.setText(currentPath);
                        });
                    }
                );
            } else {
                // 如果主页面不存在,提示用户并重新显示路径规划页面
                JOptionPane.showMessageDialog(null, "无法打开主页面进行预览", "提示", JOptionPane.WARNING_MESSAGE);
                setVisible(true);
            }
        });
    }
    /**
     * 保存路径
     */
    private void savePath() {
@@ -356,33 +477,22 @@
                obstacleList = new ArrayList<>();
            }
            // 判断是否有障碍物:只要原始输入有障碍物内容,就使用ObstaclePathPlanner
            // 即使解析后列表为空,也尝试使用ObstaclePathPlanner(它会处理空障碍物列表的情况)
            boolean hasObstacles = hasObstacleInput && !obstacleList.isEmpty();
            // 如果原始输入有障碍物但解析失败,给出提示
            if (hasObstacleInput && obstacleList.isEmpty()) {
                if (showMessages) {
                    JOptionPane.showMessageDialog(parentComponent,
                        "障碍物坐标格式可能不正确,将尝试生成路径。如果路径不正确,请检查障碍物坐标格式。",
                        "提示", JOptionPane.WARNING_MESSAGE);
                }
                // 仍然尝试使用ObstaclePathPlanner,即使障碍物列表为空
                // 这样至少可以确保使用正确的路径规划器
            }
            // 判断是否有有效的障碍物:只有当解析成功且列表不为空时,才认为有障碍物
            boolean hasValidObstacles = !obstacleList.isEmpty();
            
            String generated;
            
            if (!hasObstacles && !hasObstacleInput) {
                // 完全没有障碍物输入时,使用Lunjingguihua类的方法生成路径
            if (!hasValidObstacles) {
                // 障碍物坐标不存在或为空时,使用Lunjingguihua类的方法生成路径
                generated = Lunjingguihua.generatePathFromStrings(
                    boundary,
                    obstacles != null ? obstacles : "",
                    plannerWidth,
                    null,  // safetyDistStr,使用默认值
                    mode
                );
            } else {
                // 有障碍物输入时(即使解析失败),使用ObstaclePathPlanner处理路径生成
                // 有有效障碍物时,使用ObstaclePathPlanner处理路径生成
                List<Coordinate> polygon = Lunjingguihua.parseCoordinates(boundary);
                if (polygon.size() < 4) {
                    if (showMessages) {
@@ -392,15 +502,8 @@
                    return null;
                }
                // 根据是否有障碍物设置不同的安全距离
                double safetyDistance;
                if (!obstacleList.isEmpty()) {
                    // 有障碍物时使用割草宽度的一半 + 0.05米额外安全距离
                    safetyDistance = widthMeters / 2.0 + 0.05;
                } else {
                    // 障碍物解析失败但输入存在,使用较小的安全距离
                    safetyDistance = 0.01;
                }
                // 有障碍物时使用割草宽度的一半 + 0.05米额外安全距离
                double safetyDistance = widthMeters / 2.0 + 0.05;
                ObstaclePathPlanner pathPlanner = new ObstaclePathPlanner(
                    polygon, widthMeters, mode, obstacleList, safetyDistance);