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