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

---
 src/dikuai/ObstacleManagementPage.java   |   24 
 src/gecaoji/Device.java                  |   16 
 src/zhuye/AreaSelectionDialog.java       |    4 
 dikuai.properties                        |    8 
 src/zhuye/WangfanDraw.java               |  411 +++++++++
 src/dikuai/Wangfanpathpage.java          |  200 ++++
 src/zhuye/MapRenderer.java               |   80 +
 set.properties                           |   10 
 src/udpdell/UDPServer.java               |   18 
 pom.xml                                  |   35 
 src/publicway/buttonset.java             |    2 
 src/dikuai/Dikuaiguanli.java             |  220 ++++
 src/gecaoji/GecaojiMeg.java              |    4 
 src/set/Sets.java                        |    3 
 src/lujing/MowingPathGenerationPage.java |    2 
 src/publicway/Fuzhibutton.java           |    2 
 src/zhangaiwu/yulanzhangaiwu.java        |   32 
 src/zhuye/daohangyulan.java              |    1 
 src/zhuye/zijian.java                    |    3 
 src/dikuai/addzhangaiwu.java             |   31 
 src/dikuai/daohangyulan.java             |    2 
 src/yaokong/Control02.java               |   26 
 src/zhuye/LegendDialog.java              |   30 
 .vscode/settings.json                    |    3 
 src/zhangaiwu/AddDikuai.java             |    2 
 src/dikuai/FanhuiDialog.java             |    5 
 src/zhuye/Shouye.java                    |  225 ++++
 src/dikuai/Dikuai.java                   |   16 
 src/publicway/Gpstoxuzuobiao.java        |  141 +++
 src/set/debug.java                       |    3 
 src/publicway/Lookbutton.java            |    9 
 src/dikuai/Huizhiwanfanpath.java         |  896 +++++++++++++++++++++
 src/baseStation/BaseStationDialog.java   |    3 
 33 files changed, 2,280 insertions(+), 187 deletions(-)

diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..9250139
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,3 @@
+{
+    "java.jdt.ls.vmargs": "-XX:+UseParallelGC -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -Dsun.zip.disableMemoryMapping=true -Xmx4G -Xms100m -Xlog:disable"
+}
\ No newline at end of file
diff --git a/dikuai.properties b/dikuai.properties
index 15b98c9..b6eab9a 100644
--- a/dikuai.properties
+++ b/dikuai.properties
@@ -1,5 +1,5 @@
 #Dikuai Properties
-#Sat Dec 20 14:47:09 GMT+08:00 2025
+#Sun Dec 21 11:15:33 GMT+08:00 2025
 LAND2.boundaryCoordinates=5.38,-6.41;-11.15,-8.94;-12.75,-4.68;-12.23,-3.28;-11.12,-3.17;-9.29,-3.53;-7.46,-3.89;-5.62,-4.25;-3.79,-4.61;-1.96,-4.97;-0.12,-5.33;1.71,-5.69;3.54,-6.05;5.38,-6.41
 LAND1.intelligentSceneAnalysis=-1
 LAND1.mowingSafetyDistance=-1
@@ -11,13 +11,15 @@
 LAND2.intelligentSceneAnalysis=-1
 LAND2.mowingOverlapDistance=0.06
 LAND2.landArea=55.11
+LAND2.returnPathRawCoordinates=38.12,1.53;36.68,1.24;35.24,0.94;33.80,0.59;32.43,0.16;31.15,-0.38;30.26,-1.26;30.03,-2.37;30.12,-3.81;30.34,-5.22;30.59,-6.60;30.87,-7.98;31.10,-9.36;31.33,-10.77;31.57,-12.20;31.82,-13.68;32.07,-15.16;32.28,-16.60;32.52,-17.92;32.78,-19.37;33.07,-20.80;33.35,-22.37;33.62,-23.91;33.89,-25.35;34.16,-26.79;34.23,-28.32;33.75,-29.45;32.72,-30.03;31.41,-30.28;30.15,-30.22;29.26,-29.73;28.93,-28.62;28.72,-27.16;28.54,-25.66;28.26,-24.17;28.01,-22.74
 LAND1.returnPathCoordinates=-1
 LAND1.mowingPattern=骞宠绾�
 LAND1.mowingOverlapDistance=0.06
-LAND2.updateTime=2025-12-20 14\:47\:09
+LAND2.updateTime=2025-12-21 11\:15\:33
+LAND1.returnPathRawCoordinates=-1
 LAND2.createTime=2025-12-20 12\:24\:28
 LAND1.mowingWidth=34
-LAND2.returnPathCoordinates=-1
+LAND2.returnPathCoordinates=38.12,1.53;33.80,0.59;31.15,-0.38;30.26,-1.26;30.03,-2.37;30.34,-5.22;34.16,-26.79;34.23,-28.32;33.75,-29.45;32.72,-30.03;31.41,-30.28;30.15,-30.22;29.26,-29.73;28.93,-28.62;28.01,-22.74
 LAND2.angleThreshold=-1
 LAND2.boundaryPointInterval=-1
 LAND2.mowingWidth=34
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..e0c6222
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>com.example</groupId>
+    <artifactId>gecao-app</artifactId>
+    <version>1.0.0-SNAPSHOT</version>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <!-- Use a widely compatible release for baseline; will upgrade to 21 in plan -->
+        <maven.compiler.release>11</maven.compiler.release>
+    </properties>
+
+    <build>
+        <!-- Project uses non-standard src layout, point Maven to existing source directory -->
+        <sourceDirectory>src</sourceDirectory>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>3.11.0</version>
+                <configuration>
+                    <release>${maven.compiler.release}</release>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+    <dependencies>
+        <!-- Add dependencies as needed; current project appears to use local libs -->
+    </dependencies>
+</project>
diff --git a/set.properties b/set.properties
index a526d41..f4e9df7 100644
--- a/set.properties
+++ b/set.properties
@@ -1,5 +1,5 @@
-#Current work land selection updated
-#Sat Dec 20 15:10:30 GMT+08:00 2025
+#Mower Configuration Properties - Updated
+#Sun Dec 21 12:36:00 GMT+08:00 2025
 appVersion=-1
 simCardNumber=-1
 currentWorkLandNumber=LAND2
@@ -7,13 +7,13 @@
 boundaryLengthVisible=false
 idleTrailDurationSeconds=60
 handheldMarkerId=1872
-viewCenterX=5.62
-viewCenterY=6.22
+viewCenterX=-13.31
+viewCenterY=3.75
 manualBoundaryDrawingMode=false
 mowerId=860
 serialPortName=COM15
 serialAutoConnect=true
-mapScale=13.68
+mapScale=11.63
 measurementModeEnabled=false
 firmwareVersion=-1
 cuttingWidth=200
diff --git a/src/baseStation/BaseStationDialog.java b/src/baseStation/BaseStationDialog.java
index dc9d8b9..a878c06 100644
--- a/src/baseStation/BaseStationDialog.java
+++ b/src/baseStation/BaseStationDialog.java
@@ -3,6 +3,7 @@
 import javax.swing.*;
 
 import gecaoji.Device;
+import publicway.buttonset;
 
 import java.awt.*;
 import java.awt.event.ActionListener;
@@ -16,8 +17,6 @@
 import java.util.Locale;
 import java.util.Properties;
 
-import zhuye.buttonset;
-
 public class BaseStationDialog extends JDialog {
     private final Color THEME_COLOR;
     private final Device device;
diff --git a/src/dikuai/Dikuai.java b/src/dikuai/Dikuai.java
index a21456c..12a4edd 100644
--- a/src/dikuai/Dikuai.java
+++ b/src/dikuai/Dikuai.java
@@ -25,6 +25,8 @@
     private String returnPointCoordinates;
     // 寰�杩旇矾寰勫潗鏍囷紙鍓茶崏鏈哄畬鎴愬壊鑽変綔涓氳繑鍥炵殑璺緞鍧愭爣锛屾牸寮忥細X1,Y1;X2,Y2;...;XN,YN锛�
     private String returnPathCoordinates;
+    // 寰�杩旇矾寰勫師濮嬪潗鏍�
+    private String returnPathRawCoordinates;
     // 杈圭晫鐐归棿闅�
     private String boundaryPointInterval;
     // 瑙掑害闃堝��
@@ -103,6 +105,7 @@
                 dikuai.plannedPath = landProps.getProperty("plannedPath", "-1");
                 dikuai.returnPointCoordinates = landProps.getProperty("returnPointCoordinates", "-1");
                 dikuai.returnPathCoordinates = landProps.getProperty("returnPathCoordinates", "-1");
+                dikuai.returnPathRawCoordinates = landProps.getProperty("returnPathRawCoordinates", "-1");
                 dikuai.boundaryPointInterval = landProps.getProperty("boundaryPointInterval", "-1");
                 dikuai.angleThreshold = landProps.getProperty("angleThreshold", "-1");
                 dikuai.intelligentSceneAnalysis = landProps.getProperty("intelligentSceneAnalysis", "-1");
@@ -210,6 +213,9 @@
             case "returnPathCoordinates":
                 this.returnPathCoordinates = value;
                 return true;
+            case "returnPathRawCoordinates":
+                this.returnPathRawCoordinates = value;
+                return true;
             case "boundaryPointInterval":
                 this.boundaryPointInterval = value;
                 return true;
@@ -274,6 +280,7 @@
             if (dikuai.plannedPath != null) properties.setProperty(landNumber + ".plannedPath", dikuai.plannedPath);
             if (dikuai.returnPointCoordinates != null) properties.setProperty(landNumber + ".returnPointCoordinates", dikuai.returnPointCoordinates);
             if (dikuai.returnPathCoordinates != null) properties.setProperty(landNumber + ".returnPathCoordinates", dikuai.returnPathCoordinates);
+            if (dikuai.returnPathRawCoordinates != null) properties.setProperty(landNumber + ".returnPathRawCoordinates", dikuai.returnPathRawCoordinates);
             if (dikuai.boundaryPointInterval != null) properties.setProperty(landNumber + ".boundaryPointInterval", dikuai.boundaryPointInterval);
             if (dikuai.angleThreshold != null) properties.setProperty(landNumber + ".angleThreshold", dikuai.angleThreshold);
             if (dikuai.intelligentSceneAnalysis != null) properties.setProperty(landNumber + ".intelligentSceneAnalysis", dikuai.intelligentSceneAnalysis);
@@ -366,6 +373,14 @@
         this.returnPathCoordinates = returnPathCoordinates;
     }
 
+    public String getReturnPathRawCoordinates() {
+        return returnPathRawCoordinates;
+    }
+
+    public void setReturnPathRawCoordinates(String returnPathRawCoordinates) {
+        this.returnPathRawCoordinates = returnPathRawCoordinates;
+    }
+
     public String getBoundaryPointInterval() {
         return boundaryPointInterval;
     }
@@ -481,6 +496,7 @@
                 ", plannedPath='" + plannedPath + '\'' +
                 ", returnPointCoordinates='" + returnPointCoordinates + '\'' +
                 ", returnPathCoordinates='" + returnPathCoordinates + '\'' +
+                ", returnPathRawCoordinates='" + returnPathRawCoordinates + '\'' +
                 ", boundaryPointInterval='" + boundaryPointInterval + '\'' +
                 ", angleThreshold='" + angleThreshold + '\'' +
                 ", intelligentSceneAnalysis='" + intelligentSceneAnalysis + '\'' +
diff --git a/src/dikuai/Dikuaiguanli.java b/src/dikuai/Dikuaiguanli.java
index 740ccf8..70bc5b1 100644
--- a/src/dikuai/Dikuaiguanli.java
+++ b/src/dikuai/Dikuaiguanli.java
@@ -23,14 +23,14 @@
 
 import lujing.Lunjingguihua;
 import lujing.MowingPathGenerationPage;
+import publicway.Fuzhibutton;
+import publicway.Lookbutton;
+import publicway.buttonset;
 import zhangaiwu.AddDikuai;
 import zhangaiwu.Obstacledge;
 import zhuye.MapRenderer;
 import zhuye.Shouye;
 import zhuye.Coordinate;
