From 48ee74129bb09a817a0bbbabe860c4007b74c66b Mon Sep 17 00:00:00 2001
From: 826220679@qq.com <826220679@qq.com>
Date: 星期日, 21 十二月 2025 12:37:44 +0800
Subject: [PATCH] 新增了往返路径

---
 src/lujing/MowingPathGenerationPage.java |  289 ++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 262 insertions(+), 27 deletions(-)

diff --git a/src/lujing/MowingPathGenerationPage.java b/src/lujing/MowingPathGenerationPage.java
index 3e0cd48..503a1fd 100644
--- a/src/lujing/MowingPathGenerationPage.java
+++ b/src/lujing/MowingPathGenerationPage.java
@@ -3,6 +3,8 @@
 import javax.swing.*;
 import javax.swing.SwingUtilities;
 import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
 import java.math.BigDecimal;
 import java.math.RoundingMode;
 import java.util.ArrayList;
@@ -11,7 +13,15 @@
 import dikuai.Dikuai;
 import lujing.Lunjingguihua;
 import lujing.ObstaclePathPlanner;
+import lujing.Qufenxingzhuang;
+import lujing.AoxinglujingNoObstacle;
+import lujing.YixinglujingNoObstacle;
+import publicway.Fuzhibutton;
+import lujing.AoxinglujingHaveObstacel;
+import lujing.YixinglujingHaveObstacel;
 import org.locationtech.jts.geom.Coordinate;
