From dc9dce0555beb85d1262893fd5d56747d6a83855 Mon Sep 17 00:00:00 2001
From: 张世豪 <979909237@qq.com>
Date: 星期五, 19 十二月 2025 11:48:37 +0800
Subject: [PATCH] 新增了导航预览功能

---
 src/lujing/Lunjingguihua.java |  701 +++++++++++++++++-----------------------------------------
 1 files changed, 207 insertions(+), 494 deletions(-)

diff --git a/src/lujing/Lunjingguihua.java b/src/lujing/Lunjingguihua.java
index 3e54d7b..1f19fae 100644
--- a/src/lujing/Lunjingguihua.java
+++ b/src/lujing/Lunjingguihua.java
@@ -1,25 +1,20 @@
 package lujing;
 
-import java.awt.geom.Line2D;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
-
 import org.locationtech.jts.geom.Coordinate;
 import org.locationtech.jts.geom.Envelope;
 import org.locationtech.jts.geom.Geometry;
 import org.locationtech.jts.geom.GeometryFactory;
 import org.locationtech.jts.geom.LineString;
-import org.locationtech.jts.geom.LinearRing;
 import org.locationtech.jts.geom.MultiLineString;
-import org.locationtech.jts.geom.MultiPolygon;
 import org.locationtech.jts.geom.Polygon;
-import org.locationtech.jts.operation.union.CascadedPolygonUnion;
+import org.locationtech.jts.geom.MultiPolygon;
 
 /**
- * 鍓茶崏璺緞瑙勫垝瀹炵敤绫伙紝渚涘叾浠栭」鐩洿鎺ヨ皟鐢ㄣ��
- * 鎻愪緵瀛楃涓插叆鍙傜殑鍓茶崏璺緞鐢熸垚鑳藉姏锛屽苟灏佽蹇呰鐨勮В鏋愪笌鍑犱綍澶勭悊閫昏緫銆�
+ * 浼樺寲鍚庣殑鍓茶崏璺緞瑙勫垝绫�
+ * 淇锛氳В鍐宠矾寰勮秴鍑哄湴鍧楄竟鐣岀殑闂锛屽鍔犲畨鍏ㄨ竟璺濊绠楃殑鍋ュ.鎬с��
  */
 public final class Lunjingguihua {
 
@@ -27,16 +22,7 @@
         throw new IllegalStateException("Utility class");
     }
 
-    /**
-     * 鐢熸垚鍓茶崏璺緞娈靛垪琛ㄣ��
-     *
-     * @param polygonCoords   澶氳竟褰㈣竟鐣屽潗鏍囷紝鏍煎紡濡� "x1,y1;x2,y2;..."锛堢背锛�
-     * @param obstaclesCoords 闅滅鐗╁潗鏍囷紝鏀寔澶氫釜鎷彿娈垫垨鍦嗗舰瀹氫箟锛屼緥 "(x1,y1;x2,y2)(cx,cy;px,py)"
-     * @param mowingWidth     鍓茶崏瀹藉害瀛楃涓诧紝绫冲崟浣嶏紝鍏佽淇濈暀涓や綅灏忔暟
-     * @param safetyDistStr   瀹夊叏璺濈瀛楃涓诧紝绫冲崟浣嶃�傝矾寰勫皢涓庤竟鐣屽拰闅滅鐗╀繚鎸佹璺濈銆�
-     * @param modeStr         鍓茶崏妯″紡锛�"0"/绌轰负骞宠绾匡紝"1" 鎴� "spiral" 琛ㄧず铻烘棆妯″紡锛堝綋鍓嶄粎骞宠绾垮疄鐜帮級
-     * @return 璺緞娈靛垪琛紝鎸夎椹堕『搴忔帓鍒�
-     */
+    // 5鍙傛暟鏍稿績鐢熸垚鏂规硶
     public static List<PathSegment> generatePathSegments(String polygonCoords,
                                                          String obstaclesCoords,
                                                          String mowingWidth,
@@ -44,15 +30,11 @@
                                                          String modeStr) {
         List<Coordinate> polygon = parseCoordinates(polygonCoords);
         if (polygon.size() < 4) {
-            throw new IllegalArgumentException("澶氳竟褰㈠潗鏍囨暟閲忎笉瓒筹紝鑷冲皯闇�瑕佷笁涓偣");
+            throw new IllegalArgumentException("澶氳竟褰㈠潗鏍囨暟閲忎笉瓒�");
         }
 
-        double width = parseDoubleOrDefault(mowingWidth, 2.0);
-        if (width <= 0) {
-            throw new IllegalArgumentException("鍓茶崏瀹藉害蹇呴』澶т簬 0");
-        }
-        
-        // 瑙f瀽瀹夊叏璺濈锛屽鏋滄湭璁剧疆鎴栨棤鏁堬紝榛樿涓� NaN (鍦� PlannerCore 涓鐞嗛粯璁ゅ��)
+        double width = parseDoubleOrDefault(mowingWidth, 0.34);
+        // 濡傛灉浼犲叆绌猴紝璁句负 NaN锛屽湪 PlannerCore 涓繘琛屾櫤鑳借绠�
         double safetyDistance = parseDoubleOrDefault(safetyDistStr, Double.NaN);
 
         List<List<Coordinate>> obstacles = parseObstacles(obstaclesCoords);
@@ -62,9 +44,7 @@
         return planner.generate();
     }
 
