From 64e0880d2d81ce2b3f0e366b1537c5efe2f2c4ea Mon Sep 17 00:00:00 2001
From: 826220679@qq.com <826220679@qq.com>
Date: 星期日, 21 十二月 2025 20:49:24 +0800
Subject: [PATCH] 需改优化了绘制往返路径

---
 src/lujing/SavaXyZuobiao.java     |  125 ++++++++
 src/lujing/WangfanpathJisuan.java |  531 +++++++++++++++++++++++++++++++++++++
 src/zhuye/WangfanDraw.java        |   22 +
 src/dikuai/Huizhiwanfanpath.java  |    5 
 set.properties                    |    8 
 src/zhuye/Shouye.java             |   34 +
 src/publicway/Fanhuibutton.java   |   98 +++++++
 image/backbutton.png              |    0 
 8 files changed, 808 insertions(+), 15 deletions(-)

diff --git a/image/backbutton.png b/image/backbutton.png
new file mode 100644
index 0000000..1a5a3e3
--- /dev/null
+++ b/image/backbutton.png
Binary files differ
diff --git a/set.properties b/set.properties
index f4e9df7..00d235c 100644
--- a/set.properties
+++ b/set.properties
@@ -1,5 +1,5 @@
 #Mower Configuration Properties - Updated
-#Sun Dec 21 12:36:00 GMT+08:00 2025
+#Sun Dec 21 20:48:14 GMT+08:00 2025
 appVersion=-1
 simCardNumber=-1
 currentWorkLandNumber=LAND2
@@ -7,13 +7,13 @@
 boundaryLengthVisible=false
 idleTrailDurationSeconds=60
 handheldMarkerId=1872
-viewCenterX=-13.31
-viewCenterY=3.75
+viewCenterX=-37.40
+viewCenterY=0.91
 manualBoundaryDrawingMode=false
 mowerId=860
 serialPortName=COM15
 serialAutoConnect=true
-mapScale=11.63
+mapScale=11.61
 measurementModeEnabled=false
 firmwareVersion=-1
 cuttingWidth=200
diff --git a/src/dikuai/Huizhiwanfanpath.java b/src/dikuai/Huizhiwanfanpath.java
index b3806f0..fda0a00 100644
--- a/src/dikuai/Huizhiwanfanpath.java
+++ b/src/dikuai/Huizhiwanfanpath.java
@@ -557,8 +557,9 @@
                 });
             };
             