-import zhuye.buttonset;
-import zhuye.Fuzhibutton;
-import zhuye.Lookbutton;
 import gecaoji.Device;
 
 /**
@@ -316,8 +316,7 @@
 		contentPanel.add(Box.createRigidArea(new Dimension(0, 10)));
 
 		// 寰�杩旂偣璺緞锛堝甫鏌ョ湅鍥炬爣鎸夐挳锛�
-		JPanel returnPathPanel = createCardInfoItemWithButton("寰�杩旂偣璺緞:",
-			getDisplayValue(dikuai.getReturnPathCoordinates(), "鏈缃�"),
+		JPanel returnPathPanel = createCardInfoItemWithIconButton("寰�杩旂偣璺緞:",
 			createViewButton(e -> editReturnPath(dikuai)));
 		configureInteractiveLabel(getInfoItemTitleLabel(returnPathPanel),
 			() -> editReturnPath(dikuai),
@@ -755,6 +754,20 @@
 	}
 
 	private String promptCoordinateEditing(String title, String initialValue) {
+		return promptCoordinateEditing(title, initialValue, null);
+	}
+	
+	private String promptCoordinateEditing(String title, String initialValue, Dikuai dikuai) {
+		// 鍒ゆ柇鏄惁鏄線杩旂偣璺緞瀵硅瘽妗�
+		boolean isReturnPathDialog = title != null && title.contains("寰�杩旂偣璺緞");
+		
+		if (isReturnPathDialog) {
+			Window owner = SwingUtilities.getWindowAncestor(this);
+			Wangfanpathpage page = new Wangfanpathpage(owner, title, initialValue, dikuai);
+			page.setVisible(true);
+			return page.getResult();
+		}
+		
 		JTextArea textArea = new JTextArea(prepareCoordinateForEditor(initialValue));
 		textArea.setLineWrap(true);
 		textArea.setWrapStyleWord(true);
@@ -763,7 +776,8 @@
 		textArea.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
 
 		JScrollPane scrollPane = new JScrollPane(textArea);
-		scrollPane.setPreferredSize(new Dimension(360, 240));
+		// 濡傛灉鏄線杩旂偣璺緞瀵硅瘽妗嗭紝楂樺害璋冩暣涓洪�傚簲涓や釜鏂囨湰鍩�
+		scrollPane.setPreferredSize(new Dimension(360, isReturnPathDialog ? 100 : 240));
 
 		Window owner = SwingUtilities.getWindowAncestor(this);
 		JDialog dialog;
@@ -776,17 +790,115 @@
 		}
 		dialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
 
-		JPanel contentPanel = new JPanel(new BorderLayout());
+		JPanel contentPanel = new JPanel();
 		contentPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
-		contentPanel.add(scrollPane, BorderLayout.CENTER);
+		
+		if (isReturnPathDialog) {
+			contentPanel.setLayout(new BoxLayout(contentPanel, BoxLayout.Y_AXIS));
+			// 鍑忓皬杈硅窛浠ュ鍔犳枃鏈煙瀹藉害 (98%宸﹀彸)
+			contentPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
+			
+			// 1. 鍘熷寰�杩旇矾寰勫潗鏍囧尯鍩�
+			String rawCoords = dikuai != null ? prepareCoordinateForEditor(dikuai.getReturnPathRawCoordinates()) : "";
+			int rawCount = 0;
+			if (rawCoords != null && !rawCoords.isEmpty() && !"-1".equals(rawCoords)) {
+				rawCount = rawCoords.split(";").length;
+			}
+			
+			JPanel rawHeaderPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
+			rawHeaderPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
+			rawHeaderPanel.setBackground(BACKGROUND_COLOR);
+			rawHeaderPanel.setMaximumSize(new Dimension(Integer.MAX_VALUE, 30));
+			
+			JLabel rawTitleLabel = new JLabel("鍘熷寰�杩旇矾寰勫潗鏍� (" + rawCount + "鐐�)  ");
+			rawTitleLabel.setFont(new Font("寰蒋闆呴粦", Font.BOLD, 14));
+			rawHeaderPanel.add(rawTitleLabel);
+			
+			// 鍘熷鍧愭爣澶嶅埗鎸夐挳
+			final String finalRawCoords = rawCoords;
+			JButton rawCopyBtn = Fuzhibutton.createCopyButton(
+				() -> {
+					if (finalRawCoords == null || finalRawCoords.isEmpty() || "-1".equals(finalRawCoords)) return null;
+					return finalRawCoords;
+				},
+				"澶嶅埗",
+				new Color(230, 250, 240)
+			);
+			rawCopyBtn.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 12));
+			rawCopyBtn.setPreferredSize(new Dimension(50, 24));
+			rawCopyBtn.setMargin(new Insets(0,0,0,0));
+			rawHeaderPanel.add(rawCopyBtn);
+			
+			contentPanel.add(rawHeaderPanel);
+			contentPanel.add(Box.createVerticalStrut(5));
+			
+			JTextArea rawTextArea = new JTextArea(rawCoords);
+			rawTextArea.setLineWrap(true);
+			rawTextArea.setWrapStyleWord(true);
+			rawTextArea.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 13));
+			rawTextArea.setEditable(false); // 鍘熷鍧愭爣閫氬父涓嶅彲缂栬緫
+			rawTextArea.setRows(4);
+			rawTextArea.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
+			
+			JScrollPane rawScroll = new JScrollPane(rawTextArea);
+			rawScroll.setAlignmentX(Component.LEFT_ALIGNMENT);
+			// 璁剧疆鏈�澶у搴﹀厑璁告墿灞曪紝棣栭�夊搴﹂�備腑
+			rawScroll.setPreferredSize(new Dimension(300, 100));
+			rawScroll.setMaximumSize(new Dimension(Integer.MAX_VALUE, 100));
+			contentPanel.add(rawScroll);
+			
+			contentPanel.add(Box.createVerticalStrut(15));
+			
+			// 2. 浼樺寲鍚庡線杩旇矾寰勫潗鏍囧尯鍩�
+			String optCoords = prepareCoordinateForEditor(initialValue);
+			int optCount = 0;
+			if (optCoords != null && !optCoords.isEmpty() && !"-1".equals(optCoords)) {
+				optCount = optCoords.split(";").length;
+			}
+			
+			JPanel optHeaderPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
+			optHeaderPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
+			optHeaderPanel.setMaximumSize(new Dimension(Integer.MAX_VALUE, 30));
+			
+			JLabel optTitleLabel = new JLabel("浼樺寲鍚庡線杩旇矾寰勫潗鏍� (" + optCount + "鐐�)  ");
+			optTitleLabel.setFont(new Font("寰蒋闆呴粦", Font.BOLD, 14));
+			optHeaderPanel.add(optTitleLabel);
+			
+			// 浼樺寲鍧愭爣澶嶅埗鎸夐挳 - 鍔ㄦ�佽幏鍙栨枃鏈煙鍐呭
+			JButton optCopyBtn = Fuzhibutton.createCopyButton(
+				() -> {
+					String text = textArea.getText();
+					if (text == null || text.trim().isEmpty() || "-1".equals(text.trim())) return null;
+					return text;
+				},
+				"澶嶅埗",
+				new Color(230, 250, 240)
+			);
+			optCopyBtn.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 12));
+			optCopyBtn.setPreferredSize(new Dimension(50, 24));
+			optCopyBtn.setMargin(new Insets(0,0,0,0));
+			optHeaderPanel.add(optCopyBtn);
+			
+			contentPanel.add(optHeaderPanel);
+			contentPanel.add(Box.createVerticalStrut(5));
+			
+			// 浣跨敤浼犲叆鐨� textArea (宸插垵濮嬪寲涓� initialValue)
+			textArea.setRows(4);
+			scrollPane.setAlignmentX(Component.LEFT_ALIGNMENT);
+			scrollPane.setPreferredSize(new Dimension(300, 100));
+			scrollPane.setMaximumSize(new Dimension(Integer.MAX_VALUE, 100));
+			contentPanel.add(scrollPane);
+			
+		} else {
+			contentPanel.setLayout(new BorderLayout());
+			contentPanel.add(scrollPane, BorderLayout.CENTER);
+		}
 
 		JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
 		
-		// 鍒ゆ柇鏄惁鏄線杩旂偣璺緞瀵硅瘽妗�
-		boolean isReturnPathDialog = title != null && title.contains("寰�杩旂偣璺緞");
 		JButton okButton;
 		JButton cancelButton;
-		JButton copyButton;
+		JButton copyButton = null; // 鍒濆鍖栦负null
 		
 		if (isReturnPathDialog) {
 			// 寰�杩旂偣璺緞瀵硅瘽妗嗭細浣跨敤 buttonset 椋庢牸鐨勭‘瀹氭寜閽紝鍥炬爣鎸夐挳
@@ -811,22 +923,8 @@
 				public void mouseExited(MouseEvent e) { cancelButton.setOpaque(false); }
 			});
 			
-			// 浣跨敤 Fuzhibutton 鍒涘缓澶嶅埗鎸夐挳
-			copyButton = Fuzhibutton.createCopyButton(
-				(java.util.function.Supplier<String>) () -> {
-					String text = textArea.getText();
-					if (text == null) {
-						text = "";
-					}
-					String trimmed = text.trim();
-					if (trimmed.isEmpty() || "-1".equals(trimmed)) {
-						return null; // 杩斿洖null浼氳Е鍙�"鏈缃澶嶅埗鐨勫唴瀹�"鎻愮ず
-					}
-					return text;
-				},
-				"澶嶅埗" + title,
-				new Color(230, 250, 240)
-			);
+			// 浣跨敤 Fuzhibutton 鍒涘缓澶嶅埗鎸夐挳 (杩欓噷涓嶅啀闇�瑕佸簳閮ㄧ殑澶嶅埗鎸夐挳锛屽洜涓轰笂闈㈠凡缁忔湁浜�)
+			// copyButton = ... 
 			
 		} else {
 			// 鍏朵粬瀵硅瘽妗嗕繚鎸佸師鏈夋牱寮�
@@ -860,18 +958,41 @@
 		final String[] resultHolder = new String[1];
 
 		okButton.addActionListener(e -> {
-			resultHolder[0] = textArea.getText();
-			confirmed[0] = true;
-			dialog.dispose();
+			if (isReturnPathDialog) {
+				// 寰�杩旂偣璺緞瀵硅瘽妗嗭細鏍囪涓烘墦寮�缁樺埗椤甸潰
+				// 濡傛灉鏂囨湰鍩熶腑宸茬粡鏈夊潗鏍囷紝琛ㄧず瑕侀噸鏂扮粯鍒�
+				String currentText = textArea.getText();
+				if (currentText != null && !currentText.trim().isEmpty() && !"-1".equals(currentText.trim())) {
+					// 鏈夊潗鏍囷紝琛ㄧず閲嶆柊缁樺埗
+					resultHolder[0] = "__OPEN_DRAW_PAGE_REFRESH__";
+				} else {
+					// 娌℃湁鍧愭爣锛屾甯哥粯鍒�
+					resultHolder[0] = "__OPEN_DRAW_PAGE__";
+				}
+				confirmed[0] = true;
+				dialog.dispose();
+			} else {
+				resultHolder[0] = textArea.getText();
+				confirmed[0] = true;
+				dialog.dispose();
+			}
 		});
 
 		cancelButton.addActionListener(e -> dialog.dispose());
 
 		buttonPanel.add(okButton);
 		buttonPanel.add(cancelButton);
-		buttonPanel.add(copyButton);
+		if (copyButton != null) {
+			buttonPanel.add(copyButton);
+		}
 
-		contentPanel.add(buttonPanel, BorderLayout.SOUTH);
+		contentPanel.add(buttonPanel, isReturnPathDialog ? null : BorderLayout.SOUTH);
+		if (isReturnPathDialog) {
+			// 瀵逛簬 BoxLayout锛岀洿鎺ユ坊鍔犲埌搴曢儴
+			JPanel bottomWrapper = new JPanel(new BorderLayout());
+			bottomWrapper.add(buttonPanel, BorderLayout.EAST);
+			contentPanel.add(bottomWrapper);
+		}
 		dialog.setContentPane(contentPanel);
 		dialog.getRootPane().setDefaultButton(okButton);
 		dialog.pack();
@@ -1914,10 +2035,41 @@
 		if (dikuai == null) {
 			return;
 		}
-		String edited = promptCoordinateEditing("鏌ョ湅 / 缂栬緫寰�杩旂偣璺緞", dikuai.getReturnPathCoordinates());
+		String edited = promptCoordinateEditing("鏌ョ湅 / 缂栬緫寰�杩旂偣璺緞", dikuai.getReturnPathCoordinates(), dikuai);
 		if (edited == null) {
 			return;
 		}
+		// 妫�鏌ユ槸鍚︽槸鐗规畩鏍囪锛岃〃绀虹偣鍑讳簡"鍘荤粯鍒�"鎸夐挳
+		if ("__OPEN_DRAW_PAGE__".equals(edited) || "__OPEN_DRAW_PAGE_REFRESH__".equals(edited)) {
+			// 鑾峰彇鍦板潡绠$悊瀵硅瘽妗�
+			Window owner = SwingUtilities.getWindowAncestor(this);
+			Window managementWindow = null;
+			if (owner instanceof JDialog) {
+				managementWindow = owner;
+			}
+			
+			// 鑾峰彇鍦板潡绠$悊瀵硅瘽妗嗙殑鐖剁獥鍙o紙涓荤獥鍙o級锛屼綔涓虹粯鍒堕〉闈㈢殑鐖剁獥鍙�
+			Window drawPageOwner = null;
+			if (managementWindow != null) {
+				drawPageOwner = managementWindow.getOwner();
+			}
+			if (drawPageOwner == null && owner != null) {
+				drawPageOwner = owner.getOwner();
+			}
+			if (drawPageOwner == null) {
+				drawPageOwner = owner;
+			}
+			
+			// 鍏堝叧闂湴鍧楃鐞嗛〉闈�
+			if (managementWindow != null) {
+				managementWindow.dispose();
+			}
+			
+			// 鐒跺悗鎵撳紑缁樺埗椤甸潰锛屽鏋滄槸閲嶆柊缁樺埗锛屼紶閫掓爣璁�
+			boolean isRefresh = "__OPEN_DRAW_PAGE_REFRESH__".equals(edited);
+			Huizhiwanfanpath.showDrawReturnPathDialog(drawPageOwner, dikuai, isRefresh);
+			return;
+		}
 		String normalized = normalizeCoordinateInput(edited);
 		if (!saveFieldAndRefresh(dikuai, "returnPathCoordinates", normalized)) {
 			JOptionPane.showMessageDialog(this, "鏃犳硶鏇存柊寰�杩旂偣璺緞", "閿欒", JOptionPane.ERROR_MESSAGE);
@@ -2322,4 +2474,6 @@
 			return new ArrayList<>(names);
 		}
 	}
+
+
 }
\ No newline at end of file
diff --git a/src/dikuai/FanhuiDialog.java b/src/dikuai/FanhuiDialog.java
index ab5188f..bca38a7 100644
--- a/src/dikuai/FanhuiDialog.java
+++ b/src/dikuai/FanhuiDialog.java
@@ -1,13 +1,16 @@
 package dikuai;
 
 import javax.swing.*;
+
+import publicway.buttonset;
+
 import java.awt.*;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.io.FileInputStream;
 import java.util.Properties;
 import zhuye.MowerLocationData;
-import zhuye.buttonset;
+
 import java.text.DecimalFormat;
 import java.awt.GridBagLayout;
 import java.awt.GridBagConstraints;
diff --git a/src/dikuai/Huizhiwanfanpath.java b/src/dikuai/Huizhiwanfanpath.java
new file mode 100644
index 0000000..b3806f0
--- /dev/null
+++ b/src/dikuai/Huizhiwanfanpath.java
@@ -0,0 +1,896 @@
+package dikuai;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.*;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.List;
+
+import set.Setsys;
+import ui.UIConfig;
+import zhuye.Coordinate;
+import lujing.WangfanpathJisuan;
+import publicway.buttonset;
+
+/**
+ * 缁樺埗寰�杩旇矾寰勯〉闈�
+ * 鍙傝�冩柊澧炲湴鍧楁楠�2锛岀敤浜庣粯鍒跺線杩旂偣璺緞
+ */
+public class Huizhiwanfanpath extends JDialog {
+    private static final long serialVersionUID = 1L;
+    
+    // 涓婚棰滆壊 - 浼樺寲閰嶈壊鏂规
+    private final Color PRIMARY_COLOR = new Color(46, 139, 87);
+    private final Color PRIMARY_LIGHT = new Color(232, 245, 233);
+    private final Color PRIMARY_DARK = new Color(30, 107, 69);
+    private final Color WHITE = Color.WHITE;
+    private final Color LIGHT_GRAY = new Color(248, 249, 250);
+    private final Color TEXT_COLOR = new Color(33, 37, 41);
+    private final Color LIGHT_TEXT = new Color(108, 117, 125);
+    private final Color BORDER_COLOR = new Color(222, 226, 230);
+    private final Color ERROR_COLOR = new Color(220, 53, 69);
+    
+    // 涓婚潰鏉�
+    private JPanel mainPanel;
+    private Map<String, JPanel> drawingOptionPanels = new HashMap<>();
+    
+    // 閫夐」鐘舵��
+    private JPanel selectedOptionPanel = null;
+    private JButton startEndDrawingBtn;
+    private boolean isDrawing = false;
+    private boolean hasDrawnPath = false;  // 鏄惁宸茬粡缁樺埗杩囪矾寰�
+    private JLabel pathCountLabel;
+    private JLabel drawingMethodHintLabel;  // 缁樺埗鏂瑰紡鎻愮ず鏍囩
+    private JButton generatePathBtn;  // 鐢熸垚璺緞鎸夐挳
+    private JButton previewBtn;  // 棰勮鎸夐挳
+    private JButton saveBtn;  // 淇濆瓨鎸夐挳
+    private JPanel actionButtonsPanel;  // 鎿嶄綔鎸夐挳闈㈡澘
+    
+    // 鍦板潡淇℃伅
+    private Dikuai currentDikuai;
+    private boolean isRefreshMode = false;  // 鏄惁閲嶆柊缁樺埗妯″紡
+    private String optimizedPathCoordinates = null;  // 浼樺寲鍚庣殑璺緞鍧愭爣
+    private JTextArea rawCoordinatesArea; // 鍘熷鍧愭爣鏂囨湰鍩�
+    private JTextArea optimizedCoordinatesArea; // 璁$畻鍚庡潗鏍囨枃鏈煙
+    private JLabel rawCoordinatesLabel; // 鍘熷鍧愭爣鏍囬
+    private JLabel optimizedCoordinatesLabel; // 浼樺寲鍚庡潗鏍囨爣棰�
+    
+    public Huizhiwanfanpath(Window parent, Dikuai dikuai) {
+        this(parent, dikuai, false);
+    }
+    
+    public Huizhiwanfanpath(Window parent, Dikuai dikuai, boolean isRefresh) {
+        super(parent, "缁樺埗寰�杩旇矾寰�", Dialog.ModalityType.APPLICATION_MODAL);
+        this.currentDikuai = dikuai;
+        this.isRefreshMode = isRefresh;
+        initializeUI();
+    }
+    
+    private void initializeUI() {
+        setLayout(new BorderLayout());
+        setBackground(WHITE);
+        
+        // 缁熶竴浣跨敤 6.5 瀵哥珫灞忛�傞厤灏哄
+        setSize(UIConfig.DIALOG_WIDTH, UIConfig.DIALOG_HEIGHT);
+        setLocationRelativeTo(getParent());
+        setResizable(false);
+        
+        createMainPanel();
+        add(mainPanel, BorderLayout.CENTER);
+    }
+    
+    private void createMainPanel() {
+        mainPanel = new JPanel();
+        mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
+        mainPanel.setBackground(WHITE);
+        mainPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
+        
+        // 姝ラ鏍囬 - 宸﹀榻愶紙鍘绘帀"缁樺埗杈圭晫"鏂囧瓧锛�
+        // JLabel stepTitle = new JLabel("姝ラ1锛�");
+        // stepTitle.setFont(new Font("寰蒋闆呴粦", Font.BOLD, 20));
+        // stepTitle.setForeground(TEXT_COLOR);
+        // stepTitle.setAlignmentX(Component.LEFT_ALIGNMENT);
+        // mainPanel.add(stepTitle);
+        // mainPanel.add(Box.createRigidArea(new Dimension(0, 20)));
+        
+        // 姝ラ璇存槑
+        JPanel instructionPanel = createInstructionPanel(
+            "璇烽�夋嫨缁樺埗寰�杩旇矾寰勭殑鏂瑰紡銆傚壊鑽夋満缁樺埗闇�瑕侀┚椹跺壊鑽夋満娌胯矾寰勮椹讹紝" +
+            "鎵嬫寔璁惧缁樺埗鍒欎娇鐢ㄤ究鎼鸿澶囨爣璁拌矾寰勭偣銆�"
+        );
+        instructionPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
+        mainPanel.add(instructionPanel);
+        mainPanel.add(Box.createRigidArea(new Dimension(0, 25)));
+        
+        // 缁樺埗鏂瑰紡閫夋嫨
+        JLabel methodLabel = new JLabel("閫夋嫨缁樺埗鏂瑰紡");
+        methodLabel.setFont(new Font("寰蒋闆呴粦", Font.BOLD, 16));
+        methodLabel.setForeground(TEXT_COLOR);
+        methodLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
+        
+        mainPanel.add(methodLabel);
+        mainPanel.add(Box.createRigidArea(new Dimension(0, 15)));
+        
+        // 缁樺埗閫夐」闈㈡澘 - 鍨傜洿甯冨眬浠ュ畬鏁存樉绀哄浘鏍�
+        JPanel optionsPanel = new JPanel();
+        optionsPanel.setLayout(new BoxLayout(optionsPanel, BoxLayout.Y_AXIS));
+        optionsPanel.setBackground(WHITE);
+        optionsPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
+        
+        // 鍓茶崏鏈虹粯鍒堕�夐」
+        JPanel mowerOption = createDrawingOption("馃殰", "鍓茶崏鏈虹粯鍒�", 
+            "", "mower");
+        mowerOption.setAlignmentX(Component.LEFT_ALIGNMENT);
+        mowerOption.setBorder(BorderFactory.createLineBorder(BORDER_COLOR, 2));
+        
+        // 鎵嬫寔璁惧缁樺埗閫夐」
+        JPanel handheldOption = createDrawingOption("馃摫", "鎵嬫寔璁惧缁樺埗", 
+            "", "handheld");
+        handheldOption.setAlignmentX(Component.LEFT_ALIGNMENT);
+        handheldOption.setBorder(BorderFactory.createLineBorder(BORDER_COLOR, 2));
+        
+        optionsPanel.add(mowerOption);
+        optionsPanel.add(Box.createRigidArea(new Dimension(0, 15)));
+        optionsPanel.add(handheldOption);
+        
+        mainPanel.add(optionsPanel);
+        mainPanel.add(Box.createRigidArea(new Dimension(0, 30)));
+        
+        // 缁樺埗鏂瑰紡鎻愮ず鏍囩锛堝鏋滄病鏈夐�夋嫨缁樺埗鏂瑰紡鏃舵樉绀猴級
+        // 鎻愮ず鏂囨湰锛氭彁閱掑厛閫夋嫨缁樺埗鏂瑰紡鍐嶅紑濮�
+        drawingMethodHintLabel = new JLabel("璇峰厛閫夋嫨缁樺埗鏂瑰紡鍐嶇偣鍑诲紑濮嬬粯鍒�");
+        drawingMethodHintLabel.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 14));
+        drawingMethodHintLabel.setForeground(ERROR_COLOR);
+        drawingMethodHintLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
+        drawingMethodHintLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 10, 0));
+        drawingMethodHintLabel.setVisible(false);
+        mainPanel.add(drawingMethodHintLabel);
+        
+        // 寮�濮�/缁撴潫缁樺埗鎸夐挳
+        startEndDrawingBtn = createPrimaryButton("寮�濮嬬粯鍒�", 16);
+        startEndDrawingBtn.setAlignmentX(Component.LEFT_ALIGNMENT);
+        startEndDrawingBtn.setMaximumSize(new Dimension(400, 55));
+        startEndDrawingBtn.setEnabled(true); // 鍒濆鍚敤锛屼互渚跨偣鍑绘椂妫�鏌ユ槸鍚﹂�夋嫨浜嗙粯鍒舵柟寮�
+        
+        startEndDrawingBtn.addActionListener(e -> toggleDrawing());
+        
+        mainPanel.add(startEndDrawingBtn);
+        
+        // 鍘熷鍧愭爣鏄剧ず鍖哄煙锛堥噸鏂扮粯鍒舵寜閽笅鏂癸級
+        rawCoordinatesLabel = new JLabel("璺緞鍘熷鍧愭爣");
+        rawCoordinatesLabel.setFont(new Font("寰蒋闆呴粦", Font.BOLD, 14));
+        rawCoordinatesLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
+        rawCoordinatesLabel.setBorder(BorderFactory.createEmptyBorder(20, 0, 5, 0));
+        rawCoordinatesLabel.setVisible(false);
+        mainPanel.add(rawCoordinatesLabel);
+
+        rawCoordinatesArea = new JTextArea(3, 20);
+        rawCoordinatesArea.setFont(new Font("Consolas", Font.PLAIN, 12));
+        rawCoordinatesArea.setLineWrap(true);
+        rawCoordinatesArea.setWrapStyleWord(true);
+        rawCoordinatesArea.setEditable(false);
+        rawCoordinatesArea.setBorder(BorderFactory.createLineBorder(BORDER_COLOR));
+        
+        JScrollPane rawScrollPane = new JScrollPane(rawCoordinatesArea);
+        rawScrollPane.setAlignmentX(Component.LEFT_ALIGNMENT);
+        rawScrollPane.setMaximumSize(new Dimension(400, 60)); // 闄愬埗楂樺害
+        rawScrollPane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); // 鍘绘帀椤堕儴闂撮殧锛岀敱鏍囩鎻愪緵
+        rawScrollPane.setVisible(false); // 鍒濆闅愯棌
+        mainPanel.add(rawScrollPane);
+        
+        // 鎿嶄綔鎸夐挳闈㈡澘锛堢敓鎴愯矾寰勩�侀瑙堛�佷繚瀛橈級
+        actionButtonsPanel = createActionButtonsPanel();
+        actionButtonsPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
+        actionButtonsPanel.setVisible(false);
+        mainPanel.add(actionButtonsPanel);
+        
+        // 璁$畻鍚庡潗鏍囨樉绀哄尯鍩燂紙淇濆瓨鎸夐挳涓嬫柟锛�
+        optimizedCoordinatesLabel = new JLabel("浼樺寲鍚庤矾寰勫潗鏍�");
+        optimizedCoordinatesLabel.setFont(new Font("寰蒋闆呴粦", Font.BOLD, 14));
+        optimizedCoordinatesLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
+        optimizedCoordinatesLabel.setBorder(BorderFactory.createEmptyBorder(20, 0, 5, 0));
+        optimizedCoordinatesLabel.setVisible(false);
+        mainPanel.add(optimizedCoordinatesLabel);
+
+        optimizedCoordinatesArea = new JTextArea(3, 20);
+        optimizedCoordinatesArea.setFont(new Font("Consolas", Font.PLAIN, 12));
+        optimizedCoordinatesArea.setLineWrap(true);
+        optimizedCoordinatesArea.setWrapStyleWord(true);
+        optimizedCoordinatesArea.setEditable(false);
+        optimizedCoordinatesArea.setBorder(BorderFactory.createLineBorder(BORDER_COLOR));
+        
+        JScrollPane optimizedScrollPane = new JScrollPane(optimizedCoordinatesArea);
+        optimizedScrollPane.setAlignmentX(Component.LEFT_ALIGNMENT);
+        optimizedScrollPane.setMaximumSize(new Dimension(400, 60)); // 闄愬埗楂樺害
+        optimizedScrollPane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); // 鍘绘帀椤堕儴闂撮殧锛岀敱鏍囩鎻愪緵
+        optimizedScrollPane.setVisible(false); // 鍒濆闅愯棌
+        mainPanel.add(optimizedScrollPane);
+        
+        mainPanel.add(Box.createVerticalGlue());
+    }
+    
+    private JPanel createDrawingOption(String icon, String text, String description, String type) {
+        JPanel optionPanel = new JPanel(new BorderLayout(15, 0));
+        optionPanel.setBackground(WHITE);
+        optionPanel.setCursor(new Cursor(Cursor.HAND_CURSOR));
+        optionPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
+        optionPanel.setMaximumSize(new Dimension(500, 120));
+        
+        // 鍥炬爣鍖哄煙
+        JLabel iconLabel;
+        if ("handheld".equals(type) || "mower".equals(type)) {
+            iconLabel = new JLabel();
+            iconLabel.setHorizontalAlignment(SwingConstants.CENTER);
+            iconLabel.setPreferredSize(new Dimension(80, 80));
+            String iconPath = "handheld".equals(type) ? "image/URT.png" : "image/mow.png";
+            ImageIcon rawIcon = new ImageIcon(iconPath);
+            if (rawIcon.getIconWidth() > 0 && rawIcon.getIconHeight() > 0) {
+                Image scaled = rawIcon.getImage().getScaledInstance(64, 64, Image.SCALE_SMOOTH);
+                iconLabel.setIcon(new ImageIcon(scaled));
+            } else {
+                iconLabel.setText(icon);
+                iconLabel.setFont(new Font("Segoe UI Emoji", Font.PLAIN, 48));
+            }
+        } else {
+            iconLabel = new JLabel(icon, JLabel.CENTER);
+            iconLabel.setFont(new Font("Segoe UI Emoji", Font.PLAIN, 48));
+            iconLabel.setPreferredSize(new Dimension(80, 80));
+        }
+        
+        // 鏂囨湰鍖哄煙
+        JPanel textPanel = new JPanel(new GridBagLayout());
+        textPanel.setBackground(WHITE);
+
+        JLabel textLabel = new JLabel(text);
+        textLabel.setFont(new Font("寰蒋闆呴粦", Font.BOLD, 16));
+        textLabel.setHorizontalAlignment(SwingConstants.CENTER);
+        textLabel.setVerticalAlignment(SwingConstants.CENTER);
+
+        GridBagConstraints gbc = new GridBagConstraints();
+        gbc.gridx = 0;
+        gbc.gridy = 0;
+        gbc.weightx = 1;
+        gbc.weighty = description == null || description.trim().isEmpty() ? 1 : 0;
+        gbc.fill = GridBagConstraints.HORIZONTAL;
+        gbc.anchor = GridBagConstraints.CENTER;
+        textPanel.add(textLabel, gbc);
+
+        if (description != null && !description.trim().isEmpty()) {
+            JLabel descLabel = new JLabel(description);
+            descLabel.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 13));
+            descLabel.setForeground(LIGHT_TEXT);
+            descLabel.setHorizontalAlignment(SwingConstants.CENTER);
+
+            GridBagConstraints descGbc = new GridBagConstraints();
+            descGbc.gridx = 0;
+            descGbc.gridy = 1;
+            descGbc.weightx = 1;
+            descGbc.weighty = 1;
+            descGbc.fill = GridBagConstraints.HORIZONTAL;
+            descGbc.anchor = GridBagConstraints.CENTER;
+            textPanel.add(descLabel, descGbc);
+        }
+
+        optionPanel.putClientProperty("titleLabel", textLabel);
+        
+        optionPanel.add(iconLabel, BorderLayout.WEST);
+        optionPanel.add(textPanel, BorderLayout.CENTER);
+        
+        // 娣诲姞鐐瑰嚮浜嬩欢
+        optionPanel.addMouseListener(new MouseAdapter() {
+            @Override
+            public void mouseClicked(MouseEvent e) {
+                if (!optionPanel.isEnabled()) {
+                    return;
+                }
+                if (selectDrawingOption(optionPanel, type, true)) {
+                    startEndDrawingBtn.setEnabled(true); // 閫夋嫨鍚庡惎鐢ㄦ寜閽�
+                    // 闅愯棌鎻愮ず鏂囧瓧
+                    if (drawingMethodHintLabel != null) {
+                        drawingMethodHintLabel.setVisible(false);
+                    }
+                }
+            }
+            
+            @Override
+            public void mouseEntered(MouseEvent e) {
+                if (optionPanel != selectedOptionPanel) {
+                    optionPanel.setBackground(new Color(245, 245, 245));
+                }
+            }
+            
+            @Override
+            public void mouseExited(MouseEvent e) {
+                if (optionPanel != selectedOptionPanel) {
+                    optionPanel.setBackground(WHITE);
+                }
+            }
+        });
+        
+        drawingOptionPanels.put(type, optionPanel);
+        return optionPanel;
+    }
+    
+    private boolean selectDrawingOption(JPanel optionPanel, String type, boolean userTriggered) {
+        if (optionPanel == null) {
+            return false;
+        }
+        if (userTriggered && "handheld".equalsIgnoreCase(type) && !hasConfiguredHandheldMarker()) {
+            JOptionPane.showMessageDialog(this, "璇峰厛鍘荤郴缁熻缃坊鍔犱究鎼烘墦鐐瑰櫒缂栧彿", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
+            return false;
+        }
+
+        // 閲嶇疆涔嬪墠閫変腑鐨勯�夐」
+        if (selectedOptionPanel != null) {
+            selectedOptionPanel.setBorder(BorderFactory.createLineBorder(BORDER_COLOR, 2));
+            selectedOptionPanel.setBackground(WHITE);
+            Object oldTitle = selectedOptionPanel.getClientProperty("titleLabel");
+            if (oldTitle instanceof JLabel) {
+                ((JLabel) oldTitle).setForeground(TEXT_COLOR);
+            }
+        }
+
+        // 璁剧疆鏂扮殑閫変腑鐘舵��
+        optionPanel.setBorder(BorderFactory.createLineBorder(PRIMARY_COLOR, 3));
+        optionPanel.setBackground(PRIMARY_LIGHT);
+        Object titleObj = optionPanel.getClientProperty("titleLabel");
+        if (titleObj instanceof JLabel) {
+            ((JLabel) titleObj).setForeground(PRIMARY_COLOR);
+        }
+        selectedOptionPanel = optionPanel;
+
+        return true;
+    }
+
+    private boolean hasConfiguredHandheldMarker() {
+        String handheldId = Setsys.getPropertyValue("handheldMarkerId");
+        return handheldId != null && !handheldId.trim().isEmpty();
+    }
+    
+    private void toggleDrawing() {
+        if (!isDrawing) {
+            // 妫�鏌ユ槸鍚﹂�夋嫨浜嗙粯鍒舵柟寮�
+            if (selectedOptionPanel == null) {
+                // 鏄剧ず鎻愮ず鏂囧瓧
+                if (drawingMethodHintLabel != null) {
+                    drawingMethodHintLabel.setVisible(true);
+                }
+                return;
+            } else {
+                // 闅愯棌鎻愮ず鏂囧瓧
+                if (drawingMethodHintLabel != null) {
+                    drawingMethodHintLabel.setVisible(false);
+                }
+            }
+            
+            // 濡傛灉鏄噸鏂扮粯鍒讹紝娓呯┖涔嬪墠鐨勮矾寰勭偣
+            if (hasDrawnPath || isRefreshMode) {
+                int confirm = JOptionPane.showConfirmDialog(this, 
+                    "閲嶆柊缁樺埗灏嗘竻绌轰箣鍓嶇殑璺緞鐐癸紝鏄惁缁х画锛�", 
+                    "纭", 
+                    JOptionPane.YES_NO_OPTION);
+                if (confirm != JOptionPane.YES_OPTION) {
+                    return;
+                }
+                // 娓呯┖涔嬪墠鐨勫潗鏍�
+                Coordinate.coordinates.clear();
+                lujing.SavaXyZuobiao.clearCoordinates(); // 娓呯┖宸ュ叿绫诲潗鏍�
+                hasDrawnPath = false;
+                isRefreshMode = false;
+                optimizedPathCoordinates = null;
+                // 闅愯棌鎿嶄綔鎸夐挳
+                if (actionButtonsPanel != null) {
+                    actionButtonsPanel.setVisible(false);
+                }
+                // 闅愯棌鍘熷鍧愭爣鍜岃绠楀悗鍧愭爣
+                if (rawCoordinatesArea != null && rawCoordinatesArea.getParent() instanceof JViewport) {
+                    rawCoordinatesArea.getParent().getParent().setVisible(false);
+                    rawCoordinatesArea.setText("");
+                }
+                if (optimizedCoordinatesArea != null && optimizedCoordinatesArea.getParent() instanceof JViewport) {
+                    optimizedCoordinatesArea.getParent().getParent().setVisible(false);
+                    optimizedCoordinatesArea.setText("");
+                }
+                // 閲嶇疆淇濆瓨鎸夐挳鐘舵��
+                if (saveBtn != null) {
+                    saveBtn.setEnabled(false);
+                }
+                hidePathPointSummary();
+            }
+            
+            if (!prepareDrawingSession()) {
+                return;
+            }
+            isDrawing = true;
+            // hidePathPointSummary();
+            Coordinate.setStartSaveGngga(true);
+            lujing.SavaXyZuobiao.startSaving(); // 寮�濮嬩繚瀛樺潗鏍�
+            startEndDrawingBtn.setText("缁撴潫缁樺埗");
+            startEndDrawingBtn.setBackground(ERROR_COLOR);
+            updateOtherOptionsState(true);
+
+            if (!startDrawingPath()) {
+                Coordinate.setStartSaveGngga(false);
+                resetDrawingState();
+            }
+        } else {
+            // 鐢ㄦ埛鍦ㄥ璇濇鍐呬富鍔ㄧ粨鏉�
+            isDrawing = false;
+            Coordinate.setStartSaveGngga(false);
+            startEndDrawingBtn.setText(hasDrawnPath ? "閲嶆柊缁樺埗" : "寮�濮嬬粯鍒�");
+            startEndDrawingBtn.setBackground(PRIMARY_COLOR);
+            updateOtherOptionsState(false);
+            JOptionPane.showMessageDialog(this, "寰�杩旇矾寰勭粯鍒跺凡瀹屾垚", "鎻愮ず", JOptionPane.INFORMATION_MESSAGE);
+            // showPathPointSummary();
+            // 鏄剧ず鎿嶄綔鎸夐挳
+            if (actionButtonsPanel != null) {
+                actionButtonsPanel.setVisible(true);
+            }
+            // 閲嶇疆淇濆瓨鎸夐挳鐘舵�侊紙闇�瑕佺敓鎴愯矾寰勫悗鎵嶈兘淇濆瓨锛�
+            if (saveBtn != null) {
+                saveBtn.setEnabled(false);
+            }
+            optimizedPathCoordinates = null;  // 娓呯┖浼樺寲璺緞
+            hasDrawnPath = true;
+        }
+    }
+
+    private boolean prepareDrawingSession() {
+        if (currentDikuai == null) {
+            JOptionPane.showMessageDialog(this, "鍦板潡淇℃伅涓嶅瓨鍦�", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
+            return false;
+        }
+        if (selectedOptionPanel == null) {
+            JOptionPane.showMessageDialog(this, "璇烽�夋嫨缁樺埗鏂瑰紡", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
+            return false;
+        }
+        // 娓呯┖涔嬪墠鐨勫潗鏍�
+        Coordinate.coordinates.clear();
+        return true;
+    }
+
+    private void updateOtherOptionsState(boolean disable) {
+        if (selectedOptionPanel == null) {
+            return;
+        }
+        Component[] components = selectedOptionPanel.getParent().getComponents();
+        for (Component comp : components) {
+            if (comp instanceof JPanel && comp != selectedOptionPanel) {
+                comp.setEnabled(!disable);
+                ((JPanel) comp).setBackground(disable ? LIGHT_GRAY : WHITE);
+            }
+        }
+    }
+
+    private void resetDrawingState() {
+        isDrawing = false;
+        Coordinate.setStartSaveGngga(false);
+        startEndDrawingBtn.setText("寮�濮嬬粯鍒�");
+        startEndDrawingBtn.setBackground(PRIMARY_COLOR);
+        updateOtherOptionsState(false);
+        // hidePathPointSummary();
+    }
+    
+    private boolean startDrawingPath() {
+        // 鑾峰彇閫変腑鐨勭粯鍒舵柟寮�
+        String method = null;
+        for (Map.Entry<String, JPanel> entry : drawingOptionPanels.entrySet()) {
+            if (entry.getValue() == selectedOptionPanel) {
+                method = entry.getKey();
+                break;
+            }
+        }
+        
+        if ("mower".equals(method) || "handheld".equals(method)) {
+            zhuye.Shouye shouye = zhuye.Shouye.getInstance();
+            if (shouye == null) {
+                JOptionPane.showMessageDialog(this, "鏃犳硶杩涘叆涓婚〉闈紝璇风◢鍚庨噸璇�", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
+                return false;
+            }
+            
+            // 鍒涘缓瀹屾垚缁樺埗鍥炶皟锛岃繑鍥炲埌缁樺埗椤甸潰
+            Runnable finishCallback = () -> {
+                SwingUtilities.invokeLater(() -> {
+                    // 鍋滄淇濆瓨鍧愭爣
+                    lujing.SavaXyZuobiao.pauseSaving();
+                    
+                    // 鎭㈠棣栭〉榛樿鐨勬殏鍋滃拰缁撴潫鎸夐挳
+                    // 杩欎釜鍦� stopReturnPathDrawing 涓凡缁忓鐞嗕簡
+                    
+                    // 鏄剧ず缁樺埗椤甸潰
+                    Window owner = SwingUtilities.getWindowAncestor(this);
+                    if (owner == null) {
+                        owner = (Window) SwingUtilities.getWindowAncestor(shouye);
+                    }
+                    if (owner != null) {
+                        setLocationRelativeTo(owner);
+                    }
+                    
+                    // 閲嶇疆缁樺埗鐘舵��
+                    isDrawing = false;
+                    hasDrawnPath = true;  // 鏍囪宸茬粯鍒惰繃璺緞
+                    startEndDrawingBtn.setText("閲嶆柊缁樺埗");
+                    startEndDrawingBtn.setBackground(PRIMARY_COLOR);
+                    startEndDrawingBtn.setEnabled(true);  // 淇濇寔鍚敤鐘舵��
+                    updateOtherOptionsState(false);
+                    
+                    // 鏄剧ず鍘熷鍧愭爣
+                    if (rawCoordinatesArea != null) {
+                        String rawCoords = lujing.SavaXyZuobiao.getCoordinatesString();
+                        rawCoordinatesArea.setText(rawCoords);
+                        if (rawCoordinatesArea.getParent() instanceof JViewport) {
+                            rawCoordinatesArea.getParent().getParent().setVisible(true);
+                        }
+                        if (rawCoordinatesLabel != null) {
+                            int count = 0;
+                            if (rawCoords != null && !rawCoords.trim().isEmpty()) {
+                                count = rawCoords.split(";").length;
+                            }
+                            rawCoordinatesLabel.setText("璺緞鍘熷鍧愭爣 (鍏�" + count + "涓偣)");
+                            rawCoordinatesLabel.setVisible(true);
+                        }
+                    }
+                    
+                    // 鏄剧ず鎿嶄綔鎸夐挳
+                    if (actionButtonsPanel != null) {
+                        actionButtonsPanel.setVisible(true);
+                    }
+                    // 閲嶇疆淇濆瓨鎸夐挳鐘舵�侊紙闇�瑕佺敓鎴愯矾寰勫悗鎵嶈兘淇濆瓨锛�
+                    if (saveBtn != null) {
+                        saveBtn.setEnabled(false);
+                    }
+                    optimizedPathCoordinates = null;  // 娓呯┖浼樺寲璺緞
+                    
+                    // 寮哄埗鍒锋柊甯冨眬
+                    if (mainPanel != null) {
+                        mainPanel.revalidate();
+                        mainPanel.repaint();
+                    }
+                    
+                    setVisible(true);
+                    
+                    // 鏇存柊璺緞鐐硅鏁�
+                    // showPathPointSummary();
+                    
+                    // JOptionPane.showMessageDialog(this, "寰�杩旇矾寰勭粯鍒跺凡瀹屾垚", "鎻愮ず", JOptionPane.INFORMATION_MESSAGE);
+                });
+            };
+            
+            // 鍚姩寰�杩旇矾寰勭粯鍒�
+            if (!shouye.startReturnPathDrawing(finishCallback)) {
+                JOptionPane.showMessageDialog(this, "鏈兘寮�濮嬬粯鍒讹紝璇风‘璁よ澶囩姸鎬佸拰鍩哄噯绔欒缃悗閲嶈瘯", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
+                return false;
+            }
+            
+            // 鏄剧ず棣栭〉鐨勨�滅粨鏉熺粯鍒垛�濇偓娴寜閽紝骞剁粦瀹氱粨鏉熼�昏緫
+            shouye.showEndDrawingButton(() -> {
+                // 鍋滄缁樺埗骞舵墽琛屽畬鎴愬洖璋冿紙鎭㈠鍒版湰椤甸潰骞舵樉绀轰繚瀛�/棰勮绛夛級
+                shouye.stopReturnPathDrawing();
+                zhuye.WangfanDraw drawer = shouye.getReturnPathDrawer();
+                if (drawer != null) {
+                    drawer.executeFinishCallback();
+                }
+                // 鍏抽棴鎮诞鎺у埗
+                shouye.hideEndDrawingButton();
+            });
+
+            setVisible(false);
+            return true;
+        }
+        return false;
+    }
+    
+    /**
+     * 淇濆瓨璺緞鍧愭爣锛堜繚瀛樹紭鍖栧悗鐨勫潗鏍囷紝濡傛灉娌℃湁浼樺寲鍒欎繚瀛樺師濮嬪潗鏍囷級
+     */
+    private void savePathCoordinates() {
+        if (currentDikuai == null) {
+            return;
+        }
+        
+        // 濡傛灉宸茬粡鐢熸垚浼樺寲璺緞锛屼娇鐢ㄤ紭鍖栧悗鐨勫潗鏍�
+        String pathCoordinates = optimizedPathCoordinates;
+        if (pathCoordinates == null || pathCoordinates.trim().isEmpty()) {
+            // 濡傛灉娌℃湁浼樺寲璺緞锛屼娇鐢ㄥ師濮嬪潗鏍囩偣锛圶,Y鏍煎紡锛屽崟浣嶇背锛�
+            pathCoordinates = buildXYCoordinatesString();
+        }
+        
+        if (pathCoordinates == null || pathCoordinates.trim().isEmpty() || "-1".equals(pathCoordinates.trim())) {
+            JOptionPane.showMessageDialog(this, "娌℃湁鍙繚瀛樼殑璺緞鍧愭爣", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
+            return;
+        }
+        
+        // 淇濆瓨鍒板湴鍧�
+        if (Dikuai.updateField(currentDikuai.getLandNumber(), "returnPathCoordinates", pathCoordinates)) {
+            // 鍚屾椂淇濆瓨鍘熷鍧愭爣
+            String rawCoords = rawCoordinatesArea != null ? rawCoordinatesArea.getText() : "";
+            if (rawCoords != null && !rawCoords.trim().isEmpty()) {
+                Dikuai.updateField(currentDikuai.getLandNumber(), "returnPathRawCoordinates", rawCoords);
+            }
+            
+            Dikuai.updateField(currentDikuai.getLandNumber(), "updateTime", getCurrentTime());
+            Dikuai.saveToProperties();
+            
+            // 娓呯┖宸ュ叿绫诲潗鏍�
+            lujing.SavaXyZuobiao.clearCoordinates();
+            
+            JOptionPane.showMessageDialog(this, "璺緞宸蹭繚瀛�", "鎴愬姛", JOptionPane.INFORMATION_MESSAGE);
+        } else {
+            JOptionPane.showMessageDialog(this, "淇濆瓨澶辫触", "閿欒", JOptionPane.ERROR_MESSAGE);
+        }
+    }
+    
+    /**
+     * 鏋勫缓X,Y鍧愭爣瀛楃涓诧紙鍗曚綅绫筹紝绮剧‘鍒板皬鏁扮偣鍚�2浣嶏級
+     */
+    private String buildXYCoordinatesString() {
+        // 浠� WangfanDraw 鑾峰彇璺緞鐐癸紙宸茬粡鏄疿,Y鍧愭爣锛屽崟浣嶇背锛�
+        zhuye.Shouye shouye = zhuye.Shouye.getInstance();
+        if (shouye == null || shouye.getReturnPathDrawer() == null) {
+            return "-1";
+        }
+        
+        List<java.awt.geom.Point2D.Double> points = shouye.getReturnPathDrawer().getPointsSnapshot();
+        if (points == null || points.isEmpty()) {
+            return "-1";
+        }
+        
+        StringBuilder sb = new StringBuilder();
+        java.text.DecimalFormat xyFormat = new java.text.DecimalFormat("0.00");
+        
+        for (java.awt.geom.Point2D.Double point : points) {
+            if (point == null) continue;
+            
+            if (sb.length() > 0) {
+                sb.append(";");
+            }
+            sb.append(xyFormat.format(point.x)).append(",")
+              .append(xyFormat.format(point.y));
+        }
+        
+        return sb.length() > 0 ? sb.toString() : "-1";
+    }
+    
+    private double convertToDecimalDegree(String dmm, String direction) {
+        if (dmm == null || dmm.isEmpty()) {
+            return 0.0;
+        }
+        try {
+            int dotIndex = dmm.indexOf('.');
+            if (dotIndex == -1) {
+                return 0.0;
+            }
+            int degrees = Integer.parseInt(dmm.substring(0, dotIndex - 2));
+            double minutes = Double.parseDouble(dmm.substring(dotIndex - 2));
+            double decimal = degrees + minutes / 60.0;
+            if ("S".equals(direction) || "W".equals(direction)) {
+                decimal = -decimal;
+            }
+            return decimal;
+        } catch (Exception e) {
+            return 0.0;
+        }
+    }
+    
+    private String getCurrentTime() {
+        java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        return sdf.format(new java.util.Date());
+    }
+    
+    private JPanel createInstructionPanel(String text) {
+        JPanel instructionPanel = new JPanel(new BorderLayout());
+        instructionPanel.setBackground(PRIMARY_LIGHT);
+        instructionPanel.setBorder(BorderFactory.createCompoundBorder(
+            BorderFactory.createMatteBorder(0, 5, 0, 0, PRIMARY_COLOR),
+            BorderFactory.createEmptyBorder(12, 12, 12, 12)
+        ));
+        instructionPanel.setMaximumSize(new Dimension(Integer.MAX_VALUE, 70));
+        
+        JLabel iconLabel = new JLabel("馃挕");
+        iconLabel.setFont(new Font("Segoe UI Emoji", Font.PLAIN, 16));
+        iconLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 10));
+        
+        JTextArea instructionText = new JTextArea(text);
+        instructionText.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 13));
+        instructionText.setForeground(TEXT_COLOR);
+        instructionText.setBackground(PRIMARY_LIGHT);
+        instructionText.setLineWrap(true);
+        instructionText.setWrapStyleWord(true);
+        instructionText.setEditable(false);
+        
+        instructionPanel.add(iconLabel, BorderLayout.WEST);
+        instructionPanel.add(instructionText, BorderLayout.CENTER);
+        
+        return instructionPanel;
+    }
+    
+    private JButton createPrimaryButton(String text, int fontSize) {
+        JButton button = buttonset.createStyledButton(text, PRIMARY_COLOR);
+        button.setFont(new Font("寰蒋闆呴粦", Font.BOLD, fontSize));
+        button.setBorder(BorderFactory.createCompoundBorder(
+            BorderFactory.createLineBorder(PRIMARY_DARK, 2),
+            BorderFactory.createEmptyBorder(12, 25, 12, 25)
+        ));
+        button.setCursor(new Cursor(Cursor.HAND_CURSOR));
+
+        button.addMouseListener(new MouseAdapter() {
+            @Override
+            public void mouseEntered(MouseEvent e) {
+                if (button.isEnabled()) {
+                    button.setBackground(PRIMARY_DARK);
+                }
+            }
+
+            @Override
+            public void mouseExited(MouseEvent e) {
+                if (button.isEnabled()) {
+                    button.setBackground(PRIMARY_COLOR);
+                }
+            }
+        });
+
+        return button;
+    }
+    
+    private void showPathPointSummary() {
+        if (pathCountLabel == null) {
+            return;
+        }
+        int count = Coordinate.coordinates != null ? Coordinate.coordinates.size() : 0;
+        pathCountLabel.setText("宸查噰闆嗗埌鏈夋晥鍧愭爣鐐�" + count + "涓�");
+        // pathCountLabel.setVisible(true);
+    }
+
+    private void hidePathPointSummary() {
+        if (pathCountLabel != null) {
+            // pathCountLabel.setVisible(false);
+        }
+    }
+    
+    /**
+     * 鍒涘缓鎿嶄綔鎸夐挳闈㈡澘锛堢敓鎴愯矾寰勩�侀瑙堛�佷繚瀛橈級
+     */
+    private JPanel createActionButtonsPanel() {
+        JPanel panel = new JPanel();
+        panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
+        panel.setBackground(WHITE);
+        panel.setBorder(BorderFactory.createEmptyBorder(15, 0, 0, 0));
+        panel.setAlignmentX(Component.LEFT_ALIGNMENT);
+        
+        // 鐢熸垚璺緞鎸夐挳
+        generatePathBtn = createPrimaryButton("鐢熸垚璺緞", 16);
+        generatePathBtn.setAlignmentX(Component.LEFT_ALIGNMENT);
+        generatePathBtn.addActionListener(e -> generatePath());
+        
+        // 棰勮鎸夐挳
+        previewBtn = createPrimaryButton("棰勮", 16);
+        previewBtn.setAlignmentX(Component.LEFT_ALIGNMENT);
+        previewBtn.addActionListener(e -> previewPath());
+        
+        // 淇濆瓨鎸夐挳锛堝垵濮嬩笉鍙敤锛�
+        saveBtn = createPrimaryButton("淇濆瓨", 16);
+        saveBtn.setAlignmentX(Component.LEFT_ALIGNMENT);
+        saveBtn.setEnabled(false);  // 鍒濆涓嶅彲鐢紝鐢熸垚璺緞鍚庢墠鍙偣鍑�
+        saveBtn.addActionListener(e -> savePath());
+        
+        panel.add(generatePathBtn);
+        panel.add(Box.createHorizontalStrut(15));
+        panel.add(previewBtn);
+        panel.add(Box.createHorizontalStrut(15));
+        panel.add(saveBtn);
+        
+        return panel;
+    }
+    
+    /**
+     * 鐢熸垚璺緞
+     */
+    private void generatePath() {
+        // 鑾峰彇璺緞鐐癸紙浠庡師濮嬪潗鏍囨枃鏈煙鑾峰彇锛�
+        String pathStr = rawCoordinatesArea != null ? rawCoordinatesArea.getText() : "";
+        if (pathStr == null || pathStr.trim().isEmpty()) {
+            JOptionPane.showMessageDialog(this, "娌℃湁鍙敤鐨勮矾寰勭偣锛岃鍏堝畬鎴愮粯鍒�", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
+            return;
+        }
+        
+        try {
+            // 璋冪敤 WangfanpathJisuan 浼樺寲璺緞
+            lujing.WangfanpathJisuan calculator = new lujing.WangfanpathJisuan();
+            // 璁剧疆杈撳嚭绮惧害涓�2浣嶅皬鏁�
+            lujing.WangfanpathJisuan.OptimizationConfig config = new lujing.WangfanpathJisuan.OptimizationConfig();
+            config.setOutputPrecision(2);
+            
+            String optimizedPath = calculator.optimizePath(pathStr, config);
+            
+            if (optimizedPath == null || optimizedPath.trim().isEmpty()) {
+                JOptionPane.showMessageDialog(this, "璺緞浼樺寲澶辫触", "閿欒", JOptionPane.ERROR_MESSAGE);
+                return;
+            }
+            
+            // 淇濆瓨浼樺寲鍚庣殑璺緞鍧愭爣
+            optimizedPathCoordinates = optimizedPath;
+            
+            // 鏄剧ず璁$畻鍚庡潗鏍�
+            if (optimizedCoordinatesArea != null) {
+                optimizedCoordinatesArea.setText(optimizedPath);
+                if (optimizedCoordinatesArea.getParent() instanceof JViewport) {
+                    optimizedCoordinatesArea.getParent().getParent().setVisible(true);
+                }
+                if (optimizedCoordinatesLabel != null) {
+                    int count = 0;
+                    if (optimizedPath != null && !optimizedPath.trim().isEmpty()) {
+                        count = optimizedPath.split(";").length;
+                    }
+                    optimizedCoordinatesLabel.setText("浼樺寲鍚庤矾寰勫潗鏍� (鍏�" + count + "涓偣)");
+                    optimizedCoordinatesLabel.setVisible(true);
+                }
+            }
+            
+            // 鍚敤淇濆瓨鎸夐挳
+            if (saveBtn != null) {
+                saveBtn.setEnabled(true);
+            }
+            
+            // 鍒锋柊鐣岄潰
+            if (mainPanel != null) {
+                mainPanel.revalidate();
+                mainPanel.repaint();
+            }
+        } catch (Exception e) {
+            JOptionPane.showMessageDialog(this, "璺緞鐢熸垚澶辫触: " + e.getMessage(), "閿欒", JOptionPane.ERROR_MESSAGE);
+        }
+    }
+    
+    /**
+     * 棰勮璺緞
+     */
+    private void previewPath() {
+        if (optimizedPathCoordinates == null || optimizedPathCoordinates.trim().isEmpty()) {
+            JOptionPane.showMessageDialog(this, "璇峰厛鐢熸垚璺緞", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
+            return;
+        }
+        
+        zhuye.Shouye shouye = zhuye.Shouye.getInstance();
+        if (shouye != null) {
+            // 闅愯棌褰撳墠绐楀彛
+            setVisible(false);
+            
+            // 鍚姩棰勮
+            shouye.startReturnPathPreview(optimizedPathCoordinates, () -> {
+                // 杩斿洖鍥炶皟锛氭樉绀哄綋鍓嶇獥鍙�
+                setVisible(true);
+            });
+        }
+    }
+    
+    /**
+     * 淇濆瓨璺緞
+     */
+    private void savePath() {
+        if (optimizedPathCoordinates == null || optimizedPathCoordinates.trim().isEmpty()) {
+            JOptionPane.showMessageDialog(this, "璇峰厛鐢熸垚璺緞", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
+            return;
+        }
+        savePathCoordinates();
+    }
+    
+    /**
+     * 鏄剧ず缁樺埗寰�杩旇矾寰勫璇濇
+     */
+    public static void showDrawReturnPathDialog(Window parent, Dikuai dikuai) {
+        showDrawReturnPathDialog(parent, dikuai, false);
+    }
+    
+    /**
+     * 鏄剧ず缁樺埗寰�杩旇矾寰勫璇濇
+     * @param parent 鐖剁獥鍙�
+     * @param dikuai 鍦板潡淇℃伅
+     * @param isRefresh 鏄惁閲嶆柊缁樺埗锛堝鏋滃凡鏈夊潗鏍囷級
+     */
+    public static void showDrawReturnPathDialog(Window parent, Dikuai dikuai, boolean isRefresh) {
+        Huizhiwanfanpath dialog = new Huizhiwanfanpath(parent, dikuai, isRefresh);
+        dialog.setVisible(true);
+    }
+}
+
diff --git a/src/dikuai/ObstacleManagementPage.java b/src/dikuai/ObstacleManagementPage.java
index 96c801a..45e5d7e 100644
--- a/src/dikuai/ObstacleManagementPage.java
+++ b/src/dikuai/ObstacleManagementPage.java
@@ -20,6 +20,8 @@
 /**
  * 闅滅鐗╃鐞嗛〉闈� - UI浼樺寲鐗�
  */
+import publicway.Gpstoxuzuobiao;
+
 public class ObstacleManagementPage extends JDialog {
     private static final long serialVersionUID = 1L;
     
@@ -904,29 +906,11 @@
     }
 
     private double parseDMToDecimal(String dmm, String direction) {
-        if (dmm == null || dmm.trim().isEmpty()) return Double.NaN;
-        try {
-            String trimmed = dmm.trim();
-            int dotIndex = trimmed.indexOf('.');
-            if (dotIndex < 2) return Double.NaN;
-            int degrees = Integer.parseInt(trimmed.substring(0, dotIndex - 2));
-            double minutes = Double.parseDouble(trimmed.substring(dotIndex - 2));
-            double decimal = degrees + minutes / 60.0;
-            if ("S".equalsIgnoreCase(direction) || "W".equalsIgnoreCase(direction)) decimal = -decimal;
-            return decimal;
-        } catch (NumberFormatException ex) {
-            return Double.NaN;
-        }
+        return Gpstoxuzuobiao.parseDMToDecimal(dmm, direction);
     }
     
     private double[] convertLatLonToLocal(double lat, double lon, double baseLat, double baseLon) {
-        double deltaLat = lat - baseLat;
-        double deltaLon = lon - baseLon;
-        double meanLatRad = Math.toRadians((baseLat + lat) / 2.0);
-        double METERS_PER_DEGREE_LAT = 111320.0;
-        double eastMeters = deltaLon * METERS_PER_DEGREE_LAT * Math.cos(meanLatRad);
-        double northMeters = deltaLat * METERS_PER_DEGREE_LAT;
-        return new double[]{eastMeters, northMeters};
+        return Gpstoxuzuobiao.convertLatLonToLocal(lat, lon, baseLat, baseLon);
     }
     
     private void deleteObstacle(Obstacledge.Obstacle obstacle) {
diff --git a/src/dikuai/Wangfanpathpage.java b/src/dikuai/Wangfanpathpage.java
new file mode 100644
index 0000000..d7f53f0
--- /dev/null
+++ b/src/dikuai/Wangfanpathpage.java
@@ -0,0 +1,200 @@
+package dikuai;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.*;
+import publicway.Fuzhibutton;
+import zhuye.Shouye;
+
+/**
+ * 鏌ョ湅/缂栬緫寰�杩旂偣璺緞椤甸潰
+ * 鐙珛鐨勫璇濇绫伙紝鐢ㄤ簬鏄剧ず鍜岀紪杈戝線杩旇矾寰�
+ */
+public class Wangfanpathpage extends JDialog {
+    private static final long serialVersionUID = 1L;
+    
+    // 灏哄甯搁噺 - 涓庡湴鍧楃鐞嗛〉闈繚鎸佷竴鑷�
+    private static final int SCREEN_WIDTH = 400;
+    private static final int SCREEN_HEIGHT = 800;
+
+    // 棰滆壊甯搁噺
+    private static final Color PRIMARY_COLOR = new Color(46, 139, 87);
+    private static final Color PRIMARY_DARK = new Color(30, 107, 69);
+    private static final Color TEXT_COLOR = new Color(51, 51, 51);
+    private static final Color WHITE = Color.WHITE;
+    private static final Color BORDER_COLOR = new Color(200, 200, 200);
+    private static final Color BACKGROUND_COLOR = new Color(250, 250, 250);
+
+    private String result = null;
+
+    public Wangfanpathpage(Window owner, String title, String initialValue, Dikuai dikuai) {
+        super(owner, title, Dialog.ModalityType.APPLICATION_MODAL);
+        initializeUI(title, initialValue, dikuai);
+    }
+
+    public String getResult() {
+        return result;
+    }
+
+    private void initializeUI(String title, String initialValue, Dikuai dikuai) {
+        setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
+        getContentPane().setLayout(new BorderLayout());
+        getContentPane().setBackground(BACKGROUND_COLOR);
+
+        JPanel contentPanel = new JPanel();
+        contentPanel.setLayout(new BoxLayout(contentPanel, BoxLayout.Y_AXIS));
+        contentPanel.setBackground(BACKGROUND_COLOR);
+        contentPanel.setBorder(BorderFactory.createEmptyBorder(12, 16, 12, 16));
+
+        // 鏍囬
+        String landName = dikuai != null ? (dikuai.getLandName() != null ? dikuai.getLandName() : "鏈煡鍦板潡") : "鏈煡鍦板潡";
+        String landNumber = dikuai != null ? (dikuai.getLandNumber() != null ? dikuai.getLandNumber() : "鏈煡缂栧彿") : "鏈煡缂栧彿";
+        JLabel headerLabel = new JLabel(landName + " / " + landNumber);
+        headerLabel.setFont(new Font("寰蒋闆呴粦", Font.BOLD, 16));
+        headerLabel.setForeground(TEXT_COLOR);
+        headerLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
+        contentPanel.add(headerLabel);
+        contentPanel.add(Box.createVerticalStrut(12));
+
+        // 1. 鍘熷寰�杩旇矾寰勫潗鏍囧尯鍩�
+        String rawCoords = dikuai != null ? prepareCoordinateForEditor(dikuai.getReturnPathRawCoordinates()) : "";
+        int rawCount = 0;
+        if (rawCoords != null && !rawCoords.isEmpty() && !"-1".equals(rawCoords)) {
+            rawCount = rawCoords.split(";").length;
+        }
+        JTextArea rawTextArea = createInfoTextArea(rawCoords, false, 4);
+        contentPanel.add(createTextAreaSection("鍘熷寰�杩旇矾寰勫潗鏍� (" + rawCount + "鐐�)", rawTextArea));
+
+        // 2. 浼樺寲鍚庡線杩旇矾寰勫潗鏍囧尯鍩�
+        String optCoords = prepareCoordinateForEditor(initialValue);
+        int optCount = 0;
+        if (optCoords != null && !optCoords.isEmpty() && !"-1".equals(optCoords)) {
+            optCount = optCoords.split(";").length;
+        }
+        JTextArea optTextArea = createInfoTextArea(optCoords, true, 4);
+        contentPanel.add(createTextAreaSection("浼樺寲鍚庡線杩旇矾寰勫潗鏍� (" + optCount + "鐐�)", optTextArea));
+
+        JScrollPane dialogScrollPane = new JScrollPane(contentPanel);
+        dialogScrollPane.setBorder(BorderFactory.createEmptyBorder());
+        dialogScrollPane.getVerticalScrollBar().setUnitIncrement(16);
+        add(dialogScrollPane, BorderLayout.CENTER);
+
+        // 鎸夐挳闈㈡澘
+        JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 12, 12));
+        buttonPanel.setBackground(BACKGROUND_COLOR);
+
+        JButton goDrawBtn = createPrimaryFooterButton("鍘荤粯鍒�");
+        JButton closeBtn = createPrimaryFooterButton("鍏抽棴");
+        
+        goDrawBtn.addActionListener(e -> {
+            String currentText = optTextArea.getText();
+            if (currentText != null && !currentText.trim().isEmpty() && !"-1".equals(currentText.trim())) {
+                result = "__OPEN_DRAW_PAGE_REFRESH__";
+            } else {
+                result = "__OPEN_DRAW_PAGE__";
+            }
+            dispose();
+        });
+
+        closeBtn.addActionListener(e -> dispose());
+
+        buttonPanel.add(goDrawBtn);
+        buttonPanel.add(closeBtn);
+        add(buttonPanel, BorderLayout.SOUTH);
+
+        pack();
+        setSize(SCREEN_WIDTH, SCREEN_HEIGHT); // 璁剧疆涓哄浐瀹氬昂瀵�
+        setLocationRelativeTo(getOwner());
+    }
+
+    private String prepareCoordinateForEditor(String value) {
+        if (value == null) {
+            return "";
+        }
+        String trimmed = value.trim();
+        if (trimmed.isEmpty() || "-1".equals(trimmed)) {
+            return "";
+        }
+        return trimmed;
+    }
+
+    private JTextArea createInfoTextArea(String text, boolean editable, int rows) {
+        JTextArea area = new JTextArea(text);
+        area.setEditable(editable);
+        area.setLineWrap(true);
+        area.setWrapStyleWord(true);
+        area.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 13));
+        area.setRows(Math.max(rows, 2));
+        area.setCaretPosition(0);
+        area.setBorder(BorderFactory.createEmptyBorder(6, 6, 6, 6));
+        area.setBackground(editable ? WHITE : new Color(245, 245, 245));
+        return area;
+    }
+
+    private JPanel createTextAreaSection(String title, JTextArea textArea) {
+        JPanel section = new JPanel(new BorderLayout(0, 6));
+        section.setBackground(BACKGROUND_COLOR);
+        section.setAlignmentX(Component.LEFT_ALIGNMENT);
+        
+        // 鍒涘缓鏍囬闈㈡澘锛屽寘鍚爣棰樺拰澶嶅埗鍥炬爣
+        JPanel titlePanel = new JPanel(new BorderLayout());
+        titlePanel.setBackground(BACKGROUND_COLOR);
+        titlePanel.setOpaque(false);
+        
+        JLabel titleLabel = new JLabel(title);
+        titleLabel.setFont(new Font("寰蒋闆呴粦", Font.BOLD, 14));
+        titleLabel.setForeground(TEXT_COLOR);
+        titlePanel.add(titleLabel, BorderLayout.WEST);
+        
+        // 鍒涘缓澶嶅埗鎸夐挳锛堜娇鐢� Fuzhibutton锛�
+        JButton copyButton = Fuzhibutton.createCopyButton(
+            () -> {
+                String text = textArea.getText();
+                if (text == null || text.trim().isEmpty() || "-1".equals(text.trim())) {
+                    return null; // 杩斿洖null浼氳Е鍙�"鏈缃�"鎻愮ず
+                }
+                return text;
+            },
+            "澶嶅埗", // 绠�鍖栨寜閽枃瀛楋紝鍙樉绀�"澶嶅埗"
+            new Color(230, 250, 240)
+        );
+        // 璋冩暣澶嶅埗鎸夐挳鏍峰紡浠ュ尮閰�
+        copyButton.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 12));
+        copyButton.setPreferredSize(new Dimension(50, 24));
+        copyButton.setMargin(new Insets(0,0,0,0));
+        
+        titlePanel.add(copyButton, BorderLayout.EAST);
+        
+        section.add(titlePanel, BorderLayout.NORTH);
+        
+        JScrollPane scrollPane = new JScrollPane(textArea);
+        scrollPane.setBorder(BorderFactory.createLineBorder(BORDER_COLOR));
+        scrollPane.getVerticalScrollBar().setUnitIncrement(12);
+        section.add(scrollPane, BorderLayout.CENTER);
+        
+        section.setBorder(BorderFactory.createEmptyBorder(4, 0, 12, 0));
+        return section;
+    }
+
+    private JButton createPrimaryFooterButton(String text) {
+        JButton button = new JButton(text);
+        button.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 12));
+        button.setBackground(PRIMARY_COLOR);
+        button.setForeground(WHITE);
+        button.setBorder(BorderFactory.createEmptyBorder(6, 12, 6, 12));
+        button.setFocusPainted(false);
+        button.setCursor(new Cursor(Cursor.HAND_CURSOR));
+        
+        button.addMouseListener(new java.awt.event.MouseAdapter() {
+            public void mouseEntered(java.awt.event.MouseEvent e) {
+                button.setBackground(PRIMARY_DARK);
+            }
+            
+            public void mouseExited(java.awt.event.MouseEvent e) {
+                button.setBackground(PRIMARY_COLOR);
+            }
+        });
+        
+        return button;
+    }
+}
diff --git a/src/dikuai/addzhangaiwu.java b/src/dikuai/addzhangaiwu.java
index 662c5c1..1fa7376 100644
--- a/src/dikuai/addzhangaiwu.java
+++ b/src/dikuai/addzhangaiwu.java
@@ -46,6 +46,7 @@
 
 import baseStation.BaseStation;
 import gecaoji.Device;