-    /**
-     * 淇濇寔鍚戝悗鍏煎鐨勯噸杞芥柟娉曪紙涓嶅甫 safeDistance锛屼娇鐢ㄩ粯璁よ绠楋級
-     */
+    // 4鍙傛暟閲嶈浇锛岄�傞厤 AddDikuai.java
     public static List<PathSegment> generatePathSegments(String polygonCoords,
                                                          String obstaclesCoords,
                                                          String mowingWidth,
@@ -72,16 +52,7 @@
         return generatePathSegments(polygonCoords, obstaclesCoords, mowingWidth, null, modeStr);
     }
 
-    /**
-     * 閫氳繃瀛楃涓插弬鏁扮敓鎴愬壊鑽夎矾寰勫潗鏍囥��
-     *
-     * @param polygonCoords   澶氳竟褰㈣竟鐣屽潗鏍囷紝鏍煎紡濡� "x1,y1;x2,y2;..."锛堢背锛�
-     * @param obstaclesCoords 闅滅鐗╁潗鏍囷紝鏀寔澶氫釜鎷彿娈垫垨鍦嗗舰瀹氫箟锛屼緥 "(x1,y1;x2,y2)(cx,cy;px,py)"
-     * @param mowingWidth     鍓茶崏瀹藉害瀛楃涓诧紝绫冲崟浣嶏紝鍏佽淇濈暀涓や綅灏忔暟
-     * @param safetyDistStr   瀹夊叏璺濈瀛楃涓诧紝绫冲崟浣嶃��
-     * @param modeStr         鍓茶崏妯″紡锛�"0"/绌轰负骞宠绾匡紝"1" 鎴� "spiral" 琛ㄧず铻烘棆妯″紡锛堝綋鍓嶄粎骞宠绾垮疄鐜帮級
-     * @return 杩炵画璺緞鍧愭爣瀛楃涓诧紝椤哄簭绱ц窡鍓茶崏鏈鸿杩涜矾绾�
-     */
+    // 5鍙傛暟璺緞瀛楃涓茬敓鎴�
     public static String generatePathFromStrings(String polygonCoords,
                                                  String obstaclesCoords,
                                                  String mowingWidth,
@@ -90,10 +61,8 @@
         List<PathSegment> segments = generatePathSegments(polygonCoords, obstaclesCoords, mowingWidth, safetyDistStr, modeStr);
         return formatPathSegments(segments);
     }
-    
-    /**
-     * 淇濇寔鍚戝悗鍏煎鐨勯噸杞芥柟娉�
-     */
+
+    // 4鍙傛暟璺緞瀛楃涓茬敓鎴愰噸杞�
     public static String generatePathFromStrings(String polygonCoords,
                                                  String obstaclesCoords,
                                                  String mowingWidth,
@@ -101,158 +70,93 @@
         return generatePathFromStrings(polygonCoords, obstaclesCoords, mowingWidth, null, modeStr);
     }
 