-            // 鍚姩寰�杩旇矾寰勭粯鍒�
-            if (!shouye.startReturnPathDrawing(finishCallback)) {
+            // 鍚姩寰�杩旇矾寰勭粯鍒讹紝浼犻�掓槸鍚︿负鎵嬫寔璁惧妯″紡
+            boolean isHandheld = "handheld".equals(method);
+            if (!shouye.startReturnPathDrawing(finishCallback, isHandheld)) {
                 JOptionPane.showMessageDialog(this, "鏈兘寮�濮嬬粯鍒讹紝璇风‘璁よ澶囩姸鎬佸拰鍩哄噯绔欒缃悗閲嶈瘯", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
                 return false;
             }
diff --git a/src/lujing/SavaXyZuobiao.java b/src/lujing/SavaXyZuobiao.java
new file mode 100644
index 0000000..2ce42a3
--- /dev/null
+++ b/src/lujing/SavaXyZuobiao.java
@@ -0,0 +1,125 @@
+package lujing;
+import java.text.DecimalFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * 淇濆瓨X,Y鍧愭爣鐨勫伐鍏风被
+ * 鍧愭爣鍗曚綅锛氱背锛岀簿纭埌灏忔暟鐐瑰悗2浣嶅皬鏁�
+ */
+public class SavaXyZuobiao {
+    
+    // 鍧愭爣闆嗗悎锛屼娇鐢ㄧ嚎绋嬪畨鍏ㄧ殑List
+    private static final List<double[]> COORDINATES = Collections.synchronizedList(new ArrayList<>());
+    
+    // 淇濆瓨鐘舵�佹爣蹇�
+    private static volatile boolean isSaving = false;
+    
+    // 鏁板瓧鏍煎紡鍖栧櫒锛岀敤浜庝繚鐣�2浣嶅皬鏁�
+    private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("0.00");
+    
+    // 绉佹湁鏋勯�犳柟娉曪紝闃叉瀹炰緥鍖�
+    private SavaXyZuobiao() {
+        throw new UnsupportedOperationException("杩欐槸涓�涓伐鍏风被锛屼笉鑳藉疄渚嬪寲");
+    }
+    
+    /**
+     * 娣诲姞鍧愭爣鍒伴泦鍚堜腑锛堜粎鍦ㄤ繚瀛樼姸鎬佷笅锛�
+     * @param x X鍧愭爣锛堢背锛�
+     * @param y Y鍧愭爣锛堢背锛�
+     */
+    public static void addCoordinate(double x, double y) {
+        if (isSaving) {
+            // 鏍煎紡鍖栧潗鏍囷紝淇濈暀2浣嶅皬鏁�
+            double formattedX = Double.parseDouble(DECIMAL_FORMAT.format(x));
+            double formattedY = Double.parseDouble(DECIMAL_FORMAT.format(y));
+            
+            double[] coordinate = {formattedX, formattedY};
+            synchronized (COORDINATES) {
+                COORDINATES.add(coordinate);
+            }
+        }
+    }
+    
+    /**
+     * 鑾峰彇鍧愭爣闆嗗悎鐨勫瓧绗︿覆琛ㄧず
+     * 鏍煎紡锛歑1,Y1;X2,Y2;...;Xn,Yn
+     * @return 鏍煎紡鍖栧悗鐨勫潗鏍囧瓧绗︿覆
+     */
+    public static String getCoordinatesString() {
+        if (COORDINATES.isEmpty()) {
+            return "";
+        }
+        
+        StringBuilder sb = new StringBuilder();
+        synchronized (COORDINATES) {
+            for (int i = 0; i < COORDINATES.size(); i++) {
+                double[] coordinate = COORDINATES.get(i);
+                sb.append(DECIMAL_FORMAT.format(coordinate[0]))
+                  .append(",")
+                  .append(DECIMAL_FORMAT.format(coordinate[1]));
+                
+                if (i < COORDINATES.size() - 1) {
+                    sb.append(";");
+                }
+            }
+        }
+        return sb.toString();
+    }
+    
+    /**
+     * 寮�濮嬩繚瀛樺潗鏍�
+     */
+    public static void startSaving() {
+        isSaving = true;
+    }
+    
+    /**
+     * 鏆傚仠淇濆瓨鍧愭爣
+     */
+    public static void pauseSaving() {
+        isSaving = false;
+    }
+    
+    /**
+     * 鑾峰彇褰撳墠淇濆瓨鐘舵��
+     * @return true琛ㄧず姝e湪淇濆瓨锛宖alse琛ㄧず宸叉殏鍋�
+     */
+    public static boolean isSaving() {
+        return isSaving;
+    }
+    
+    /**
+     * 娓呯┖鍧愭爣闆嗗悎涓殑鎵�鏈夋暟鎹�
+     */
+    public static void clearCoordinates() {
+        synchronized (COORDINATES) {
+            COORDINATES.clear();
+        }
+    }
+    
+    /**
+     * 鑾峰彇褰撳墠淇濆瓨鐨勫潗鏍囨暟閲�
+     * @return 鍧愭爣鏁伴噺
+     */
+    public static int getCoordinateCount() {
+        synchronized (COORDINATES) {
+            return COORDINATES.size();
+        }
+    }
+    
+    /**
+     * 鑾峰彇鎵�鏈夊潗鏍囩殑鍒楄〃锛堝壇鏈紝闃叉澶栭儴淇敼鍐呴儴鏁版嵁锛�
+     * @return 鍧愭爣鍒楄〃鐨勫壇鏈�
+     */
+    public static List<double[]> getAllCoordinates() {
+        synchronized (COORDINATES) {
+            List<double[]> copy = new ArrayList<>(COORDINATES.size());
+            for (double[] coord : COORDINATES) {
+                copy.add(new double[]{coord[0], coord[1]});
+            }
+            return copy;
+        }
+    }
+}
diff --git a/src/lujing/WangfanpathJisuan.java b/src/lujing/WangfanpathJisuan.java
new file mode 100644
index 0000000..1aa9840
--- /dev/null
+++ b/src/lujing/WangfanpathJisuan.java
@@ -0,0 +1,531 @@
+package lujing;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class WangfanpathJisuan {
+    
+    /**
+     * 鍧愭爣鐐圭被锛屼娇鐢ㄨ褰曞鐞嗘彁楂樼簿搴︽帶鍒�
+     */
+    private static class Point {
+        final double x;
+        final double y;
+        final int originalIndex; // 璁板綍鍘熷浣嶇疆锛屼究浜庤皟璇�
+        
+        Point(double x, double y, int index) {
+            this.x = x;
+            this.y = y;
+            this.originalIndex = index;
+        }
+        
+        Point(double x, double y) {
+            this(x, y, -1);
+        }
+        
+        double distanceTo(Point other) {
+            if (other == null) return Double.MAX_VALUE;
+            double dx = this.x - other.x;
+            double dy = this.y - other.y;
+            return Math.sqrt(dx * dx + dy * dy);
+        }
+        
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) return true;
+            if (obj == null || getClass() != obj.getClass()) return false;
+            Point point = (Point) obj;
+            // 浣跨敤1e-6鐨勭簿搴﹀垽鏂浉绛夛紝姣旂洿鎺ユ瘮杈僤ouble鏇寸ǔ瀹�
+            return Math.abs(point.x - x) < 1e-6 && Math.abs(point.y - y) < 1e-6;
+        }
+        
+        @Override
+        public int hashCode() {
+            // 浣跨敤鍥哄畾绮惧害杩涜鍝堝笇璁$畻锛岀‘淇濈簿搴﹁寖鍥村唴鐩哥瓑鐨勭偣鏈夌浉鍚屽搱甯屽��
+            long xBits = Double.doubleToLongBits(Math.round(x * 1e6) / 1e6);
+            long yBits = Double.doubleToLongBits(Math.round(y * 1e6) / 1e6);
+            return (int)(xBits ^ (xBits >>> 32) ^ yBits ^ (yBits >>> 32));
+        }
+        
+        @Override
+        public String toString() {
+            return String.format("%.3f,%.3f", x, y);
+        }
+        
+        public String toString(int precision) {
+            return String.format("%." + precision + "f,%." + precision + "f", x, y);
+        }
+    }
+    
+    /**
+     * 绾挎绫伙紝鐢ㄤ簬璁$畻鐐瑰埌绾挎鐨勮窛绂�
+     */
+    private static class LineSegment {
+        final Point start;
+        final Point end;
+        final double length;
+        
+        LineSegment(Point start, Point end) {
+            this.start = start;
+            this.end = end;
+            this.length = start.distanceTo(end);
+        }
+        
+        /**
+         * 璁$畻鐐瑰埌绾挎鐨勫瀭鐩磋窛绂�
+         */
+        double perpendicularDistance(Point point) {
+            if (length == 0) {
+                return point.distanceTo(start);
+            }
+            
+            // 浣跨敤鍚戦噺鏂规硶璁$畻鎶曞奖璺濈
+            double x1 = start.x, y1 = start.y;
+            double x2 = end.x, y2 = end.y;
+            double x0 = point.x, y0 = point.y;
+            
+            // 璁$畻鐐瑰埌鐩寸嚎璺濈鍏紡
+            double numerator = Math.abs((y2 - y1) * x0 - (x2 - x1) * y0 + x2 * y1 - y2 * x1);
+            double denominator = Math.sqrt((y2 - y1) * (y2 - y1) + (x2 - x1) * (x2 - x1));
+            
+            return numerator / denominator;
+        }
+        
+        /**
+         * 鍒ゆ柇鐐规槸鍚﹀湪绾挎鐨勮竟鐣屾鍐咃紙鐢ㄤ簬鍒ゆ柇鏄惁鍦ㄧ嚎娈典笂锛�
+         */
+        boolean isPointInBoundingBox(Point point) {
+            double minX = Math.min(start.x, end.x);
+            double maxX = Math.max(start.x, end.x);
+            double minY = Math.min(start.y, end.y);
+            double maxY = Math.max(start.y, end.y);
+            
+            return point.x >= minX && point.x <= maxX && 
+                   point.y >= minY && point.y <= maxY;
+        }
+    }
+    
+    /**
+     * 浼樺寲閰嶇疆绫�
+     */
+    public static class OptimizationConfig {
+        private double distanceTolerance = 0.1;       // 璺濈瀹瑰樊锛堢背锛�
+        private double angleTolerance = 1.0;          // 瑙掑害瀹瑰樊锛堝害锛�
+        private int outputPrecision = 3;              // 杈撳嚭绮惧害锛堝皬鏁颁綅鏁帮級
+        private boolean keepEndpoints = true;         // 鏄惁淇濈暀绔偣
+        private boolean useFastSimplify = false;      // 鏄惁浣跨敤蹇�熺畝鍖栫畻娉�
+        
+        public OptimizationConfig() {}
+        
+        public OptimizationConfig setDistanceTolerance(double tolerance) {
+            this.distanceTolerance = Math.max(0.01, tolerance); // 鏈�灏�0.01绫�
+            return this;
+        }
+        
+        public OptimizationConfig setAngleTolerance(double degrees) {
+            this.angleTolerance = Math.max(0.1, Math.min(degrees, 45)); // 闄愬埗鍦�0.1-45搴�
+            return this;
+        }
+        
+        public OptimizationConfig setOutputPrecision(int precision) {
+            this.outputPrecision = Math.max(0, Math.min(precision, 8)); // 闄愬埗鍦�0-8浣�
+            return this;
+        }
+        
+        public OptimizationConfig setKeepEndpoints(boolean keep) {
+            this.keepEndpoints = keep;
+            return this;
+        }
+        
+        public OptimizationConfig setUseFastSimplify(boolean useFast) {
+            this.useFastSimplify = useFast;
+            return this;
+        }
+    }
+    
+    private OptimizationConfig config;
+    
+    public WangfanpathJisuan() {
+        this.config = new OptimizationConfig();
+    }
+    
+    public WangfanpathJisuan(OptimizationConfig config) {
+        this.config = config;
+    }
+    
+    /**
+     * 涓讳紭鍖栨柟娉�
+     */
+    public String optimizePath(String pathStr) {
+        return optimizePath(pathStr, this.config);
+    }
+    
+    /**
+     * 甯﹂厤缃殑浼樺寲鏂规硶
+     */
+    public String optimizePath(String pathStr, OptimizationConfig config) {
+        if (pathStr == null || pathStr.trim().isEmpty()) {
+            return "";
+        }
+        
+        List<Point> points = parsePoints(pathStr);
+        if (points.size() <= 2) {
+            return pointsToString(points, config.outputPrecision);
+        }
+        
+        // 鎵ц浼樺寲娴佹按绾�
+        List<Point> result = optimizationPipeline(points, config);
+        
+        return pointsToString(result, config.outputPrecision);
+    }
+    
+    /**
+     * 浼樺寲娴佹按绾匡細鎸夐『搴忔墽琛屽涓紭鍖栨楠�
+     */
+    private List<Point> optimizationPipeline(List<Point> points, OptimizationConfig config) {
+        List<Point> result = new ArrayList<>(points);
+        
+        // 姝ラ1: 鍘婚櫎杩炵画閲嶅鐐�
+        result = removeConsecutiveDuplicates(result);
+        
+        // 姝ラ2: 鏍规嵁閰嶇疆閫夋嫨绠�鍖栫畻娉�
+        if (config.useFastSimplify) {
+            result = fastSimplify(result, config.distanceTolerance, config.angleTolerance);
+        } else {
+            result = douglasPeuckerSimplify(result, config.distanceTolerance);
+        }
+        
+        // 姝ラ3: 纭繚绔偣锛堝彲閫夛級
+        if (config.keepEndpoints && result.size() > 1) {
+            ensureEndpoints(points, result);
+        }
+        
+        return result;
+    }
+    
+    /**
+     * 瑙f瀽鍧愭爣鐐癸紝甯︿綅缃储寮�
+     */
+    private List<Point> parsePoints(String pathStr) {
+        List<Point> points = new ArrayList<>();
+        String[] pointStrs = pathStr.split(";");
+        
+        for (int i = 0; i < pointStrs.length; i++) {
+            String pointStr = pointStrs[i].trim();
+            if (pointStr.isEmpty()) continue;
+            
+            String[] xy = pointStr.split(",");
+            if (xy.length != 2) continue;
+            
+            try {
+                double x = Double.parseDouble(xy[0].trim());
+                double y = Double.parseDouble(xy[1].trim());
+                points.add(new Point(x, y, i));
+            } catch (NumberFormatException e) {
+                // 璺宠繃鏍煎紡閿欒鐨勭偣锛岃褰曟棩蹇楋紙瀹為檯浣跨敤鏃跺彲娣诲姞鏃ュ織锛�
+                continue;
+            }
+        }
+        
+        return points;
+    }
+    
+    /**
+     * 鍘婚櫎杩炵画閲嶅鐐癸紙浼樺寲鐗堬級
+     */
+    private List<Point> removeConsecutiveDuplicates(List<Point> points) {
+        if (points.size() <= 1) {
+            return new ArrayList<>(points);
+        }
+        
+        List<Point> result = new ArrayList<>(points.size());
+        result.add(points.get(0));
+        
+        for (int i = 1; i < points.size(); i++) {
+            Point current = points.get(i);
+            Point last = result.get(result.size() - 1);
+            
+            // 浣跨敤璺濈鍒ゆ柇鏄惁閲嶅锛岃�冭檻娴偣绮惧害
+            if (current.distanceTo(last) > config.distanceTolerance * 0.1) {
+                result.add(current);
+            }
+            // 濡傛灉璺濈寰堝皬浣嗗疄闄呮槸涓嶅悓鐨勭偣锛堟诞鐐硅宸級锛屼粛淇濈暀
+            else if (!current.equals(last)) {
+                result.add(current);
+            }
+        }
+        
+        return result;
+    }
+    
+    /**
+     * 蹇�熺畝鍖栫畻娉曪紙缁撳悎璺濈鍜岃搴﹀垽鏂級
+     */
+    private List<Point> fastSimplify(List<Point> points, double distanceTolerance, double angleToleranceDeg) {
+        if (points.size() < 3) {
+            return new ArrayList<>(points);
+        }
+        
+        List<Point> result = new ArrayList<>();
+        result.add(points.get(0));
+        
+        int i = 1;
+        while (i < points.size() - 1) {
+            Point prev = result.get(result.size() - 1);
+            Point current = points.get(i);
+            Point next = points.get(i + 1);
+            
+            // 妫�鏌ヨ窛绂绘潯浠�
+            double distToPrev = current.distanceTo(prev);
+            double distToNext = current.distanceTo(next);
+            
+            // 妫�鏌ヨ搴︽潯浠讹紙灏嗚搴﹀宸浆鎹负寮у害锛�
+            double angleToleranceRad = Math.toRadians(angleToleranceDeg);
+            double angle = calculateAngle(prev, current, next);
+            
+            // 濡傛灉鐐硅窛绂诲墠涓�鐐规垨鍚庝竴鐐瑰緢杩戯紝鎴栬�呬笁鐐瑰舰鎴愮殑瑙掑害鎺ヨ繎180搴︼紙鍏辩嚎锛夛紝鍒欏墧闄ゅ綋鍓嶇偣
+            if (distToPrev < distanceTolerance || 
+                distToNext < distanceTolerance ||
+                Math.abs(Math.PI - angle) < angleToleranceRad) {
+                i++; // 璺宠繃褰撳墠鐐�
+            } else {
+                result.add(current);
+                i++;
+            }
+        }
+        
+        // 娣诲姞鏈�鍚庝竴涓偣
+        if (points.size() > 1) {
+            result.add(points.get(points.size() - 1));
+        }
+        
+        return result;
+    }
+    
+    /**
+     * 璁$畻涓夌偣褰㈡垚鐨勮搴︼紙浠ヤ腑闂寸偣涓洪《鐐癸級
+     */
+    private double calculateAngle(Point a, Point b, Point c) {
+        double baX = a.x - b.x;
+        double baY = a.y - b.y;
+        double bcX = c.x - b.x;
+        double bcY = c.y - b.y;
+        
+        double dotProduct = baX * bcX + baY * bcY;
+        double magnitudeBA = Math.sqrt(baX * baX + baY * baY);
+        double magnitudeBC = Math.sqrt(bcX * bcX + bcY * bcY);
+        
+        if (magnitudeBA == 0 || magnitudeBC == 0) {
+            return 0;
+        }
+        
+        double cosAngle = dotProduct / (magnitudeBA * magnitudeBC);
+        // 澶勭悊娴偣璇樊
+        cosAngle = Math.max(-1.0, Math.min(1.0, cosAngle));
+        
+        return Math.acos(cosAngle);
+    }
+    
+    /**
+     * 閬撴牸鎷夋柉-鏅厠绠楁硶锛堣凯浠e疄鐜帮紝閬垮厤閫掑綊鏍堟孩鍑猴級
+     */
+    private List<Point> douglasPeuckerSimplify(List<Point> points, double epsilon) {
+        if (points.size() <= 2) {
+            return new ArrayList<>(points);
+        }
+        
+        // 浣跨敤浣嶆爣璁版暟缁勶紝姣旈�掑綊鏇磋妭鐪佸唴瀛�
+        boolean[] keep = new boolean[points.size()];
+        keep[0] = keep[points.size() - 1] = true;
+        
+        // 浣跨敤鏍堟潵妯℃嫙閫掑綊
+        LinkedList<int[]> stack = new LinkedList<>();
+        stack.push(new int[]{0, points.size() - 1});
+        
+        while (!stack.isEmpty()) {
+            int[] range = stack.pop();
+            int start = range[0];
+            int end = range[1];
+            
+            if (end - start < 2) {
+                continue;
+            }
+            
+            double maxDistance = 0;
+            int maxIndex = start;
+            
+            Point startPoint = points.get(start);
+            Point endPoint = points.get(end);
+            LineSegment segment = new LineSegment(startPoint, endPoint);
+            
+            // 瀵绘壘绂荤嚎娈垫渶杩滅殑鐐�
+            for (int i = start + 1; i < end; i++) {
+                double distance = segment.perpendicularDistance(points.get(i));
+                if (distance > maxDistance) {
+                    maxDistance = distance;
+                    maxIndex = i;
+                }
+            }
+            
+            // 濡傛灉鏈�杩滅偣璺濈澶т簬瀹瑰樊锛屽垯澶勭悊涓や晶
+            if (maxDistance > epsilon) {
+                keep[maxIndex] = true;
+                if (maxIndex - start > 1) {
+                    stack.push(new int[]{start, maxIndex});
+                }
+                if (end - maxIndex > 1) {
+                    stack.push(new int[]{maxIndex, end});
+                }
+            }
+        }
+        
+        // 鏀堕泦淇濈暀鐨勭偣
+        List<Point> result = new ArrayList<>();
+        for (int i = 0; i < points.size(); i++) {
+            if (keep[i]) {
+                result.add(points.get(i));
+            }
+        }
+        
+        return result;
+    }
+    
+    /**
+     * 纭繚绔偣琚繚鐣�
+     */
+    private void ensureEndpoints(List<Point> original, List<Point> simplified) {
+        if (original.isEmpty() || simplified.isEmpty()) return;
+        
+        Point firstOriginal = original.get(0);
+        Point lastOriginal = original.get(original.size() - 1);
+        
+        // 妫�鏌ラ鐐�
+        if (!simplified.get(0).equals(firstOriginal)) {
+            simplified.add(0, firstOriginal);
+        }
+        
+        // 妫�鏌ュ熬鐐�
+        Point lastSimplified = simplified.get(simplified.size() - 1);
+        if (!lastSimplified.equals(lastOriginal)) {
+            simplified.add(lastOriginal);
+        }
+    }
+    
+    /**
+     * 灏嗙偣鍒楄〃杞崲涓哄瓧绗︿覆
+     */
+    private String pointsToString(List<Point> points, int precision) {
+        if (points.isEmpty()) {
+            return "";
+        }
+        
+        return points.stream()
+            .map(p -> p.toString(precision))
+            .collect(Collectors.joining(";"));
+    }
+    
+    /**
+     * 鎵瑰鐞嗕紭鍖栨柟娉�
+     */
+    public List<String> optimizePaths(List<String> pathStrings, OptimizationConfig config) {
+        return pathStrings.stream()
+            .map(path -> optimizePath(path, config))
+            .collect(Collectors.toList());
+    }
+    
+    /**
+     * 鎬ц兘缁熻淇℃伅
+     */
+    public static class OptimizationStats {
+        public final int originalPoints;
+        public final int optimizedPoints;
+        public final double reductionPercentage;
+        public final long processingTimeMs;
+        
+        public OptimizationStats(int original, int optimized, long timeMs) {
+            this.originalPoints = original;
+            this.optimizedPoints = optimized;
+            this.reductionPercentage = original > 0 ? 
+                (1.0 - (double)optimized / original) * 100 : 0;
+            this.processingTimeMs = timeMs;
+        }
+        
+        @Override
+        public String toString() {
+            return String.format("浼樺寲缁熻: %d -> %d 鐐� (鍑忓皯 %.1f%%)锛岃�楁椂 %dms",
+                originalPoints, optimizedPoints, reductionPercentage, processingTimeMs);
+        }
+    }
+    
+    /**
+     * 甯︾粺璁′俊鎭殑浼樺寲鏂规硶
+     */
+    public OptimizationResult optimizePathWithStats(String pathStr, OptimizationConfig config) {
+        long startTime = System.currentTimeMillis();
+        
+        if (pathStr == null || pathStr.trim().isEmpty()) {
+            return new OptimizationResult("", new OptimizationStats(0, 0, 0));
+        }
+        
+        List<Point> originalPoints = parsePoints(pathStr);
+        String optimizedPath = optimizePath(pathStr, config);
+        List<Point> optimizedPoints = parsePoints(optimizedPath);
+        
+        long endTime = System.currentTimeMillis();
+        
+        OptimizationStats stats = new OptimizationStats(
+            originalPoints.size(), 
+            optimizedPoints.size(), 
+            endTime - startTime
+        );
+        
+        return new OptimizationResult(optimizedPath, stats);
+    }
+    
+    /**
+     * 浼樺寲缁撴灉灏佽绫�
+     */
+    public static class OptimizationResult {
+        public final String optimizedPath;
+        public final OptimizationStats stats;
+        
+        public OptimizationResult(String path, OptimizationStats stats) {
+            this.optimizedPath = path;
+            this.stats = stats;
+        }
+    }
+    
+   
+    
+    /**
+     * 鐢熸垚娴嬭瘯璺緞
+     */
+    private static String generateTestPath(int pointCount) {
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < pointCount; i++) {
+            sb.append(i).append(",").append(i % 10);
+            if (i < pointCount - 1) {
+                sb.append(";");
+            }
+        }
+        return sb.toString();
+    }
+    
+    /**
+     * 鎬ц兘娴嬭瘯
+     */
+    private static void testPerformance(WangfanpathJisuan calculator, int iterations) {
+        String testPath = generateTestPath(1000);
+        
+        long startTime = System.currentTimeMillis();
+        for (int i = 0; i < iterations; i++) {
+            calculator.optimizePath(testPath);
+        }
+        long endTime = System.currentTimeMillis();
+        
+        System.out.printf("澶勭悊 %d 娆★紝姣忔1000鐐癸紝鎬昏�楁椂: %dms锛屽钩鍧囨瘡娆�: %.2fms\n",
+            iterations, endTime - startTime, 
+            (double)(endTime - startTime) / iterations);
+    }
+}
\ No newline at end of file
diff --git a/src/publicway/Fanhuibutton.java b/src/publicway/Fanhuibutton.java
new file mode 100644
index 0000000..5b53da1
--- /dev/null
+++ b/src/publicway/Fanhuibutton.java
@@ -0,0 +1,98 @@
+package publicway;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.ActionListener;
+import java.awt.geom.RoundRectangle2D;
+
+/**
+ * 杩斿洖鎸夐挳宸ュ叿绫�
+ * 鎻愪緵缁熶竴鐨勮繑鍥炴寜閽垱寤烘柟娉曪紝宸︿晶鏄剧ず"杩斿洖"鏂囧瓧锛屽彸渚ф樉绀哄浘鏍�
+ */
+public final class Fanhuibutton {
+    
+    // 鎸夐挳鍥哄畾灏哄
+    private static final Dimension BUTTON_SIZE = new Dimension(150, 30);
+    // 鍦嗚鍗婂緞
+    private static final int CORNER_RADIUS = 8;
+    // 涓昏壊璋� (缁胯壊)
+    private static final Color BASE_COLOR = new Color(46, 139, 87);
+    
+    private Fanhuibutton() {
+        // 宸ュ叿绫讳笉闇�瑕佸疄渚嬪寲
+    }
+    
+    /**
+     * 鍒涘缓杩斿洖鎸夐挳
+     * 鏍峰紡鍙傝�� buttonset锛屾樉绀� "杩斿洖 >>"
+     * 
+     * @param listener 鎸夐挳鐐瑰嚮浜嬩欢鐩戝惉鍣�
+     * @return 閰嶇疆濂界殑杩斿洖鎸夐挳
+     */
+    public static JButton createReturnButton(ActionListener listener) {
+        // 鍒涘缓鑷畾涔夌粯鍒剁殑鎸夐挳
+        JButton returnButton = new JButton("杩斿洖 >>") {
+            private static final long serialVersionUID = 1L;
+
+            @Override
+            protected void paintComponent(Graphics g) {
+                Graphics2D g2 = (Graphics2D) g.create();
+                // 寮�鍚姉閿娇
+                g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+                g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+
+                // 鑾峰彇鎸夐挳鐘舵��
+                boolean isPressed = getModel().isPressed();
+                boolean isRollover = getModel().isRollover();
+                int w = getWidth();
+                int h = getHeight();
+
+                // 璁$畻褰撳墠鑳屾櫙鑹�
+                if (isPressed) {
+                    g2.setColor(BASE_COLOR.darker());
+                } else if (isRollover) {
+                    g2.setColor(new Color(BASE_COLOR.getRed(), BASE_COLOR.getGreen(), BASE_COLOR.getBlue(), 220));
+                } else {
+                    g2.setColor(BASE_COLOR);
+                }
+
+                // 缁樺埗鍦嗚鐭╁舰鑳屾櫙
+                g2.fill(new RoundRectangle2D.Double(0, 0, w, h, CORNER_RADIUS, CORNER_RADIUS));
+
+                // 缁樺埗鏂囧瓧
+                g2.setColor(Color.WHITE);
+                g2.setFont(getFont());
+                FontMetrics fm = g2.getFontMetrics();
+                
+                // 鏂囧瓧灞呬腑
+                String text = getText();
+                int textX = (w - fm.stringWidth(text)) / 2;
+                int textY = (h - fm.getHeight()) / 2 + fm.getAscent();
+                
+                g2.drawString(text, textX, textY);
+
+                g2.dispose();
+            }
+        };
+        
+        // 璁剧疆鎸夐挳鏍峰紡灞炴��
+        returnButton.setFont(new Font("寰蒋闆呴粦", Font.BOLD, 14));
+        returnButton.setForeground(Color.WHITE);
+        returnButton.setFocusPainted(false);
+        returnButton.setContentAreaFilled(false);
+        returnButton.setBorderPainted(false);
+        returnButton.setCursor(new Cursor(Cursor.HAND_CURSOR));
+        
+        // 璁剧疆鍥哄畾澶у皬
+        returnButton.setPreferredSize(BUTTON_SIZE);
+        returnButton.setMinimumSize(BUTTON_SIZE);
+        returnButton.setMaximumSize(BUTTON_SIZE);
+        
+        // 娣诲姞鐐瑰嚮浜嬩欢
+        if (listener != null) {
+            returnButton.addActionListener(listener);
+        }
+        
+        return returnButton;
+    }
+}
diff --git a/src/zhuye/Shouye.java b/src/zhuye/Shouye.java
index 22f8fc6..97dddac 100644
--- a/src/zhuye/Shouye.java
+++ b/src/zhuye/Shouye.java
@@ -2125,7 +2125,12 @@
 			updateStopButtonIcon();
 		}
 		if (statusLabel != null) {
-			statusLabel.setText(storedStatusBeforeDrawing != null ? storedStatusBeforeDrawing : "寰呮満");
+			// 濡傛灉鏄線杩旇矾寰勭粯鍒讹紝閫�鍑烘椂鎭㈠涓�"寰呮満"
+			if (returnPathDrawer != null && returnPathDrawer.isActive()) {
+				statusLabel.setText("寰呮満");
+			} else {
+				statusLabel.setText(storedStatusBeforeDrawing != null ? storedStatusBeforeDrawing : "寰呮満");
+			}
 		}
 		storedStatusBeforeDrawing = null;
 	}