+import publicway.buttonset;
 import set.Setsys;
 import ui.UIConfig;
 import zhuye.Coordinate;
@@ -54,13 +55,14 @@
 import zhangaiwu.AddDikuai;
 import zhangaiwu.Obstacledge;
 import zhangaiwu.yulanzhangaiwu;
-import zhuye.buttonset;
 import bianjie.bianjieguihua2;
 import bianjie.ThreePointCircle;
 
 /**
  * 闅滅鐗╂柊澧�/缂栬緫瀵硅瘽妗嗐�傝璁¤瑷�鍙傝�� {@link AddDikuai}锛屾敮鎸侀�氳繃瀹炲湴缁樺埗閲囬泦闅滅鐗╁潗鏍囥��
  */
+import publicway.Gpstoxuzuobiao;
+
 public class addzhangaiwu extends JDialog {
     private static final long serialVersionUID = 1L;
     private static final double METERS_PER_DEGREE_LAT = 111320.0d;
@@ -1217,34 +1219,11 @@
     }
 
     private static double parseDMToDecimal(String dmm, String direction) {
-        if (dmm == null || dmm.trim().isEmpty()) {
-            return Double.NaN;
-        }
-        try {
-            String trimmed = dmm.trim();
-            int dotIndex = trimmed.indexOf('.');
-            if (dotIndex < 2) {
-                return Double.NaN;
-            }
-            int degrees = Integer.parseInt(trimmed.substring(0, dotIndex - 2));
-            double minutes = Double.parseDouble(trimmed.substring(dotIndex - 2));
-            double decimal = degrees + minutes / 60.0;
-            if ("S".equalsIgnoreCase(direction) || "W".equalsIgnoreCase(direction)) {
-                decimal = -decimal;
-            }
-            return decimal;
-        } catch (NumberFormatException ex) {
-            return Double.NaN;
-        }
+        return Gpstoxuzuobiao.parseDMToDecimal(dmm, direction);
     }
 
     private static double[] convertLatLonToLocal(double lat, double lon, double baseLat, double baseLon) {
-        double deltaLat = lat - baseLat;
-        double deltaLon = lon - baseLon;
-        double meanLatRad = Math.toRadians((baseLat + lat) / 2.0);
-        double eastMeters = deltaLon * METERS_PER_DEGREE_LAT * Math.cos(meanLatRad);
-        double northMeters = deltaLat * METERS_PER_DEGREE_LAT;
-        return new double[]{eastMeters, northMeters};
+        return Gpstoxuzuobiao.convertLatLonToLocal(lat, lon, baseLat, baseLon);
     }
 
     private static CircleFitResult fitCircleFromPoints(List<double[]> points) {
diff --git a/src/dikuai/daohangyulan.java b/src/dikuai/daohangyulan.java
index a65ffcf..2db9acb 100644
--- a/src/dikuai/daohangyulan.java
+++ b/src/dikuai/daohangyulan.java
@@ -9,9 +9,9 @@
 import java.util.ArrayList;
 import zhuye.Shouye;
 import zhuye.MapRenderer;
-import zhuye.buttonset;
 import gecaoji.Gecaoji;
 import gecaoji.lujingdraw;
+import publicway.buttonset;
 
 /**
  * 瀵艰埅棰勮鍔熻兘绫�
diff --git a/src/gecaoji/Device.java b/src/gecaoji/Device.java
index d37e21f..97a3333 100644
--- a/src/gecaoji/Device.java
+++ b/src/gecaoji/Device.java
@@ -1,6 +1,7 @@
 package gecaoji;
 import baseStation.BaseStation;
 import set.Setsys;
+import zhuye.MowerLocationData;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
@@ -436,6 +437,12 @@
         }
 
         positioningStatus = defaultIfEmpty(sanitizeField(fields, 6));
+        // 鍚屾鍒扮粯鍒舵ā鍧楃殑鏁版嵁婧愶紝淇濊瘉寰�杩旂粯鍒跺畾鏃跺櫒鑳借瘑鍒畾浣嶈川閲�
+        try {
+            MowerLocationData.updateProperty("positioningQuality", positioningStatus);
+        } catch (Throwable ignored) {
+            // 闃插尽寮忥細鍗充娇鏇存柊澶辫触涔熶笉褰卞搷璁惧鏁版嵁澶勭悊
+        }
         satelliteCount = defaultIfEmpty(sanitizeField(fields, 7));
         differentialAge = defaultIfEmpty(sanitizeField(fields, 13));
         battery = defaultIfEmpty(sanitizeField(fields, 16));
@@ -485,6 +492,12 @@
         }
 
         positioningStatus = defaultIfEmpty(sanitizeField(fields, 6));
+        // 鍚屾鍒扮粯鍒舵ā鍧楃殑鏁版嵁婧愶紝淇濊瘉寰�杩旂粯鍒跺畾鏃跺櫒鑳借瘑鍒畾浣嶈川閲�
+        try {
+            MowerLocationData.updateProperty("positioningQuality", positioningStatus);
+        } catch (Throwable ignored) {
+            // 闃插尽寮忥細鍗充娇鏇存柊澶辫触涔熶笉褰卞搷璁惧鏁版嵁澶勭悊
+        }
         satelliteCount = defaultIfEmpty(sanitizeField(fields, 7));
         differentialAge = defaultIfEmpty(sanitizeField(fields, 13));       
         realtimeSpeed ="0";        
@@ -546,6 +559,9 @@
         if (Double.isFinite(eastMeters) && Double.isFinite(northMeters)) {
             realtimeX = formatMeters(eastMeters);
             realtimeY = formatMeters(northMeters);
+            
+            // 淇濆瓨鍧愭爣鍒板伐鍏风被
+            lujing.SavaXyZuobiao.addCoordinate(eastMeters, northMeters);
         }
     }
 
diff --git a/src/gecaoji/GecaojiMeg.java b/src/gecaoji/GecaojiMeg.java
index a1560d2..e573211 100644
--- a/src/gecaoji/GecaojiMeg.java
+++ b/src/gecaoji/GecaojiMeg.java
@@ -1,12 +1,14 @@
 package gecaoji;
 
 import javax.swing.*;
+
+import publicway.buttonset;
+
 import java.awt.*;
 import java.awt.event.WindowAdapter;
 import java.awt.event.WindowEvent;
 import java.text.SimpleDateFormat;
 import java.util.Date;
-import zhuye.buttonset;
 
 // Manages the mower info dialog to keep MapRenderer focused on rendering.
 public class GecaojiMeg {
diff --git a/src/lujing/MowingPathGenerationPage.java b/src/lujing/MowingPathGenerationPage.java
index c55639b..503a1fd 100644
--- a/src/lujing/MowingPathGenerationPage.java
+++ b/src/lujing/MowingPathGenerationPage.java
@@ -16,12 +16,12 @@
 import lujing.Qufenxingzhuang;
 import lujing.AoxinglujingNoObstacle;
 import lujing.YixinglujingNoObstacle;
+import publicway.Fuzhibutton;
 import lujing.AoxinglujingHaveObstacel;
 import lujing.YixinglujingHaveObstacel;
 import org.locationtech.jts.geom.Coordinate;
 import gecaoji.Device;
 import java.util.Locale;
-import zhuye.Fuzhibutton;
 
 /**
  * 鐢熸垚鍓茶崏璺緞椤甸潰
diff --git a/src/zhuye/Fuzhibutton.java b/src/publicway/Fuzhibutton.java
similarity index 99%
rename from src/zhuye/Fuzhibutton.java
rename to src/publicway/Fuzhibutton.java
index 340977f..8f1dc10 100644
--- a/src/zhuye/Fuzhibutton.java
+++ b/src/publicway/Fuzhibutton.java
@@ -1,4 +1,4 @@
-package zhuye;
+package publicway;
 
 import javax.swing.*;
 import java.awt.*;
diff --git a/src/publicway/Gpstoxuzuobiao.java b/src/publicway/Gpstoxuzuobiao.java
new file mode 100644
index 0000000..072d319
--- /dev/null
+++ b/src/publicway/Gpstoxuzuobiao.java
@@ -0,0 +1,141 @@
+package publicway;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Properties;
+
+public class Gpstoxuzuobiao {
+    private static final double METERS_PER_DEGREE_LAT = 111320.0d;
+    
+    // 缂撳瓨鍩哄噯绔欏潗鏍�
+    private static double cachedBaseLat = 0.0;
+    private static double cachedBaseLon = 0.0;
+    private static boolean baseStationLoaded = false;
+
+    /**
+     * 瑙f瀽GNGGA鏁版嵁骞惰浆鎹负XY鍧愭爣
+     * @param gnggaData $GNGGA鏁版嵁
+     * @return double[]{x, y} 鐩稿鍧愭爣锛屽鏋滆В鏋愬け璐ユ垨鏃犲熀绔欐暟鎹繑鍥瀗ull
+     */
+    public static double[] processGNGGAToXY(String gnggaData) {
+        ensureBaseStationLoaded();
+        if (!baseStationLoaded) {
+            return null;
+        }
+        return processGNGGAToXY(gnggaData, cachedBaseLat, cachedBaseLon);
+    }
+
+    /**
+     * 瑙f瀽GNGGA鏁版嵁骞惰浆鎹负XY鍧愭爣
+     * @param gnggaData $GNGGA鏁版嵁
+     * @param baseLat 鍩哄噯绔欑含搴�
+     * @param baseLon 鍩哄噯绔欑粡搴�
+     * @return double[]{x, y} 鐩稿鍧愭爣
+     */
+    public static double[] processGNGGAToXY(String gnggaData, double baseLat, double baseLon) {
+        if (gnggaData == null || !gnggaData.contains("$GNGGA")) {
+            return null;
+        }
+        
+        // 绠�鍗曠殑瑙f瀽閫昏緫锛屾彁鍙栫粡绾害
+        // 鏍煎紡: $GNGGA,hhmmss.ss,lat,latDir,lon,lonDir,quality,sats,hdop,alt,units,sep,units,age,refID*cs
+        
+        String[] parts = gnggaData.split(",");
+        // 鎵惧埌$GNGGA鐨勪綅缃�
+        int index = -1;
+        for(int i=0; i<parts.length; i++) {
+            if (parts[i].contains("$GNGGA")) {
+                index = i;
+                break;
+            }
+        }
+        
+        // 纭繚鏈夎冻澶熺殑瀛楁: lat(2), latDir(3), lon(4), lonDir(5)
+        if (index == -1 || index + 5 >= parts.length) {
+            return null;
+        }
+        
+        String latStr = parts[index + 2];
+        String latDir = parts[index + 3];
+        String lonStr = parts[index + 4];
+        String lonDir = parts[index + 5];
+        
+        if (latStr.isEmpty() || lonStr.isEmpty()) {
+            return null;
+        }
+        
+        double lat = parseDMToDecimal(latStr, latDir);
+        double lon = parseDMToDecimal(lonStr, lonDir);
+        
+        return convertLatLonToLocal(lat, lon, baseLat, baseLon);
+    }
+
+    /**
+     * 灏嗗害鍒嗘牸寮�(DMM)杞崲涓哄崄杩涘埗鏍煎紡(DD)
+     * @param dmm 搴﹀垎鏍煎紡瀛楃涓� (e.g. "3015.1234")
+     * @param direction 鏂瑰悜 (N/S/E/W)
+     * @return 鍗佽繘鍒剁粡绾害
+     */
+    public static double parseDMToDecimal(String dmm, String direction) {
+        if (dmm == null || dmm.isEmpty()) {
+            return 0.0;
+        }
+        try {
+            double val = Double.parseDouble(dmm);
+            int degrees = (int) (val / 100);
+            double minutes = val - degrees * 100;
+            double decimal = degrees + minutes / 60.0;
+            if (direction != null && (direction.equalsIgnoreCase("S") || direction.equalsIgnoreCase("W"))) {
+                decimal = -decimal;
+            }
+            return decimal;
+        } catch (NumberFormatException e) {
+            return 0.0;
+        }
+    }
+
+    /**
+     * 灏嗙粡绾害杞崲涓虹浉瀵瑰潗鏍�(XY)
+     * @param lat 鐩爣绾害
+     * @param lon 鐩爣缁忓害
+     * @param baseLat 鍩哄噯绔欑含搴�
+     * @param baseLon 鍩哄噯绔欑粡搴�
+     * @return double[]{x, y} (鍗曚綅: 绫�)
+     */
+    public static double[] convertLatLonToLocal(double lat, double lon, double baseLat, double baseLon) {
+        double deltaLat = lat - baseLat;
+        double deltaLon = lon - baseLon;
+        double meanLatRad = Math.toRadians((baseLat + lat) / 2.0);
+        double eastMeters = deltaLon * METERS_PER_DEGREE_LAT * Math.cos(meanLatRad);
+        double northMeters = deltaLat * METERS_PER_DEGREE_LAT;
+        return new double[]{eastMeters, northMeters};
+    }
+    
+    private static void ensureBaseStationLoaded() {
+        if (baseStationLoaded) return;
+        
+        Properties props = new Properties();
+        try (FileInputStream input = new FileInputStream("basestation.properties")) {
+            props.load(input);
+            String coords = props.getProperty("installationCoordinates");
+            if (coords != null && !coords.isEmpty() && !"-1".equals(coords)) {
+                String[] parts = coords.split(",");
+                if (parts.length >= 4) {
+                    cachedBaseLat = parseDMToDecimal(parts[0], parts[1]);
+                    cachedBaseLon = parseDMToDecimal(parts[2], parts[3]);
+                    baseStationLoaded = true;
+                }
+            }
+        } catch (IOException e) {
+            // ignore
+        }
+    }
+    
+    /**
+     * 閲嶆柊鍔犺浇鍩哄噯绔欎俊鎭�
+     */
+    public static void reloadBaseStation() {
+        baseStationLoaded = false;
+        ensureBaseStationLoaded();
+    }
+}
diff --git a/src/zhuye/Lookbutton.java b/src/publicway/Lookbutton.java
similarity index 98%
rename from src/zhuye/Lookbutton.java
rename to src/publicway/Lookbutton.java
index aebfb9e..52d7727 100644
--- a/src/zhuye/Lookbutton.java
+++ b/src/publicway/Lookbutton.java
@@ -1,4 +1,4 @@
-package zhuye;
+package publicway;
 
 import javax.swing.*;
 import java.awt.*;
