From 1cf1ecbc75c6d14b40efb3161e7db0b8b64f7de2 Mon Sep 17 00:00:00 2001
From: 张世豪 <979909237@qq.com>
Date: 星期三, 17 十二月 2025 12:05:27 +0800
Subject: [PATCH] 新增有障碍物的路径规划算法和优化没有障碍物的路径算法

---
 src/lujing/Lunjingguihua.java |   95 +++++++++++++++++++++++++++++++++++++----------
 1 files changed, 75 insertions(+), 20 deletions(-)

diff --git a/src/lujing/Lunjingguihua.java b/src/lujing/Lunjingguihua.java
index 907a4f7..3e54d7b 100644
--- a/src/lujing/Lunjingguihua.java
+++ b/src/lujing/Lunjingguihua.java
@@ -30,16 +30,18 @@
     /**
      * 鐢熸垚鍓茶崏璺緞娈靛垪琛ㄣ��
      *
-     * @param polygonCoords 澶氳竟褰㈣竟鐣屽潗鏍囷紝鏍煎紡濡� "x1,y1;x2,y2;..."锛堢背锛�
+     * @param polygonCoords   澶氳竟褰㈣竟鐣屽潗鏍囷紝鏍煎紡濡� "x1,y1;x2,y2;..."锛堢背锛�
      * @param obstaclesCoords 闅滅鐗╁潗鏍囷紝鏀寔澶氫釜鎷彿娈垫垨鍦嗗舰瀹氫箟锛屼緥 "(x1,y1;x2,y2)(cx,cy;px,py)"
-     * @param mowingWidth 鍓茶崏瀹藉害瀛楃涓诧紝绫冲崟浣嶏紝鍏佽淇濈暀涓や綅灏忔暟
-     * @param modeStr 鍓茶崏妯″紡锛�"0"/绌轰负骞宠绾匡紝"1" 鎴� "spiral" 琛ㄧず铻烘棆妯″紡锛堝綋鍓嶄粎骞宠绾垮疄鐜帮級
+     * @param mowingWidth     鍓茶崏瀹藉害瀛楃涓诧紝绫冲崟浣嶏紝鍏佽淇濈暀涓や綅灏忔暟
+     * @param safetyDistStr   瀹夊叏璺濈瀛楃涓诧紝绫冲崟浣嶃�傝矾寰勫皢涓庤竟鐣屽拰闅滅鐗╀繚鎸佹璺濈銆�
+     * @param modeStr         鍓茶崏妯″紡锛�"0"/绌轰负骞宠绾匡紝"1" 鎴� "spiral" 琛ㄧず铻烘棆妯″紡锛堝綋鍓嶄粎骞宠绾垮疄鐜帮級
      * @return 璺緞娈靛垪琛紝鎸夎椹堕『搴忔帓鍒�
      */
     public static List<PathSegment> generatePathSegments(String polygonCoords,
-                                                          String obstaclesCoords,
-                                                          String mowingWidth,
-                                                          String modeStr) {
+                                                         String obstaclesCoords,
+                                                         String mowingWidth,
+                                                         String safetyDistStr,
+                                                         String modeStr) {
         List<Coordinate> polygon = parseCoordinates(polygonCoords);
         if (polygon.size() < 4) {
             throw new IllegalArgumentException("澶氳竟褰㈠潗鏍囨暟閲忎笉瓒筹紝鑷冲皯闇�瑕佷笁涓偣");
@@ -49,30 +51,55 @@
         if (width <= 0) {
             throw new IllegalArgumentException("鍓茶崏瀹藉害蹇呴』澶т簬 0");
         }
+        
+        // 瑙f瀽瀹夊叏璺濈锛屽鏋滄湭璁剧疆鎴栨棤鏁堬紝榛樿涓� NaN (鍦� PlannerCore 涓鐞嗛粯璁ゅ��)
+        double safetyDistance = parseDoubleOrDefault(safetyDistStr, Double.NaN);
 
         List<List<Coordinate>> obstacles = parseObstacles(obstaclesCoords);
         String mode = normalizeMode(modeStr);
 
-        PlannerCore planner = new PlannerCore(polygon, width, mode, obstacles);
+        PlannerCore planner = new PlannerCore(polygon, width, safetyDistance, mode, obstacles);
         return planner.generate();
     }
 
     /**
+     * 淇濇寔鍚戝悗鍏煎鐨勯噸杞芥柟娉曪紙涓嶅甫 safeDistance锛屼娇鐢ㄩ粯璁よ绠楋級
+     */
+    public static List<PathSegment> generatePathSegments(String polygonCoords,
+                                                         String obstaclesCoords,
+                                                         String mowingWidth,
+                                                         String modeStr) {
+        return generatePathSegments(polygonCoords, obstaclesCoords, mowingWidth, null, modeStr);
+    }
+
+    /**
      * 閫氳繃瀛楃涓插弬鏁扮敓鎴愬壊鑽夎矾寰勫潗鏍囥��
      *
-     * @param polygonCoords 澶氳竟褰㈣竟鐣屽潗鏍囷紝鏍煎紡濡� "x1,y1;x2,y2;..."锛堢背锛�
+     * @param polygonCoords   澶氳竟褰㈣竟鐣屽潗鏍囷紝鏍煎紡濡� "x1,y1;x2,y2;..."锛堢背锛�
      * @param obstaclesCoords 闅滅鐗╁潗鏍囷紝鏀寔澶氫釜鎷彿娈垫垨鍦嗗舰瀹氫箟锛屼緥 "(x1,y1;x2,y2)(cx,cy;px,py)"
-     * @param mowingWidth 鍓茶崏瀹藉害瀛楃涓诧紝绫冲崟浣嶏紝鍏佽淇濈暀涓や綅灏忔暟
-     * @param modeStr 鍓茶崏妯″紡锛�"0"/绌轰负骞宠绾匡紝"1" 鎴� "spiral" 琛ㄧず铻烘棆妯″紡锛堝綋鍓嶄粎骞宠绾垮疄鐜帮級
+     * @param mowingWidth     鍓茶崏瀹藉害瀛楃涓诧紝绫冲崟浣嶏紝鍏佽淇濈暀涓や綅灏忔暟
+     * @param safetyDistStr   瀹夊叏璺濈瀛楃涓诧紝绫冲崟浣嶃��
+     * @param modeStr         鍓茶崏妯″紡锛�"0"/绌轰负骞宠绾匡紝"1" 鎴� "spiral" 琛ㄧず铻烘棆妯″紡锛堝綋鍓嶄粎骞宠绾垮疄鐜帮級
      * @return 杩炵画璺緞鍧愭爣瀛楃涓诧紝椤哄簭绱ц窡鍓茶崏鏈鸿杩涜矾绾�
      */
     public static String generatePathFromStrings(String polygonCoords,
                                                  String obstaclesCoords,
                                                  String mowingWidth,
+                                                 String safetyDistStr,
                                                  String modeStr) {
-        List<PathSegment> segments = generatePathSegments(polygonCoords, obstaclesCoords, mowingWidth, modeStr);
+        List<PathSegment> segments = generatePathSegments(polygonCoords, obstaclesCoords, mowingWidth, safetyDistStr, modeStr);
         return formatPathSegments(segments);
     }
+    
+    /**
+     * 淇濇寔鍚戝悗鍏煎鐨勯噸杞芥柟娉�
+     */
+    public static String generatePathFromStrings(String polygonCoords,
+                                                 String obstaclesCoords,
+                                                 String mowingWidth,
+                                                 String modeStr) {
+        return generatePathFromStrings(polygonCoords, obstaclesCoords, mowingWidth, null, modeStr);
+    }
 
     /**
      * 灏嗚矾寰勬鍒楄〃杞崲涓哄潗鏍囧瓧绗︿覆銆�
@@ -168,7 +195,7 @@
         try {
             return Double.parseDouble(value.trim());
         } catch (NumberFormatException ex) {
-            throw new IllegalArgumentException("鍓茶崏瀹藉害鏍煎紡涓嶆纭�: " + value, ex);
+            throw new IllegalArgumentException("鏍煎紡涓嶆纭�: " + value, ex);
         }
     }
 
@@ -227,7 +254,7 @@
         public boolean isStartPoint;
         public boolean isEndPoint;
 
-        PathSegment(Coordinate start, Coordinate end, boolean isMowing) {
+        public PathSegment(Coordinate start, Coordinate end, boolean isMowing) {
             this.start = start;
             this.end = end;
             this.isMowing = isMowing;
@@ -251,28 +278,53 @@
     /**
      * 鍐呴儴鏍稿績瑙勫垝鍣紝瀹炵幇涓� MowingPathPlanner 绛夋晥鐨勯�昏緫銆�
      */
-    private static final class PlannerCore {
+    static final class PlannerCore {
         private final List<Coordinate> polygon;
         private final double width;
+        private final double safetyDistance; // 鏂板瀹夊叏璺濈瀛楁
         private final String mode;
         private final List<List<Coordinate>> obstacles;
         private final GeometryFactory gf = new GeometryFactory();
 
-        PlannerCore(List<Coordinate> polygon, double width, String mode, List<List<Coordinate>> obstacles) {
+        PlannerCore(List<Coordinate> polygon, double width, double safetyDistance, String mode, List<List<Coordinate>> obstacles) {
             this.polygon = polygon;
             this.width = width;
             this.mode = mode;
             this.obstacles = obstacles != null ? obstacles : new ArrayList<>();
+            
+            // 鍒濆鍖栧畨鍏ㄨ窛绂婚�昏緫
+            if (Double.isNaN(safetyDistance)) {
+                // 濡傛灉鏈彁渚涳紝浣跨敤榛樿鍊硷細瀹藉害鐨勪竴鍗� + 0.05绫�
+                this.safetyDistance = width / 2.0 + 0.05;
+            } else {
+                // 濡傛灉鎻愪緵浜嗭紝浣跨敤鎻愪緵鐨勫�硷紝浣嗚嚦灏戣淇濊瘉鏈哄櫒涓績涓嶇澹侊紙瀹藉害涓�鍗婏級
+                // 鍏佽鐢ㄦ埛璁剧疆姣� width/2 鏇村ぇ鐨勫�兼潵杩滅杈圭晫
+                this.safetyDistance = Math.max(safetyDistance, width / 2.0);
+            }
+        }
+        
+        // 鍏煎鏃ф瀯閫犲嚱鏁�
+        PlannerCore(List<Coordinate> polygon, double width, String mode, List<List<Coordinate>> obstacles) {
+            this(polygon, width, Double.NaN, mode, obstacles);
         }
 
         List<PathSegment> generate() {
+            // 濡傛灉鏈夐殰纰嶇墿锛屼娇鐢ㄥ甫闅滅鐗╅伩璁╃殑璺緞瑙勫垝鍣�
+            if (!obstacles.isEmpty()) {
+                // 浣跨敤璁$畻濂界殑瀹夊叏璺濈
+                ObstaclePathPlanner obstaclePlanner = new ObstaclePathPlanner(
+                    polygon, width, mode, obstacles, this.safetyDistance);
+                return obstaclePlanner.generate();
+            }
+            
+            // 娌℃湁闅滅鐗╂椂浣跨敤鍘熸湁閫昏緫
             if ("spiral".equals(mode)) {
                 return generateSpiralPath();
             }
             return generateParallelPath();
         }
 
-        private List<PathSegment> generateParallelPath() {
+        List<PathSegment> generateParallelPath() {
             List<PathSegment> path = new ArrayList<>();
             Geometry safeArea = buildSafeArea();
             if (safeArea == null || safeArea.isEmpty()) {
@@ -285,7 +337,7 @@
                                             longest.end.y - longest.start.y).normalize();
             Vector2D perp = baseDir.rotate90CCW();
             Vector2D baseStartVec = new Vector2D(longest.start.x, longest.start.y);
-            double baseProjection = perp.dot(baseStartVec); // keep offsets relative to the longest edge start
+            double baseProjection = perp.dot(baseStartVec); 
 
             double minProj = Double.POSITIVE_INFINITY;
             double maxProj = Double.NEGATIVE_INFINITY;
@@ -361,7 +413,7 @@
             return path;
         }
 
-        private List<PathSegment> generateSpiralPath() {
+        List<PathSegment> generateSpiralPath() {
             Geometry safeArea = buildSafeArea();
             if (safeArea == null || safeArea.isEmpty()) {
                 System.err.println("瀹夊叏鍖哄煙涓虹┖锛屾棤娉曠敓鎴愯灪鏃嬭矾寰�");
@@ -418,7 +470,10 @@
                     }
                 }
 
-                Geometry shrunk = shrinkStraight(result, width / 2.0);
+                // 淇敼锛氫娇鐢ㄤ紶鍏ョ殑 safetyDistance 鏉ヨ繘琛岃竟鐣屽唴缂�
+                // 涔嬪墠鏄� width / 2.0锛岀幇鍦ㄤ娇鐢� this.safetyDistance
+                // 杩欑‘淇濅簡璺緞瑙勫垝鍖哄煙涓庤竟鐣屼繚鎸佺敤鎴锋寚瀹氱殑璺濈
+                Geometry shrunk = shrinkStraight(result, this.safetyDistance);
                 return shrunk.isEmpty() ? result : shrunk;
             } catch (Exception ex) {
                 System.err.println("鏋勫缓瀹夊叏鍖哄煙澶辫触: " + ex.getMessage());
@@ -620,4 +675,4 @@
             this.index = index;
         }
     }
-}
+}
\ No newline at end of file

--
Gitblit v1.10.0