张世豪
4 天以前 df006129448b6f0653b67caed7c061b84af8e1df
src/lujing/MowingPathGenerationPage.java
@@ -3,6 +3,10 @@
import javax.swing.*;
import javax.swing.SwingUtilities;
import java.awt.*;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
@@ -12,6 +16,7 @@
import lujing.Lunjingguihua;
import lujing.ObstaclePathPlanner;
import org.locationtech.jts.geom.Coordinate;
import gecaoji.Device;
/**
 * 生成割草路径页面
@@ -125,6 +130,26 @@
        widthField = createInfoTextField(widthValue != null ? widthValue : "", true);
        contentPanel.add(createTextFieldSection("割草宽度 (厘米)", widthField));
        
        // 割草安全距离(只读显示)
        String displaySafetyDistance = "未设置";
        Device device = Device.getActiveDevice();
        if (device != null) {
            String safetyDistanceValue = device.getMowingSafetyDistance();
            if (safetyDistanceValue != null && !"-1".equals(safetyDistanceValue) && !safetyDistanceValue.trim().isEmpty()) {
                try {
                    double distanceMeters = Double.parseDouble(safetyDistanceValue.trim());
                    // 如果值大于100,认为是厘米,需要转换为米
                    if (distanceMeters > 100) {
                        distanceMeters = distanceMeters / 100.0;
                    }
                    displaySafetyDistance = String.format("%.2f米", distanceMeters);
                } catch (NumberFormatException e) {
                    displaySafetyDistance = "未设置";
                }
            }
        }
        contentPanel.add(createInfoValueSection("割草安全距离", displaySafetyDistance));
        // 割草模式(只读显示)
        contentPanel.add(createInfoValueSection("割草模式", formatMowingPatternForDialog(modeValue)));
        
@@ -477,33 +502,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) {
@@ -513,15 +527,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);
@@ -577,10 +584,28 @@
        section.setBackground(BACKGROUND_COLOR);
        section.setAlignmentX(Component.LEFT_ALIGNMENT);
        
        // 创建标题面板,包含标题和复制图标
        JPanel titlePanel = new JPanel(new BorderLayout());
        titlePanel.setBackground(BACKGROUND_COLOR);
        titlePanel.setOpaque(false);
        JLabel titleLabel = new JLabel(title);
        titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 14));
        titleLabel.setForeground(TEXT_COLOR);
        section.add(titleLabel, BorderLayout.NORTH);
        titlePanel.add(titleLabel, BorderLayout.WEST);
        // 创建复制按钮
        JButton copyButton = createCopyButton(title, () -> {
            String text = textArea.getText();
            if (text == null || text.trim().isEmpty()) {
                JOptionPane.showMessageDialog(this, title + " 未设置", "提示", JOptionPane.INFORMATION_MESSAGE);
                return;
            }
            copyToClipboard(text, title);
        });
        titlePanel.add(copyButton, BorderLayout.EAST);
        section.add(titlePanel, BorderLayout.NORTH);
        
        JScrollPane scrollPane = new JScrollPane(textArea);
        scrollPane.setBorder(BorderFactory.createLineBorder(BORDER_COLOR));
@@ -609,10 +634,28 @@
        section.setBackground(BACKGROUND_COLOR);
        section.setAlignmentX(Component.LEFT_ALIGNMENT);
        
        // 创建标题面板,包含标题和复制图标
        JPanel titlePanel = new JPanel(new BorderLayout());
        titlePanel.setBackground(BACKGROUND_COLOR);
        titlePanel.setOpaque(false);
        JLabel titleLabel = new JLabel(title);
        titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 14));
        titleLabel.setForeground(TEXT_COLOR);
        section.add(titleLabel, BorderLayout.NORTH);
        titlePanel.add(titleLabel, BorderLayout.WEST);
        // 创建复制按钮
        JButton copyButton = createCopyButton(title, () -> {
            String text = textField.getText();
            if (text == null || text.trim().isEmpty()) {
                JOptionPane.showMessageDialog(this, title + " 未设置", "提示", JOptionPane.INFORMATION_MESSAGE);
                return;
            }
            copyToClipboard(text, title);
        });
        titlePanel.add(copyButton, BorderLayout.EAST);
        section.add(titlePanel, BorderLayout.NORTH);
        
        JPanel fieldWrapper = new JPanel(new BorderLayout());
        fieldWrapper.setBackground(textField.isEditable() ? WHITE : new Color(245, 245, 245));
@@ -750,6 +793,81 @@
        }
        return "parallel";
    }
    /**
     * 创建复制按钮
     */
    private JButton createCopyButton(String title, Runnable copyAction) {
        JButton copyButton = new JButton();
        Font titleFont = new Font("微软雅黑", Font.BOLD, 14);
        FontMetrics metrics = getFontMetrics(titleFont);
        int iconSize = metrics.getHeight(); // 使用标题字体高度作为图标大小
        // 加载复制图标
        ImageIcon copyIcon = null;
        ImageIcon successIcon = null;
        try {
            ImageIcon originalCopyIcon = new ImageIcon("image/fuzhi.png");
            Image scaledCopyImage = originalCopyIcon.getImage().getScaledInstance(iconSize, iconSize, Image.SCALE_SMOOTH);
            copyIcon = new ImageIcon(scaledCopyImage);
            // 加载成功图标
            ImageIcon originalSuccessIcon = new ImageIcon("image/fuzhisucc.png");
            Image scaledSuccessImage = originalSuccessIcon.getImage().getScaledInstance(iconSize, iconSize, Image.SCALE_SMOOTH);
            successIcon = new ImageIcon(scaledSuccessImage);
        } catch (Exception e) {
            // 如果图片加载失败,使用文本
            copyButton.setText("复制");
            copyButton.setFont(new Font("微软雅黑", Font.PLAIN, 12));
            System.err.println("无法加载复制图标: " + e.getMessage());
        }
        final ImageIcon finalCopyIcon = copyIcon;
        final ImageIcon finalSuccessIcon = successIcon;
        copyButton.setIcon(finalCopyIcon);
        copyButton.setContentAreaFilled(false);
        copyButton.setBorder(null);
        copyButton.setFocusPainted(false);
        copyButton.setCursor(new Cursor(Cursor.HAND_CURSOR));
        copyButton.setToolTipText("复制" + title);
        // 添加点击事件
        copyButton.addActionListener(e -> {
            copyAction.run();
            // 复制成功后切换图标
            if (finalSuccessIcon != null) {
                copyButton.setIcon(finalSuccessIcon);
                // 1秒后恢复原图标
                Timer timer = new Timer(1000, evt -> {
                    copyButton.setIcon(finalCopyIcon);
                });
                timer.setRepeats(false);
                timer.start();
            }
        });
        return copyButton;
    }
    /**
     * 复制文本到剪贴板
     */
    private void copyToClipboard(String text, String title) {
        if (text == null || text.trim().isEmpty()) {
            JOptionPane.showMessageDialog(this, title + " 未设置", "提示", JOptionPane.INFORMATION_MESSAGE);
            return;
        }
        try {
            StringSelection selection = new StringSelection(text);
            Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
            clipboard.setContents(selection, selection);
            // 去掉成功提示弹窗
        } catch (Exception ex) {
            JOptionPane.showMessageDialog(this, "复制失败: " + ex.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
        }
    }
}