+import gecaoji.Device;
+import java.util.Locale;
 
 /**
  * 鐢熸垚鍓茶崏璺緞椤甸潰
@@ -125,6 +135,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)));
         
@@ -469,8 +499,24 @@
             obstacles = obstacles.replace("\r\n", " ").replace('\r', ' ').replace('\n', ' ');
         }
 
+        // 鑾峰彇瀹夊叏璺濈
+        String safetyMarginStr = getSafetyDistanceString();
+        if (safetyMarginStr == null) {
+            // 濡傛灉娌℃湁璁剧疆瀹夊叏璺濈锛屼娇鐢ㄩ粯璁ゅ�硷細鍓茶崏瀹藉害鐨勪竴鍗� + 0.2绫�
+            double defaultSafetyDistance = widthMeters / 2.0 + 0.2;
+            safetyMarginStr = BigDecimal.valueOf(defaultSafetyDistance)
+                .setScale(3, RoundingMode.HALF_UP)
+                .stripTrailingZeros()
+                .toPlainString();
+        }
+
         String mode = normalizeExistingMowingPattern(modeInput);
         try {
+            // 1. 棣栧厛鍒ゆ柇鍦板潡绫诲瀷锛堝嚫褰㈣繕鏄紓褰級
+            Qufenxingzhuang shapeJudger = new Qufenxingzhuang();
+            int grassType = shapeJudger.judgeGrassType(boundary);
+            // grassType: 0=鏃犳硶鍒ゆ柇, 1=鍑稿舰, 2=寮傚舰
+            
             // 瑙f瀽闅滅鐗╁垪琛�
             List<List<Coordinate>> obstacleList = Lunjingguihua.parseObstacles(obstacles);
             if (obstacleList == null) {
@@ -480,35 +526,110 @@
             // 鍒ゆ柇鏄惁鏈夋湁鏁堢殑闅滅鐗╋細鍙湁褰撹В鏋愭垚鍔熶笖鍒楄〃涓嶄负绌烘椂锛屾墠璁や负鏈夐殰纰嶇墿
             boolean hasValidObstacles = !obstacleList.isEmpty();
             
-            String generated;
+            String generated = null;
             
+            // 2. 鏍规嵁鍦板潡绫诲瀷鍜屾槸鍚︽湁闅滅鐗╋紝璋冪敤涓嶅悓鐨勮矾寰勭敓鎴愮被
             if (!hasValidObstacles) {
-                // 闅滅鐗╁潗鏍囦笉瀛樺湪鎴栦负绌烘椂锛屼娇鐢↙unjingguihua绫荤殑鏂规硶鐢熸垚璺緞
-                generated = Lunjingguihua.generatePathFromStrings(
-                    boundary,
-                    obstacles != null ? obstacles : "",
-                    plannerWidth,
-                    null,  // safetyDistStr锛屼娇鐢ㄩ粯璁ゅ��
-                    mode
-                );
-            } else {
-                // 鏈夋湁鏁堥殰纰嶇墿鏃讹紝浣跨敤ObstaclePathPlanner澶勭悊璺緞鐢熸垚
-                List<Coordinate> polygon = Lunjingguihua.parseCoordinates(boundary);
-                if (polygon.size() < 4) {
-                    if (showMessages) {
-                        JOptionPane.showMessageDialog(parentComponent, "澶氳竟褰㈠潗鏍囨暟閲忎笉瓒筹紝鑷冲皯闇�瑕佷笁涓偣",
-                            "閿欒", JOptionPane.ERROR_MESSAGE);
+                // 鏃犻殰纰嶇墿鐨勬儏鍐�
+                if (grassType == 1) {
+                    // 鍑稿舰鍦板潡锛屾棤闅滅鐗� -> 璋冪敤 AoxinglujingNoObstacle
+                    List<AoxinglujingNoObstacle.PathSegment> segments = 
+                        AoxinglujingNoObstacle.planPath(boundary, plannerWidth, safetyMarginStr);
+                    generated = formatAoxingPathSegments(segments);
+                } else if (grassType == 2) {
+                    // 寮傚舰鍦板潡锛屾棤闅滅鐗� -> 璋冪敤 YixinglujingNoObstacle
+                    // 娉ㄦ剰锛氬鏋滆绫昏繕娌℃湁瀹炵幇锛岃繖閲屼細鎶涘嚭寮傚父鎴栬繑鍥瀗ull
+                    try {
+                        // 鍋囪 YixinglujingNoObstacle 鏈夌被浼肩殑鏂规硶绛惧悕
+                        // 濡傛灉绫昏繕娌℃湁瀹炵幇锛屽彲鑳介渶瑕佷娇鐢ㄥ師鏉ョ殑鏂规硶浣滀负鍚庡
+                        generated = YixinglujingNoObstacle.planPath(boundary, plannerWidth, safetyMarginStr);
+                    } catch (Exception e) {
+                        // 濡傛灉绫昏繕娌℃湁瀹炵幇锛屼娇鐢ㄥ師鏉ョ殑鏂规硶浣滀负鍚庡
+                        if (showMessages) {
+                            System.err.println("YixinglujingNoObstacle 灏氭湭瀹炵幇锛屼娇鐢ㄩ粯璁ゆ柟娉�: " + e.getMessage());
+                        }
+                        generated = Lunjingguihua.generatePathFromStrings(
+                            boundary, obstacles != null ? obstacles : "", plannerWidth, safetyMarginStr, mode);
                     }
-                    return null;
+                } else {
+                    // 鏃犳硶鍒ゆ柇鍦板潡绫诲瀷锛屼娇鐢ㄥ師鏉ョ殑鏂规硶浣滀负鍚庡
+                    if (showMessages) {
+                        JOptionPane.showMessageDialog(parentComponent, "鏃犳硶鍒ゆ柇鍦板潡绫诲瀷锛屼娇鐢ㄩ粯璁よ矾寰勭敓鎴愭柟娉�", 
+                            "鎻愮ず", JOptionPane.WARNING_MESSAGE);
+                    }
+                    generated = Lunjingguihua.generatePathFromStrings(
+                        boundary, obstacles != null ? obstacles : "", plannerWidth, safetyMarginStr, mode);
                 }
-
-                // 鏈夐殰纰嶇墿鏃朵娇鐢ㄥ壊鑽夊搴︾殑涓�鍗� + 0.05绫抽澶栧畨鍏ㄨ窛绂�
-                double safetyDistance = widthMeters / 2.0 + 0.05;
-
-                ObstaclePathPlanner pathPlanner = new ObstaclePathPlanner(
-                    polygon, widthMeters, mode, obstacleList, safetyDistance);
-                List<Lunjingguihua.PathSegment> segments = pathPlanner.generate();
-                generated = Lunjingguihua.formatPathSegments(segments);
+            } else {
+                // 鏈夐殰纰嶇墿鐨勬儏鍐�
+                if (grassType == 1) {
+                    // 鍑稿舰鍦板潡锛屾湁闅滅鐗� -> 璋冪敤 AoxinglujingHaveObstacel
+                    try {
+                        // 鍋囪 AoxinglujingHaveObstacel 鏈夌被浼肩殑鏂规硶绛惧悕
+                        generated = AoxinglujingHaveObstacel.planPath(boundary, obstacles, plannerWidth, safetyMarginStr);
+                    } catch (Exception e) {
+                        // 濡傛灉绫昏繕娌℃湁瀹炵幇锛屼娇鐢ㄥ師鏉ョ殑鏂规硶浣滀负鍚庡
+                        if (showMessages) {
+                            System.err.println("AoxinglujingHaveObstacel 灏氭湭瀹炵幇锛屼娇鐢ㄩ粯璁ゆ柟娉�: " + e.getMessage());
+                        }
+                        List<Coordinate> polygon = Lunjingguihua.parseCoordinates(boundary);
+                        if (polygon.size() < 4) {
+                            if (showMessages) {
+                                JOptionPane.showMessageDialog(parentComponent, "澶氳竟褰㈠潗鏍囨暟閲忎笉瓒筹紝鑷冲皯闇�瑕佷笁涓偣",
+                                    "閿欒", JOptionPane.ERROR_MESSAGE);
+                            }
+                            return null;
+                        }
+                        double safetyDistance = Double.parseDouble(safetyMarginStr);
+                        ObstaclePathPlanner pathPlanner = new ObstaclePathPlanner(
+                            polygon, widthMeters, mode, obstacleList, safetyDistance);
+                        List<Lunjingguihua.PathSegment> segments = pathPlanner.generate();
+                        generated = Lunjingguihua.formatPathSegments(segments);
+                    }
+                } else if (grassType == 2) {
+                    // 寮傚舰鍦板潡锛屾湁闅滅鐗� -> 璋冪敤 YixinglujingHaveObstacel
+                    try {
+                        // 鍋囪 YixinglujingHaveObstacel 鏈夌被浼肩殑鏂规硶绛惧悕
+                        generated = YixinglujingHaveObstacel.planPath(boundary, obstacles, plannerWidth, safetyMarginStr);
+                    } catch (Exception e) {
+                        // 濡傛灉绫昏繕娌℃湁瀹炵幇锛屼娇鐢ㄥ師鏉ョ殑鏂规硶浣滀负鍚庡
+                        if (showMessages) {
+                            System.err.println("YixinglujingHaveObstacel 灏氭湭瀹炵幇锛屼娇鐢ㄩ粯璁ゆ柟娉�: " + e.getMessage());
+                        }
+                        List<Coordinate> polygon = Lunjingguihua.parseCoordinates(boundary);
+                        if (polygon.size() < 4) {
+                            if (showMessages) {
+                                JOptionPane.showMessageDialog(parentComponent, "澶氳竟褰㈠潗鏍囨暟閲忎笉瓒筹紝鑷冲皯闇�瑕佷笁涓偣",
+                                    "閿欒", JOptionPane.ERROR_MESSAGE);
+                            }
+                            return null;
+                        }
+                        double safetyDistance = Double.parseDouble(safetyMarginStr);
+                        ObstaclePathPlanner pathPlanner = new ObstaclePathPlanner(
+                            polygon, widthMeters, mode, obstacleList, safetyDistance);
+                        List<Lunjingguihua.PathSegment> segments = pathPlanner.generate();
+                        generated = Lunjingguihua.formatPathSegments(segments);
+                    }
+                } else {
+                    // 鏃犳硶鍒ゆ柇鍦板潡绫诲瀷锛屼娇鐢ㄥ師鏉ョ殑鏂规硶浣滀负鍚庡
+                    if (showMessages) {
+                        JOptionPane.showMessageDialog(parentComponent, "鏃犳硶鍒ゆ柇鍦板潡绫诲瀷锛屼娇鐢ㄩ粯璁よ矾寰勭敓鎴愭柟娉�", 
+                            "鎻愮ず", JOptionPane.WARNING_MESSAGE);
+                    }
+                    List<Coordinate> polygon = Lunjingguihua.parseCoordinates(boundary);
+                    if (polygon.size() < 4) {
+                        if (showMessages) {
+                            JOptionPane.showMessageDialog(parentComponent, "澶氳竟褰㈠潗鏍囨暟閲忎笉瓒筹紝鑷冲皯闇�瑕佷笁涓偣",
+                                "閿欒", JOptionPane.ERROR_MESSAGE);
+                        }
+                        return null;
+                    }
+                    double safetyDistance = Double.parseDouble(safetyMarginStr);
+                    ObstaclePathPlanner pathPlanner = new ObstaclePathPlanner(
+                        polygon, widthMeters, mode, obstacleList, safetyDistance);
+                    List<Lunjingguihua.PathSegment> segments = pathPlanner.generate();
+                    generated = Lunjingguihua.formatPathSegments(segments);
+                }
             }
             
             String trimmed = generated != null ? generated.trim() : "";
@@ -539,6 +660,77 @@
         return null;
     }
     
+    /**
+     * 鑾峰彇瀹夊叏璺濈瀛楃涓诧紙绫筹級
+     */
+    private String getSafetyDistanceString() {
+        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;
+                    }
+                    return BigDecimal.valueOf(distanceMeters)
+                        .setScale(3, RoundingMode.HALF_UP)
+                        .stripTrailingZeros()
+                        .toPlainString();
+                } catch (NumberFormatException e) {
+                    // 瑙f瀽澶辫触锛岃繑鍥瀗ull锛屼娇鐢ㄩ粯璁ゅ��
+                }
+            }
+        }
+        return null;
+    }
+    
+    /**
+     * 鏍煎紡鍖� AoxinglujingNoObstacle.PathSegment 鍒楄〃涓哄潗鏍囧瓧绗︿覆
+     */
+    private String formatAoxingPathSegments(List<AoxinglujingNoObstacle.PathSegment> segments) {
+        if (segments == null || segments.isEmpty()) {
+            return "";
+        }
+        StringBuilder sb = new StringBuilder();
+        AoxinglujingNoObstacle.Point last = null;
+        for (AoxinglujingNoObstacle.PathSegment segment : segments) {
+            // 鍙坊鍔犲壊鑽夊伐浣滄锛岃烦杩囪繃娓℃
+            if (segment.isMowing) {
+                // 濡傛灉璧风偣涓庝笂涓�涓粓鐐逛笉鍚岋紝娣诲姞璧风偣
+                if (last == null || !equals2D(last, segment.start)) {
+                    appendPoint(sb, segment.start);
+                }
+                // 娣诲姞缁堢偣
+                appendPoint(sb, segment.end);
+                last = segment.end;
+            }
+        }
+        return sb.toString();
+    }
+    
+    /**
+     * 姣旇緝涓や釜鐐规槸鍚︾浉鍚岋紙浣跨敤灏忕殑瀹瑰樊锛�
+     */
+    private boolean equals2D(AoxinglujingNoObstacle.Point p1, AoxinglujingNoObstacle.Point p2) {
+        if (p1 == null || p2 == null) {
+            return p1 == p2;
+        }
+        double tolerance = 1e-6;
+        return Math.abs(p1.x - p2.x) < tolerance && Math.abs(p1.y - p2.y) < tolerance;
+    }
+    
+    /**
+     * 娣诲姞鐐瑰埌瀛楃涓叉瀯寤哄櫒
+     */
+    private void appendPoint(StringBuilder sb, AoxinglujingNoObstacle.Point point) {
+        if (sb.length() > 0) {
+            sb.append(";");
+        }
+        sb.append(String.format(Locale.US, "%.6f,%.6f", point.x, point.y));
+    }
+    
     // ========== UI杈呭姪鏂规硶 ==========
     
     private JTextArea createInfoTextArea(String text, boolean editable, int rows) {
@@ -559,10 +751,31 @@
         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);