@@ -105,3 +105,10 @@
     }
 }
 
+
+
+
+
+
+
+
diff --git a/src/zhuye/buttonset.java b/src/publicway/buttonset.java
similarity index 99%
rename from src/zhuye/buttonset.java
rename to src/publicway/buttonset.java
index 549a9f5..9b87678 100644
--- a/src/zhuye/buttonset.java
+++ b/src/publicway/buttonset.java
@@ -1,4 +1,4 @@
-package zhuye;
+package publicway;
 import java.awt.Color;
 import java.awt.Cursor;
 import java.awt.Dimension;
diff --git a/src/set/Sets.java b/src/set/Sets.java
index 6f5ea93..ab09098 100644
--- a/src/set/Sets.java
+++ b/src/set/Sets.java
@@ -3,10 +3,9 @@
 import baseStation.BaseStation;
 import gecaoji.Device;
 import gecaoji.MowerSafetyDistanceCalculator;
-
+import publicway.buttonset;
 import zhuye.MapRenderer;
 import zhuye.Shouye;
-import zhuye.buttonset;
 import zhuye.celiangmoshi;
 import javax.swing.*;
 import javax.swing.filechooser.FileNameExtensionFilter;
diff --git a/src/set/debug.java b/src/set/debug.java
index ca549df..a8af0fa 100644
--- a/src/set/debug.java
+++ b/src/set/debug.java
@@ -4,6 +4,8 @@
 import chuankou.SerialPortPreferences;
 import chuankou.SerialPortService;
 import chuankou.sendmessage;
