From df006129448b6f0653b67caed7c061b84af8e1df Mon Sep 17 00:00:00 2001
From: 张世豪 <979909237@qq.com>
Date: 星期五, 19 十二月 2025 13:01:28 +0800
Subject: [PATCH] 新增了割草安全距离信息复制功能

---
 src/lujing/MowingPathGenerationPage.java |  295 +++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 267 insertions(+), 28 deletions(-)

diff --git a/src/lujing/MowingPathGenerationPage.java b/src/lujing/MowingPathGenerationPage.java
index 8f96af2..4bc81b4 100644
--- a/src/lujing/MowingPathGenerationPage.java
+++ b/src/lujing/MowingPathGenerationPage.java
@@ -1,7 +1,12 @@
 package lujing;
 
 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;
@@ -11,6 +16,7 @@
 import lujing.Lunjingguihua;
 import lujing.ObstaclePathPlanner;
 import org.locationtech.jts.geom.Coordinate;
+import gecaoji.Device;
 
 /**
  * 鐢熸垚鍓茶崏璺緞椤甸潰
@@ -124,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)));
         
@@ -143,14 +169,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 +216,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 +502,22 @@
                 obstacleList = new ArrayList<>();
             }
 
-            // 鍒ゆ柇鏄惁鏈夐殰纰嶇墿锛氬彧瑕佸師濮嬭緭鍏ユ湁闅滅鐗╁唴瀹癸紝灏变娇鐢∣bstaclePathPlanner
-            // 鍗充娇瑙f瀽鍚庡垪琛ㄤ负绌猴紝涔熷皾璇曚娇鐢∣bstaclePathPlanner锛堝畠浼氬鐞嗙┖闅滅鐗╁垪琛ㄧ殑鎯呭喌锛�
-            boolean hasObstacles = hasObstacleInput && !obstacleList.isEmpty();
-            
-            // 濡傛灉鍘熷杈撳叆鏈夐殰纰嶇墿浣嗚В鏋愬け璐ワ紝缁欏嚭鎻愮ず
-            if (hasObstacleInput && obstacleList.isEmpty()) {
-                if (showMessages) {
-                    JOptionPane.showMessageDialog(parentComponent, 
-                        "闅滅鐗╁潗鏍囨牸寮忓彲鑳戒笉姝g‘锛屽皢灏濊瘯鐢熸垚璺緞銆傚鏋滆矾寰勪笉姝g‘锛岃妫�鏌ラ殰纰嶇墿鍧愭爣鏍煎紡銆�", 
-                        "鎻愮ず", JOptionPane.WARNING_MESSAGE);
-                }
-                // 浠嶇劧灏濊瘯浣跨敤ObstaclePathPlanner锛屽嵆浣块殰纰嶇墿鍒楄〃涓虹┖
-                // 杩欐牱鑷冲皯鍙互纭繚浣跨敤姝g‘鐨勮矾寰勮鍒掑櫒
-            }
+            // 鍒ゆ柇鏄惁鏈夋湁鏁堢殑闅滅鐗╋細鍙湁褰撹В鏋愭垚鍔熶笖鍒楄〃涓嶄负绌烘椂锛屾墠璁や负鏈夐殰纰嶇墿
+            boolean hasValidObstacles = !obstacleList.isEmpty();
             
             String generated;
             
-            if (!hasObstacles && !hasObstacleInput) {
-                // 瀹屽叏娌℃湁闅滅鐗╄緭鍏ユ椂锛屼娇鐢↙unjingguihua绫荤殑鏂规硶鐢熸垚璺緞
+            if (!hasValidObstacles) {
+                // 闅滅鐗╁潗鏍囦笉瀛樺湪鎴栦负绌烘椂锛屼娇鐢↙unjingguihua绫荤殑鏂规硶鐢熸垚璺緞
                 generated = Lunjingguihua.generatePathFromStrings(
                     boundary,
                     obstacles != null ? obstacles : "",
                     plannerWidth,
+                    null,  // safetyDistStr锛屼娇鐢ㄩ粯璁ゅ��
                     mode
                 );
             } else {
-                // 鏈夐殰纰嶇墿杈撳叆鏃讹紙鍗充娇瑙f瀽澶辫触锛夛紝浣跨敤ObstaclePathPlanner澶勭悊璺緞鐢熸垚
+                // 鏈夋湁鏁堥殰纰嶇墿鏃讹紝浣跨敤ObstaclePathPlanner澶勭悊璺緞鐢熸垚
                 List<Coordinate> polygon = Lunjingguihua.parseCoordinates(boundary);
                 if (polygon.size() < 4) {
                     if (showMessages) {
@@ -392,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);
@@ -456,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));
@@ -488,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));
@@ -629,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);
+        }
+    }
 }
 
 

--
Gitblit v1.10.0