+        
+        // 鍒涘缓澶嶅埗鎸夐挳锛堜娇鐢� Fuzhibutton锛�
+        JButton copyButton = Fuzhibutton.createCopyButton(
+            () -> {
+                String text = textArea.getText();
+                if (text == null || text.trim().isEmpty() || "-1".equals(text.trim())) {
+                    return null; // 杩斿洖null浼氳Е鍙�"鏈缃�"鎻愮ず
+                }
+                return text;
+            },
+            "澶嶅埗" + title,
+            new Color(230, 250, 240)
+        );
+        titlePanel.add(copyButton, BorderLayout.EAST);
+        
+        section.add(titlePanel, BorderLayout.NORTH);
         
         JScrollPane scrollPane = new JScrollPane(textArea);
         scrollPane.setBorder(BorderFactory.createLineBorder(BORDER_COLOR));
@@ -591,10 +804,31 @@
         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);
+        
+        // 鍒涘缓澶嶅埗鎸夐挳锛堜娇鐢� Fuzhibutton锛�
+        JButton copyButton = Fuzhibutton.createCopyButton(
+            () -> {
+                String text = textField.getText();
+                if (text == null || text.trim().isEmpty() || "-1".equals(text.trim())) {
+                    return null; // 杩斿洖null浼氳Е鍙�"鏈缃�"鎻愮ず
+                }
+                return text;
+            },
+            "澶嶅埗" + title,
+            new Color(230, 250, 240)
+        );
+        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));
@@ -732,6 +966,7 @@
         }
         return "parallel";
     }
+    
 }
 
 

--
Gitblit v1.10.0