+import publicway.buttonset;
+
 import com.fazecast.jSerialComm.SerialPort;
 import ui.UIConfig;
 import javax.swing.*;
@@ -16,7 +18,6 @@
 import java.nio.charset.StandardCharsets;
 import java.text.SimpleDateFormat;
 import java.util.Date;
-import zhuye.buttonset;
 
 /**
  * 绯荤粺璋冭瘯瀵硅瘽妗嗐��
diff --git a/src/udpdell/UDPServer.java b/src/udpdell/UDPServer.java
index 7243090..b59526f 100644
--- a/src/udpdell/UDPServer.java
+++ b/src/udpdell/UDPServer.java
@@ -10,6 +10,8 @@
 import gecaoji.Device;
 import zhuye.Coordinate;
 
+import publicway.Gpstoxuzuobiao;
+
 public class UDPServer {
 	private static final int PORT = 7000; // 榛樿UDP鐩戝惉绔彛
 	private static final int BUFFER_SIZE = 65507; // UDP鏈�澶у寘澶у皬
@@ -87,6 +89,14 @@
 		}
 		int sequence = incrementReceivedPacketCounter();
 		System.out.println("鏀跺埌浜嗗樊鍒嗘暟鎹�(" + sequence + ")锛�" + message);
+		
+		// 浣跨敤Gpstoxuzuobiao澶勭悊骞惰幏鍙朮Y鍧愭爣
+		double[] xy = Gpstoxuzuobiao.processGNGGAToXY(message);
+		if (xy != null) {
+			// 杩欓噷鍙互灏哫Y鍧愭爣浼犻�掔粰鍏朵粬鏂规硶浣跨敤
+			// System.out.println("UDP GNGGA -> XY: " + xy[0] + ", " + xy[1]);
+		}
+		
 		Coordinate.parseGNGGAToCoordinateList(message);
 		int count = Coordinate.coordinates.size();
 		System.out.println("savenum:" + count);
@@ -110,6 +120,14 @@
 		}
 		int sequence = incrementReceivedPacketCounter();
 		System.out.println("鏀跺埌浜嗕覆鍙f暟鎹�(" + sequence + ")锛�" + message);
+		
+		// 浣跨敤Gpstoxuzuobiao澶勭悊骞惰幏鍙朮Y鍧愭爣
+		double[] xy = Gpstoxuzuobiao.processGNGGAToXY(message);
+		if (xy != null) {
+			// 杩欓噷鍙互灏哫Y鍧愭爣浼犻�掔粰鍏朵粬鏂规硶浣跨敤
+			// System.out.println("Serial GNGGA -> XY: " + xy[0] + ", " + xy[1]);
+		}
+		
 		Coordinate.dellchuankougngga(message);
 		int count = Coordinate.coordinates.size();
 		System.out.println("savenum:" + count);
diff --git a/src/yaokong/Control02.java b/src/yaokong/Control02.java
index afe55be..5cef25c 100644
--- a/src/yaokong/Control02.java
+++ b/src/yaokong/Control02.java
@@ -3,6 +3,8 @@
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 
+import publicway.Gpstoxuzuobiao;
+
 public class Control02 {
     
     /**
@@ -98,29 +100,7 @@
      * 渚嬪锛�3949.90238860 -> 39.83170647666667
      */
     private static double parseDMToDecimal(String dmm, String direction) {
-        try {
-            // 鎵惧埌灏忔暟鐐圭殑浣嶇疆
-            int dotIndex = dmm.indexOf('.');
-            if (dotIndex < 2) {
-                throw new IllegalArgumentException("搴﹀垎鏍煎紡閿欒: " + dmm);
-            }
-            
-            // 鎻愬彇搴﹀拰鍒�
-            int degrees = Integer.parseInt(dmm.substring(0, dotIndex - 2));
-            double minutes = Double.parseDouble(dmm.substring(dotIndex - 2));
-            
-            // 杞崲涓哄崄杩涘埗
-            double decimal = degrees + minutes / 60.0;
-            
-            // 鏍规嵁鏂瑰悜璋冩暣姝h礋
-            if ("S".equalsIgnoreCase(direction) || "W".equalsIgnoreCase(direction)) {
-                decimal = -decimal;
-            }
-            
-            return decimal;
-        } catch (Exception e) {
-            throw new IllegalArgumentException("鍧愭爣鏍煎紡瑙f瀽閿欒: " + dmm, e);
-        }
+        return Gpstoxuzuobiao.parseDMToDecimal(dmm, direction);
     }
     
     private static String bytesToHex(byte[] bytes) {
diff --git a/src/zhangaiwu/AddDikuai.java b/src/zhangaiwu/AddDikuai.java
index 8d8001b..32a7a4f 100644
--- a/src/zhangaiwu/AddDikuai.java
+++ b/src/zhangaiwu/AddDikuai.java
@@ -27,12 +27,12 @@
 import dikuai.Dikuaiguanli;
 import bianjie.bianjieguihua2;
 import lujing.Lunjingguihua;
+import publicway.buttonset;
 import set.Setsys;
 import ui.UIConfig;
 import zhuye.MowerLocationData;
 import zhuye.Shouye;
 import zhuye.Coordinate;
-import zhuye.buttonset;
 import gecaoji.Device;
 
 /**
diff --git a/src/zhangaiwu/yulanzhangaiwu.java b/src/zhangaiwu/yulanzhangaiwu.java
index f9cacf8..14b266a 100644
--- a/src/zhangaiwu/yulanzhangaiwu.java
+++ b/src/zhangaiwu/yulanzhangaiwu.java
@@ -12,6 +12,7 @@
 import java.util.List;
 import java.util.Locale;
 
+import javax.swing.JDialog;
 import javax.swing.SwingUtilities;
 
 import zhuye.Coordinate;
@@ -20,7 +21,9 @@
 /**
  * 鍦ㄥ湴鍥句笂瀹炴椂棰勮姝e湪缁樺埗鐨勯殰纰嶇墿銆�
  */
-public final class yulanzhangaiwu {
+import publicway.Gpstoxuzuobiao;
+
+public class yulanzhangaiwu extends JDialog {
     private static final Object LOCK = new Object();
     private static final double METERS_PER_DEGREE_LAT = 111320.0d;
     private static final Color PREVIEW_LINE_COLOR = new Color(0, 123, 255, 200);
@@ -229,34 +232,11 @@
     }
 
     private static double parseDMToDecimal(String dmm, String direction) {
-        if (dmm == null || dmm.trim().isEmpty()) {
-            return Double.NaN;
-        }
-        try {
-            String trimmed = dmm.trim();
-            int dotIndex = trimmed.indexOf('.');
-            if (dotIndex < 2) {
-                return Double.NaN;
-            }
-            int degrees = Integer.parseInt(trimmed.substring(0, dotIndex - 2));
-            double minutes = Double.parseDouble(trimmed.substring(dotIndex - 2));
-            double decimal = degrees + minutes / 60.0;
-            if ("S".equalsIgnoreCase(direction) || "W".equalsIgnoreCase(direction)) {
-                decimal = -decimal;
-            }
-            return decimal;
-        } catch (NumberFormatException ex) {
-            return Double.NaN;
-        }
+        return Gpstoxuzuobiao.parseDMToDecimal(dmm, direction);
     }
 
     private static double[] convertLatLonToLocal(double lat, double lon, double baseLat, double baseLon) {
-        double deltaLat = lat - baseLat;
-        double deltaLon = lon - baseLon;
-        double meanLatRad = Math.toRadians((baseLat + lat) / 2.0);
-        double eastMeters = deltaLon * METERS_PER_DEGREE_LAT * Math.cos(meanLatRad);
-        double northMeters = deltaLat * METERS_PER_DEGREE_LAT;
-        return new double[]{eastMeters, northMeters};
+        return Gpstoxuzuobiao.convertLatLonToLocal(lat, lon, baseLat, baseLon);
     }
 
     private static CircleState fitCircle(List<double[]> points) {
diff --git a/src/zhuye/AreaSelectionDialog.java b/src/zhuye/AreaSelectionDialog.java
index 0e87a12..965e1dc 100644
--- a/src/zhuye/AreaSelectionDialog.java
+++ b/src/zhuye/AreaSelectionDialog.java
@@ -3,9 +3,11 @@
 import ui.UIConfig;
 
 import javax.swing.*;
+
+import publicway.buttonset;
+
 import java.awt.*;
 import java.awt.event.*;
-import zhuye.buttonset;
 
 public class AreaSelectionDialog extends JDialog {
     private final Color THEME_COLOR;
diff --git a/src/zhuye/LegendDialog.java b/src/zhuye/LegendDialog.java
index 096e239..f3c852f 100644
--- a/src/zhuye/LegendDialog.java
+++ b/src/zhuye/LegendDialog.java
@@ -48,6 +48,7 @@
             {"璺緞鏂瑰悜", "255,0,0", "arrow"},
             {"闅滅鐗╁尯鍩�", "255,0,0", "obstacle_fill"},
             {"鍓茶崏鏈轰綅缃�", "0,150,0", "mow"},
+            {"寰�杩旇矾寰�", "0,0,0", "railway"},
             {"鍓茶崏杞ㄨ抗", "100,150,200", "trail"}
         };
         
@@ -120,11 +121,30 @@
                         g2d.fillPolygon(xPoints, yPoints, 3);
                         break;
                     case "mow":
-                        g2d.setColor(itemColor);
-                        g2d.fillOval(x, y, size, size);
-                        g2d.setColor(new Color(100, 100, 100));
-                        g2d.setStroke(new BasicStroke(1));
-                        g2d.drawOval(x, y, size, size);
+                        ImageIcon icon = loadIcon("image/gecaoji.png", size + 8, size + 8);
+                        if (icon != null) {
+                            icon.paintIcon(this, g2d, x - 4, y - 4);
+                        } else {
+                            g2d.setColor(itemColor);
+                            g2d.fillOval(x, y, size, size);
+                            g2d.setColor(new Color(100, 100, 100));
+                            g2d.setStroke(new BasicStroke(1));
+                            g2d.drawOval(x, y, size, size);
+                        }
+                        break;
+                    case "railway":
+                        // 1. 缁樺埗搴曞眰榛戣壊瀹炵嚎
+                        g2d.setColor(Color.BLACK);
+                        g2d.setStroke(new BasicStroke(3.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
+                        g2d.drawLine(x, y + size/2, x + size, y + size/2);
+                        
+                        // 2. 缁樺埗椤跺眰鐧借壊铏氱嚎
+                        float dashLen = 3.0f * 2.0f;
+                        float dashSpace = 3.0f * 2.0f;
+                        float[] dashPattern = {dashLen, dashSpace};
+                        g2d.setColor(Color.WHITE);
+                        g2d.setStroke(new BasicStroke(1.2f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND, 10.0f, dashPattern, 0.0f));
+                        g2d.drawLine(x, y + size/2, x + size, y + size/2);
                         break;
                     case "trail":
                         g2d.setColor(itemColor);
diff --git a/src/zhuye/MapRenderer.java b/src/zhuye/MapRenderer.java
index 790f3b9..ed61778 100644
--- a/src/zhuye/MapRenderer.java
+++ b/src/zhuye/MapRenderer.java
@@ -107,6 +107,9 @@
     private boolean idleTrailSuppressed;
     private Path2D.Double realtimeBoundaryPathCache;
     private String realtimeBoundaryPathLand;
+    private WangfanDraw returnPathDrawer;  // 寰�杩旇矾寰勭粯鍒剁鐞嗗櫒
+    private List<Point2D.Double> currentReturnPath; // 褰撳墠鍦板潡鐨勫線杩旇矾寰勶紙鐢ㄤ簬鏄剧ず锛�
+    private List<Point2D.Double> previewReturnPath; // 棰勮鐨勫線杩旇矾寰�
 
     private static final double TRACK_SAMPLE_MIN_DISTANCE_METERS = 0.2d;
     private static final double TRACK_DUPLICATE_TOLERANCE_METERS = 1e-3d;
@@ -459,6 +462,17 @@
             drawNavigationPreviewCoverage(g2d);
         }
 
+        // 鍏堢敾寰�杩旇矾寰勶紙绾�+鐐癸級锛屼繚璇佸壊鑽夋満鍥炬爣鍦ㄥ叾涓婃柟
+        if (returnPathDrawer != null && returnPathDrawer.isActive()) {
+            returnPathDrawer.draw(g2d, scale);
+        } else if (previewReturnPath != null && !previewReturnPath.isEmpty()) {
+            // 缁樺埗棰勮鐨勫線杩旇矾寰勶紙閾佺嚎璺浘椋庢牸锛�
+            WangfanDraw.drawRailwayPath(g2d, previewReturnPath, scale);
+        } else if (currentReturnPath != null && !currentReturnPath.isEmpty()) {
+            // 缁樺埗淇濆瓨鐨勫線杩旇矾寰勶紙閾佺嚎璺浘椋庢牸锛�
+            WangfanDraw.drawRailwayPath(g2d, currentReturnPath, scale);
+        }
+
         drawMower(g2d);
         
         // 缁樺埗瀵艰埅棰勮閫熷害锛堝鏋滄鍦ㄥ鑸瑙堬級
@@ -962,6 +976,14 @@
             mowerEffectiveWidthMeters = defaultMowerWidthMeters;
         }
 
+        // 鍔犺浇寰�杩旇矾寰�
+        String returnPathStr = dikuai != null ? dikuai.getReturnPathCoordinates() : null;
+        if (returnPathStr != null && !returnPathStr.isEmpty() && !"-1".equals(returnPathStr)) {
+            currentReturnPath = lujingdraw.parsePlannedPath(returnPathStr);
+        } else {
+            currentReturnPath = null;
+        }
+
         loadRealtimeTrack(landNumber, dikuai != null ? dikuai.getMowingTrack() : null);
         visualizationPanel.repaint();
     }
@@ -2993,5 +3015,63 @@
     public Gecaoji getMower() {
         return mower;
     }
+    
+    /**
+     * 璁剧疆寰�杩旇矾寰勭粯鍒剁鐞嗗櫒
+     */
+    public void setReturnPathDrawer(WangfanDraw drawer) {
+        this.returnPathDrawer = drawer;
+    }
+
+    /**
+     * 璁剧疆棰勮鐨勫線杩旇矾寰�
+     */
+    public void setPreviewReturnPath(List<Point2D.Double> path) {
+        this.previewReturnPath = path;
+        if (visualizationPanel != null) {
+            visualizationPanel.repaint();
+        }
+    }
+    
+    /**
+     * 寮�濮嬪線杩旇矾寰勭粯鍒�
+     */
+    public void startReturnPathDrawing() {
+        if (returnPathDrawer != null) {
+            // 绂佺敤鎷栧熬鏁堟灉锛堝湪寰�杩旇矾寰勭粯鍒舵ā寮忎笅涓嶆樉绀哄疄鏃惰建杩规嫋灏撅級
+            idleTrailSuppressed = true;
+            clearIdleMowerTrail();
+            // 娓呯┖涔嬪墠鐨勮矾寰勭偣锛堥�氳繃 WangfanDraw 绠$悊锛�
+            repaint();
+        }
+    }
+    
+    /**
+     * 鍋滄寰�杩旇矾寰勭粯鍒�
+     */
+    public void stopReturnPathDrawing() {
+        // 鎭㈠鎷栧熬鏁堟灉
+        idleTrailSuppressed = false;
+        repaint();
+    }
+    
+    /**
+     * 娣诲姞寰�杩旇矾寰勭偣锛堝凡搴熷純锛岃矾寰勭偣鐢� WangfanDraw 鐩存帴绠$悊锛�
+     */
+    @Deprecated
+    public void addReturnPathPoint(double x, double y) {
+        // 璺緞鐐圭敱 WangfanDraw 鐩存帴绠$悊锛岃繖閲屽彧闇�瑕侀噸缁�
+        repaint();
+    }
+    
+    /**
+     * 鑾峰彇寰�杩旇矾寰勭偣鍒楄〃鐨勫揩鐓�
+     */
+    public List<Point2D.Double> getReturnPathPointsSnapshot() {
+        if (returnPathDrawer != null) {
+            return returnPathDrawer.getPointsSnapshot();
+        }
+        return new ArrayList<>();
+    }
 
 }
\ No newline at end of file
diff --git a/src/zhuye/Shouye.java b/src/zhuye/Shouye.java
index 1dbc337..22f8fc6 100644
--- a/src/zhuye/Shouye.java
+++ b/src/zhuye/Shouye.java
@@ -19,23 +19,23 @@
 import gecaoji.Device;
 import gecaoji.Gecaoji;
 import gecaoji.MowerBoundaryChecker;
+import publicway.buttonset;
 import set.Sets;
 import set.debug;
 import udpdell.UDPServer;
 import zhangaiwu.AddDikuai;
-import yaokong.Control04;
 import yaokong.RemoteControlDialog;
-
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.Locale;
-import java.util.Objects;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.function.Consumer;
 import java.awt.geom.Point2D;
 
+import publicway.Gpstoxuzuobiao;
+
 /**
  * 棣栭〉鐣岄潰 - 閫傞厤6.5瀵哥珫灞忥紝浣跨敤鐙珛鐨凪apRenderer杩涜缁樺埗
  */
@@ -107,12 +107,14 @@
 	// 鍦板浘娓叉煋鍣�
 	private MapRenderer mapRenderer;
 	
+	private boolean pathPreviewActive;
+	
 	private final Consumer<String> serialLineListener = line -> {
 		SwingUtilities.invokeLater(() -> {
 			updateDataPacketCountLabel();
 			// 濡傛灉鏀跺埌$GNGGA鏁版嵁锛岀珛鍗虫洿鏂版嫋灏�
 			if (line != null && line.trim().startsWith("$GNGGA")) {
-				if (mapRenderer != null) {
+				if (mapRenderer != null && !pathPreviewActive) {
 					mapRenderer.forceUpdateIdleMowerTrail();
 				}
 			}
@@ -125,7 +127,6 @@
 	private JPanel floatingButtonColumn;
 	private Runnable endDrawingCallback;
 	private JButton pathPreviewReturnButton;
-	private boolean pathPreviewActive;
 	private Runnable pathPreviewReturnAction;
 	private JButton settingsReturnButton;  // 杩斿洖绯荤粺璁剧疆椤甸潰鐨勬偓娴寜閽�
 	private JButton saveManualBoundaryButton;  // 淇濆瓨鎵嬪姩缁樺埗杈圭晫鐨勬寜閽�
@@ -170,6 +171,7 @@
 	private boolean storedStopButtonActive;
 	private String storedStatusBeforeDrawing;
 	private boolean handheldCaptureInlineUiActive;
+	private WangfanDraw returnPathDrawer;  // 寰�杩旇矾寰勭粯鍒剁鐞嗗櫒
 	private Timer handheldCaptureStatusTimer;
 	private String handheldCaptureStoredStatusText;
 	private Color handheldStartButtonOriginalBackground;
@@ -209,6 +211,54 @@
 		// 鍒濆鍖栧湴鍥炬覆鏌撳櫒
 		mapRenderer = new MapRenderer(visualizationPanel);
 		applyIdleTrailDurationFromSettings();
+		
+		// 鍒濆鍖栧線杩旇矾寰勭粯鍒剁鐞嗗櫒
+		returnPathDrawer = new WangfanDraw(this, mapRenderer, new WangfanDraw.DrawingHelper() {
+			@Override
+			public double[] resolveBaseLatLon() {
+				return resolveCircleBaseLatLon();
+			}
+			
+			@Override
+			public Coordinate getLatestCoordinate() {
+				return Shouye.this.getLatestCoordinate();
+			}
+			
+			@Override
+			public double parseDMToDecimal(String dmm, String direction) {
+				return Shouye.this.parseDMToDecimal(dmm, direction);
+			}
+			
+			@Override
+			public double[] convertLatLonToLocal(double lat, double lon, double baseLat, double baseLon) {
+				return Shouye.this.convertLatLonToLocal(lat, lon, baseLat, baseLon);
+			}
+			
+			@Override
+			public boolean arePointsClose(Point2D.Double a, Point2D.Double b) {
+				return Shouye.this.arePointsClose(a, b);
+			}
+			
+			@Override
+			public void enterDrawingControlMode() {
+				Shouye.this.enterDrawingControlMode();
+			}
+			
+			@Override
+			public void exitDrawingControlMode() {
+				Shouye.this.exitDrawingControlMode();
+			}
+			
+			@Override
+			public boolean isDrawingPaused() {
+				return drawingPaused;
+			}
+		});
+		
+		// 璁剧疆 MapRenderer 鐨勫線杩旇矾寰勭粯鍒剁鐞嗗櫒
+		if (mapRenderer != null) {
+			mapRenderer.setReturnPathDrawer(returnPathDrawer);
+		}
 
 		// 鍒濆鍖栧璇濇寮曠敤涓簄ull锛屽欢杩熷垱寤�
 		legendDialog = null;
@@ -1839,7 +1889,11 @@
 	}
 
 	private void handleDrawingStopFromControlPanel() {
-		if (endDrawingCallback != null) {
+		// 濡傛灉鏄線杩旇矾寰勭粯鍒舵ā寮忥紝璋冪敤瀹屾垚缁樺埗鍥炶皟
+		if (returnPathDrawer != null && returnPathDrawer.isActive()) {
+			returnPathDrawer.stop();
+			returnPathDrawer.executeFinishCallback();
+		} else if (endDrawingCallback != null) {
 			endDrawingCallback.run();
 		} else {
 			addzhangaiwu.finishDrawingSession();
@@ -2086,7 +2140,8 @@
 			startBtn.setText(drawingPaused ? "寮�濮嬬粯鍒�" : "鏆傚仠缁樺埗");
 		}
 		if (stopBtn != null) {
-			stopBtn.setText("缁撴潫缁樺埗");
+			// 濡傛灉鏄線杩旇矾寰勭粯鍒舵ā寮忥紝鏄剧ず"瀹屾垚缁樺埗"锛屽惁鍒欐樉绀�"缁撴潫缁樺埗"
+			stopBtn.setText((returnPathDrawer != null && returnPathDrawer.isActive()) ? "瀹屾垚缁樺埗" : "缁撴潫缁樺埗");
 		}
 	}
 
@@ -3645,34 +3700,11 @@
 	}
 
 	private double parseDMToDecimal(String dmm, String direction) {
-		if (dmm == null || dmm.trim().isEmpty()) {
-			return Double.NaN;
-		}
-		try {
-			String trimmed = dmm.trim();
-			int dotIndex = trimmed.indexOf('.');
-			if (dotIndex < 2) {
-				return Double.NaN;
-			}
-			int degrees = Integer.parseInt(trimmed.substring(0, dotIndex - 2));
-			double minutes = Double.parseDouble(trimmed.substring(dotIndex - 2));
-			double decimal = degrees + minutes / 60.0;
-			if ("S".equalsIgnoreCase(direction) || "W".equalsIgnoreCase(direction)) {
-				decimal = -decimal;
-			}
-			return decimal;
-		} catch (NumberFormatException ex) {
-			return Double.NaN;
-		}
+		return Gpstoxuzuobiao.parseDMToDecimal(dmm, direction);
 	}
 
 	private double[] convertLatLonToLocal(double lat, double lon, double baseLat, double baseLon) {
-		double deltaLat = lat - baseLat;
-		double deltaLon = lon - baseLon;
-		double meanLatRad = Math.toRadians((baseLat + lat) / 2.0);
-		double eastMeters = deltaLon * METERS_PER_DEGREE_LAT * Math.cos(meanLatRad);
-		double northMeters = deltaLat * METERS_PER_DEGREE_LAT;
-		return new double[]{eastMeters, northMeters};
+		return Gpstoxuzuobiao.convertLatLonToLocal(lat, lon, baseLat, baseLon);
 	}
 
 	private CircleSolution fitCircleFromPoints(List<double[]> points) {
@@ -4114,6 +4146,135 @@
 	}
 
     
+    /**
+     * 鍚姩寰�杩旇矾寰勭粯鍒�
+     * @param finishCallback 瀹屾垚缁樺埗鏃剁殑鍥炶皟
+     * @return 鏄惁鎴愬姛鍚姩
+     */
+    public boolean startReturnPathDrawing(Runnable finishCallback) {
+        if (returnPathDrawer == null) {
+            return false;
+        }
+        return returnPathDrawer.start(finishCallback);
+    }
+    
+    /**
+     * 鍋滄寰�杩旇矾寰勭粯鍒�
+     */
+    public void stopReturnPathDrawing() {
+        if (returnPathDrawer != null) {
+            returnPathDrawer.stop();
+        }
+    }
+    
+    /**
+     * 鑾峰彇寰�杩旇矾寰勭粯鍒剁鐞嗗櫒
+     */
+    public WangfanDraw getReturnPathDrawer() {
+        return returnPathDrawer;
+    }
+    
+    /**
+     * 鍚姩寰�杩旇矾寰勯瑙�
+     * @param coordinatesStr 璺緞鍧愭爣瀛楃涓� (x,y;x,y)
+     * @param returnCallback 杩斿洖鍥炶皟
+     */
+    public void startReturnPathPreview(String coordinatesStr, Runnable returnCallback) {
+        if (returnPathDrawer == null || coordinatesStr == null || coordinatesStr.isEmpty()) {
+            return;
+        }
+        
+        // 瑙f瀽鍧愭爣
+        List<Point2D.Double> points = new ArrayList<>();
+        String[] pairs = coordinatesStr.split(";");
+        for (String pair : pairs) {
+            String[] xy = pair.split(",");
+            if (xy.length == 2) {
+                try {
+                    double x = Double.parseDouble(xy[0]);
+                    double y = Double.parseDouble(xy[1]);
+                    points.add(new Point2D.Double(x, y));
+                } catch (NumberFormatException e) {
+                    // 蹇界暐鏃犳晥鍧愭爣
+                }
+            }
+        }
+        
+        if (points.isEmpty()) {
+            JOptionPane.showMessageDialog(this, "娌℃湁鏈夋晥鐨勮矾寰勭偣鍙瑙�", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
+            return;
+        }
+        
+        // 璁剧疆棰勮鐐�
+        returnPathDrawer.setPoints(points);
+        if (mapRenderer != null) {
+            mapRenderer.setPreviewReturnPath(points);
+        }
+        
+        // 寮�鍚瑙堟ā寮�
+        pathPreviewActive = true;
+        if (mapRenderer != null) {
+            mapRenderer.clearIdleTrail();
+        }
+        pathPreviewReturnAction = returnCallback;
+        
+        // 纭繚鎮诞鎸夐挳鍩虹璁炬柦宸插垱寤�
+        ensureFloatingButtonInfrastructure();
+        
+        // 鍒涘缓鎴栨樉绀鸿繑鍥炴寜閽�
+        if (pathPreviewReturnButton == null) {
+            pathPreviewReturnButton = publicway.buttonset.createStyledButton("杩斿洖", null);
+            pathPreviewReturnButton.setToolTipText("杩斿洖缁樺埗椤甸潰");
+            pathPreviewReturnButton.addActionListener(e -> {
+                // 鍋滄棰勮
+                stopReturnPathPreview();
+            });
+        }
+        
+        // 闅愯棌鍏朵粬鎮诞鎸夐挳
+        hideFloatingDrawingControls();
+        
+        // 鏄剧ず杩斿洖鎸夐挳
+        pathPreviewReturnButton.setVisible(true);
+        floatingButtonPanel.setVisible(true);
+        if (floatingButtonPanel.getParent() != visualizationPanel) {
+            visualizationPanel.add(floatingButtonPanel, BorderLayout.SOUTH);
+        }
+        rebuildFloatingButtonColumn();
+        
+        visualizationPanel.revalidate();
+        visualizationPanel.repaint();
+    }
+    
+    /**
+     * 鍋滄寰�杩旇矾寰勯瑙�
+     */
+    private void stopReturnPathPreview() {
+        pathPreviewActive = false;
+        
+        // 娓呯┖棰勮鐐�
+        if (returnPathDrawer != null) {
+            returnPathDrawer.clearPoints();
+        }
+        if (mapRenderer != null) {
+            mapRenderer.setPreviewReturnPath(null);
+        }
+        
+        // 闅愯棌杩斿洖鎸夐挳
+        if (pathPreviewReturnButton != null) {
+            pathPreviewReturnButton.setVisible(false);
+        }
+        
+        // 闅愯棌鎮诞闈㈡澘
+        if (floatingButtonPanel != null) {
+            floatingButtonPanel.setVisible(false);
+        }
+        
+        // 鎵ц杩斿洖鍥炶皟
+        if (pathPreviewReturnAction != null) {
+            pathPreviewReturnAction.run();
+        }
+    }
 
 	// 娴嬭瘯鏂规硶
     public static void main(String[] args) {
diff --git a/src/zhuye/WangfanDraw.java b/src/zhuye/WangfanDraw.java
new file mode 100644
index 0000000..464cedf
--- /dev/null
+++ b/src/zhuye/WangfanDraw.java
@@ -0,0 +1,411 @@
+package zhuye;
+
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Ellipse2D;
+import java.awt.geom.Path2D;
+import java.awt.geom.Point2D;
+import java.util.ArrayList;
+import java.util.List;
+import javax.swing.Timer;
+import gecaoji.Device;
+
+/**
+ * 寰�杩旇矾寰勭粯鍒剁鐞嗗櫒
+ * 璐熻矗绠$悊寰�杩旇矾寰勭殑缁樺埗閫昏緫鍜岀姸鎬�
+ */
+public class WangfanDraw {
+    // 寰�杩旇矾寰勭偣鍒楄〃
+    private final List<Point2D.Double> returnPathPoints = new ArrayList<>();
+    
+    // 缁樺埗鐘舵��
+    private boolean drawingActive = false;
+    private boolean paused = false;
+    
+    // 鍩哄噯鍧愭爣
+    private double[] baseLatLon;
+    
+    // 鐩戞帶瀹氭椂鍣�
+    private Timer monitorTimer;
+    
+    // 鍥炶皟鎺ュ彛
+    private Runnable finishCallback;
+    
+    // 渚濊禆瀵硅薄
+    private Shouye shouye;
+    private MapRenderer mapRenderer;
+    
+    // 寰�杩旇矾寰勭粯鍒舵帴鍙�
+    public interface DrawingHelper {
+        double[] resolveBaseLatLon();
+        Coordinate getLatestCoordinate();
+        double parseDMToDecimal(String dmm, String direction);
+        double[] convertLatLonToLocal(double lat, double lon, double baseLat, double baseLon);
+        boolean arePointsClose(Point2D.Double a, Point2D.Double b);
+        void enterDrawingControlMode();
+        void exitDrawingControlMode();
+        boolean isDrawingPaused();
+    }
+    
+    private DrawingHelper helper;
+    
+    /**
+     * 鏋勯�犲嚱鏁�
+     */
+    public WangfanDraw(Shouye shouye, MapRenderer mapRenderer, DrawingHelper helper) {
+        this.shouye = shouye;
+        this.mapRenderer = mapRenderer;
+        this.helper = helper;
+    }
+    
+    /**
+     * 鍚姩寰�杩旇矾寰勭粯鍒�
+     * @param finishCallback 瀹屾垚缁樺埗鏃剁殑鍥炶皟
+     * @return 鏄惁鎴愬姛鍚姩
+     */
+    public boolean start(Runnable finishCallback) {
+        if (mapRenderer == null || helper == null) {
+            return false;
+        }
+        
+        double[] baseLatLonCandidate = helper.resolveBaseLatLon();
+        if (baseLatLonCandidate == null) {
+            return false;
+        }
+
+        if (mapRenderer != null) {
+            mapRenderer.clearIdleTrail();
+        }
+        
+        drawingActive = true;
+        paused = false;
+        this.finishCallback = finishCallback;
+        this.baseLatLon = baseLatLonCandidate;
+
+        // 娓呯┖璺緞鐐�
+        synchronized (returnPathPoints) {
+            returnPathPoints.clear();
+        }
+
+        synchronized (Coordinate.coordinates) {
+            Coordinate.coordinates.clear();
+        }
+        
+        if (mapRenderer != null) {
+            mapRenderer.startReturnPathDrawing();
+        }
+
+        Coordinate.setStartSaveGngga(true);
+        if (helper != null) {
+            helper.enterDrawingControlMode();
+        }
+        startMonitor();
+        return true;
+    }
+    
+    /**
+     * 璁剧疆棰勮璺緞鐐�
+     * @param points 璺緞鐐瑰垪琛�
+     */
+    public void setPoints(List<Point2D.Double> points) {
+        synchronized (returnPathPoints) {
+            returnPathPoints.clear();
+            if (points != null) {
+                returnPathPoints.addAll(points);
+            }
+        }
+        if (mapRenderer != null) {
+            mapRenderer.repaint();
+        }
+    }
+    
+    /**
+     * 娓呯┖璺緞鐐�
+     */
+    public void clearPoints() {
+        synchronized (returnPathPoints) {
+            returnPathPoints.clear();
+        }
+        if (mapRenderer != null) {
+            mapRenderer.repaint();
+        }
+    }
+    
+    /**
+     * 鍚姩鐩戞帶瀹氭椂鍣�
+     */
+    private void startMonitor() {
+        if (monitorTimer == null) {
+            monitorTimer = new Timer(600, new ActionListener() {
+                @Override
+                public void actionPerformed(ActionEvent e) {
+                    pollCoordinate();
+                }
+            });
+            monitorTimer.setRepeats(true);
+        }
+        if (!monitorTimer.isRunning()) {
+            monitorTimer.start();
+        }
+        pollCoordinate();
+    }
+    
+    /**
+     * 鍋滄鐩戞帶瀹氭椂鍣�
+     */
+    private void stopMonitor() {
+        if (monitorTimer != null && monitorTimer.isRunning()) {
+            monitorTimer.stop();
+        }
+    }
+    
+    /**
+     * 杞寰�杩旇矾寰勫潗鏍囷紙鍙繚瀛樺畾浣嶇姸鎬�=4鐨勬湁鏁堝潗鏍囷級
+     */
+    private void pollCoordinate() {
+        if (!drawingActive || (helper != null && helper.isDrawingPaused())) {
+            return;
+        }
+        
+        // 妫�鏌ュ畾浣嶇姸鎬佹槸鍚︿负4锛堝浐瀹氳В锛�- 缁熶竴鏉ユ簮涓鸿澶囨暟鎹�
+        Device device = Device.getGecaoji();
+        if (device == null) {
+            return;
+        }
+        String positioningQuality = device.getPositioningStatus();
+        if (positioningQuality == null || !"4".equals(positioningQuality.trim())) {
+            return;  // 鍙繚瀛樺畾浣嶇姸鎬�=4鐨勬湁鏁堝潗鏍�
+        }
+
+        if (helper == null) {
+            return;
+        }
+        
+        Coordinate latest = helper.getLatestCoordinate();
+        if (latest == null) {
+            return;
+        }
+
+        if (baseLatLon == null || baseLatLon.length < 2) {
+            return;
+        }
+
+        double lat = helper.parseDMToDecimal(latest.getLatitude(), latest.getLatDirection());
+        double lon = helper.parseDMToDecimal(latest.getLongitude(), latest.getLonDirection());
+        if (!Double.isFinite(lat) || !Double.isFinite(lon)) {
+            return;
+        }
+
+        double[] local = helper.convertLatLonToLocal(lat, lon, baseLatLon[0], baseLatLon[1]);
+        Point2D.Double candidate = new Point2D.Double(local[0], local[1]);
+        if (!Double.isFinite(candidate.x) || !Double.isFinite(candidate.y)) {
+            return;
+        }
+
+        // 妫�鏌ユ槸鍚︿笌涓婁竴涓偣澶繎锛堥伩鍏嶉噸澶嶇偣锛�
+        synchronized (returnPathPoints) {
+            if (!returnPathPoints.isEmpty()) {
+                Point2D.Double lastPoint = returnPathPoints.get(returnPathPoints.size() - 1);
+                if (helper.arePointsClose(lastPoint, candidate)) {
+                    return;  // 鐐瑰お杩戯紝璺宠繃
+                }
+            }
+        }
+
+        // 娣诲姞鍒拌矾寰勭偣鍒楄〃
+        synchronized (returnPathPoints) {
+            returnPathPoints.add(candidate);
+        }
+        
+        // 瑙﹀彂閲嶇粯
+        if (mapRenderer != null) {
+            mapRenderer.repaint();
+        }
+        
+        // 鍚屾椂淇濆瓨鍒� Coordinate.coordinates 鐢ㄤ簬鍚庣画淇濆瓨
+        synchronized (Coordinate.coordinates) {
+            Coordinate.coordinates.add(latest);
+        }
+    }
+    
+    /**
+     * 鍋滄寰�杩旇矾寰勭粯鍒�
+     */
+    public void stop() {
+        stopMonitor();
+        drawingActive = false;
+        paused = false;
+        baseLatLon = null;
+        if (mapRenderer != null) {
+            mapRenderer.stopReturnPathDrawing();
+        }
+        Coordinate.setStartSaveGngga(false);
+        if (helper != null) {
+            helper.exitDrawingControlMode();
+        }
+    }
+    
+    /**
+     * 鏆傚仠/鎭㈠缁樺埗
+     */
+    public void setPaused(boolean paused) {
+        this.paused = paused;
+    }
+    
+    /**
+     * 妫�鏌ユ槸鍚︽鍦ㄧ粯鍒�
+     */
+    public boolean isActive() {
+        return drawingActive;
+    }
+    
+    /**
+     * 妫�鏌ユ槸鍚︽殏鍋�
+     */
+    public boolean isPaused() {
+        return paused;
+    }
+    
+    /**
+     * 鑾峰彇瀹屾垚缁樺埗鍥炶皟
+     */
+    public Runnable getFinishCallback() {
+        return finishCallback;
+    }
+    
+    /**
+     * 鎵ц瀹屾垚缁樺埗鍥炶皟
+     */
+    public void executeFinishCallback() {
+        if (finishCallback != null) {
+            finishCallback.run();
+            finishCallback = null;
+        }
+    }
+    
+    /**
+     * 鑾峰彇璺緞鐐瑰垪琛ㄧ殑蹇収
+     */
+    public List<Point2D.Double> getPointsSnapshot() {
+        synchronized (returnPathPoints) {
+            return new ArrayList<>(returnPathPoints);
+        }
+    }
+    
+    /**
+     * 缁樺埗寰�杩旇矾寰�
+     */
+    public void draw(Graphics2D g2d, double scale) {
+        List<Point2D.Double> points = getPointsSnapshot();
+        if (points.isEmpty()) {
+            return;
+        }
+        
+        // 淇濆瓨鍘熷鍙樻崲
+        AffineTransform originalTransform = g2d.getTransform();
+        
+        // 璁剧疆寰�杩旇矾寰勯鑹�
+        Color lineColor = Color.GREEN;  // 缁胯壊杩炵嚎
+        Color pointColor = Color.RED;   // 绾㈣壊瀹炲績鍦�
+        
+        // 璁剧疆绾垮
+        float lineWidth = (float)(3.0 / Math.max(0.5, scale));
+        g2d.setStroke(new BasicStroke(lineWidth, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
+        
+        // 鐐圭殑澶у皬锛堝湪涓栫晫鍧愭爣绯讳腑锛岀背锛夛紝鐩村緞涓虹嚎瀹藉害鐨�3鍊�
+        // 娉ㄦ剰锛歭ineWidth宸茬粡鏄笘鐣屽潗鏍囩郴涓嬬殑瀹藉害(3.0/scale)锛屾墍浠ョ洿鎺ヤ箻浠ュ�嶆暟鍗冲彲寰楀埌涓栫晫鍧愭爣绯讳笅鐨勭洿寰�
+        // 涓嶉渶瑕佸啀闄や互scale锛屽惁鍒欎細瀵艰嚧鏀惧ぇ鍦板浘鏃跺渾鍦堝彉灏�
+        double pointSizeInWorld = lineWidth * 3.0;
+        double halfSize = pointSizeInWorld / 2.0;
+        
+        // 鍏堢粯鍒舵墍鏈夎矾寰勭偣锛堜綔涓哄熀纭�灞傦級
+        g2d.setColor(pointColor);
+        for (Point2D.Double point : points) {
+            Ellipse2D.Double pointShape = new Ellipse2D.Double(
+                point.x - halfSize,
+                point.y - halfSize,
+                pointSizeInWorld,
+                pointSizeInWorld
+            );
+            g2d.fill(pointShape);
+        }
+        
+        // 鐒跺悗缁樺埗杩炵嚎
+        g2d.setColor(lineColor);
+        if (points.size() >= 2) {
+            Path2D.Double linePath = new Path2D.Double();
+            linePath.moveTo(points.get(0).x, points.get(0).y);
+            for (int i = 1; i < points.size(); i++) {
+                linePath.lineTo(points.get(i).x, points.get(i).y);
+            }
+            g2d.draw(linePath);
+        }
+        
+        // 鏈�鍚庡啀娆$粯鍒惰矾寰勭偣锛堝湪杩炵嚎涔嬩笂锛岀‘淇濈偣瑕嗙洊鍦ㄧ嚎鐨勭鐐逛笂锛�
+        // 鍑嗗瀛椾綋锛氬ぇ灏忎笌鍦嗗湀涓�鑷达紙涓栫晫鍧愭爣绯伙級锛岄粦鑹�
+        float fontSizeInWorld = (float)pointSizeInWorld;
+        // 浣跨敤0.8鍊嶅ぇ灏忎互纭繚鏁板瓧鍦ㄥ渾鍦堝唴涓嶆嫢鎸�
+        Font font = new Font("Arial", Font.BOLD, 1).deriveFont(fontSizeInWorld * 0.8f);
+        g2d.setFont(font);
+        FontMetrics fm = g2d.getFontMetrics();
+        
+        for (int i = 0; i < points.size(); i++) {
+            Point2D.Double point = points.get(i);
+            
+            // 缁樺埗鐐�
+            g2d.setColor(pointColor);
+            Ellipse2D.Double pointShape = new Ellipse2D.Double(
+                point.x - halfSize,
+                point.y - halfSize,
+                pointSizeInWorld,
+                pointSizeInWorld
+            );
+            g2d.fill(pointShape);
+            
+            // 缁樺埗缂栧彿
+            g2d.setColor(Color.BLACK);
+            String number = String.valueOf(i + 1);
+            java.awt.geom.Rectangle2D bounds = fm.getStringBounds(number, g2d);
+            double textX = point.x - bounds.getWidth() / 2.0;
+            double textY = point.y - bounds.getCenterY();
+            g2d.drawString(number, (float)textX, (float)textY);
+        }
+    }
+
+    /**
+     * 缁樺埗瀹炵嚎绾挎潯涓棿鍔犱笂铏氱嚎铏氱嚎鐧借壊锛屽疄绾块粦鑹茬殑椋庢牸
+     * @param g2d Graphics2D瀵硅薄
+     * @param points 璺緞鐐瑰垪琛�
+     * @param scale 褰撳墠缂╂斁姣斾緥
+     */
+    public static void drawRailwayPath(Graphics2D g2d, List<Point2D.Double> points, double scale) {
+        if (points == null || points.size() < 2) {
+            return;
+        }
+
+        // 1. 缁樺埗搴曞眰榛戣壊瀹炵嚎
+        float baseWidth = (float)(3.0 / Math.max(0.5, scale)); // 鍩虹瀹藉害
+        g2d.setColor(Color.BLACK);
+        g2d.setStroke(new BasicStroke(baseWidth, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
+        
+        Path2D.Double path = new Path2D.Double();
+        path.moveTo(points.get(0).x, points.get(0).y);
+        for (int i = 1; i < points.size(); i++) {
+            path.lineTo(points.get(i).x, points.get(i).y);
+        }
+        g2d.draw(path);
+
+        // 2. 缁樺埗椤跺眰鐧借壊铏氱嚎
+        float dashWidth = baseWidth * 0.4f; // 铏氱嚎瀹藉害姣斿疄绾跨粏涓�浜�
+        float dashLen = baseWidth * 2.0f;   // 铏氱嚎娈甸暱搴�
+        float dashSpace = baseWidth * 2.0f; // 铏氱嚎闂撮殧
+        float[] dashPattern = {dashLen, dashSpace};
+        
+        g2d.setColor(Color.WHITE);
+        g2d.setStroke(new BasicStroke(dashWidth, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND, 10.0f, dashPattern, 0.0f));
+        g2d.draw(path);
+    }
+}
+
diff --git a/src/zhuye/daohangyulan.java b/src/zhuye/daohangyulan.java
index edafba9..42e0876 100644
--- a/src/zhuye/daohangyulan.java
+++ b/src/zhuye/daohangyulan.java
@@ -19,6 +19,7 @@
 import dikuai.Dikuai;
 import gecaoji.Gecaoji;
 import gecaoji.lujingdraw;
+import publicway.buttonset;
 import zhangaiwu.Obstacledge;
 
 /**
diff --git a/src/zhuye/zijian.java b/src/zhuye/zijian.java
index dac3806..4cc9648 100644
--- a/src/zhuye/zijian.java
+++ b/src/zhuye/zijian.java
@@ -7,6 +7,9 @@
 import javax.swing.JPanel;
 import javax.swing.SwingUtilities;
 import javax.swing.WindowConstants;
+
+import publicway.buttonset;
+
 import java.awt.BorderLayout;
 import java.awt.Color;
 import java.awt.Component;

--
Gitblit v1.10.0