@@ -2437,6 +2442,12 @@
 		mapRenderer.setHandheldMowerIconActive(active);
 	}
 
+	public void setStatusLabelText(String text) {
+		if (statusLabel != null) {
+			statusLabel.setText(text);
+		}
+	}
+
 	public boolean startMowerBoundaryCapture() {
 		if (mapRenderer == null) {
 			return false;
@@ -3080,7 +3091,11 @@
 		if (drawingControlModeActive) {
 			updateDrawingControlButtonLabels();
 			if (statusLabel != null) {
-				statusLabel.setText(paused ? "缁樺埗鏆傚仠" : "缁樺埗涓�");
+				if (returnPathDrawer != null && returnPathDrawer.isActive()) {
+					statusLabel.setText("姝e湪缁樺埗寰�杩旇矾寰�");
+				} else {
+					statusLabel.setText(paused ? "缁樺埗鏆傚仠" : "缁樺埗涓�");
+				}
 			}
 		}
 	}
@@ -3106,7 +3121,9 @@
 		
 		// 鏄剧ず"姝e湪缁樺埗杈圭晫"鎻愮ず
 		if (drawingBoundaryLabel != null) {
-			drawingBoundaryLabel.setVisible(true);
+			// 濡傛灉鏄線杩旇矾寰勭粯鍒讹紝涓嶆樉绀烘鏍囩锛堢姸鎬佹爮宸叉樉绀�"姝e湪缁樺埗寰�杩旇矾寰�"锛�
+			boolean isReturnPathDrawing = returnPathDrawer != null && returnPathDrawer.isActive();
+			drawingBoundaryLabel.setVisible(!isReturnPathDrawing);
 		}
 
 		boolean enableCircleGuidance = drawingShape != null
@@ -4149,13 +4166,14 @@
     /**
      * 鍚姩寰�杩旇矾寰勭粯鍒�
      * @param finishCallback 瀹屾垚缁樺埗鏃剁殑鍥炶皟
+     * @param isHandheld 鏄惁浣跨敤鎵嬫寔璁惧妯″紡
      * @return 鏄惁鎴愬姛鍚姩
      */
-    public boolean startReturnPathDrawing(Runnable finishCallback) {
+    public boolean startReturnPathDrawing(Runnable finishCallback, boolean isHandheld) {
         if (returnPathDrawer == null) {
             return false;
         }
-        return returnPathDrawer.start(finishCallback);
+        return returnPathDrawer.start(finishCallback, isHandheld);
     }
     
     /**
@@ -4223,12 +4241,12 @@
         
         // 鍒涘缓鎴栨樉绀鸿繑鍥炴寜閽�
         if (pathPreviewReturnButton == null) {
-            pathPreviewReturnButton = publicway.buttonset.createStyledButton("杩斿洖", null);
-            pathPreviewReturnButton.setToolTipText("杩斿洖缁樺埗椤甸潰");
-            pathPreviewReturnButton.addActionListener(e -> {
+            // 浣跨敤 Fanhuibutton 鍒涘缓杩斿洖鎸夐挳
+            pathPreviewReturnButton = publicway.Fanhuibutton.createReturnButton(e -> {
                 // 鍋滄棰勮
                 stopReturnPathPreview();
             });
+            pathPreviewReturnButton.setToolTipText("杩斿洖缁樺埗椤甸潰");
         }
         
         // 闅愯棌鍏朵粬鎮诞鎸夐挳
diff --git a/src/zhuye/WangfanDraw.java b/src/zhuye/WangfanDraw.java
index 464cedf..c56abf5 100644
--- a/src/zhuye/WangfanDraw.java
+++ b/src/zhuye/WangfanDraw.java
@@ -23,6 +23,7 @@
     // 缁樺埗鐘舵��
     private boolean drawingActive = false;
     private boolean paused = false;
+    private boolean isHandheldMode = false;  // 鏄惁浣跨敤鎵嬫寔璁惧妯″紡
     
     // 鍩哄噯鍧愭爣
     private double[] baseLatLon;
@@ -63,9 +64,10 @@
     /**
      * 鍚姩寰�杩旇矾寰勭粯鍒�
      * @param finishCallback 瀹屾垚缁樺埗鏃剁殑鍥炶皟
+     * @param isHandheld 鏄惁浣跨敤鎵嬫寔璁惧妯″紡
      * @return 鏄惁鎴愬姛鍚姩
      */
-    public boolean start(Runnable finishCallback) {
+    public boolean start(Runnable finishCallback, boolean isHandheld) {
         if (mapRenderer == null || helper == null) {
             return false;
         }
@@ -83,6 +85,12 @@
         paused = false;
         this.finishCallback = finishCallback;
         this.baseLatLon = baseLatLonCandidate;
+        this.isHandheldMode = isHandheld;
+        
+        // 濡傛灉鏄墜鎸佽澶囨ā寮忥紝鍒囨崲鍥炬爣
+        if (isHandheld && shouye != null) {
+            shouye.setHandheldMowerIconActive(true);
+        }
 
         // 娓呯┖璺緞鐐�
         synchronized (returnPathPoints) {
@@ -101,6 +109,12 @@
         if (helper != null) {
             helper.enterDrawingControlMode();
         }
+        
+        // 璁剧疆鐘舵�佹彁绀轰负"姝e湪缁樺埗寰�杩旇矾寰�"
+        if (shouye != null) {
+            shouye.setStatusLabelText("姝e湪缁樺埗寰�杩旇矾寰�");
+        }
+        
         startMonitor();
         return true;
     }
@@ -245,6 +259,12 @@
         if (helper != null) {
             helper.exitDrawingControlMode();
         }
+        
+        // 鎭㈠鍓茶崏鏈哄浘鏍�
+        if (isHandheldMode && shouye != null) {
+            shouye.setHandheldMowerIconActive(false);
+        }
+        isHandheldMode = false;
     }
     
     /**

--
Gitblit v1.10.0