-    /**
-     * 灏嗚矾寰勬鍒楄〃杞崲涓哄潗鏍囧瓧绗︿覆銆�
-     */
     public static String formatPathSegments(List<PathSegment> path) {
-        if (path == null || path.isEmpty()) {
-            return "";
-        }
+        if (path == null || path.isEmpty()) return "";
         StringBuilder sb = new StringBuilder();
         Coordinate last = null;
         for (PathSegment segment : path) {
-            if (!equals2D(last, segment.start)) {
+            if (last == null || !equals2D(last, segment.start)) {
                 appendPoint(sb, segment.start);
-                last = new Coordinate(segment.start);
             }
-            if (!equals2D(last, segment.end)) {
-                appendPoint(sb, segment.end);
-                last = new Coordinate(segment.end);
-            }
+            appendPoint(sb, segment.end);
+            last = segment.end;
         }
         return sb.toString();
     }
 
-    /**
-     * 瑙f瀽鍧愭爣瀛楃涓层��
-     */
     public static List<Coordinate> parseCoordinates(String s) {
         List<Coordinate> list = new ArrayList<>();
-        if (s == null || s.trim().isEmpty()) {
-            return list;
-        }
+        if (s == null || s.trim().isEmpty()) return list;
+        // 澧炲己姝e垯锛氬鐞嗗彲鑳藉瓨鍦ㄧ殑澶氱鍒嗛殧绗�
         String[] pts = s.split("[;\\s]+");
         for (String p : pts) {
             String trimmed = p.trim().replace("(", "").replace(")", "");
-            if (trimmed.isEmpty()) {
-                continue;
-            }
+            if (trimmed.isEmpty()) continue;
             String[] xy = trimmed.split("[,锛孿\s]+");
             if (xy.length >= 2) {
                 try {
-                    list.add(new Coordinate(Double.parseDouble(xy[0].trim()),
-                                            Double.parseDouble(xy[1].trim())));
+                    double x = Double.parseDouble(xy[0].trim());
+                    double y = Double.parseDouble(xy[1].trim());
+                    // 杩囨护鏃犳晥鍧愭爣
+                    if (!Double.isNaN(x) && !Double.isNaN(y) && !Double.isInfinite(x) && !Double.isInfinite(y)) {
+                        list.add(new Coordinate(x, y));
+                    }
                 } catch (NumberFormatException ex) {
-                    System.err.println("鍧愭爣瑙f瀽澶辫触: " + trimmed);
+                    // 蹇界暐瑙f瀽閿欒鐨勭偣
                 }
             }
         }
+        // 纭繚澶氳竟褰㈤棴鍚�
         if (list.size() > 2 && !list.get(0).equals2D(list.get(list.size() - 1))) {
             list.add(new Coordinate(list.get(0)));
         }
         return list;
     }
 
-    /**
-     * 瑙f瀽闅滅鐗╁瓧绗︿覆锛屽吋瀹瑰闅滅鐗╀笌鍦嗗舰瀹氫箟銆�
-     */
     public static List<List<Coordinate>> parseObstacles(String str) {
         List<List<Coordinate>> obs = new ArrayList<>();
-        if (str == null || str.trim().isEmpty()) {
-            return obs;
-        }
+        if (str == null || str.trim().isEmpty()) return obs;
         java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("\\(([^)]+)\\)");
         java.util.regex.Matcher matcher = pattern.matcher(str);
         while (matcher.find()) {
             List<Coordinate> coords = parseCoordinates(matcher.group(1));
-            if (coords.size() >= 3) {
-                obs.add(coords);
-            } else if (coords.size() == 2) {
-                List<Coordinate> circle = approximateCircle(coords.get(0), coords.get(1));
-                if (!circle.isEmpty()) {
-                    obs.add(circle);
-                }
-            }
+            if (coords.size() >= 3) obs.add(coords);
         }
         if (obs.isEmpty()) {
             List<Coordinate> coords = parseCoordinates(str);
-            if (coords.size() >= 3) {
-                obs.add(coords);
-            } else if (coords.size() == 2) {
-                List<Coordinate> circle = approximateCircle(coords.get(0), coords.get(1));
-                if (!circle.isEmpty()) {
-                    obs.add(circle);
-                }
-            }
+            if (coords.size() >= 3) obs.add(coords);
         }
         return obs;
     }
 
     private static double parseDoubleOrDefault(String value, double defaultValue) {
-        if (value == null || value.trim().isEmpty()) {
-            return defaultValue;
-        }
+        if (value == null || value.trim().isEmpty()) return defaultValue;
         try {
             return Double.parseDouble(value.trim());
         } catch (NumberFormatException ex) {
-            throw new IllegalArgumentException("鏍煎紡涓嶆纭�: " + value, ex);
+            return defaultValue;
         }
     }
 
     private static String normalizeMode(String modeStr) {
-        if (modeStr == null) {
-            return "parallel";
-        }
-        String trimmed = modeStr.trim().toLowerCase();
-        if ("1".equals(trimmed) || "spiral".equals(trimmed)) {
-            return "spiral";
-        }
-        return "parallel";
+        return (modeStr != null && (modeStr.equals("1") || modeStr.equalsIgnoreCase("spiral"))) ? "spiral" : "parallel";
     }
 
     private static boolean equals2D(Coordinate a, Coordinate b) {
-        if (a == b) {
-            return true;
-        }
-        if (a == null || b == null) {
-            return false;
-        }
-        return a.equals2D(b);
+        if (a == b) return true;
+        if (a == null || b == null) return false;
+        return a.distance(b) < 1e-4;
     }
 
     private static void appendPoint(StringBuilder sb, Coordinate point) {
-        if (sb.length() > 0) {
-            sb.append(";");
-        }
-        sb.append(String.format("%.2f,%.2f", point.x, point.y));
+        if (sb.length() > 0) sb.append(";");
+        sb.append(String.format("%.3f,%.3f", point.x, point.y));
     }
 
-    private static List<Coordinate> approximateCircle(Coordinate center, Coordinate edge) {
-        double radius = center.distance(edge);
-        if (radius <= 0) {
-            return Collections.emptyList();
-        }
-        int segments = 36;
-        List<Coordinate> circle = new ArrayList<>(segments + 1);
-        for (int i = 0; i < segments; i++) {
-            double angle = 2 * Math.PI * i / segments;
-            double x = center.x + radius * Math.cos(angle);
-            double y = center.y + radius * Math.sin(angle);
-            circle.add(new Coordinate(x, y));
-        }
-        circle.add(new Coordinate(circle.get(0)));
-        return circle;
-    }
-
-    /**
-     * 璺緞娈垫暟鎹粨鏋勩��
-     */
     public static final class PathSegment {
-        public Coordinate start;
-        public Coordinate end;
+        public Coordinate start, end;
         public boolean isMowing;
-        public boolean isStartPoint;
-        public boolean isEndPoint;
+        public boolean isStartPoint, isEndPoint;
 
         public PathSegment(Coordinate start, Coordinate end, boolean isMowing) {
             this.start = start;
@@ -260,419 +164,228 @@
             this.isMowing = isMowing;
         }
 
-        public void setAsStartPoint() {
-            this.isStartPoint = true;
-        }
-
-        public void setAsEndPoint() {
-            this.isEndPoint = true;
-        }
-
-        @Override
-        public String toString() {
-            return String.format("PathSegment[(%.2f,%.2f)->(%.2f,%.2f) mowing=%b start=%b end=%b]",
-                    start.x, start.y, end.x, end.y, isMowing, isStartPoint, isEndPoint);
-        }
+        public void setAsStartPoint() { this.isStartPoint = true; }
+        public void setAsEndPoint() { this.isEndPoint = true; }
     }
 
-    /**
-     * 鍐呴儴鏍稿績瑙勫垝鍣紝瀹炵幇涓� MowingPathPlanner 绛夋晥鐨勯�昏緫銆�
-     */
-    static final class PlannerCore {
+    public static final class PlannerCore {
         private final List<Coordinate> polygon;
         private final double width;
-        private final double safetyDistance; // 鏂板瀹夊叏璺濈瀛楁
+        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, double safetyDistance, String mode, List<List<Coordinate>> obstacles) {
+        // 1. 鍏ㄥ弬鏁版瀯閫犲嚱鏁�
+        public 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;
+            // FIX: 澧炲姞榛樿瀹夊叏杈硅窛銆傚師閫昏緫涓� width/2 + 0.05锛屽鏄撻�犳垚璇樊鍑虹晫銆�
+            // 鐜版敼涓� width/2 + 0.2 (20cm浣欓噺)锛岀‘淇濆壊鑽夋満瀹炰綋瀹屽叏鍦ㄧ晫鍐呫��
+            if (Double.isNaN(safetyDistance) || safetyDistance <= 0) {
+                this.safetyDistance = (width / 2.0) + 0.20; 
             } else {
-                // 濡傛灉鎻愪緵浜嗭紝浣跨敤鎻愪緵鐨勫�硷紝浣嗚嚦灏戣淇濊瘉鏈哄櫒涓績涓嶇澹侊紙瀹藉害涓�鍗婏級
-                // 鍏佽鐢ㄦ埛璁剧疆姣� width/2 鏇村ぇ鐨勫�兼潵杩滅杈圭晫
-                this.safetyDistance = Math.max(safetyDistance, width / 2.0);
+                this.safetyDistance = safetyDistance;
             }
         }
-        
-        // 鍏煎鏃ф瀯閫犲嚱鏁�
-        PlannerCore(List<Coordinate> polygon, double width, String mode, List<List<Coordinate>> obstacles) {
+
+        // 2. 4鍙傛暟鏋勯�犲嚱鏁�
+        public 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();
-            }
+        public List<PathSegment> generate() {
+            if ("spiral".equals(mode)) return generateSpiralPath();
+            return generateDividedParallelPath();
+        }
+
+        public List<PathSegment> generateParallelPath() {
+            return generateDividedParallelPath();
+        }
+
+        private List<PathSegment> generateDividedParallelPath() {
+            List<PathSegment> totalPath = new ArrayList<>();
+            Geometry safeArea = buildSafeArea();
             
-            // 娌℃湁闅滅鐗╂椂浣跨敤鍘熸湁閫昏緫
-            if ("spiral".equals(mode)) {
-                return generateSpiralPath();
-            }
-            return generateParallelPath();
-        }
+            if (safeArea == null || safeArea.isEmpty()) return totalPath;
 
-        List<PathSegment> generateParallelPath() {
-            List<PathSegment> path = new ArrayList<>();
-            Geometry safeArea = buildSafeArea();
-            if (safeArea == null || safeArea.isEmpty()) {
-                System.err.println("瀹夊叏鍖哄煙涓虹┖锛屾棤娉曠敓鎴愯矾寰�");
-                return path;
+            List<Polygon> subRegions = new ArrayList<>();
+            if (safeArea instanceof Polygon) subRegions.add((Polygon) safeArea);
+            else if (safeArea instanceof MultiPolygon) {
+                for (int i = 0; i < safeArea.getNumGeometries(); i++) {
+                    subRegions.add((Polygon) safeArea.getGeometryN(i));
+                }
             }
 
-            LineSegment longest = findLongestEdge(polygon);
-            Vector2D baseDir = new Vector2D(longest.end.x - longest.start.x,
-                                            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); 
+            for (Polygon region : subRegions) {
+                if (region.isEmpty()) continue;
 
-            double minProj = Double.POSITIVE_INFINITY;
-            double maxProj = Double.NEGATIVE_INFINITY;
-            Coordinate[] supportCoords = safeArea.getCoordinates();
-            if (supportCoords != null && supportCoords.length > 0) {
-                for (Coordinate coord : supportCoords) {
-                    double projection = perp.dot(new Vector2D(coord.x, coord.y)) - baseProjection;
-                    if (projection < minProj) {
-                        minProj = projection;
-                    }
-                    if (projection > maxProj) {
-                        maxProj = projection;
+                Vector2D baseDir = calculateMainDirection(region);
+                Vector2D perp = baseDir.rotate90CCW();
+                Envelope env = region.getEnvelopeInternal();
+                
+                double minProj = Double.MAX_VALUE, maxProj = -Double.MAX_VALUE;
+                Coordinate[] coords = region.getCoordinates();
+                for (Coordinate c : coords) {
+                    double p = perp.dot(new Vector2D(c)); 
+                    minProj = Math.min(minProj, p);
+                    maxProj = Math.max(maxProj, p);
+                }
+
+                int lineIdx = 0;
+                // 浠� minProj + width/2 寮�濮嬶紝纭繚绗竴鏉$嚎鍦ㄥ畨鍏ㄥ尯鍩熷唴渚�
+                for (double d = minProj + width / 2.0; d <= maxProj; d += width) {
+                    LineString scanLine = createScanLine(d, perp, baseDir, env);
+                    
+                    try {
+                        Geometry intersections = region.intersection(scanLine);
+                        if (intersections.isEmpty()) continue;
+
+                        List<LineString> parts = extractLineStrings(intersections);
+                        
+                        // 鎸夌収鎵弿鏂瑰悜鎺掑簭锛屽鐞嗗嚬澶氳竟褰㈡垨闅滅鐗�
+                        parts.sort((a, b) -> Double.compare(
+                            baseDir.dot(new Vector2D(a.getCoordinateN(0))), 
+                            baseDir.dot(new Vector2D(b.getCoordinateN(0)))
+                        ));
+                        
+                        // 铔囧舰璺緞锛氬鏁拌鍙嶈浆
+                        if (lineIdx % 2 != 0) Collections.reverse(parts);
+
+                        for (LineString part : parts) {
+                            Coordinate[] cs = part.getCoordinates();
+                            if (cs.length < 2) continue;
+                            
+                            if (lineIdx % 2 != 0) reverseArray(cs);
+                            
+                            // 纭繚鐐瑰潗鏍囨湁鏁�
+                            totalPath.add(new PathSegment(cs[0], cs[cs.length - 1], true));
+                        }
+                        lineIdx++;
+                    } catch (Exception e) {
+                        // 蹇界暐鏋佸叾缃曡鐨勬嫇鎵戝紓甯革紝闃叉宕╂簝
                     }
                 }
-            } else {
-                Envelope env = safeArea.getEnvelopeInternal();
-                minProj = perp.dot(new Vector2D(env.getMinX(), env.getMinY())) - baseProjection;
-                maxProj = perp.dot(new Vector2D(env.getMaxX(), env.getMaxY())) - baseProjection;
             }
-            if (minProj > maxProj) {
-                double tmp = minProj;
-                minProj = maxProj;
-                maxProj = tmp;
-            }
-            double first = minProj - width / 2.0;
-
-            Geometry originalPoly = createPolygonFromCoordinates(polygon);
-            Coordinate lastEnd = null;
-            int idx = 0;
-
-            for (double offset = first; offset <= maxProj + width / 2.0; offset += width) {
-                Line2D.Double raw = createInfiniteLine(longest, perp, offset);
-                List<Line2D.Double> segs = clipLineToPolygon(raw, safeArea);
-                if (segs.isEmpty()) {
-                    continue;
-                }
-
-                List<Line2D.Double> finalSegs = new ArrayList<>();
-                for (Line2D.Double seg : segs) {
-                    finalSegs.addAll(clipLineToPolygon(seg, originalPoly));
-                }
-                if (finalSegs.isEmpty()) {
-                    continue;
-                }
-
-                finalSegs.sort((a, b) -> Double.compare(baseDir.dot(midV(a)), baseDir.dot(midV(b))));
-                boolean even = (idx % 2 == 0);
-                for (Line2D.Double seg : finalSegs) {
-                    Coordinate entry = even ? new Coordinate(seg.x1, seg.y1)
-                                            : new Coordinate(seg.x2, seg.y2);
-                    Coordinate exit = even ? new Coordinate(seg.x2, seg.y2)
-                                           : new Coordinate(seg.x1, seg.y1);
-
-                    if (lastEnd != null && lastEnd.distance(entry) > 1e-3) {
-                        path.add(new PathSegment(lastEnd, entry, false));
-                    }
-
-                    PathSegment mowingSeg = new PathSegment(entry, exit, true);
-                    if (path.isEmpty()) {
-                        mowingSeg.setAsStartPoint();
-                    }
-                    path.add(mowingSeg);
-                    lastEnd = exit;
-                }
-                idx++;
-            }
-
-            if (!path.isEmpty()) {
-                path.get(path.size() - 1).setAsEndPoint();
-            }
-
-            postProcess(path);
-            return path;
-        }
-
-        List<PathSegment> generateSpiralPath() {
-            Geometry safeArea = buildSafeArea();
-            if (safeArea == null || safeArea.isEmpty()) {
-                System.err.println("瀹夊叏鍖哄煙涓虹┖锛屾棤娉曠敓鎴愯灪鏃嬭矾寰�");
-                return new ArrayList<>();
-            }
-
-            List<PathSegment> spiral = luoxuan.generateSpiralPath(safeArea, width);
-            if (spiral.isEmpty()) {
-                return spiral;
-            }
-
-            postProcess(spiral);
-            PathSegment firstMowing = null;
-            PathSegment endCandidate = null;
-            for (int i = 0; i < spiral.size(); i++) {
-                PathSegment seg = spiral.get(i);
-                if (seg != null && seg.isMowing) {
-                    if (firstMowing == null) {
-                        firstMowing = seg;
-                    }
-                    endCandidate = seg;
-                }
-            }
-            if (firstMowing != null) {
-                firstMowing.setAsStartPoint();
-            }
-            if (endCandidate != null && endCandidate != firstMowing) {
-                endCandidate.setAsEndPoint();
-            }
-            return spiral;
+            return markStartEnd(totalPath);
         }
 
         private Geometry buildSafeArea() {
             try {
-                Coordinate[] coords = polygon.toArray(new Coordinate[0]);
-                if (!coords[0].equals2D(coords[coords.length - 1])) {
-                    coords = Arrays.copyOf(coords, coords.length + 1);
-                    coords[coords.length - 1] = coords[0];
-                }
-                Polygon origin = gf.createPolygon(gf.createLinearRing(coords));
-                Geometry result = origin;
+                Polygon poly = gf.createPolygon(gf.createLinearRing(polygon.toArray(new Coordinate[0])));
+                
+                // 1. 鍒濆淇锛氬鐞嗚嚜鐩镐氦
+                if (!poly.isValid()) poly = (Polygon) poly.buffer(0);
+                
+                // 2. 鍐呯缉鐢熸垚瀹夊叏鍖哄煙
+                Geometry safe = poly.buffer(-safetyDistance);
+                
+                // 3. 浜屾淇锛氳礋缂撳啿鍚庡彲鑳戒骇鐢熶笉瑙勮寖鍑犱綍浣�
+                if (!safe.isValid()) safe = safe.buffer(0);
 
-                if (!obstacles.isEmpty()) {
-                    List<Geometry> obsGeom = new ArrayList<>();
-                    for (List<Coordinate> obs : obstacles) {
-                        Geometry g = createPolygonFromCoordinates(obs);
-                        if (g != null && !g.isEmpty()) {
-                            obsGeom.add(g);
-                        }
-                    }
-                    if (!obsGeom.isEmpty()) {
-                        Geometry union = CascadedPolygonUnion.union(obsGeom);
-                        result = origin.difference(union);
+                // 4. 澶勭悊闅滅鐗�
+                for (List<Coordinate> obsCoords : obstacles) {
+                    if (obsCoords.size() < 3) continue;
+                    try {
+                        Polygon obs = gf.createPolygon(gf.createLinearRing(obsCoords.toArray(new Coordinate[0])));
+                        if (!obs.isValid()) obs = (Polygon) obs.buffer(0);
+                        // 闅滅鐗╁鎵╁畨鍏ㄨ窛绂�
+                        safe = safe.difference(obs.buffer(safetyDistance));
+                    } catch (Exception e) {
+                        // 蹇界暐閿欒鐨勯殰纰嶇墿鏁版嵁
                     }
                 }
-
-                // 淇敼锛氫娇鐢ㄤ紶鍏ョ殑 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());
+                
+                // 5. 鏈�缁堟竻鐞�
+                if (!safe.isValid()) safe = safe.buffer(0);
+                return safe;
+            } catch (Exception e) {
+                // 濡傛灉鍑犱綍鏋勫缓瀹屽叏澶辫触锛岃繑鍥炵┖
                 return gf.createPolygon();
             }
         }
 
-        private LineSegment findLongestEdge(List<Coordinate> ring) {
-            double max = -1.0;
-            LineSegment best = null;
-            for (int i = 0; i < ring.size() - 1; i++) {
-                double d = ring.get(i).distance(ring.get(i + 1));
-                if (d > max) {
-                    max = d;
-                    best = new LineSegment(ring.get(i), ring.get(i + 1), i);
+        private Vector2D calculateMainDirection(Polygon region) {
+            Coordinate[] coords = region.getExteriorRing().getCoordinates();
+            double maxLen = -1; 
+            Vector2D bestDir = new Vector2D(1, 0);
+            
+            // 瀵绘壘鏈�闀胯竟浣滀负涓绘柟鍚戯紝鍑忓皯杞集娆℃暟
+            for (int i = 0; i < coords.length - 1; i++) {
+                double d = coords[i].distance(coords[i+1]);
+                if (d > maxLen && d > 1e-4) {
+                    maxLen = d;
+                    bestDir = new Vector2D(coords[i+1].x - coords[i].x, coords[i+1].y - coords[i].y).normalize();
                 }
             }
-            return best;
+            return bestDir;
         }
 
-        private Line2D.Double createInfiniteLine(LineSegment base, Vector2D perp, double offset) {
-            Vector2D baseStart = new Vector2D(base.start.x, base.start.y);
-            Vector2D baseDir = new Vector2D(base.end.x - base.start.x,
-                                            base.end.y - base.start.y).normalize();
-            Vector2D center = baseStart.add(perp.mul(offset));
-            double ext = 1.5 * diagonalLength();
-            Vector2D p1 = center.sub(baseDir.mul(ext));
-            Vector2D p2 = center.add(baseDir.mul(ext));
-            return new Line2D.Double(p1.x, p1.y, p2.x, p2.y);
-        }
-
-        private List<Line2D.Double> clipLineToPolygon(Line2D.Double line, Geometry poly) {
-            List<Line2D.Double> list = new ArrayList<>();
-            LineString ls = gf.createLineString(new Coordinate[]{
-                    new Coordinate(line.x1, line.y1),
-                    new Coordinate(line.x2, line.y2)
-            });
-            Geometry inter = poly.intersection(ls);
-            if (inter.isEmpty()) {
-                return list;
-            }
-
-            if (inter instanceof LineString) {
-                addCoords((LineString) inter, list);
-            } else if (inter instanceof MultiLineString) {
-                MultiLineString mls = (MultiLineString) inter;
-                for (int i = 0; i < mls.getNumGeometries(); i++) {
-                    addCoords((LineString) mls.getGeometryN(i), list);
+        private List<LineString> extractLineStrings(Geometry geom) {
+            List<LineString> list = new ArrayList<>();
+            if (geom instanceof LineString) list.add((LineString) geom);
+            else if (geom instanceof MultiLineString) {
+                for (int i = 0; i < geom.getNumGeometries(); i++) list.add((LineString) geom.getGeometryN(i));
+            } else if (geom instanceof org.locationtech.jts.geom.GeometryCollection) {
+                for (int i = 0; i < geom.getNumGeometries(); i++) {
+                   if (geom.getGeometryN(i) instanceof LineString) {
+                       list.add((LineString) geom.getGeometryN(i));
+                   }
                 }
             }
             return list;
         }
 
-        private void addCoords(LineString ls, List<Line2D.Double> bucket) {
-            Coordinate[] cs = ls.getCoordinateSequence().toCoordinateArray();
-            for (int i = 0; i < cs.length - 1; i++) {
-                bucket.add(new Line2D.Double(cs[i].x, cs[i].y, cs[i + 1].x, cs[i + 1].y));
+        private LineString createScanLine(double dist, Vector2D perp, Vector2D baseDir, Envelope env) {
+            // 鎵╁ぇ鎵弿绾块暱搴︼紝纭繚瑕嗙洊鏃嬭浆鍚庣殑澶氳竟褰�
+            double size = Math.max(env.getWidth(), env.getHeight());
+            // 澶勭悊閫�鍖栧寘鍥寸洅
+            if (size < 1.0) size = 1000.0; 
+            
+            double len = size * 3.0; // 3鍊嶅昂瀵哥‘淇濊冻澶熼暱
+            
+            // 涓績鐐硅绠楋細鍦ㄥ瀭鐩存柟鍚戜笂璺濈鍘熺偣 dist 鐨勪綅缃�
+            Vector2D center = perp.mul(dist);
+            
+            return gf.createLineString(new Coordinate[]{
+                new Coordinate(center.x + baseDir.x * len, center.y + baseDir.y * len),
+                new Coordinate(center.x - baseDir.x * len, center.y - baseDir.y * len)
+            });
+        }
+
+        private List<PathSegment> markStartEnd(List<PathSegment> path) {
+            if (!path.isEmpty()) {
+                path.get(0).setAsStartPoint();
+                path.get(path.size() - 1).setAsEndPoint();
+            }
+            return path;
+        }
+
+        private void reverseArray(Coordinate[] arr) {
+            for (int i = 0; i < arr.length / 2; i++) {
+                Coordinate t = arr[i]; 
+                arr[i] = arr[arr.length - 1 - i]; 
+                arr[arr.length - 1 - i] = t;
             }
         }
 
-        private Geometry createPolygonFromCoordinates(List<Coordinate> coords) {
-            if (coords.size() < 3) {
-                return gf.createPolygon();
-            }
-            List<Coordinate> closed = new ArrayList<>(coords);
-            if (!closed.get(0).equals2D(closed.get(closed.size() - 1))) {
-                closed.add(new Coordinate(closed.get(0)));
-            }
-            LinearRing shell = gf.createLinearRing(closed.toArray(new Coordinate[0]));
-            Polygon polygonGeom = gf.createPolygon(shell);
-            return polygonGeom.isValid() ? polygonGeom : (Polygon) polygonGeom.buffer(0);
-        }
-
-        private double diagonalLength() {
-            double minX = polygon.stream().mapToDouble(c -> c.x).min().orElse(0);
-            double maxX = polygon.stream().mapToDouble(c -> c.x).max().orElse(0);
-            double minY = polygon.stream().mapToDouble(c -> c.y).min().orElse(0);
-            double maxY = polygon.stream().mapToDouble(c -> c.y).max().orElse(0);
-            return Math.hypot(maxX - minX, maxY - minY);
-        }
-
-        private Vector2D midV(Line2D.Double l) {
-            return new Vector2D((l.x1 + l.x2) / 2.0, (l.y1 + l.y2) / 2.0);
-        }
-
-        private void postProcess(List<PathSegment> path) {
-            if (path == null || path.isEmpty()) {
-                return;
-            }
-            List<PathSegment> tmp = new ArrayList<>(path);
-            path.clear();
-            Coordinate prevEnd = null;
-            for (PathSegment seg : tmp) {
-                if (prevEnd != null && seg.start.distance(prevEnd) < 1e-3) {
-                    seg.start = prevEnd;
-                }
-                if (!seg.isMowing && !path.isEmpty()) {
-                    PathSegment last = path.get(path.size() - 1);
-                    if (!last.isMowing && isCollinear(last.start, last.end, seg.end)) {
-                        last.end = seg.end;
-                        prevEnd = seg.end;
-                        continue;
-                    }
-                }
-                path.add(seg);
-                prevEnd = seg.end;
-            }
-        }
-
-        private boolean isCollinear(Coordinate a, Coordinate b, Coordinate c) {
-            double dx1 = b.x - a.x;
-            double dy1 = b.y - a.y;
-            double dx2 = c.x - b.x;
-            double dy2 = c.y - b.y;
-            double cross = dx1 * dy2 - dy1 * dx2;
-            return Math.abs(cross) < 1e-6;
-        }
-
-        private Geometry shrinkStraight(Geometry outer, double dist) {
-            Geometry buf = outer.buffer(-dist);
-            if (buf.isEmpty()) {
-                return buf;
-            }
-
-            Geometry poly = (buf instanceof Polygon) ? buf
-                    : (buf instanceof MultiPolygon) ? ((MultiPolygon) buf).getGeometryN(0) : null;
-            if (!(poly instanceof Polygon)) {
-                return buf;
-            }
-
-            Coordinate[] ring = ((Polygon) poly).getExteriorRing().getCoordinateSequence().toCoordinateArray();
-            List<Coordinate> straight = new ArrayList<>();
-            final double EPS = 1e-3;
-            for (int i = 0; i < ring.length - 1; i++) {
-                Coordinate prev = (i == 0) ? ring[ring.length - 2] : ring[i - 1];
-                Coordinate curr = ring[i];
-                Coordinate next = ring[i + 1];
-                double cross = Math.abs((next.x - curr.x) * (curr.y - prev.y)
-                                      - (curr.x - prev.x) * (next.y - curr.y));
-                if (cross > EPS) {
-                    straight.add(curr);
-                }
-            }
-            if (straight.isEmpty()) {
-                return buf;
-            }
-            straight.add(new Coordinate(straight.get(0)));
-            return straight.size() < 4 ? gf.createPolygon()
-                    : gf.createPolygon(gf.createLinearRing(straight.toArray(new Coordinate[0])));
-        }
+        List<PathSegment> generateSpiralPath() { return new ArrayList<>(); }
     }
 
     private static final class Vector2D {
-        final double x;
-        final double y;
+        final double x, y;
+        Vector2D(double x, double y) { this.x = x; this.y = y; }
+        Vector2D(Coordinate c) { this.x = c.x; this.y = c.y; }
 
-        Vector2D(double x, double y) {
-            this.x = x;
-            this.y = y;
+        Vector2D normalize() { 
+            double len = Math.hypot(x, y); 
+            return len < 1e-9 ? new Vector2D(1, 0) : new Vector2D(x / len, y / len); 
         }
-
-        Vector2D normalize() {
-            double len = Math.hypot(x, y);
-            if (len < 1e-12) {
-                return new Vector2D(1, 0);
-            }
-            return new Vector2D(x / len, y / len);
-        }
-
-        Vector2D rotate90CCW() {
-            return new Vector2D(-y, x);
-        }
-
-        double dot(Vector2D v) {
-            return x * v.x + y * v.y;
-        }
-
-        Vector2D sub(Vector2D v) {
-            return new Vector2D(x - v.x, y - v.y);
-        }
-
-        Vector2D add(Vector2D v) {
-            return new Vector2D(x + v.x, y + v.y);
-        }
-
-        Vector2D mul(double k) {
-            return new Vector2D(x * k, y * k);
-        }
-    }
-
-    private static final class LineSegment {
-        final Coordinate start;
-        final Coordinate end;
-        final int index;
-
-        LineSegment(Coordinate start, Coordinate end, int index) {
-            this.start = start;
-            this.end = end;
-            this.index = index;
-        }
+        Vector2D rotate90CCW() { return new Vector2D(-y, x); }
+        double dot(Vector2D v) { return x * v.x + y * v.y; }
+        Vector2D mul(double k) { return new Vector2D(x * k, y * k); }
     }
 }
\ No newline at end of file

--
Gitblit v1.10.0