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

---
 src/zhuye/celiangmoshi.java              |    5 
 src/dikuai/ObstacleManagementPage.java   |  107 ++
 device.properties                        |   26 
 src/gecaoji/Gecaoji.java                 |   32 
 dikuai.properties                        |   24 
 src/dikuai/addzhangaiwu.java             |    2 
 src/dikuai/daohangyulan.java             |  548 ++++++++++++
 src/zhuye/adddikuaiyulan.java            |   78 +
 src/gecaoji/gecaolunjing.java            |    7 
 src/zhangaiwu/AddDikuai.java             |  438 +++++++++-
 src/zhuye/MapRenderer.java               |  155 +++
 src/zhuye/pointandnumber.java            |   10 
 set.properties                           |   12 
 src/zhuye/Shouye.java                    |   84 +
 Obstacledge.properties                   |    9 
 src/dikuai/Dikuai.java                   |   30 
 src/dikuai/Dikuaiguanli.java             |  186 +++
 src/lujing/MowingPathGenerationPage.java |   34 
 src/lujing/ObstaclePathPlanner.java      |    6 
 src/zhuye/bianjiedrwa.java               |   38 
 basestation.properties                   |    6 
 src/bianjie/BoundaryLengthDrawer.java    |    5 
 src/lujing/Lunjingguihua.java            |  701 ++++-----------
 23 files changed, 1,851 insertions(+), 692 deletions(-)

diff --git a/Obstacledge.properties b/Obstacledge.properties
index cf3e2ba..54617c9 100644
--- a/Obstacledge.properties
+++ b/Obstacledge.properties
@@ -1,19 +1,14 @@
 # 鍓茶崏鏈哄湴鍧楅殰纰嶇墿閰嶇疆鏂囦欢
-# 鐢熸垚鏃堕棿锛�2025-12-17T19:15:02.630670200
+# 鐢熸垚鏃堕棿锛�2025-12-18T19:44:44.126173900
 # 鍧愭爣绯伙細WGS84锛堝害鍒嗘牸寮忥級
 
 # ============ 鍦板潡鍩哄噯绔欓厤缃� ============
 # 鏍煎紡锛歱lot.[鍦板潡缂栧彿].baseStation=[缁忓害],[N/S],[绾害],[E/W]
 plot.DK-001.baseStation=3949.902389,N,11616.756920,E
-plot.LAND1.baseStation=3949.902389,N,11616.756920,E
+plot.LAND1.baseStation=3949.891518,N,11616.792675,E
 
 # ============ 闅滅鐗╅厤缃� ============
 # 鏍煎紡锛歱lot.[鍦板潡缂栧彿].obstacle.[闅滅鐗╁悕绉癩.shape=[0|1]
 # 鏍煎紡锛歱lot.[鍦板潡缂栧彿].obstacle.[闅滅鐗╁悕绉癩.originalCoords=[鍧愭爣涓瞉
 # 鏍煎紡锛歱lot.[鍦板潡缂栧彿].obstacle.[闅滅鐗╁悕绉癩.xyCoords=[鍧愭爣涓瞉
 
-# --- 鍦板潡LAND1鐨勯殰纰嶇墿 ---
-plot.LAND1.obstacle.1234.shape=0
-plot.LAND1.obstacle.1234.originalCoords=3949.902533,N;11616.757411,E;3949.902502,N;11616.757243,E;3949.902473,N;11616.757063,E;3949.902460,N;11616.756947,E;3949.902438,N;11616.756821,E;3949.902430,N;11616.756804,E;3949.902408,N;11616.756828,E;3949.902392,N;11616.756884,E;3949.902388,N;11616.756920,E;3949.902389,N;11616.756920,E;3949.902387,N;11616.756920,E;3949.902388,N;11616.756919,E;3949.902388,N;11616.756922,E;3949.902388,N;11616.756922,E;3949.902388,N;11616.756922,E;3949.902389,N;11616.756923,E;3949.902389,N;11616.756920,E;3949.901649,N;11616.757013,E;3949.901650,N;11616.757016,E;3949.901650,N;11616.757014,E;3949.901650,N;11616.757013,E
-plot.LAND1.obstacle.1234.xyCoords=0.43,-0.56;1.30,-0.56
-
diff --git a/basestation.properties b/basestation.properties
index 1a3f4a0..a1b9dfb 100644
--- a/basestation.properties
+++ b/basestation.properties
@@ -1,7 +1,7 @@
 #Base station properties
-#Tue Dec 09 19:03:31 CST 2025
+#Thu Dec 18 16:15:01 CST 2025
 dataUpdateTime=-1
 deviceActivationTime=-1
-deviceId=4567
-installationCoordinates=3949.90238860,N,11616.75692000,E
+deviceId=1872
+installationCoordinates=3949.89151752,N,11616.79267501,E
 iotSimCardNumber=-1
diff --git a/device.properties b/device.properties
index 542d7ea..260ace6 100644
--- a/device.properties
+++ b/device.properties
@@ -1,29 +1,29 @@
-#Updated base station coordinates
-#Mon Nov 24 14:54:00 CST 2025
+#Updated base station information
+#Thu Dec 18 16:15:01 CST 2025
 BupdateTime=-1
 GupdateTime=-1
 baseStationCardNumber=-1
-baseStationCoordinates=2324.194945,N,11330.938547,E
+baseStationCoordinates=3949.89151752,N,11616.79267501,E
 baseStationNumber=-1
+battery=-1
 createTime=-1
 deviceCardnumber=-1
+differentialAge=-1
+heading=-1
+mowerBladeHeight=-1
+mowerLightStatus=-1
 mowerModel=-1
 mowerName=-1
 mowerNumber=-1
+mowerStartStatus=-1
 mowingHeight=-1
 mowingWidth=-1
+pitch=-1
+positioningStatus=-1
+realtimeAltitude=-1
 realtimeLatitude=-1
 realtimeLongitude=-1
-realtimeAltitude=-1
+realtimeSpeed=-1
 realtimeX=-1
 realtimeY=-1
-realtimeSpeed=-1
-heading=-1
-pitch=-1
-battery=-1
-positioningStatus=-1
 satelliteCount=-1
-differentialAge=-1
-mowerStartStatus=-1
-mowerLightStatus=-1
-mowerBladeHeight=-1
diff --git a/dikuai.properties b/dikuai.properties
index 35bdcf1..885a34d 100644
--- a/dikuai.properties
+++ b/dikuai.properties
@@ -1,19 +1,21 @@
 #Dikuai Properties
-#Wed Dec 17 19:15:02 CST 2025
+#Thu Dec 18 19:44:44 CST 2025
 LAND1.angleThreshold=-1
-LAND1.baseStationCoordinates=3949.90238860,N,11616.75692000,E
-LAND1.boundaryCoordinates=77.19,-32.68;80.71,-54.97;80.99,-55.90;83.54,-56.46;85.04,-55.55;85.94,-53.74;83.24,-35.82;84.55,-34.54;94.02,-31.92;94.10,-31.11;90.88,-20.39;90.35,-19.53;88.33,-19.00;84.12,-19.47;78.92,-22.36;76.63,-25.55;76.93,-29.84;77.06,-31.26;77.19,-32.68
-LAND1.boundaryOriginalCoordinates=39.831413,116.280186,49.12;39.831409,116.280188,49.09;39.831403,116.280187,49.12;39.831395,116.280189,49.13;39.831388,116.280191,49.16;39.831379,116.280193,49.18;39.831370,116.280194,49.16;39.831362,116.280195,49.15;39.831353,116.280197,49.11;39.831344,116.280200,49.15;39.831335,116.280202,49.15;39.831326,116.280204,49.08;39.831317,116.280206,49.19;39.831309,116.280209,49.18;39.831301,116.280210,49.19;39.831293,116.280212,49.11;39.831284,116.280214,49.06;39.831275,116.280215,49.16;39.831266,116.280217,49.14;39.831258,116.280220,49.08;39.831249,116.280223,49.09;39.831240,116.280225,49.10;39.831231,116.280226,49.04;39.831222,116.280226,49.17;39.831212,116.280227,49.11;39.831204,116.280230,49.09;39.831201,116.280238,49.10;39.831199,116.280249,49.07;39.831199,116.280260,49.21;39.831202,116.280270,49.16;39.831207,116.280278,49.06;39.831212,116.280284,49.04;39.831217,116.280287,49.05;39.831223,116.280288,49.09;39.831229,116.280287,49.10;39.831237,116.280286,49.05;39.831245,116.280286,49.08;39.831254,116.280284,49.07;39.831263,116.280283,49.05;39.831272,116.280280,49.11;39.831282,116.280278,49.10;39.831291,116.280276,49.11;39.831300,116.280274,49.16;39.831308,116.280270,49.13;39.831318,116.280268,49.10;39.831327,116.280267,49.14;39.831337,116.280266,49.08;39.831347,116.280263,49.10;39.831356,116.280261,49.20;39.831366,116.280258,49.14;39.831375,116.280256,49.09;39.831384,116.280257,49.13;39.831392,116.280263,49.10;39.831396,116.280272,49.12;39.831398,116.280283,49.16;39.831401,116.280294,49.11;39.831403,116.280307,49.13;39.831405,116.280318,49.19;39.831406,116.280328,49.20;39.831408,116.280340,49.22;39.831411,116.280353,49.19;39.831414,116.280363,49.26;39.831416,116.280374,49.22;39.831419,116.280383,49.20;39.831427,116.280384,49.21;39.831433,116.280379,49.17;39.831441,116.280375,49.19;39.831451,116.280372,49.09;39.831459,116.280370,49.16;39.831467,116.280364,49.21;39.831476,116.280360,49.22;39.831485,116.280357,49.20;39.831495,116.280355,49.26;39.831505,116.280351,49.21;39.831514,116.280348,49.17;39.831523,116.280346,49.20;39.831531,116.280340,49.04;39.831535,116.280328,49.08;39.831536,116.280316,49.03;39.831535,116.280304,49.03;39.831533,116.280291,49.06;39.831532,116.280279,49.07;39.831531,116.280267,49.11;39.831528,116.280257,49.09;39.831525,116.280246,49.11;39.831521,116.280237,49.09;39.831516,116.280227,49.08;39.831511,116.280216,49.12;39.831505,116.280206,49.14;39.831499,116.280197,49.12;39.831492,116.280189,49.15;39.831484,116.280184,49.14;39.831477,116.280179,49.12;39.831469,116.280178,49.12;39.831462,116.280181,49.13;39.831454,116.280182,49.12;39.831445,116.280183,49.12;39.831439,116.280183,49.14;39.831438,116.280183,49.12
+LAND1.baseStationCoordinates=3949.89151752,N,11616.79267501,E
+LAND1.boundaryCoordinates=2.87,-0.19;6.73,-1.23;22.76,1.06;27.88,3.65;35.84,9.96;38.40,10.35;41.91,8.49;44.09,4.86;43.49,2.92;33.76,0.59;30.22,-1.26;30.09,-3.80;34.19,-28.28;32.68,-29.99;30.12,-30.19;28.89,-28.59;25.58,-6.77;24.09,-4.26;21.10,-3.94;-10.36,-8.92;-11.69,-8.57;-12.75,-4.68;-12.23,-3.28;-6.21,-2.34;0.00,0.00;1.44,-0.09;2.87,-0.19
+LAND1.boundaryOriginalCoordinates=39.831524,116.279912,49.30;39.831523,116.279911,49.23;39.831521,116.279915,49.31;39.831517,116.279925,49.34;39.831514,116.279940,49.30;39.831514,116.279957,49.28;39.831516,116.279974,49.28;39.831518,116.279991,49.29;39.831521,116.280008,49.24;39.831524,116.280025,49.30;39.831526,116.280042,49.24;39.831529,116.280059,49.29;39.831529,116.280076,49.26;39.831530,116.280093,49.32;39.831531,116.280110,49.28;39.831533,116.280127,49.28;39.831535,116.280144,49.26;39.831539,116.280161,49.27;39.831544,116.280175,49.25;39.831551,116.280190,49.24;39.831558,116.280204,49.26;39.831566,116.280219,49.26;39.831574,116.280234,49.22;39.831583,116.280248,49.24;39.831591,116.280260,49.24;39.831600,116.280272,49.23;39.831608,116.280285,49.18;39.831615,116.280298,49.12;39.831618,116.280312,49.11;39.831618,116.280328,49.12;39.831615,116.280342,49.15;39.831610,116.280356,49.21;39.831602,116.280369,49.23;39.831592,116.280379,49.25;39.831581,116.280388,49.25;39.831569,116.280394,49.19;39.831559,116.280395,49.23;39.831552,116.280387,49.28;39.831547,116.280373,49.32;39.831544,116.280357,49.33;39.831541,116.280340,49.29;39.831539,116.280324,49.27;39.831536,116.280307,49.24;39.831534,116.280290,49.25;39.831531,116.280273,49.26;39.831527,116.280257,49.28;39.831522,116.280242,49.21;39.831514,116.280232,49.28;39.831504,116.280229,49.24;39.831491,116.280230,49.33;39.831478,116.280233,49.34;39.831466,116.280236,49.31;39.831454,116.280239,49.31;39.831441,116.280242,49.26;39.831429,116.280244,49.23;39.831416,116.280247,49.25;39.831402,116.280250,49.22;39.831389,116.280253,49.25;39.831376,116.280256,49.26;39.831364,116.280258,49.24;39.831351,116.280261,49.25;39.831338,116.280265,49.26;39.831324,116.280268,49.20;39.831311,116.280271,49.16;39.831298,116.280274,49.17;39.831285,116.280277,49.22;39.831271,116.280278,49.16;39.831261,116.280273,49.23;39.831256,116.280261,49.30;39.831253,116.280245,49.20;39.831254,116.280231,49.22;39.831258,116.280220,49.10;39.831268,116.280216,49.17;39.831281,116.280214,49.14;39.831295,116.280212,49.14;39.831308,116.280209,49.17;39.831321,116.280206,49.14;39.831334,116.280204,49.17;39.831348,116.280202,49.21;39.831362,116.280198,49.21;39.831375,116.280195,49.23;39.831390,116.280193,49.25;39.831405,116.280189,49.20;39.831420,116.280187,49.19;39.831436,116.280185,49.21;39.831450,116.280182,49.19;39.831464,116.280177,49.17;39.831478,116.280171,49.14;39.831487,116.280160,49.25;39.831491,116.280143,49.21;39.831490,116.280125,49.18;39.831487,116.280107,49.23;39.831485,116.280089,49.27;39.831483,116.280072,49.24;39.831482,116.280054,49.25;39.831480,116.280037,49.25;39.831477,116.280020,49.30;39.831475,116.280004,49.31;39.831473,116.279989,49.30;39.831472,116.279973,49.23;39.831470,116.279958,49.26;39.831468,116.279941,49.29;39.831465,116.279925,49.33;39.831463,116.279908,49.34;39.831462,116.279891,49.35;39.831461,116.279874,49.33;39.831458,116.279859,49.34;39.831456,116.279843,49.32;39.831454,116.279827,49.32;39.831452,116.279813,49.42;39.831450,116.279798,49.41;39.831448,116.279783,49.36;39.831447,116.279769,49.26;39.831445,116.279757,49.24;39.831445,116.279747,49.38;39.831448,116.279741,49.27;39.831455,116.279736,49.26;39.831463,116.279733,49.26;39.831473,116.279731,49.26;39.831483,116.279729,49.25;39.831491,116.279730,49.26;39.831496,116.279735,49.22;39.831497,116.279748,49.27;39.831498,116.279762,49.27;39.831500,116.279776,49.34;39.831502,116.279791,49.32;39.831504,116.279805,49.27;39.831507,116.279820,49.28;39.831510,116.279835,49.20;39.831513,116.279849,49.25;39.831517,116.279860,49.30;39.831520,116.279864,49.32;39.831520,116.279865,49.34;39.831522,116.279873,49.25;39.831524,116.279878,49.25;39.831525,116.279878,49.24
 LAND1.boundaryPointInterval=-1
-LAND1.createTime=2025-12-16 15\:43\:39
+LAND1.createTime=2025-12-18 17\:12\:20
 LAND1.intelligentSceneAnalysis=-1
-LAND1.landArea=327.17
-LAND1.landName=yyii
+LAND1.landArea=483.34
+LAND1.landName=123
 LAND1.landNumber=LAND1
+LAND1.mowingBladeWidth=0.40
+LAND1.mowingOverlapDistance=0.06
 LAND1.mowingPattern=骞宠绾�
-LAND1.mowingTrack=
-LAND1.mowingWidth=40
-LAND1.plannedPath=77.45,-31.44;81.28,-55.71;81.70,-55.80;77.91,-31.78;78.05,-31.91;78.17,-31.98;78.35,-32.01;82.12,-55.89;82.54,-55.98;78.77,-32.09;78.95,-32.12;79.17,-32.09;82.96,-56.08;83.38,-56.17;79.57,-32.03;79.96,-31.95;83.76,-56.03;84.13,-55.81;80.35,-31.86;80.50,-31.80;80.72,-31.63;84.50,-55.58;84.87,-55.33;81.08,-31.34;81.41,-30.87;85.18,-54.72;85.48,-54.10;81.75,-30.45;81.89,-30.27;81.94,-30.19;82.05,-29.82;83.00,-35.83;83.34,-35.38;81.43,-23.31;81.47,-22.18;81.43,-22.04;81.32,-21.94;81.21,-21.92;81.13,-21.42;81.50,-21.21;83.69,-35.03;84.04,-34.69;81.88,-21.00;82.25,-20.80;84.39,-34.35;84.77,-34.22;82.62,-20.59;82.99,-20.38;85.16,-34.11;85.55,-34.00;83.37,-20.18;83.74,-19.97;85.94,-33.90;86.32,-33.79;84.11,-19.76;84.50,-19.68;86.71,-33.68;87.10,-33.57;84.90,-19.63;85.30,-19.59;87.49,-33.47;87.88,-33.36;85.70,-19.55;86.09,-19.50;88.26,-33.25;88.65,-33.15;86.49,-19.46;86.89,-19.41;89.04,-33.04;89.43,-32.93;87.29,-19.37;87.69,-19.32;89.82,-32.82;90.20,-32.72;88.08,-19.28;88.49,-19.30;90.59,-32.61;90.98,-32.50;88.91,-19.41;89.34,-19.52;91.37,-32.39;91.76,-32.29;89.76,-19.63;90.18,-19.74;92.14,-32.18;92.53,-32.07;90.76,-20.88;91.62,-23.72;92.92,-31.96;93.31,-31.86;92.47,-26.56;93.33,-29.40;93.70,-31.75;81.40,-22.00;81.27,-21.93;81.21,-21.92;81.08,-21.96;80.98,-22.05;79.85,-23.55;79.64,-22.24;80.01,-22.04;80.22,-23.37;80.58,-23.05;80.39,-21.83;80.76,-21.62;80.87,-22.34;77.96,-24.59;77.63,-24.92;77.59,-24.64;77.92,-24.18;77.99,-24.57;78.36,-24.38;78.25,-23.72;78.59,-23.25;78.73,-24.19;79.11,-23.99;78.92,-22.79;79.27,-22.45;79.48,-23.76;77.99,-24.57;77.93,-24.62;77.51,-25.05;77.47,-25.11;77.20,-25.66;77.01,-26.12;76.93,-25.57;77.26,-25.10;77.31,-25.43
+LAND1.mowingTrack=-1
+LAND1.mowingWidth=34
+LAND1.plannedPath=35.722,9.394;38.565,9.844;39.065,9.579;35.179,8.964;34.636,8.534;39.565,9.314;40.065,9.049;34.094,8.104;33.551,7.673;40.565,8.784;41.066,8.519;33.009,7.243;32.466,6.813;41.566,8.254;41.804,7.947;31.923,6.383;31.381,5.953;41.993,7.633;42.182,7.319;30.838,5.523;30.296,5.093;42.371,7.004;42.560,6.690;29.753,4.663;29.210,4.232;42.748,6.375;0.018,-0.389;0.094,-0.377;1.645,-0.475;-1.557,-0.982;42.937,6.061;28.668,3.802;28.125,3.372;43.126,5.747;-3.133,-1.576;2.993,-0.606;3.797,-0.823;-4.708,-2.169;43.315,5.432;27.172,2.877;26.181,2.376;43.503,5.118;-11.978,-3.664;4.602,-1.040;5.407,-1.257;-12.114,-4.030;43.685,4.803;25.191,1.875;24.200,1.374;43.573,4.441;-12.250,-4.396;6.212,-1.474;15.278,-0.383;-12.346,-4.755;43.461,4.079;23.210,0.873;-12.256,-5.085;43.349,3.717;43.237,3.355;-12.166,-5.415;-12.076,-5.745;40.411,2.563;36.170,1.548;-11.986,-6.075;-11.896,-6.405;33.250,0.741;32.306,0.247;-11.806,-6.735;-11.717,-7.065;31.361,-0.246;30.416,-0.740;-11.627,-7.395;-11.537,-7.725;29.861,-1.172;29.836,-1.520;-11.447,-8.055;-11.095,-8.344;29.818,-1.867;29.801,-2.215;21.190,-3.578;22.488,-3.716;29.783,-2.562;29.765,-2.909;23.785,-3.855;24.424,-4.098;29.747,-3.256;29.730,-3.603;24.611,-4.413;24.798,-4.728;29.739,-3.945;29.795,-4.281;24.985,-5.042;25.171,-5.357;29.852,-4.616;29.908,-4.951;25.358,-5.672;25.545,-5.986;29.964,-5.287;30.020,-5.622;25.732,-6.301;25.915,-6.616;30.076,-5.957;30.132,-6.293;25.982,-6.950;26.033,-7.286;30.189,-6.628;30.245,-6.964;26.084,-7.622;26.135,-7.958;30.301,-7.299;30.357,-7.634;26.185,-8.295;26.236,-8.631;30.413,-7.970;30.469,-8.305;26.287,-8.967;26.338,-9.303;30.526,-8.640;30.582,-8.976;26.389,-9.639;26.440,-9.975;30.638,-9.311;30.694,-9.646;26.491,-10.312;26.542,-10.648;30.750,-9.982;30.806,-10.317;26.593,-10.984;26.644,-11.320;30.862,-10.652;30.919,-10.988;26.695,-11.656;26.746,-11.992;30.975,-11.323;31.031,-11.658;26.797,-12.328;26.848,-12.665;31.087,-11.994;31.143,-12.329;26.899,-13.001;26.950,-13.337;31.199,-12.664;31.256,-13.000;27.001,-13.673;27.052,-14.009;31.312,-13.335;31.368,-13.670;27.103,-14.345;27.154,-14.682;31.424,-14.006;31.480,-14.341;27.205,-15.018;27.256,-15.354;31.536,-14.676;31.593,-15.012;27.307,-15.690;27.358,-16.026;31.649,-15.347;31.705,-15.682;27.409,-16.362;27.460,-16.699;31.761,-16.018;31.817,-16.353;27.511,-17.035;27.562,-17.371;31.873,-16.688;31.930,-17.024;27.613,-17.707;27.664,-18.043;31.986,-17.359;32.042,-17.694;27.715,-18.379;27.766,-18.716;32.098,-18.030;32.154,-18.365;27.817,-19.052;27.868,-19.388;32.210,-18.701;32.267,-19.036;27.919,-19.724;27.970,-20.060;32.323,-19.371;32.379,-19.707;28.021,-20.396;28.072,-20.733;32.435,-20.042;32.491,-20.377;28.123,-21.069;28.174,-21.405;32.547,-20.713;32.604,-21.048;28.225,-21.741;28.276,-22.077;32.660,-21.383;32.716,-21.719;28.327,-22.413;28.378,-22.749;32.772,-22.054;32.828,-22.389;28.429,-23.086;28.480,-23.422;32.884,-22.725;32.941,-23.060;28.531,-23.758;28.582,-24.094;32.997,-23.395;33.053,-23.731;28.633,-24.430;28.684,-24.766;33.109,-24.066;33.165,-24.401;28.735,-25.103;28.786,-25.439;33.221,-24.737;33.278,-25.072;28.837,-25.775;28.888,-26.111;33.334,-25.407;33.390,-25.743;28.939,-26.447;28.990,-26.783;33.446,-26.078;33.502,-26.413;29.041,-27.120;29.092,-27.456;33.558,-26.749;33.615,-27.084;29.143,-27.792;29.194,-28.128;33.671,-27.419;33.727,-27.755;29.258,-28.462;29.494,-28.769;33.783,-28.090;33.524,-28.475;29.730,-29.076;29.966,-29.383;33.170,-28.876;32.817,-29.276;30.202,-29.690
 LAND1.returnPointCoordinates=-1
-LAND1.updateTime=2025-12-17 19\:15\:02
+LAND1.updateTime=2025-12-18 19\:44\:44
 LAND1.userId=-1
diff --git a/set.properties b/set.properties
index 1e8efa5..3bd8130 100644
--- a/set.properties
+++ b/set.properties
@@ -1,18 +1,18 @@
 #Mower Configuration Properties - Updated
-#Wed Dec 17 19:35:27 CST 2025
+#Fri Dec 19 11:48:07 CST 2025
 appVersion=-1
 boundaryLengthVisible=false
 currentWorkLandNumber=LAND1
 cuttingWidth=200
 firmwareVersion=-1
-handheldMarkerId=
+handheldMarkerId=1872
 idleTrailDurationSeconds=60
-mapScale=28.94
+mapScale=5.63
 measurementModeEnabled=false
-mowerId=1872
+mowerId=860
 serialAutoConnect=true
 serialBaudRate=115200
 serialPortName=COM15
 simCardNumber=-1
-viewCenterX=-3.17
-viewCenterY=0.87
+viewCenterX=-15.67
+viewCenterY=9.92
diff --git a/src/bianjie/BoundaryLengthDrawer.java b/src/bianjie/BoundaryLengthDrawer.java
index 125209e..c4fdafa 100644
--- a/src/bianjie/BoundaryLengthDrawer.java
+++ b/src/bianjie/BoundaryLengthDrawer.java
@@ -134,3 +134,8 @@
     }
 }
 
+
+
+
+
+
diff --git a/src/dikuai/Dikuai.java b/src/dikuai/Dikuai.java
index b3f127a..c33d8e4 100644
--- a/src/dikuai/Dikuai.java
+++ b/src/dikuai/Dikuai.java
@@ -43,6 +43,10 @@
     private String mowingPattern;
     // 鍓茶崏瀹藉害
     private String mowingWidth;
+    // 鍓茶崏鏈哄壊鍒�瀹藉害锛堢背锛夛紝榛樿0.40绫�
+    private String mowingBladeWidth;
+    // 鍓茶崏閲嶅彔璺濈锛堢背锛夛紝榛樿0.06绫�
+    private String mowingOverlapDistance;
 
     // 瀛樺偍澶氫釜鍦板潡鐨勬槧灏勮〃锛岄敭涓哄湴鍧楃紪鍙�
     private static Map<String, Dikuai> dikuaiMap = new HashMap<>();
@@ -104,6 +108,8 @@
                 dikuai.mowingPattern = landProps.getProperty("mowingPattern", "-1");
                 dikuai.mowingWidth = landProps.getProperty("mowingWidth", "-1");
                 dikuai.mowingTrack = landProps.getProperty("mowingTrack", "-1");
+                dikuai.mowingBladeWidth = landProps.getProperty("mowingBladeWidth", "0.40");
+                dikuai.mowingOverlapDistance = landProps.getProperty("mowingOverlapDistance", "0.06");
                 
                 dikuaiMap.put(landNum, dikuai);
             }
@@ -225,6 +231,12 @@
             case "mowingTrack":
                 this.mowingTrack = value;
                 return true;
+            case "mowingBladeWidth":
+                this.mowingBladeWidth = value;
+                return true;
+            case "mowingOverlapDistance":
+                this.mowingOverlapDistance = value;
+                return true;
             default:
                 System.err.println("鏈煡瀛楁: " + fieldName);
                 return false;
@@ -259,6 +271,8 @@
             if (dikuai.mowingPattern != null) properties.setProperty(landNumber + ".mowingPattern", dikuai.mowingPattern);
             if (dikuai.mowingWidth != null) properties.setProperty(landNumber + ".mowingWidth", dikuai.mowingWidth);
             if (dikuai.mowingTrack != null) properties.setProperty(landNumber + ".mowingTrack", dikuai.mowingTrack);
+            if (dikuai.mowingBladeWidth != null) properties.setProperty(landNumber + ".mowingBladeWidth", dikuai.mowingBladeWidth);
+            if (dikuai.mowingOverlapDistance != null) properties.setProperty(landNumber + ".mowingOverlapDistance", dikuai.mowingOverlapDistance);
         }
         
         try {
@@ -410,6 +424,22 @@
         this.mowingTrack = mowingTrack;
     }
 
+    public String getMowingBladeWidth() {
+        return mowingBladeWidth;
+    }
+
+    public void setMowingBladeWidth(String mowingBladeWidth) {
+        this.mowingBladeWidth = mowingBladeWidth;
+    }
+
+    public String getMowingOverlapDistance() {
+        return mowingOverlapDistance;
+    }
+
+    public void setMowingOverlapDistance(String mowingOverlapDistance) {
+        this.mowingOverlapDistance = mowingOverlapDistance;
+    }
+
     @Override
     public String toString() {
         return "Dikuai{" +
diff --git a/src/dikuai/Dikuaiguanli.java b/src/dikuai/Dikuaiguanli.java
index c84eecb..edd81bb 100644
--- a/src/dikuai/Dikuaiguanli.java
+++ b/src/dikuai/Dikuaiguanli.java
@@ -268,9 +268,7 @@
 	contentPanel.add(Box.createRigidArea(new Dimension(0, 15)));
 
 		// 鍦板潡杈圭晫鍧愭爣锛堝甫鏄剧ず椤剁偣鎸夐挳锛�
-		JPanel boundaryPanel = createBoundaryInfoItem(dikuai,
-			getTruncatedValue(dikuai.getBoundaryCoordinates(), 12, "鏈缃�"));
-		setInfoItemTooltip(boundaryPanel, dikuai.getBoundaryCoordinates());
+		JPanel boundaryPanel = createBoundaryInfoItem(dikuai);
 		configureInteractiveLabel(getInfoItemTitleLabel(boundaryPanel),
 			() -> editBoundaryCoordinates(dikuai),
 			"鐐瑰嚮鏌ョ湅/缂栬緫鍦板潡杈圭晫鍧愭爣");
@@ -291,56 +289,60 @@
 	contentPanel.add(Box.createRigidArea(new Dimension(0, 15)));
 
 		// 璺緞鍧愭爣锛堝甫鏌ョ湅鎸夐挳锛�
-		JPanel pathPanel = createCardInfoItemWithButton("璺緞鍧愭爣:",
-			getTruncatedValue(dikuai.getPlannedPath(), 12, "鏈缃�"),
-			"澶嶅埗", e -> copyCoordinatesAction("璺緞鍧愭爣", dikuai.getPlannedPath()));
-		setInfoItemTooltip(pathPanel, dikuai.getPlannedPath());
+		JPanel pathPanel = createCardInfoItemWithButtonOnly("璺緞鍧愭爣:",
+			"鏌ョ湅", e -> editPlannedPath(dikuai));
 		configureInteractiveLabel(getInfoItemTitleLabel(pathPanel),
 			() -> editPlannedPath(dikuai),
 			"鐐瑰嚮鏌ョ湅/缂栬緫璺緞鍧愭爣");
 		contentPanel.add(pathPanel);
 	contentPanel.add(Box.createRigidArea(new Dimension(0, 15)));
 
-		JPanel baseStationPanel = createCardInfoItemWithButton("鍩虹珯鍧愭爣:",
-			getTruncatedValue(dikuai.getBaseStationCoordinates(), 12, "鏈缃�"),
-			"澶嶅埗", e -> copyCoordinatesAction("鍩虹珯鍧愭爣", dikuai.getBaseStationCoordinates()));
-		setInfoItemTooltip(baseStationPanel, dikuai.getBaseStationCoordinates());
-		configureInteractiveLabel(getInfoItemTitleLabel(baseStationPanel),
-			() -> editBaseStationCoordinates(dikuai),
-			"鐐瑰嚮鏌ョ湅/缂栬緫鍩虹珯鍧愭爣");
-		contentPanel.add(baseStationPanel);
+	JPanel baseStationPanel = createCardInfoItemWithButtonOnly("鍩虹珯鍧愭爣:",
+		"鏌ョ湅", e -> editBaseStationCoordinates(dikuai));
+	configureInteractiveLabel(getInfoItemTitleLabel(baseStationPanel),
+		() -> editBaseStationCoordinates(dikuai),
+		"鐐瑰嚮鏌ョ湅/缂栬緫鍩虹珯鍧愭爣");
+	contentPanel.add(baseStationPanel);
 	contentPanel.add(Box.createRigidArea(new Dimension(0, 15)));
 
-		JPanel boundaryOriginalPanel = createCardInfoItemWithButton("杈圭晫鍘熷鍧愭爣:",
-			getTruncatedValue(dikuai.getBoundaryOriginalCoordinates(), 12, "鏈缃�"),
-			"澶嶅埗", e -> copyCoordinatesAction("杈圭晫鍘熷鍧愭爣", dikuai.getBoundaryOriginalCoordinates()));
-		setInfoItemTooltip(boundaryOriginalPanel, dikuai.getBoundaryOriginalCoordinates());
-		configureInteractiveLabel(getInfoItemTitleLabel(boundaryOriginalPanel),
-			() -> editBoundaryOriginalCoordinates(dikuai),
-			"鐐瑰嚮鏌ョ湅/缂栬緫杈圭晫鍘熷鍧愭爣");
-		contentPanel.add(boundaryOriginalPanel);
+	JPanel boundaryOriginalPanel = createCardInfoItemWithButtonOnly("杈圭晫鍘熷鍧愭爣:",
+		"鏌ョ湅", e -> editBoundaryOriginalCoordinates(dikuai));
+	configureInteractiveLabel(getInfoItemTitleLabel(boundaryOriginalPanel),
+		() -> editBoundaryOriginalCoordinates(dikuai),
+		"鐐瑰嚮鏌ョ湅/缂栬緫杈圭晫鍘熷鍧愭爣");
+	contentPanel.add(boundaryOriginalPanel);
 		contentPanel.add(Box.createRigidArea(new Dimension(0, 15)));
 
-		JPanel mowingPatternPanel = createCardInfoItemWithButton("鍓茶崏妯″紡:",
-			getTruncatedValue(dikuai.getMowingPattern(), 12, "鏈缃�"),
-			"澶嶅埗", e -> copyCoordinatesAction("鍓茶崏妯″紡", dikuai.getMowingPattern()));
-		setInfoItemTooltip(mowingPatternPanel, dikuai.getMowingPattern());
+		JPanel mowingPatternPanel = createCardInfoItem("鍓茶崏妯″紡:",
+			formatMowingPatternForDisplay(dikuai.getMowingPattern()));
 		configureInteractiveLabel(getInfoItemTitleLabel(mowingPatternPanel),
 			() -> editMowingPattern(dikuai),
 			"鐐瑰嚮鏌ョ湅/缂栬緫鍓茶崏妯″紡");
 		contentPanel.add(mowingPatternPanel);
 		contentPanel.add(Box.createRigidArea(new Dimension(0, 15)));
 
-		String mowingWidthValue = dikuai.getMowingWidth();
-		String widthSource = null;
-		if (mowingWidthValue != null && !"-1".equals(mowingWidthValue) && !mowingWidthValue.trim().isEmpty()) {
-			widthSource = mowingWidthValue + "鍘樼背";
+		// 鍓茶崏鏈哄壊鍒�瀹藉害
+		String mowingBladeWidthValue = dikuai.getMowingBladeWidth();
+		String displayBladeWidth = "鏈缃�";
+		if (mowingBladeWidthValue != null && !"-1".equals(mowingBladeWidthValue) && !mowingBladeWidthValue.trim().isEmpty()) {
+			try {
+				double bladeWidthMeters = Double.parseDouble(mowingBladeWidthValue.trim());
+				double bladeWidthCm = bladeWidthMeters * 100.0;
+				displayBladeWidth = String.format("%.2f鍘樼背", bladeWidthCm);
+			} catch (NumberFormatException e) {
+				displayBladeWidth = "鏈缃�";
+			}
 		}
-		String displayWidth = getTruncatedValue(widthSource, 12, "鏈缃�");
-		JPanel mowingWidthPanel = createCardInfoItemWithButton("鍓茶崏瀹藉害:",
-			displayWidth,
-			"缂栬緫", e -> editMowingWidth(dikuai));
-		setInfoItemTooltip(mowingWidthPanel, widthSource);
+		JPanel mowingBladeWidthPanel = createCardInfoItem("鍓茶崏鏈哄壊鍒�瀹藉害:", displayBladeWidth);
+		contentPanel.add(mowingBladeWidthPanel);
+		contentPanel.add(Box.createRigidArea(new Dimension(0, 15)));
+
+		String mowingWidthValue = dikuai.getMowingWidth();
+		String displayWidth = "鏈缃�";
+		if (mowingWidthValue != null && !"-1".equals(mowingWidthValue) && !mowingWidthValue.trim().isEmpty()) {
+			displayWidth = mowingWidthValue + "鍘樼背";
+		}
+		JPanel mowingWidthPanel = createCardInfoItem("鍓茶崏瀹藉害:", displayWidth);
 		contentPanel.add(mowingWidthPanel);
 		contentPanel.add(Box.createRigidArea(new Dimension(0, 15)));
 
@@ -361,11 +363,16 @@
 		JButton generatePathBtn = createPrimaryFooterButton("璺緞瑙勫垝");
 		generatePathBtn.addActionListener(e -> showPathPlanningPage(dikuai));
 
+		JButton navigationPreviewBtn = createPrimaryFooterButton("瀵艰埅棰勮");
+		navigationPreviewBtn.addActionListener(e -> startNavigationPreview(dikuai));
+
 		JPanel footerPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
 		footerPanel.setBackground(CARD_BACKGROUND);
 		footerPanel.setBorder(BorderFactory.createEmptyBorder(15, 0, 0, 0));
 		footerPanel.add(generatePathBtn);
 		footerPanel.add(Box.createHorizontalStrut(12));
+		footerPanel.add(navigationPreviewBtn);
+		footerPanel.add(Box.createHorizontalStrut(12));
 		footerPanel.add(deleteBtn);
 		card.add(footerPanel, BorderLayout.SOUTH);
 
@@ -387,6 +394,7 @@
 		
 		itemPanel.add(labelComp, BorderLayout.WEST);
 		itemPanel.add(valueComp, BorderLayout.EAST);
+		itemPanel.putClientProperty("titleLabel", labelComp);
 		
 		return itemPanel;
 	}
@@ -425,7 +433,35 @@
 		return itemPanel;
 	}
 
-		private JPanel createBoundaryInfoItem(Dikuai dikuai, String displayValue) {
+	private JPanel createCardInfoItemWithButtonOnly(String label, String buttonText, ActionListener listener) {
+		JPanel itemPanel = new JPanel(new BorderLayout());
+		itemPanel.setBackground(CARD_BACKGROUND);
+		// 澧炲姞楂樺害浠ョ‘淇濇寜閽畬鏁存樉绀猴紙鎸夐挳楂樺害绾�24-28鍍忕礌锛屽姞涓婁笂涓嬭竟璺濓級
+		itemPanel.setMaximumSize(new Dimension(Integer.MAX_VALUE, 35));
+		itemPanel.setPreferredSize(new Dimension(Integer.MAX_VALUE, 30));
+		itemPanel.setMinimumSize(new Dimension(0, 28));
+		
+		JLabel labelComp = new JLabel(label);
+		labelComp.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 14));
+		labelComp.setForeground(LIGHT_TEXT);
+		
+		JPanel rightPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 5, 0));
+		rightPanel.setBackground(CARD_BACKGROUND);
+		// 娣诲姞鍨傜洿鍐呰竟璺濅互纭繚鎸夐挳涓嶈瑁佸壀
+		rightPanel.setBorder(BorderFactory.createEmptyBorder(2, 0, 2, 0));
+		
+		JButton button = createSmallLinkButton(buttonText, listener);
+		
+		rightPanel.add(button);
+		
+		itemPanel.add(labelComp, BorderLayout.WEST);
+		itemPanel.add(rightPanel, BorderLayout.CENTER);
+		itemPanel.putClientProperty("titleLabel", labelComp);
+		
+		return itemPanel;
+	}
+
+		private JPanel createBoundaryInfoItem(Dikuai dikuai) {
 			JPanel itemPanel = new JPanel(new BorderLayout());
 			itemPanel.setBackground(CARD_BACKGROUND);
 			// 澧炲姞楂樺害浠ョ‘淇濇寜閽笅杈圭紭瀹屾暣鏄剧ず锛堟寜閽珮搴�56锛屽姞涓婁笂涓嬭竟璺濓級
@@ -445,18 +481,25 @@
 			rightPanel.setBackground(CARD_BACKGROUND);
 			rightPanel.setBorder(BorderFactory.createEmptyBorder(verticalPadding, 0, verticalPadding, 0));
 
-			JLabel valueComp = new JLabel(displayValue);
-			valueComp.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 14));
-			valueComp.setForeground(TEXT_COLOR);
+			// 鐘舵�佹彁绀烘枃瀛楁爣绛�
+			JLabel statusLabel = new JLabel();
+			statusLabel.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 13));
+			statusLabel.setForeground(LIGHT_TEXT);
 
 			JButton toggleButton = createBoundaryToggleButton(dikuai);
+			// 灏嗙姸鎬佹爣绛惧拰鎸夐挳鍏宠仈锛屼互渚垮湪鎸夐挳鐘舵�佸彉鍖栨椂鏇存柊鏍囩
+			toggleButton.putClientProperty("statusLabel", statusLabel);
 
-			rightPanel.add(valueComp);
+			// 鍒濆鍖栫姸鎬佹枃瀛�
+			String landNumber = dikuai.getLandNumber();
+			boolean isVisible = boundaryPointVisibility.getOrDefault(landNumber, false);
+			updateBoundaryStatusLabel(statusLabel, isVisible);
+
+			rightPanel.add(statusLabel);
 			rightPanel.add(toggleButton);
 
 			itemPanel.add(labelComp, BorderLayout.WEST);
 			itemPanel.add(rightPanel, BorderLayout.CENTER);
-			itemPanel.putClientProperty("valueLabel", valueComp);
 			itemPanel.putClientProperty("titleLabel", labelComp);
 
 			return itemPanel;
@@ -499,6 +542,24 @@
 				button.setOpaque(true);
 			}
 			button.setToolTipText(active ? "闅愯棌杈圭晫鐐瑰簭鍙�" : "鏄剧ず杈圭晫鐐瑰簭鍙�");
+			
+			// 鏇存柊鐘舵�佹彁绀烘枃瀛�
+			Object statusLabelObj = button.getClientProperty("statusLabel");
+			if (statusLabelObj instanceof JLabel) {
+				JLabel statusLabel = (JLabel) statusLabelObj;
+				updateBoundaryStatusLabel(statusLabel, active);
+			}
+		}
+		
+		private void updateBoundaryStatusLabel(JLabel statusLabel, boolean active) {
+			if (statusLabel == null) {
+				return;
+			}
+			if (active) {
+				statusLabel.setText("宸插紑鍚竟鐣岀偣鏄剧ず");
+			} else {
+				statusLabel.setText("宸插叧闂竟鐣岀偣鏄剧ず");
+			}
 		}
 
 		private void ensureBoundaryToggleIconsLoaded() {
@@ -859,6 +920,31 @@
 	}
 
 	/**
+	 * 鍚姩瀵艰埅棰勮
+	 */
+	private void startNavigationPreview(Dikuai dikuai) {
+		if (dikuai == null) {
+			return;
+		}
+		
+		Window owner = SwingUtilities.getWindowAncestor(this);
+		
+		// 鑾峰彇鍦板潡绠$悊瀵硅瘽妗嗭紝鍑嗗鍦ㄦ墦寮�瀵艰埅棰勮鏃跺叧闂�
+		Window managementWindow = null;
+		if (owner instanceof JDialog) {
+			managementWindow = owner;
+		}
+		
+		// 鍏抽棴鍦板潡绠$悊椤甸潰
+		if (managementWindow != null) {
+			managementWindow.dispose();
+		}
+		
+		// 鍚姩瀵艰埅棰勮
+		daohangyulan.getInstance().startNavigationPreview(dikuai);
+	}
+
+	/**
 	 * 鏄剧ず璺緞瑙勫垝椤甸潰
 	 */
 	private void showPathPlanningPage(Dikuai dikuai) {
@@ -940,6 +1026,7 @@
 		dialog.setVisible(true);
 	}
 
+
 	private void generateMowingPath(Dikuai dikuai) {
 		if (dikuai == null) {
 			return;
@@ -1183,6 +1270,21 @@
 		return section;
 	}
 
+	private String formatMowingPatternForDisplay(String patternValue) {
+		String sanitized = sanitizeValueOrNull(patternValue);
+		if (sanitized == null) {
+			return "鏈缃�";
+		}
+		String normalized = normalizeExistingMowingPattern(sanitized);
+		if ("parallel".equals(normalized)) {
+			return "骞宠妯″紡 (parallel)";
+		}
+		if ("spiral".equals(normalized)) {
+			return "铻烘棆妯″紡 (spiral)";
+		}
+		return sanitized;
+	}
+
 	private String formatMowingPatternForDialog(String patternValue) {
 		String sanitized = sanitizeValueOrNull(patternValue);
 		if (sanitized == null) {
diff --git a/src/dikuai/ObstacleManagementPage.java b/src/dikuai/ObstacleManagementPage.java
index 9dc7c5d..96c801a 100644
--- a/src/dikuai/ObstacleManagementPage.java
+++ b/src/dikuai/ObstacleManagementPage.java
@@ -299,7 +299,17 @@
         JTextArea xyArea = createDataTextArea(genCoords, 3); // 寮曠敤浠ヤ究鏇存柊
         JScrollPane scrollXY = new JScrollPane(xyArea);
         scrollXY.setBorder(BorderFactory.createEmptyBorder()); // 澶栭儴鐢盤anel鎻愪緵杈规
-        
+        // 璁剧疆婊氬姩鏉$瓥鐣ワ細闇�瑕佹椂鏄剧ず鍨傜洿婊氬姩鏉★紝涓嶄娇鐢ㄦ按骞虫粴鍔ㄦ潯锛堝洜涓哄惎鐢ㄤ簡鑷姩鎹㈣锛�
+        scrollXY.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
+        scrollXY.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
+        // 璁剧疆婊氬姩鏉″崟浣嶅閲忥紝浣挎粴鍔ㄦ洿娴佺晠
+        scrollXY.getVerticalScrollBar().setUnitIncrement(16);
+        // 璁剧疆婊氬姩闈㈡澘鐨勯閫夊ぇ灏忥紝纭繚鍦ㄥ唴瀹硅秴鍑烘椂鏄剧ず婊氬姩鏉�
+        int lineHeight = xyArea.getFontMetrics(xyArea.getFont()).getHeight();
+        int preferredHeight = 3 * lineHeight + 10; // 3琛岀殑楂樺害
+        scrollXY.setPreferredSize(new Dimension(Integer.MAX_VALUE, preferredHeight));
+        scrollXY.setMaximumSize(new Dimension(Integer.MAX_VALUE, 200)); // 鏈�澶ч珮搴�200鍍忕礌
+
         JPanel xyWrapper = createWrapperPanel("鐢熸垚鍧愭爣 (XY绫�)", scrollXY);
         card.add(xyWrapper);
         card.add(Box.createVerticalStrut(15));
@@ -338,6 +348,16 @@
         JTextArea area = createDataTextArea(content, rows);
         JScrollPane scroll = new JScrollPane(area);
         scroll.setBorder(BorderFactory.createEmptyBorder());
+        // 璁剧疆婊氬姩鏉$瓥鐣ワ細闇�瑕佹椂鏄剧ず鍨傜洿婊氬姩鏉★紝涓嶄娇鐢ㄦ按骞虫粴鍔ㄦ潯锛堝洜涓哄惎鐢ㄤ簡鑷姩鎹㈣锛�
+        scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
+        scroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
+        // 璁剧疆婊氬姩鏉″崟浣嶅閲忥紝浣挎粴鍔ㄦ洿娴佺晠
+        scroll.getVerticalScrollBar().setUnitIncrement(16);
+        // 璁剧疆婊氬姩闈㈡澘鐨勯閫夊ぇ灏忥紝纭繚鍦ㄥ唴瀹硅秴鍑烘椂鏄剧ず婊氬姩鏉�
+        int lineHeight = area.getFontMetrics(area.getFont()).getHeight();
+        int preferredHeight = rows * lineHeight + 10; // 鏍规嵁琛屾暟璁$畻棣栭�夐珮搴�
+        scroll.setPreferredSize(new Dimension(Integer.MAX_VALUE, preferredHeight));
+        scroll.setMaximumSize(new Dimension(Integer.MAX_VALUE, 200)); // 鏈�澶ч珮搴�200鍍忕礌
         return createWrapperPanel(title, scroll);
     }
 
@@ -366,12 +386,13 @@
         JTextArea area = new JTextArea(text);
         area.setRows(rows);
         area.setEditable(false);
+        // 鍚敤鑷姩鎹㈣
         area.setLineWrap(true);
         area.setWrapStyleWord(true);
         area.setBackground(BG_INPUT);
         area.setForeground(new Color(50, 50, 50));
         // 浣跨敤绛夊瀛椾綋鏄剧ず鏁版嵁锛岀湅璧锋潵鏇翠笓涓�
-        area.setFont(new Font("Monospaced", Font.PLAIN, 12)); 
+        area.setFont(new Font("Monospaced", Font.PLAIN, 12));
         return area;
     }
 
@@ -545,6 +566,9 @@
             return;
         }
         
+        // 璁$畻闅滅鐗╃殑涓績鐐瑰潗鏍�
+        double[] centerCoords = calculateObstacleCenter(obstacle);
+        
         List<Obstacledge.Obstacle> allObstacles = loadObstacles();
         String allObstaclesCoords = buildAllObstaclesCoordinates(allObstacles);
         
@@ -568,11 +592,85 @@
                         newPage.setVisible(true);
                     })
                 );
+                
+                // 灏嗗湴鍥捐鍥句腑蹇冭缃负闅滅鐗╃殑涓績浣嶇疆
+                if (centerCoords != null && shouye.getMapRenderer() != null) {
+                    double currentScale = shouye.getMapRenderer().getScale();
+                    // 灏嗚鍥句腑蹇冭缃负闅滅鐗╀腑蹇冿紙浣跨敤璐熷�硷紝鍥犱负translate鏄浉瀵逛簬鍘熺偣鐨勫亸绉伙級
+                    shouye.getMapRenderer().setViewTransform(currentScale, -centerCoords[0], -centerCoords[1]);
+                }
             } else {
                 JOptionPane.showMessageDialog(null, "鏃犳硶鎵撳紑涓婚〉闈㈣繘琛岄瑙�", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
             }
         });
     }
+    
+    /**
+     * 璁$畻闅滅鐗╃殑涓績鐐瑰潗鏍�
+     * @param obstacle 闅滅鐗�
+     * @return 涓績鐐瑰潗鏍� [centerX, centerY]锛屽鏋滄棤娉曡绠楀垯杩斿洖null
+     */
+    private double[] calculateObstacleCenter(Obstacledge.Obstacle obstacle) {
+        if (obstacle == null) {
+            return null;
+        }
+        
+        List<Obstacledge.XYCoordinate> xyCoords = obstacle.getXyCoordinates();
+        if (xyCoords == null || xyCoords.isEmpty()) {
+            return null;
+        }
+        
+        Obstacledge.ObstacleShape shape = obstacle.getShape();
+        double centerX, centerY;
+        
+        if (shape == Obstacledge.ObstacleShape.CIRCLE) {
+            // 鍦嗗舰闅滅鐗╋細绗竴涓潗鏍囩偣灏辨槸鍦嗗績
+            if (xyCoords.size() < 1) {
+                return null;
+            }
+            Obstacledge.XYCoordinate centerCoord = xyCoords.get(0);
+            centerX = centerCoord.getX();
+            centerY = centerCoord.getY();
+        } else if (shape == Obstacledge.ObstacleShape.POLYGON) {
+            // 澶氳竟褰㈤殰纰嶇墿锛氳绠楅噸蹇�
+            centerX = 0.0;
+            centerY = 0.0;
+            double area = 0.0;
+            int n = xyCoords.size();
+            
+            for (int i = 0; i < n; i++) {
+                Obstacledge.XYCoordinate current = xyCoords.get(i);
+                Obstacledge.XYCoordinate next = xyCoords.get((i + 1) % n);
+                double x0 = current.getX();
+                double y0 = current.getY();
+                double x1 = next.getX();
+                double y1 = next.getY();
+                double cross = x0 * y1 - x1 * y0;
+                area += cross;
+                centerX += (x0 + x1) * cross;
+                centerY += (y0 + y1) * cross;
+            }
+            
+            double areaFactor = area * 0.5;
+            if (Math.abs(areaFactor) < 1e-9) {
+                // 濡傛灉闈㈢Н涓�0鎴栨帴杩�0锛屼娇鐢ㄧ畝鍗曞钩鍧�
+                for (Obstacledge.XYCoordinate coord : xyCoords) {
+                    centerX += coord.getX();
+                    centerY += coord.getY();
+                }
+                int size = Math.max(1, xyCoords.size());
+                centerX /= size;
+                centerY /= size;
+            } else {
+                centerX = centerX / (6.0 * areaFactor);
+                centerY = centerY / (6.0 * areaFactor);
+            }
+        } else {
+            return null;
+        }
+        
+        return new double[]{centerX, centerY};
+    }
 
     private String buildAllObstaclesCoordinates(List<Obstacledge.Obstacle> obstacles) {
         if (obstacles == null || obstacles.isEmpty()) return null;
@@ -897,3 +995,8 @@
         return value != null && !value.trim().isEmpty() && !"-1".equals(value.trim());
     }
 }
+
+
+
+
+
diff --git a/src/dikuai/addzhangaiwu.java b/src/dikuai/addzhangaiwu.java
index 2952d93..6c69177 100644
--- a/src/dikuai/addzhangaiwu.java
+++ b/src/dikuai/addzhangaiwu.java
@@ -797,7 +797,7 @@
             return;
         }
         if (userTriggered && "handheld".equalsIgnoreCase(type) && !hasConfiguredHandheldMarker()) {
-            JOptionPane.showMessageDialog(this, "璇峰厛娣诲姞渚挎惡鎵撶偣鍣ㄧ紪鍙�", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
+            JOptionPane.showMessageDialog(this, "璇峰厛鍘荤郴缁熻缃坊鍔犱究鎼烘墦鐐瑰櫒缂栧彿", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
             return;
         }
         if (selectedMethodPanel != null && selectedMethodPanel != option) {
diff --git a/src/dikuai/daohangyulan.java b/src/dikuai/daohangyulan.java
new file mode 100644
index 0000000..a65ffcf
--- /dev/null
+++ b/src/dikuai/daohangyulan.java
@@ -0,0 +1,548 @@
+package dikuai;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.geom.Point2D;
+import java.util.List;
+import java.util.ArrayList;
+import zhuye.Shouye;
+import zhuye.MapRenderer;
+import zhuye.buttonset;
+import gecaoji.Gecaoji;
+import gecaoji.lujingdraw;
+
+/**
+ * 瀵艰埅棰勮鍔熻兘绫�
+ * 瀹炵幇鍓茶崏鏈烘部璺緞妯℃嫙瀵艰埅
+ */
+public class daohangyulan {
+    private static daohangyulan instance;
+    private Shouye shouye;
+    private MapRenderer mapRenderer;
+    private Gecaoji mower;
+    private Dikuai currentDikuai;
+    
+    // 璺緞鐩稿叧
+    private List<Point2D.Double> pathPoints;
+    private int currentPathIndex;
+    private double currentSpeed; // 绫�/绉�
+    private static final double DEFAULT_SPEED = 1.0; // 榛樿1绫�/绉�
+    private static final double SPEED_MULTIPLIER = 1.0; // 姣忔鍔犻��/鍑忛�熺殑鍊嶆暟
+    
+    // 瀹氭椂鍣�
+    private Timer navigationTimer;
+    private static final int TIMER_INTERVAL_MS = 50; // 50姣鏇存柊涓�娆�
+    
+    // 瀵艰埅棰勮鎸夐挳
+    private JButton speedUpBtn;
+    private JButton speedDownBtn;
+    private JButton exitBtn;
+    
+    // 淇濆瓨鍘熷鎸夐挳鍜岄潰鏉跨殑寮曠敤
+    private JButton originalStartBtn;
+    private JButton originalStopBtn;
+    private JPanel originalButtonPanel;
+    private LayoutManager originalButtonPanelLayout;
+    
+    // 瀵艰埅棰勮杞ㄨ抗
+    private List<Point2D.Double> navigationTrack;
+    
+    // 鏄惁姝e湪瀵艰埅棰勮
+    private boolean isNavigating;
+    
+    private daohangyulan() {
+        this.currentSpeed = DEFAULT_SPEED;
+        this.navigationTrack = new ArrayList<>();
+        this.isNavigating = false;
+    }
+    
+    public static daohangyulan getInstance() {
+        if (instance == null) {
+            instance = new daohangyulan();
+        }
+        return instance;
+    }
+    
+    /**
+     * 鍚姩瀵艰埅棰勮
+     * @param dikuai 鍦板潡瀵硅薄
+     */
+    public void startNavigationPreview(Dikuai dikuai) {
+        if (dikuai == null) {
+            JOptionPane.showMessageDialog(null, "鍦板潡鏁版嵁鏃犳晥", "閿欒", JOptionPane.ERROR_MESSAGE);
+            return;
+        }
+        
+        // 鑾峰彇鍦板潡鐨勫壊鑽夎矾寰勫潗鏍�
+        String plannedPath = dikuai.getPlannedPath();
+        if (plannedPath == null || plannedPath.trim().isEmpty() || "-1".equals(plannedPath.trim())) {
+            JOptionPane.showMessageDialog(null, "褰撳墠鍦板潡娌℃湁瑙勫垝璺緞锛屾棤娉曡繘琛屽鑸瑙�", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
+            return;
+        }
+        
+        // 瑙f瀽璺緞鍧愭爣
+        pathPoints = lujingdraw.parsePlannedPath(plannedPath);
+        if (pathPoints == null || pathPoints.size() < 2) {
+            JOptionPane.showMessageDialog(null, "璺緞鍧愭爣瑙f瀽澶辫触锛屾棤娉曡繘琛屽鑸瑙�", "閿欒", JOptionPane.ERROR_MESSAGE);
+            return;
+        }
+        
+        this.currentDikuai = dikuai;
+        this.currentPathIndex = 0;
+        this.currentSpeed = DEFAULT_SPEED;
+        this.navigationTrack.clear();
+        
+        // 鑾峰彇棣栭〉鍜屽湴鍥炬覆鏌撳櫒
+        shouye = Shouye.getInstance();
+        if (shouye == null) {
+            JOptionPane.showMessageDialog(null, "鏃犳硶鑾峰彇棣栭〉瀹炰緥", "閿欒", JOptionPane.ERROR_MESSAGE);
+            return;
+        }
+        
+        mapRenderer = shouye.getMapRenderer();
+        if (mapRenderer == null) {
+            JOptionPane.showMessageDialog(null, "鏃犳硶鑾峰彇鍦板浘娓叉煋鍣�", "閿欒", JOptionPane.ERROR_MESSAGE);
+            return;
+        }
+        
+        mower = mapRenderer.getMower();
+        if (mower == null) {
+            JOptionPane.showMessageDialog(null, "鏃犳硶鑾峰彇鍓茶崏鏈哄疄渚�", "閿欒", JOptionPane.ERROR_MESSAGE);
+            return;
+        }
+        
+        // 璁剧疆鍓茶崏鏈哄垵濮嬩綅缃负璺緞璧风偣
+        Point2D.Double startPoint = pathPoints.get(0);
+        mower.setPosition(startPoint.x, startPoint.y);
+        
+        // 璁$畻鍒濆鏂瑰悜锛堟湞鍚戠涓�涓洰鏍囩偣锛�
+        if (pathPoints.size() > 1) {
+            Point2D.Double nextPoint = pathPoints.get(1);
+            double heading = calculateHeading(startPoint, nextPoint);
+            setMowerHeading(heading);
+        } else {
+            // 濡傛灉鍙湁涓�涓偣锛岃缃粯璁ゆ柟鍚戯紙0搴︼紝鍚戝彸锛�
+            setMowerHeading(0.0);
+        }
+        
+        // 鍒濆鍖栧鑸瑙堣建杩�
+        navigationTrack.clear();
+        navigationTrack.add(new Point2D.Double(startPoint.x, startPoint.y));
+        mapRenderer.clearNavigationPreviewTrack();
+        mapRenderer.addNavigationPreviewTrackPoint(startPoint);
+        
+        // 鑾峰彇鍓茶崏鏈哄壊鍒�瀹藉害
+        String bladeWidthStr = dikuai.getMowingBladeWidth();
+        double bladeWidthMeters = 0.5; // 榛樿0.5绫�
+        if (bladeWidthStr != null && !bladeWidthStr.trim().isEmpty() && !"-1".equals(bladeWidthStr.trim())) {
+            try {
+                bladeWidthMeters = Double.parseDouble(bladeWidthStr.trim());
+            } catch (NumberFormatException e) {
+                // 浣跨敤榛樿鍊�
+            }
+        }
+        mapRenderer.setNavigationPreviewWidth(bladeWidthMeters);
+        
+        // 璁剧疆鍒濆閫熷害鏄剧ず
+        mapRenderer.setNavigationPreviewSpeed(currentSpeed);
+        
+        // 鍒涘缓骞舵樉绀哄鑸瑙堟寜閽紙鏇挎崲搴曢儴鎸夐挳锛�
+        createNavigationButtons();
+        
+        // 鏄剧ず瀵艰埅棰勮妯″紡鏍囩
+        if (shouye != null) {
+            shouye.setNavigationPreviewLabelVisible(true);
+        }
+        
+        // 鍚姩瀵艰埅瀹氭椂鍣�
+        startNavigationTimer();
+        
+        isNavigating = true;
+        
+        // 鍒锋柊鍦板浘鏄剧ず
+        mapRenderer.repaint();
+    }
+    
+    /**
+     * 鍒涘缓瀵艰埅棰勮鎸夐挳锛堟浛鎹㈠簳閮ㄧ殑鏆傚仠銆佺粨鏉熸寜閽級
+     */
+    private void createNavigationButtons() {
+        // 绉婚櫎鏃х殑鎸夐挳锛堝鏋滃瓨鍦級
+        removeNavigationButtons();
+        
+        if (shouye == null) {
+            return;
+        }
+        
+        // 鑾峰彇鍘熷鎸夐挳
+        originalStartBtn = shouye.getStartButton();
+        originalStopBtn = shouye.getStopButton();
+        
+        if (originalStartBtn == null || originalStopBtn == null) {
+            return;
+        }
+        
+        // 鑾峰彇鎺у埗闈㈡澘
+        JPanel controlPanel = shouye.getControlPanel();
+        if (controlPanel == null) {
+            return;
+        }
+        
+        // 鏌ユ壘鎸夐挳闈㈡澘锛堝寘鍚� startBtn 鍜� stopBtn 鐨勯潰鏉匡級
+        JPanel buttonPanel = null;
+        for (Component comp : controlPanel.getComponents()) {
+            if (comp instanceof JPanel) {
+                JPanel panel = (JPanel) comp;
+                // 妫�鏌ユ槸鍚︽槸鎸夐挳闈㈡澘锛堝寘鍚� startBtn 鍜� stopBtn锛�
+                boolean hasStartBtn = false;
+                boolean hasStopBtn = false;
+                for (Component child : panel.getComponents()) {
+                    if (child == originalStartBtn) {
+                        hasStartBtn = true;
+                    }
+                    if (child == originalStopBtn) {
+                        hasStopBtn = true;
+                    }
+                }
+                if (hasStartBtn && hasStopBtn) {
+                    buttonPanel = panel;
+                    break;
+                }
+            }
+        }
+        
+        if (buttonPanel == null) {
+            return;
+        }
+        
+        // 淇濆瓨鍘熷鎸夐挳闈㈡澘鍜屽竷灞�
+        originalButtonPanel = buttonPanel;
+        originalButtonPanelLayout = buttonPanel.getLayout();
+        
+        // 闅愯棌鍘熷鎸夐挳
+        if (originalStartBtn != null) {
+            originalStartBtn.setVisible(false);
+        }
+        if (originalStopBtn != null) {
+            originalStopBtn.setVisible(false);
+        }
+        
+        // 淇敼鎸夐挳闈㈡澘甯冨眬涓�3鍒楋紙鍔犻�熴�佸噺閫熴�侀��鍑猴級
+        // 鍑忓皯鎸夐挳闂磋窛锛岀粰鎸夐挳鏇村绌洪棿鏄剧ず鏂囧瓧
+        buttonPanel.setLayout(new GridLayout(1, 3, 10, 0));
+        
+        // 鍒涘缓鍔犻�熸寜閽�
+        speedUpBtn = createControlButton("鍔犻��", new Color(46, 139, 87));
+        speedUpBtn.addActionListener(e -> speedUp());
+        
+        // 鍒涘缓鍑忛�熸寜閽�
+        speedDownBtn = createControlButton("鍑忛��", new Color(255, 140, 0));
+        speedDownBtn.addActionListener(e -> speedDown());
+        
+        // 鍒涘缓閫�鍑烘寜閽�
+        exitBtn = createControlButton("閫�鍑�", new Color(255, 107, 107));
+        exitBtn.addActionListener(e -> exitNavigationPreview());
+        
+        // 娣诲姞鏂版寜閽埌鎸夐挳闈㈡澘
+        buttonPanel.add(speedUpBtn);
+        buttonPanel.add(speedDownBtn);
+        buttonPanel.add(exitBtn);
+        
+        // 鍒锋柊鏄剧ず
+        buttonPanel.revalidate();
+        buttonPanel.repaint();
+        controlPanel.revalidate();
+        controlPanel.repaint();
+    }
+    
+    /**
+     * 鍒涘缓鎺у埗鎸夐挳锛堜娇鐢╞uttonset椋庢牸锛屽昂瀵�40x80锛�
+     */
+    private JButton createControlButton(String text, Color color) {
+        // 浣跨敤buttonset鍒涘缓鎸夐挳
+        JButton button = buttonset.createStyledButton(text, color);
+        
+        // 璁剧疆鎸夐挳灏哄锛氬搴�40鍍忕礌锛岄珮搴�80鍍忕礌
+        Dimension buttonSize = new Dimension(80, 40);
+        button.setPreferredSize(buttonSize);
+        button.setMinimumSize(buttonSize);
+        button.setMaximumSize(buttonSize);
+        
+        return button;
+    }
+    
+    /**
+     * 绉婚櫎瀵艰埅棰勮鎸夐挳锛堟仮澶嶅師濮嬫寜閽級
+     */
+    private void removeNavigationButtons() {
+        if (originalButtonPanel == null) {
+            return;
+        }
+        
+        // 绉婚櫎瀵艰埅棰勮鎸夐挳
+        if (speedUpBtn != null && speedUpBtn.getParent() == originalButtonPanel) {
+            originalButtonPanel.remove(speedUpBtn);
+        }
+        if (speedDownBtn != null && speedDownBtn.getParent() == originalButtonPanel) {
+            originalButtonPanel.remove(speedDownBtn);
+        }
+        if (exitBtn != null && exitBtn.getParent() == originalButtonPanel) {
+            originalButtonPanel.remove(exitBtn);
+        }
+        
+        // 鎭㈠鍘熷甯冨眬
+        if (originalButtonPanelLayout != null) {
+            originalButtonPanel.setLayout(originalButtonPanelLayout);
+        }
+        
+        // 鎭㈠鍘熷鎸夐挳鏄剧ず
+        if (originalStartBtn != null) {
+            originalStartBtn.setVisible(true);
+            if (originalStartBtn.getParent() != originalButtonPanel) {
+                originalButtonPanel.add(originalStartBtn);
+            }
+        }
+        if (originalStopBtn != null) {
+            originalStopBtn.setVisible(true);
+            if (originalStopBtn.getParent() != originalButtonPanel) {
+                originalButtonPanel.add(originalStopBtn);
+            }
+        }
+        
+        // 鍒锋柊鏄剧ず
+        originalButtonPanel.revalidate();
+        originalButtonPanel.repaint();
+        
+        if (shouye != null && shouye.getControlPanel() != null) {
+            shouye.getControlPanel().revalidate();
+            shouye.getControlPanel().repaint();
+        }
+        
+        // 娓呯┖寮曠敤
+        speedUpBtn = null;
+        speedDownBtn = null;
+        exitBtn = null;
+        originalButtonPanel = null;
+        originalButtonPanelLayout = null;
+        originalStartBtn = null;
+        originalStopBtn = null;
+    }
+    
+    /**
+     * 鍚姩瀵艰埅瀹氭椂鍣�
+     */
+    private void startNavigationTimer() {
+        if (navigationTimer != null) {
+            navigationTimer.stop();
+        }
+        
+        navigationTimer = new Timer(TIMER_INTERVAL_MS, new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                updateNavigation();
+            }
+        });
+        navigationTimer.start();
+    }
+    
+    /**
+     * 鏇存柊瀵艰埅鐘舵��
+     */
+    private void updateNavigation() {
+        if (pathPoints == null || pathPoints.size() < 2 || currentPathIndex >= pathPoints.size() - 1) {
+            // 璺緞瀹屾垚
+            stopNavigation();
+            JOptionPane.showMessageDialog(null, "瀵艰埅棰勮瀹屾垚", "鎻愮ず", JOptionPane.INFORMATION_MESSAGE);
+            return;
+        }
+        
+        Point2D.Double currentPos = mower.getPosition();
+        if (currentPos == null) {
+            return;
+        }
+        
+        Point2D.Double targetPoint = pathPoints.get(currentPathIndex + 1);
+        
+        // 璁$畻鍒扮洰鏍囩偣鐨勮窛绂�
+        double dx = targetPoint.x - currentPos.x;
+        double dy = targetPoint.y - currentPos.y;
+        double distance = Math.hypot(dx, dy);
+        
+        // 璁$畻姣忓抚绉诲姩鐨勮窛绂伙紙绫筹級
+        double moveDistance = currentSpeed * (TIMER_INTERVAL_MS / 1000.0);
+        
+        if (distance <= moveDistance) {
+            // 鍒拌揪鐩爣鐐癸紝绉诲姩鍒颁笅涓�涓偣
+            mower.setPosition(targetPoint.x, targetPoint.y);
+            navigationTrack.add(new Point2D.Double(targetPoint.x, targetPoint.y));
+            mapRenderer.addNavigationPreviewTrackPoint(targetPoint);
+            
+            currentPathIndex++;
+            
+            // 濡傛灉杩樻湁涓嬩竴涓偣锛岃绠楁柟鍚�
+            if (currentPathIndex < pathPoints.size() - 1) {
+                Point2D.Double nextPoint = pathPoints.get(currentPathIndex + 1);
+                double heading = calculateHeading(targetPoint, nextPoint);
+                setMowerHeading(heading);
+            }
+        } else {
+            // 鍚戠洰鏍囩偣绉诲姩
+            // 鍏堟洿鏂版柟鍚戯紝纭繚杞﹀ご鏈濆悜鐩爣鐐�
+            double heading = calculateHeading(currentPos, targetPoint);
+            setMowerHeading(heading);
+            
+            double ratio = moveDistance / distance;
+            double newX = currentPos.x + dx * ratio;
+            double newY = currentPos.y + dy * ratio;
+            
+            mower.setPosition(newX, newY);
+            navigationTrack.add(new Point2D.Double(newX, newY));
+            mapRenderer.addNavigationPreviewTrackPoint(new Point2D.Double(newX, newY));
+        }
+        
+        // 鏇存柊閫熷害鏄剧ず鍒板湴鍥炬覆鏌撳櫒
+        if (mapRenderer != null) {
+            mapRenderer.setNavigationPreviewSpeed(currentSpeed);
+        }
+        
+        // 鏇存柊鍦板浘鏄剧ず
+        mapRenderer.repaint();
+        
+        // 鏇存柊閫熷害鏄剧ず锛堝鏋滈渶瑕侊級
+        updateSpeedDisplay();
+    }
+    
+    /**
+     * 璁$畻涓ょ偣涔嬮棿鐨勬柟鍚戣锛堝害锛�
+     * 鍥炬爣榛樿鏈濅笂锛屽悜鍙虫棆杞�90搴﹁溅澶存湞鍙�
+     * atan2杩斿洖鐨勮搴︼細鍚戝彸鏄�0搴︼紝鍚戜笂鏄�90搴�
+     * 闇�瑕佽浆鎹负鍥炬爣鏃嬭浆瑙掑害锛氬悜鍙抽渶瑕�90搴︼紝鍚戜笂闇�瑕�0搴�
+     */
+    private double calculateHeading(Point2D.Double from, Point2D.Double to) {
+        double dx = to.x - from.x;
+        double dy = to.y - from.y;
+        // atan2杩斿洖鐨勮搴︼細鍚戝彸鏄�0搴︼紝鍚戜笂鏄�90搴︼紝鍚戝乏鏄�180搴︼紝鍚戜笅鏄�-90搴︼紙270搴︼級
+        double atan2Angle = Math.toDegrees(Math.atan2(dy, dx));
+        
+        // 杞崲涓�0-360搴﹁寖鍥�
+        if (atan2Angle < 0) {
+            atan2Angle += 360;
+        }
+        
+        // 鍥炬爣榛樿鏈濅笂锛�0搴︼級锛屽悜鍙虫棆杞�90搴﹁溅澶存湞鍙�
+        // 鎵�浠ワ細杩愬姩鏂瑰悜鍚戝彸锛�0搴︼級鈫� 闇�瑕佹棆杞�90搴�
+        //      杩愬姩鏂瑰悜鍚戜笂锛�90搴︼級鈫� 闇�瑕佹棆杞�0搴�
+        //      杩愬姩鏂瑰悜鍚戝乏锛�180搴︼級鈫� 闇�瑕佹棆杞�270搴�
+        //      杩愬姩鏂瑰悜鍚戜笅锛�270搴︼級鈫� 闇�瑕佹棆杞�180搴�
+        // 鍏紡锛歨eading = (90 - atan2Angle + 360) % 360
+        double heading = (90.0 - atan2Angle + 360.0) % 360.0;
+        
+        return heading;
+    }
+    
+    /**
+     * 璁剧疆鍓茶崏鏈烘柟鍚�
+     */
+    private void setMowerHeading(double headingDegrees) {
+        if (mower != null) {
+            mower.setHeading(headingDegrees);
+        }
+    }
+    
+    /**
+     * 鍔犻��
+     */
+    private void speedUp() {
+        currentSpeed += SPEED_MULTIPLIER;
+        updateSpeedDisplay();
+    }
+    
+    /**
+     * 鍑忛��
+     */
+    private void speedDown() {
+        if (currentSpeed > 0.1) { // 鏈�灏忛�熷害0.1绫�/绉�
+            currentSpeed -= SPEED_MULTIPLIER;
+            if (currentSpeed < 0.1) {
+                currentSpeed = 0.1;
+            }
+        }
+        updateSpeedDisplay();
+    }
+    
+    /**
+     * 鏇存柊閫熷害鏄剧ず
+     */
+    private void updateSpeedDisplay() {
+        // 鍙互鍦ㄥ湴鍥句笂鏄剧ず褰撳墠閫熷害
+        // 杩欓噷鏆傛椂涓嶅疄鐜帮紝濡傛灉闇�瑕佸彲浠ュ湪MapRenderer涓坊鍔犻�熷害鏄剧ず
+    }
+    
+    /**
+     * 鍋滄瀵艰埅
+     */
+    private void stopNavigation() {
+        if (navigationTimer != null) {
+            navigationTimer.stop();
+            navigationTimer = null;
+        }
+        isNavigating = false;
+    }
+    
+    /**
+     * 閫�鍑哄鑸瑙�
+     */
+    public void exitNavigationPreview() {
+        stopNavigation();
+        removeNavigationButtons();
+        
+        // 闅愯棌瀵艰埅棰勮妯″紡鏍囩
+        if (shouye != null) {
+            shouye.setNavigationPreviewLabelVisible(false);
+        }
+        
+        // 娓呴櫎瀵艰埅棰勮杞ㄨ抗
+        if (mapRenderer != null) {
+            mapRenderer.clearNavigationPreviewTrack();
+            mapRenderer.setNavigationPreviewSpeed(0.0); // 娓呴櫎閫熷害鏄剧ず
+            mapRenderer.repaint();
+        }
+        
+        // 鎭㈠鍦板潡绠$悊椤甸潰
+        // 鍦ㄦ竻绌篶urrentDikuai涔嬪墠淇濆瓨鍦板潡缂栧彿锛屼娇鐢╢inal鍙橀噺浠ヤ究鍦╨ambda涓娇鐢�
+        final String landNumber = (currentDikuai != null) ? currentDikuai.getLandNumber() : null;
+        
+        isNavigating = false;
+        currentDikuai = null;
+        
+        // 濡傛灉鏈夊湴鍧楃紪鍙凤紝鏄剧ず鍦板潡绠$悊椤甸潰
+        if (landNumber != null && !landNumber.trim().isEmpty()) {
+            SwingUtilities.invokeLater(() -> {
+                try {
+                    Component parent = null;
+                    if (shouye != null) {
+                        Window owner = SwingUtilities.getWindowAncestor(shouye);
+                        if (owner instanceof Component) {
+                            parent = (Component) owner;
+                        } else {
+                            parent = shouye;
+                        }
+                    }
+                    Dikuaiguanli.showDikuaiManagement(parent, landNumber);
+                } catch (Exception e) {
+                    System.err.println("鏄剧ず鍦板潡绠$悊椤甸潰澶辫触: " + e.getMessage());
+                    e.printStackTrace();
+                }
+            });
+        }
+    }
+    
+    /**
+     * 妫�鏌ユ槸鍚︽鍦ㄥ鑸瑙�
+     */
+    public boolean isNavigating() {
+        return isNavigating;
+    }
+}
diff --git a/src/gecaoji/Gecaoji.java b/src/gecaoji/Gecaoji.java
index 2aca713..e89222a 100644
--- a/src/gecaoji/Gecaoji.java
+++ b/src/gecaoji/Gecaoji.java
@@ -179,6 +179,38 @@
         return new Point2D.Double(position.x, position.y);
     }
 
+    /**
+     * 璁剧疆鍓茶崏鏈轰綅缃紙鐢ㄤ簬瀵艰埅棰勮绛夊満鏅級
+     * @param x X鍧愭爣
+     * @param y Y鍧愭爣
+     */
+    public void setPosition(double x, double y) {
+        ensurePosition();
+        position.x = x;
+        position.y = y;
+        positionValid = true;
+    }
+
+    /**
+     * 璁剧疆鍓茶崏鏈烘柟鍚戯紙鐢ㄤ簬瀵艰埅棰勮绛夊満鏅級
+     * @param headingDegrees 鏂瑰悜瑙掑害锛堝害锛�0-360锛�
+     */
+    public void setHeading(double headingDegrees) {
+        double normalized = headingDegrees % 360.0;
+        if (normalized < 0) {
+            normalized += 360.0;
+        }
+        this.headingDegrees = normalized;
+    }
+
+    /**
+     * 鑾峰彇鍓茶崏鏈烘柟鍚�
+     * @return 鏂瑰悜瑙掑害锛堝害锛�0-360锛�
+     */
+    public double getHeading() {
+        return headingDegrees;
+    }
+
     public double getWorldRadius(double scale) {
         if (!positionValid) {
             return Double.NaN;
diff --git a/src/gecaoji/gecaolunjing.java b/src/gecaoji/gecaolunjing.java
index 4a0a99c..c28156f 100644
--- a/src/gecaoji/gecaolunjing.java
+++ b/src/gecaoji/gecaolunjing.java
@@ -24,9 +24,10 @@
  * 宸ュ叿绫伙細璐熻矗缁樺埗鍓茶崏瀹屾垚璺緞瑕嗙洊鏁堟灉锛屽苟鎻愪緵涓�绯诲垪澧炲己璋冧紭鑳藉姏銆�
  */
 public final class gecaolunjing {
-    private static final Color COVERAGE_FILL_COLOR = new Color(34, 139, 34, 120);
-    private static final Color COVERAGE_BORDER_COLOR = new Color(24, 98, 52, 200);
-    private static final Color COVERAGE_PATH_COLOR = new Color(0, 90, 0, 204);
+    // 娣辩豢鑹诧細鐢ㄤ簬鏄剧ず鍓插畬鐨勫尯鍩�
+    private static final Color COVERAGE_FILL_COLOR = new Color(0, 100, 0, 150); // 娣辩豢鑹诧紝鍗婇�忔槑
+    private static final Color COVERAGE_BORDER_COLOR = new Color(0, 80, 0, 200); // 鏇存繁鐨勭豢鑹茶竟妗�
+    private static final Color COVERAGE_PATH_COLOR = new Color(0, 90, 0, 204); // 璺緞棰滆壊
 
     private static final double MIN_WIDTH_METERS = 0.3d;
     private static final CoverageState STATE = new CoverageState();
diff --git a/src/lujing/Lunjingguihua.java b/src/lujing/Lunjingguihua.java
index 3e54d7b..1f19fae 100644
--- a/src/lujing/Lunjingguihua.java
+++ b/src/lujing/Lunjingguihua.java
@@ -1,25 +1,20 @@
 package lujing;
 
-import java.awt.geom.Line2D;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
-
 import org.locationtech.jts.geom.Coordinate;
 import org.locationtech.jts.geom.Envelope;
 import org.locationtech.jts.geom.Geometry;
 import org.locationtech.jts.geom.GeometryFactory;
 import org.locationtech.jts.geom.LineString;
-import org.locationtech.jts.geom.LinearRing;
 import org.locationtech.jts.geom.MultiLineString;
-import org.locationtech.jts.geom.MultiPolygon;
 import org.locationtech.jts.geom.Polygon;
-import org.locationtech.jts.operation.union.CascadedPolygonUnion;
+import org.locationtech.jts.geom.MultiPolygon;
 
 /**
- * 鍓茶崏璺緞瑙勫垝瀹炵敤绫伙紝渚涘叾浠栭」鐩洿鎺ヨ皟鐢ㄣ��
- * 鎻愪緵瀛楃涓插叆鍙傜殑鍓茶崏璺緞鐢熸垚鑳藉姏锛屽苟灏佽蹇呰鐨勮В鏋愪笌鍑犱綍澶勭悊閫昏緫銆�
+ * 浼樺寲鍚庣殑鍓茶崏璺緞瑙勫垝绫�
+ * 淇锛氳В鍐宠矾寰勮秴鍑哄湴鍧楄竟鐣岀殑闂锛屽鍔犲畨鍏ㄨ竟璺濊绠楃殑鍋ュ.鎬с��
  */
 public final class Lunjingguihua {
 
@@ -27,16 +22,7 @@
         throw new IllegalStateException("Utility class");
     }
 
-    /**
-     * 鐢熸垚鍓茶崏璺緞娈靛垪琛ㄣ��
-     *
-     * @param polygonCoords   澶氳竟褰㈣竟鐣屽潗鏍囷紝鏍煎紡濡� "x1,y1;x2,y2;..."锛堢背锛�
-     * @param obstaclesCoords 闅滅鐗╁潗鏍囷紝鏀寔澶氫釜鎷彿娈垫垨鍦嗗舰瀹氫箟锛屼緥 "(x1,y1;x2,y2)(cx,cy;px,py)"
-     * @param mowingWidth     鍓茶崏瀹藉害瀛楃涓诧紝绫冲崟浣嶏紝鍏佽淇濈暀涓や綅灏忔暟
-     * @param safetyDistStr   瀹夊叏璺濈瀛楃涓诧紝绫冲崟浣嶃�傝矾寰勫皢涓庤竟鐣屽拰闅滅鐗╀繚鎸佹璺濈銆�
-     * @param modeStr         鍓茶崏妯″紡锛�"0"/绌轰负骞宠绾匡紝"1" 鎴� "spiral" 琛ㄧず铻烘棆妯″紡锛堝綋鍓嶄粎骞宠绾垮疄鐜帮級
-     * @return 璺緞娈靛垪琛紝鎸夎椹堕『搴忔帓鍒�
-     */
+    // 5鍙傛暟鏍稿績鐢熸垚鏂规硶
     public static List<PathSegment> generatePathSegments(String polygonCoords,
                                                          String obstaclesCoords,
                                                          String mowingWidth,
@@ -44,15 +30,11 @@
                                                          String modeStr) {
         List<Coordinate> polygon = parseCoordinates(polygonCoords);
         if (polygon.size() < 4) {
-            throw new IllegalArgumentException("澶氳竟褰㈠潗鏍囨暟閲忎笉瓒筹紝鑷冲皯闇�瑕佷笁涓偣");
+            throw new IllegalArgumentException("澶氳竟褰㈠潗鏍囨暟閲忎笉瓒�");
         }
 
-        double width = parseDoubleOrDefault(mowingWidth, 2.0);
-        if (width <= 0) {
-            throw new IllegalArgumentException("鍓茶崏瀹藉害蹇呴』澶т簬 0");
-        }
-        
-        // 瑙f瀽瀹夊叏璺濈锛屽鏋滄湭璁剧疆鎴栨棤鏁堬紝榛樿涓� NaN (鍦� PlannerCore 涓鐞嗛粯璁ゅ��)
+        double width = parseDoubleOrDefault(mowingWidth, 0.34);
+        // 濡傛灉浼犲叆绌猴紝璁句负 NaN锛屽湪 PlannerCore 涓繘琛屾櫤鑳借绠�
         double safetyDistance = parseDoubleOrDefault(safetyDistStr, Double.NaN);
 
         List<List<Coordinate>> obstacles = parseObstacles(obstaclesCoords);
@@ -62,9 +44,7 @@
         return planner.generate();
     }
 
-    /**
-     * 淇濇寔鍚戝悗鍏煎鐨勯噸杞芥柟娉曪紙涓嶅甫 safeDistance锛屼娇鐢ㄩ粯璁よ绠楋級
-     */
+    // 4鍙傛暟閲嶈浇锛岄�傞厤 AddDikuai.java
     public static List<PathSegment> generatePathSegments(String polygonCoords,
                                                          String obstaclesCoords,
                                                          String mowingWidth,
@@ -72,16 +52,7 @@
         return generatePathSegments(polygonCoords, obstaclesCoords, mowingWidth, null, modeStr);
     }
 
-    /**
-     * 閫氳繃瀛楃涓插弬鏁扮敓鎴愬壊鑽夎矾寰勫潗鏍囥��
-     *
-     * @param polygonCoords   澶氳竟褰㈣竟鐣屽潗鏍囷紝鏍煎紡濡� "x1,y1;x2,y2;..."锛堢背锛�
-     * @param obstaclesCoords 闅滅鐗╁潗鏍囷紝鏀寔澶氫釜鎷彿娈垫垨鍦嗗舰瀹氫箟锛屼緥 "(x1,y1;x2,y2)(cx,cy;px,py)"
-     * @param mowingWidth     鍓茶崏瀹藉害瀛楃涓诧紝绫冲崟浣嶏紝鍏佽淇濈暀涓や綅灏忔暟
-     * @param safetyDistStr   瀹夊叏璺濈瀛楃涓诧紝绫冲崟浣嶃��
-     * @param modeStr         鍓茶崏妯″紡锛�"0"/绌轰负骞宠绾匡紝"1" 鎴� "spiral" 琛ㄧず铻烘棆妯″紡锛堝綋鍓嶄粎骞宠绾垮疄鐜帮級
-     * @return 杩炵画璺緞鍧愭爣瀛楃涓诧紝椤哄簭绱ц窡鍓茶崏鏈鸿杩涜矾绾�
-     */
+    // 5鍙傛暟璺緞瀛楃涓茬敓鎴�
     public static String generatePathFromStrings(String polygonCoords,
                                                  String obstaclesCoords,
                                                  String mowingWidth,
@@ -90,10 +61,8 @@
         List<PathSegment> segments = generatePathSegments(polygonCoords, obstaclesCoords, mowingWidth, safetyDistStr, modeStr);
         return formatPathSegments(segments);
     }
-    
-    /**
-     * 淇濇寔鍚戝悗鍏煎鐨勯噸杞芥柟娉�
-     */
+
+    // 4鍙傛暟璺緞瀛楃涓茬敓鎴愰噸杞�
     public static String generatePathFromStrings(String polygonCoords,
                                                  String obstaclesCoords,
                                                  String mowingWidth,
@@ -101,158 +70,93 @@
         return generatePathFromStrings(polygonCoords, obstaclesCoords, mowingWidth, null, modeStr);
     }
 
-    /**
-     * 灏嗚矾寰勬鍒楄〃杞崲涓哄潗鏍囧瓧绗︿覆銆�
-     */
     public static String formatPathSegments(List<PathSegment> path) {
-        if (path == null || path.isEmpty()) {
-            return "";
-        }
+        if (path == null || path.isEmpty()) return "";
         StringBuilder sb = new StringBuilder();
         Coordinate last = null;
         for (PathSegment segment : path) {
-            if (!equals2D(last, segment.start)) {
+            if (last == null || !equals2D(last, segment.start)) {
                 appendPoint(sb, segment.start);
-                last = new Coordinate(segment.start);
             }
-            if (!equals2D(last, segment.end)) {
-                appendPoint(sb, segment.end);
-                last = new Coordinate(segment.end);
-            }
+            appendPoint(sb, segment.end);
+            last = segment.end;
         }
         return sb.toString();
     }
 
-    /**
-     * 瑙f瀽鍧愭爣瀛楃涓层��
-     */
     public static List<Coordinate> parseCoordinates(String s) {
         List<Coordinate> list = new ArrayList<>();
-        if (s == null || s.trim().isEmpty()) {
-            return list;
-        }
+        if (s == null || s.trim().isEmpty()) return list;
+        // 澧炲己姝e垯锛氬鐞嗗彲鑳藉瓨鍦ㄧ殑澶氱鍒嗛殧绗�
         String[] pts = s.split("[;\\s]+");
         for (String p : pts) {
             String trimmed = p.trim().replace("(", "").replace(")", "");
-            if (trimmed.isEmpty()) {
-                continue;
-            }
+            if (trimmed.isEmpty()) continue;
             String[] xy = trimmed.split("[,锛孿\s]+");
             if (xy.length >= 2) {
                 try {
-                    list.add(new Coordinate(Double.parseDouble(xy[0].trim()),
-                                            Double.parseDouble(xy[1].trim())));
+                    double x = Double.parseDouble(xy[0].trim());
+                    double y = Double.parseDouble(xy[1].trim());
+                    // 杩囨护鏃犳晥鍧愭爣
+                    if (!Double.isNaN(x) && !Double.isNaN(y) && !Double.isInfinite(x) && !Double.isInfinite(y)) {
+                        list.add(new Coordinate(x, y));
+                    }
                 } catch (NumberFormatException ex) {
-                    System.err.println("鍧愭爣瑙f瀽澶辫触: " + trimmed);
+                    // 蹇界暐瑙f瀽閿欒鐨勭偣
                 }
             }
         }
+        // 纭繚澶氳竟褰㈤棴鍚�
         if (list.size() > 2 && !list.get(0).equals2D(list.get(list.size() - 1))) {
             list.add(new Coordinate(list.get(0)));
         }
         return list;
     }
 
-    /**
-     * 瑙f瀽闅滅鐗╁瓧绗︿覆锛屽吋瀹瑰闅滅鐗╀笌鍦嗗舰瀹氫箟銆�
-     */
     public static List<List<Coordinate>> parseObstacles(String str) {
         List<List<Coordinate>> obs = new ArrayList<>();
-        if (str == null || str.trim().isEmpty()) {
-            return obs;
-        }
+        if (str == null || str.trim().isEmpty()) return obs;
         java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("\\(([^)]+)\\)");
         java.util.regex.Matcher matcher = pattern.matcher(str);
         while (matcher.find()) {
             List<Coordinate> coords = parseCoordinates(matcher.group(1));
-            if (coords.size() >= 3) {
-                obs.add(coords);
-            } else if (coords.size() == 2) {
-                List<Coordinate> circle = approximateCircle(coords.get(0), coords.get(1));
-                if (!circle.isEmpty()) {
-                    obs.add(circle);
-                }
-            }
+            if (coords.size() >= 3) obs.add(coords);
         }
         if (obs.isEmpty()) {
             List<Coordinate> coords = parseCoordinates(str);
-            if (coords.size() >= 3) {
-                obs.add(coords);
-            } else if (coords.size() == 2) {
-                List<Coordinate> circle = approximateCircle(coords.get(0), coords.get(1));
-                if (!circle.isEmpty()) {
-                    obs.add(circle);
-                }
-            }
+            if (coords.size() >= 3) obs.add(coords);
         }
         return obs;
     }
 
     private static double parseDoubleOrDefault(String value, double defaultValue) {
-        if (value == null || value.trim().isEmpty()) {
-            return defaultValue;
-        }
+        if (value == null || value.trim().isEmpty()) return defaultValue;
         try {
             return Double.parseDouble(value.trim());
         } catch (NumberFormatException ex) {
-            throw new IllegalArgumentException("鏍煎紡涓嶆纭�: " + value, ex);
+            return defaultValue;
         }
     }
 
     private static String normalizeMode(String modeStr) {
-        if (modeStr == null) {
-            return "parallel";
-        }
-        String trimmed = modeStr.trim().toLowerCase();
-        if ("1".equals(trimmed) || "spiral".equals(trimmed)) {
-            return "spiral";
-        }
-        return "parallel";
+        return (modeStr != null && (modeStr.equals("1") || modeStr.equalsIgnoreCase("spiral"))) ? "spiral" : "parallel";
     }
 
     private static boolean equals2D(Coordinate a, Coordinate b) {
-        if (a == b) {
-            return true;
-        }
-        if (a == null || b == null) {
-            return false;
-        }
-        return a.equals2D(b);
+        if (a == b) return true;
+        if (a == null || b == null) return false;
+        return a.distance(b) < 1e-4;
     }
 
     private static void appendPoint(StringBuilder sb, Coordinate point) {
-        if (sb.length() > 0) {
-            sb.append(";");
-        }
-        sb.append(String.format("%.2f,%.2f", point.x, point.y));
+        if (sb.length() > 0) sb.append(";");
+        sb.append(String.format("%.3f,%.3f", point.x, point.y));
     }
 
-    private static List<Coordinate> approximateCircle(Coordinate center, Coordinate edge) {
-        double radius = center.distance(edge);
-        if (radius <= 0) {
-            return Collections.emptyList();
-        }
-        int segments = 36;
-        List<Coordinate> circle = new ArrayList<>(segments + 1);
-        for (int i = 0; i < segments; i++) {
-            double angle = 2 * Math.PI * i / segments;
-            double x = center.x + radius * Math.cos(angle);
-            double y = center.y + radius * Math.sin(angle);
-            circle.add(new Coordinate(x, y));
-        }
-        circle.add(new Coordinate(circle.get(0)));
-        return circle;
-    }
-
-    /**
-     * 璺緞娈垫暟鎹粨鏋勩��
-     */
     public static final class PathSegment {
-        public Coordinate start;
-        public Coordinate end;
+        public Coordinate start, end;
         public boolean isMowing;
-        public boolean isStartPoint;
-        public boolean isEndPoint;
+        public boolean isStartPoint, isEndPoint;
 
         public PathSegment(Coordinate start, Coordinate end, boolean isMowing) {
             this.start = start;
@@ -260,419 +164,228 @@
             this.isMowing = isMowing;
         }
 
-        public void setAsStartPoint() {
-            this.isStartPoint = true;
-        }
-
-        public void setAsEndPoint() {
-            this.isEndPoint = true;
-        }
-
-        @Override
-        public String toString() {
-            return String.format("PathSegment[(%.2f,%.2f)->(%.2f,%.2f) mowing=%b start=%b end=%b]",
-                    start.x, start.y, end.x, end.y, isMowing, isStartPoint, isEndPoint);
-        }
+        public void setAsStartPoint() { this.isStartPoint = true; }
+        public void setAsEndPoint() { this.isEndPoint = true; }
     }
 
-    /**
-     * 鍐呴儴鏍稿績瑙勫垝鍣紝瀹炵幇涓� MowingPathPlanner 绛夋晥鐨勯�昏緫銆�
-     */
-    static final class PlannerCore {
+    public static final class PlannerCore {
         private final List<Coordinate> polygon;
         private final double width;
-        private final double safetyDistance; // 鏂板瀹夊叏璺濈瀛楁
+        private final double safetyDistance;
         private final String mode;
         private final List<List<Coordinate>> obstacles;
         private final GeometryFactory gf = new GeometryFactory();
 
-        PlannerCore(List<Coordinate> polygon, double width, double safetyDistance, String mode, List<List<Coordinate>> obstacles) {
+        // 1. 鍏ㄥ弬鏁版瀯閫犲嚱鏁�
+        public PlannerCore(List<Coordinate> polygon, double width, double safetyDistance, String mode, List<List<Coordinate>> obstacles) {
             this.polygon = polygon;
             this.width = width;
             this.mode = mode;
             this.obstacles = obstacles != null ? obstacles : new ArrayList<>();
             
-            // 鍒濆鍖栧畨鍏ㄨ窛绂婚�昏緫
-            if (Double.isNaN(safetyDistance)) {
-                // 濡傛灉鏈彁渚涳紝浣跨敤榛樿鍊硷細瀹藉害鐨勪竴鍗� + 0.05绫�
-                this.safetyDistance = width / 2.0 + 0.05;
+            // FIX: 澧炲姞榛樿瀹夊叏杈硅窛銆傚師閫昏緫涓� width/2 + 0.05锛屽鏄撻�犳垚璇樊鍑虹晫銆�
+            // 鐜版敼涓� width/2 + 0.2 (20cm浣欓噺)锛岀‘淇濆壊鑽夋満瀹炰綋瀹屽叏鍦ㄧ晫鍐呫��
+            if (Double.isNaN(safetyDistance) || safetyDistance <= 0) {
+                this.safetyDistance = (width / 2.0) + 0.20; 
             } else {
-                // 濡傛灉鎻愪緵浜嗭紝浣跨敤鎻愪緵鐨勫�硷紝浣嗚嚦灏戣淇濊瘉鏈哄櫒涓績涓嶇澹侊紙瀹藉害涓�鍗婏級
-                // 鍏佽鐢ㄦ埛璁剧疆姣� width/2 鏇村ぇ鐨勫�兼潵杩滅杈圭晫
-                this.safetyDistance = Math.max(safetyDistance, width / 2.0);
+                this.safetyDistance = safetyDistance;
             }
         }
-        
-        // 鍏煎鏃ф瀯閫犲嚱鏁�
-        PlannerCore(List<Coordinate> polygon, double width, String mode, List<List<Coordinate>> obstacles) {
+
+        // 2. 4鍙傛暟鏋勯�犲嚱鏁�
+        public PlannerCore(List<Coordinate> polygon, double width, String mode, List<List<Coordinate>> obstacles) {
             this(polygon, width, Double.NaN, mode, obstacles);
         }
 
-        List<PathSegment> generate() {
-            // 濡傛灉鏈夐殰纰嶇墿锛屼娇鐢ㄥ甫闅滅鐗╅伩璁╃殑璺緞瑙勫垝鍣�
-            if (!obstacles.isEmpty()) {
-                // 浣跨敤璁$畻濂界殑瀹夊叏璺濈
-                ObstaclePathPlanner obstaclePlanner = new ObstaclePathPlanner(
-                    polygon, width, mode, obstacles, this.safetyDistance);
-                return obstaclePlanner.generate();
-            }
+        public List<PathSegment> generate() {
+            if ("spiral".equals(mode)) return generateSpiralPath();
+            return generateDividedParallelPath();
+        }
+
+        public List<PathSegment> generateParallelPath() {
+            return generateDividedParallelPath();
+        }
+
+        private List<PathSegment> generateDividedParallelPath() {
+            List<PathSegment> totalPath = new ArrayList<>();
+            Geometry safeArea = buildSafeArea();
             
-            // 娌℃湁闅滅鐗╂椂浣跨敤鍘熸湁閫昏緫
-            if ("spiral".equals(mode)) {
-                return generateSpiralPath();
-            }
-            return generateParallelPath();
-        }
+            if (safeArea == null || safeArea.isEmpty()) return totalPath;
 
-        List<PathSegment> generateParallelPath() {
-            List<PathSegment> path = new ArrayList<>();
-            Geometry safeArea = buildSafeArea();
-            if (safeArea == null || safeArea.isEmpty()) {
-                System.err.println("瀹夊叏鍖哄煙涓虹┖锛屾棤娉曠敓鎴愯矾寰�");
-                return path;
+            List<Polygon> subRegions = new ArrayList<>();
+            if (safeArea instanceof Polygon) subRegions.add((Polygon) safeArea);
+            else if (safeArea instanceof MultiPolygon) {
+                for (int i = 0; i < safeArea.getNumGeometries(); i++) {
+                    subRegions.add((Polygon) safeArea.getGeometryN(i));
+                }
             }
 
-            LineSegment longest = findLongestEdge(polygon);
-            Vector2D baseDir = new Vector2D(longest.end.x - longest.start.x,
-                                            longest.end.y - longest.start.y).normalize();
-            Vector2D perp = baseDir.rotate90CCW();
-            Vector2D baseStartVec = new Vector2D(longest.start.x, longest.start.y);
-            double baseProjection = perp.dot(baseStartVec); 
+            for (Polygon region : subRegions) {
+                if (region.isEmpty()) continue;
 
-            double minProj = Double.POSITIVE_INFINITY;
-            double maxProj = Double.NEGATIVE_INFINITY;
-            Coordinate[] supportCoords = safeArea.getCoordinates();
-            if (supportCoords != null && supportCoords.length > 0) {
-                for (Coordinate coord : supportCoords) {
-                    double projection = perp.dot(new Vector2D(coord.x, coord.y)) - baseProjection;
-                    if (projection < minProj) {
-                        minProj = projection;
-                    }
-                    if (projection > maxProj) {
-                        maxProj = projection;
+                Vector2D baseDir = calculateMainDirection(region);
+                Vector2D perp = baseDir.rotate90CCW();
+                Envelope env = region.getEnvelopeInternal();
+                
+                double minProj = Double.MAX_VALUE, maxProj = -Double.MAX_VALUE;
+                Coordinate[] coords = region.getCoordinates();
+                for (Coordinate c : coords) {
+                    double p = perp.dot(new Vector2D(c)); 
+                    minProj = Math.min(minProj, p);
+                    maxProj = Math.max(maxProj, p);
+                }
+
+                int lineIdx = 0;
+                // 浠� minProj + width/2 寮�濮嬶紝纭繚绗竴鏉$嚎鍦ㄥ畨鍏ㄥ尯鍩熷唴渚�
+                for (double d = minProj + width / 2.0; d <= maxProj; d += width) {
+                    LineString scanLine = createScanLine(d, perp, baseDir, env);
+                    
+                    try {
+                        Geometry intersections = region.intersection(scanLine);
+                        if (intersections.isEmpty()) continue;
+
+                        List<LineString> parts = extractLineStrings(intersections);
+                        
+                        // 鎸夌収鎵弿鏂瑰悜鎺掑簭锛屽鐞嗗嚬澶氳竟褰㈡垨闅滅鐗�
+                        parts.sort((a, b) -> Double.compare(
+                            baseDir.dot(new Vector2D(a.getCoordinateN(0))), 
+                            baseDir.dot(new Vector2D(b.getCoordinateN(0)))
+                        ));
+                        
+                        // 铔囧舰璺緞锛氬鏁拌鍙嶈浆
+                        if (lineIdx % 2 != 0) Collections.reverse(parts);
+
+                        for (LineString part : parts) {
+                            Coordinate[] cs = part.getCoordinates();
+                            if (cs.length < 2) continue;
+                            
+                            if (lineIdx % 2 != 0) reverseArray(cs);
+                            
+                            // 纭繚鐐瑰潗鏍囨湁鏁�
+                            totalPath.add(new PathSegment(cs[0], cs[cs.length - 1], true));
+                        }
+                        lineIdx++;
+                    } catch (Exception e) {
+                        // 蹇界暐鏋佸叾缃曡鐨勬嫇鎵戝紓甯革紝闃叉宕╂簝
                     }
                 }
-            } else {
-                Envelope env = safeArea.getEnvelopeInternal();
-                minProj = perp.dot(new Vector2D(env.getMinX(), env.getMinY())) - baseProjection;
-                maxProj = perp.dot(new Vector2D(env.getMaxX(), env.getMaxY())) - baseProjection;
             }
-            if (minProj > maxProj) {
-                double tmp = minProj;
-                minProj = maxProj;
-                maxProj = tmp;
-            }
-            double first = minProj - width / 2.0;
-
-            Geometry originalPoly = createPolygonFromCoordinates(polygon);
-            Coordinate lastEnd = null;
-            int idx = 0;
-
-            for (double offset = first; offset <= maxProj + width / 2.0; offset += width) {
-                Line2D.Double raw = createInfiniteLine(longest, perp, offset);
-                List<Line2D.Double> segs = clipLineToPolygon(raw, safeArea);
-                if (segs.isEmpty()) {
-                    continue;
-                }
-
-                List<Line2D.Double> finalSegs = new ArrayList<>();
-                for (Line2D.Double seg : segs) {
-                    finalSegs.addAll(clipLineToPolygon(seg, originalPoly));
-                }
-                if (finalSegs.isEmpty()) {
-                    continue;
-                }
-
-                finalSegs.sort((a, b) -> Double.compare(baseDir.dot(midV(a)), baseDir.dot(midV(b))));
-                boolean even = (idx % 2 == 0);
-                for (Line2D.Double seg : finalSegs) {
-                    Coordinate entry = even ? new Coordinate(seg.x1, seg.y1)
-                                            : new Coordinate(seg.x2, seg.y2);
-                    Coordinate exit = even ? new Coordinate(seg.x2, seg.y2)
-                                           : new Coordinate(seg.x1, seg.y1);
-
-                    if (lastEnd != null && lastEnd.distance(entry) > 1e-3) {
-                        path.add(new PathSegment(lastEnd, entry, false));
-                    }
-
-                    PathSegment mowingSeg = new PathSegment(entry, exit, true);
-                    if (path.isEmpty()) {
-                        mowingSeg.setAsStartPoint();
-                    }
-                    path.add(mowingSeg);
-                    lastEnd = exit;
-                }
-                idx++;
-            }
-
-            if (!path.isEmpty()) {
-                path.get(path.size() - 1).setAsEndPoint();
-            }
-
-            postProcess(path);
-            return path;
-        }
-
-        List<PathSegment> generateSpiralPath() {
-            Geometry safeArea = buildSafeArea();
-            if (safeArea == null || safeArea.isEmpty()) {
-                System.err.println("瀹夊叏鍖哄煙涓虹┖锛屾棤娉曠敓鎴愯灪鏃嬭矾寰�");
-                return new ArrayList<>();
-            }
-
-            List<PathSegment> spiral = luoxuan.generateSpiralPath(safeArea, width);
-            if (spiral.isEmpty()) {
-                return spiral;
-            }
-
-            postProcess(spiral);
-            PathSegment firstMowing = null;
-            PathSegment endCandidate = null;
-            for (int i = 0; i < spiral.size(); i++) {
-                PathSegment seg = spiral.get(i);
-                if (seg != null && seg.isMowing) {
-                    if (firstMowing == null) {
-                        firstMowing = seg;
-                    }
-                    endCandidate = seg;
-                }
-            }
-            if (firstMowing != null) {
-                firstMowing.setAsStartPoint();
-            }
-            if (endCandidate != null && endCandidate != firstMowing) {
-                endCandidate.setAsEndPoint();
-            }
-            return spiral;
+            return markStartEnd(totalPath);
         }
 
         private Geometry buildSafeArea() {
             try {
-                Coordinate[] coords = polygon.toArray(new Coordinate[0]);
-                if (!coords[0].equals2D(coords[coords.length - 1])) {
-                    coords = Arrays.copyOf(coords, coords.length + 1);
-                    coords[coords.length - 1] = coords[0];
-                }
-                Polygon origin = gf.createPolygon(gf.createLinearRing(coords));
-                Geometry result = origin;
+                Polygon poly = gf.createPolygon(gf.createLinearRing(polygon.toArray(new Coordinate[0])));
+                
+                // 1. 鍒濆淇锛氬鐞嗚嚜鐩镐氦
+                if (!poly.isValid()) poly = (Polygon) poly.buffer(0);
+                
+                // 2. 鍐呯缉鐢熸垚瀹夊叏鍖哄煙
+                Geometry safe = poly.buffer(-safetyDistance);
+                
+                // 3. 浜屾淇锛氳礋缂撳啿鍚庡彲鑳戒骇鐢熶笉瑙勮寖鍑犱綍浣�
+                if (!safe.isValid()) safe = safe.buffer(0);
 
-                if (!obstacles.isEmpty()) {
-                    List<Geometry> obsGeom = new ArrayList<>();
-                    for (List<Coordinate> obs : obstacles) {
-                        Geometry g = createPolygonFromCoordinates(obs);
-                        if (g != null && !g.isEmpty()) {
-                            obsGeom.add(g);
-                        }
-                    }
-                    if (!obsGeom.isEmpty()) {
-                        Geometry union = CascadedPolygonUnion.union(obsGeom);
-                        result = origin.difference(union);
+                // 4. 澶勭悊闅滅鐗�
+                for (List<Coordinate> obsCoords : obstacles) {
+                    if (obsCoords.size() < 3) continue;
+                    try {
+                        Polygon obs = gf.createPolygon(gf.createLinearRing(obsCoords.toArray(new Coordinate[0])));
+                        if (!obs.isValid()) obs = (Polygon) obs.buffer(0);
+                        // 闅滅鐗╁鎵╁畨鍏ㄨ窛绂�
+                        safe = safe.difference(obs.buffer(safetyDistance));
+                    } catch (Exception e) {
+                        // 蹇界暐閿欒鐨勯殰纰嶇墿鏁版嵁
                     }
                 }
-
-                // 淇敼锛氫娇鐢ㄤ紶鍏ョ殑 safetyDistance 鏉ヨ繘琛岃竟鐣屽唴缂�
-                // 涔嬪墠鏄� width / 2.0锛岀幇鍦ㄤ娇鐢� this.safetyDistance
-                // 杩欑‘淇濅簡璺緞瑙勫垝鍖哄煙涓庤竟鐣屼繚鎸佺敤鎴锋寚瀹氱殑璺濈
-                Geometry shrunk = shrinkStraight(result, this.safetyDistance);
-                return shrunk.isEmpty() ? result : shrunk;
-            } catch (Exception ex) {
-                System.err.println("鏋勫缓瀹夊叏鍖哄煙澶辫触: " + ex.getMessage());
+                
+                // 5. 鏈�缁堟竻鐞�
+                if (!safe.isValid()) safe = safe.buffer(0);
+                return safe;
+            } catch (Exception e) {
+                // 濡傛灉鍑犱綍鏋勫缓瀹屽叏澶辫触锛岃繑鍥炵┖
                 return gf.createPolygon();
             }
         }
 
-        private LineSegment findLongestEdge(List<Coordinate> ring) {
-            double max = -1.0;
-            LineSegment best = null;
-            for (int i = 0; i < ring.size() - 1; i++) {
-                double d = ring.get(i).distance(ring.get(i + 1));
-                if (d > max) {
-                    max = d;
-                    best = new LineSegment(ring.get(i), ring.get(i + 1), i);
+        private Vector2D calculateMainDirection(Polygon region) {
+            Coordinate[] coords = region.getExteriorRing().getCoordinates();
+            double maxLen = -1; 
+            Vector2D bestDir = new Vector2D(1, 0);
+            
+            // 瀵绘壘鏈�闀胯竟浣滀负涓绘柟鍚戯紝鍑忓皯杞集娆℃暟
+            for (int i = 0; i < coords.length - 1; i++) {
+                double d = coords[i].distance(coords[i+1]);
+                if (d > maxLen && d > 1e-4) {
+                    maxLen = d;
+                    bestDir = new Vector2D(coords[i+1].x - coords[i].x, coords[i+1].y - coords[i].y).normalize();
                 }
             }
-            return best;
+            return bestDir;
         }
 
-        private Line2D.Double createInfiniteLine(LineSegment base, Vector2D perp, double offset) {
-            Vector2D baseStart = new Vector2D(base.start.x, base.start.y);
-            Vector2D baseDir = new Vector2D(base.end.x - base.start.x,
-                                            base.end.y - base.start.y).normalize();
-            Vector2D center = baseStart.add(perp.mul(offset));
-            double ext = 1.5 * diagonalLength();
-            Vector2D p1 = center.sub(baseDir.mul(ext));
-            Vector2D p2 = center.add(baseDir.mul(ext));
-            return new Line2D.Double(p1.x, p1.y, p2.x, p2.y);
-        }
-
-        private List<Line2D.Double> clipLineToPolygon(Line2D.Double line, Geometry poly) {
-            List<Line2D.Double> list = new ArrayList<>();
-            LineString ls = gf.createLineString(new Coordinate[]{
-                    new Coordinate(line.x1, line.y1),
-                    new Coordinate(line.x2, line.y2)
-            });
-            Geometry inter = poly.intersection(ls);
-            if (inter.isEmpty()) {
-                return list;
-            }
-
-            if (inter instanceof LineString) {
-                addCoords((LineString) inter, list);
-            } else if (inter instanceof MultiLineString) {
-                MultiLineString mls = (MultiLineString) inter;
-                for (int i = 0; i < mls.getNumGeometries(); i++) {
-                    addCoords((LineString) mls.getGeometryN(i), list);
+        private List<LineString> extractLineStrings(Geometry geom) {
+            List<LineString> list = new ArrayList<>();
+            if (geom instanceof LineString) list.add((LineString) geom);
+            else if (geom instanceof MultiLineString) {
+                for (int i = 0; i < geom.getNumGeometries(); i++) list.add((LineString) geom.getGeometryN(i));
+            } else if (geom instanceof org.locationtech.jts.geom.GeometryCollection) {
+                for (int i = 0; i < geom.getNumGeometries(); i++) {
+                   if (geom.getGeometryN(i) instanceof LineString) {
+                       list.add((LineString) geom.getGeometryN(i));
+                   }
                 }
             }
             return list;
         }
 
-        private void addCoords(LineString ls, List<Line2D.Double> bucket) {
-            Coordinate[] cs = ls.getCoordinateSequence().toCoordinateArray();
-            for (int i = 0; i < cs.length - 1; i++) {
-                bucket.add(new Line2D.Double(cs[i].x, cs[i].y, cs[i + 1].x, cs[i + 1].y));
+        private LineString createScanLine(double dist, Vector2D perp, Vector2D baseDir, Envelope env) {
+            // 鎵╁ぇ鎵弿绾块暱搴︼紝纭繚瑕嗙洊鏃嬭浆鍚庣殑澶氳竟褰�
+            double size = Math.max(env.getWidth(), env.getHeight());
+            // 澶勭悊閫�鍖栧寘鍥寸洅
+            if (size < 1.0) size = 1000.0; 
+            
+            double len = size * 3.0; // 3鍊嶅昂瀵哥‘淇濊冻澶熼暱
+            
+            // 涓績鐐硅绠楋細鍦ㄥ瀭鐩存柟鍚戜笂璺濈鍘熺偣 dist 鐨勪綅缃�
+            Vector2D center = perp.mul(dist);
+            
+            return gf.createLineString(new Coordinate[]{
+                new Coordinate(center.x + baseDir.x * len, center.y + baseDir.y * len),
+                new Coordinate(center.x - baseDir.x * len, center.y - baseDir.y * len)
+            });
+        }
+
+        private List<PathSegment> markStartEnd(List<PathSegment> path) {
+            if (!path.isEmpty()) {
+                path.get(0).setAsStartPoint();
+                path.get(path.size() - 1).setAsEndPoint();
+            }
+            return path;
+        }
+
+        private void reverseArray(Coordinate[] arr) {
+            for (int i = 0; i < arr.length / 2; i++) {
+                Coordinate t = arr[i]; 
+                arr[i] = arr[arr.length - 1 - i]; 
+                arr[arr.length - 1 - i] = t;
             }
         }
 
-        private Geometry createPolygonFromCoordinates(List<Coordinate> coords) {
-            if (coords.size() < 3) {
-                return gf.createPolygon();
-            }
-            List<Coordinate> closed = new ArrayList<>(coords);
-            if (!closed.get(0).equals2D(closed.get(closed.size() - 1))) {
-                closed.add(new Coordinate(closed.get(0)));
-            }
-            LinearRing shell = gf.createLinearRing(closed.toArray(new Coordinate[0]));
-            Polygon polygonGeom = gf.createPolygon(shell);
-            return polygonGeom.isValid() ? polygonGeom : (Polygon) polygonGeom.buffer(0);
-        }
-
-        private double diagonalLength() {
-            double minX = polygon.stream().mapToDouble(c -> c.x).min().orElse(0);
-            double maxX = polygon.stream().mapToDouble(c -> c.x).max().orElse(0);
-            double minY = polygon.stream().mapToDouble(c -> c.y).min().orElse(0);
-            double maxY = polygon.stream().mapToDouble(c -> c.y).max().orElse(0);
-            return Math.hypot(maxX - minX, maxY - minY);
-        }
-
-        private Vector2D midV(Line2D.Double l) {
-            return new Vector2D((l.x1 + l.x2) / 2.0, (l.y1 + l.y2) / 2.0);
-        }
-
-        private void postProcess(List<PathSegment> path) {
-            if (path == null || path.isEmpty()) {
-                return;
-            }
-            List<PathSegment> tmp = new ArrayList<>(path);
-            path.clear();
-            Coordinate prevEnd = null;
-            for (PathSegment seg : tmp) {
-                if (prevEnd != null && seg.start.distance(prevEnd) < 1e-3) {
-                    seg.start = prevEnd;
-                }
-                if (!seg.isMowing && !path.isEmpty()) {
-                    PathSegment last = path.get(path.size() - 1);
-                    if (!last.isMowing && isCollinear(last.start, last.end, seg.end)) {
-                        last.end = seg.end;
-                        prevEnd = seg.end;
-                        continue;
-                    }
-                }
-                path.add(seg);
-                prevEnd = seg.end;
-            }
-        }
-
-        private boolean isCollinear(Coordinate a, Coordinate b, Coordinate c) {
-            double dx1 = b.x - a.x;
-            double dy1 = b.y - a.y;
-            double dx2 = c.x - b.x;
-            double dy2 = c.y - b.y;
-            double cross = dx1 * dy2 - dy1 * dx2;
-            return Math.abs(cross) < 1e-6;
-        }
-
-        private Geometry shrinkStraight(Geometry outer, double dist) {
-            Geometry buf = outer.buffer(-dist);
-            if (buf.isEmpty()) {
-                return buf;
-            }
-
-            Geometry poly = (buf instanceof Polygon) ? buf
-                    : (buf instanceof MultiPolygon) ? ((MultiPolygon) buf).getGeometryN(0) : null;
-            if (!(poly instanceof Polygon)) {
-                return buf;
-            }
-
-            Coordinate[] ring = ((Polygon) poly).getExteriorRing().getCoordinateSequence().toCoordinateArray();
-            List<Coordinate> straight = new ArrayList<>();
-            final double EPS = 1e-3;
-            for (int i = 0; i < ring.length - 1; i++) {
-                Coordinate prev = (i == 0) ? ring[ring.length - 2] : ring[i - 1];
-                Coordinate curr = ring[i];
-                Coordinate next = ring[i + 1];
-                double cross = Math.abs((next.x - curr.x) * (curr.y - prev.y)
-                                      - (curr.x - prev.x) * (next.y - curr.y));
-                if (cross > EPS) {
-                    straight.add(curr);
-                }
-            }
-            if (straight.isEmpty()) {
-                return buf;
-            }
-            straight.add(new Coordinate(straight.get(0)));
-            return straight.size() < 4 ? gf.createPolygon()
-                    : gf.createPolygon(gf.createLinearRing(straight.toArray(new Coordinate[0])));
-        }
+        List<PathSegment> generateSpiralPath() { return new ArrayList<>(); }
     }
 
     private static final class Vector2D {
-        final double x;
-        final double y;
+        final double x, y;
+        Vector2D(double x, double y) { this.x = x; this.y = y; }
+        Vector2D(Coordinate c) { this.x = c.x; this.y = c.y; }
 
-        Vector2D(double x, double y) {
-            this.x = x;
-            this.y = y;
+        Vector2D normalize() { 
+            double len = Math.hypot(x, y); 
+            return len < 1e-9 ? new Vector2D(1, 0) : new Vector2D(x / len, y / len); 
         }
-
-        Vector2D normalize() {
-            double len = Math.hypot(x, y);
-            if (len < 1e-12) {
-                return new Vector2D(1, 0);
-            }
-            return new Vector2D(x / len, y / len);
-        }
-
-        Vector2D rotate90CCW() {
-            return new Vector2D(-y, x);
-        }
-
-        double dot(Vector2D v) {
-            return x * v.x + y * v.y;
-        }
-
-        Vector2D sub(Vector2D v) {
-            return new Vector2D(x - v.x, y - v.y);
-        }
-
-        Vector2D add(Vector2D v) {
-            return new Vector2D(x + v.x, y + v.y);
-        }
-
-        Vector2D mul(double k) {
-            return new Vector2D(x * k, y * k);
-        }
-    }
-
-    private static final class LineSegment {
-        final Coordinate start;
-        final Coordinate end;
-        final int index;
-
-        LineSegment(Coordinate start, Coordinate end, int index) {
-            this.start = start;
-            this.end = end;
-            this.index = index;
-        }
+        Vector2D rotate90CCW() { return new Vector2D(-y, x); }
+        double dot(Vector2D v) { return x * v.x + y * v.y; }
+        Vector2D mul(double k) { return new Vector2D(x * k, y * k); }
     }
 }
\ No newline at end of file
diff --git a/src/lujing/MowingPathGenerationPage.java b/src/lujing/MowingPathGenerationPage.java
index 5c080b0..3e0cd48 100644
--- a/src/lujing/MowingPathGenerationPage.java
+++ b/src/lujing/MowingPathGenerationPage.java
@@ -477,33 +477,22 @@
                 obstacleList = new ArrayList<>();
             }
 
-            // 鍒ゆ柇鏄惁鏈夐殰纰嶇墿锛氬彧瑕佸師濮嬭緭鍏ユ湁闅滅鐗╁唴瀹癸紝灏变娇鐢∣bstaclePathPlanner
-            // 鍗充娇瑙f瀽鍚庡垪琛ㄤ负绌猴紝涔熷皾璇曚娇鐢∣bstaclePathPlanner锛堝畠浼氬鐞嗙┖闅滅鐗╁垪琛ㄧ殑鎯呭喌锛�
-            boolean hasObstacles = hasObstacleInput && !obstacleList.isEmpty();
-            
-            // 濡傛灉鍘熷杈撳叆鏈夐殰纰嶇墿浣嗚В鏋愬け璐ワ紝缁欏嚭鎻愮ず
-            if (hasObstacleInput && obstacleList.isEmpty()) {
-                if (showMessages) {
-                    JOptionPane.showMessageDialog(parentComponent, 
-                        "闅滅鐗╁潗鏍囨牸寮忓彲鑳戒笉姝g‘锛屽皢灏濊瘯鐢熸垚璺緞銆傚鏋滆矾寰勪笉姝g‘锛岃妫�鏌ラ殰纰嶇墿鍧愭爣鏍煎紡銆�", 
-                        "鎻愮ず", JOptionPane.WARNING_MESSAGE);
-                }
-                // 浠嶇劧灏濊瘯浣跨敤ObstaclePathPlanner锛屽嵆浣块殰纰嶇墿鍒楄〃涓虹┖
-                // 杩欐牱鑷冲皯鍙互纭繚浣跨敤姝g‘鐨勮矾寰勮鍒掑櫒
-            }
+            // 鍒ゆ柇鏄惁鏈夋湁鏁堢殑闅滅鐗╋細鍙湁褰撹В鏋愭垚鍔熶笖鍒楄〃涓嶄负绌烘椂锛屾墠璁や负鏈夐殰纰嶇墿
+            boolean hasValidObstacles = !obstacleList.isEmpty();
             
             String generated;
             
-            if (!hasObstacles && !hasObstacleInput) {
-                // 瀹屽叏娌℃湁闅滅鐗╄緭鍏ユ椂锛屼娇鐢↙unjingguihua绫荤殑鏂规硶鐢熸垚璺緞
+            if (!hasValidObstacles) {
+                // 闅滅鐗╁潗鏍囦笉瀛樺湪鎴栦负绌烘椂锛屼娇鐢↙unjingguihua绫荤殑鏂规硶鐢熸垚璺緞
                 generated = Lunjingguihua.generatePathFromStrings(
                     boundary,
                     obstacles != null ? obstacles : "",
                     plannerWidth,
+                    null,  // safetyDistStr锛屼娇鐢ㄩ粯璁ゅ��
                     mode
                 );
             } else {
-                // 鏈夐殰纰嶇墿杈撳叆鏃讹紙鍗充娇瑙f瀽澶辫触锛夛紝浣跨敤ObstaclePathPlanner澶勭悊璺緞鐢熸垚
+                // 鏈夋湁鏁堥殰纰嶇墿鏃讹紝浣跨敤ObstaclePathPlanner澶勭悊璺緞鐢熸垚
                 List<Coordinate> polygon = Lunjingguihua.parseCoordinates(boundary);
                 if (polygon.size() < 4) {
                     if (showMessages) {
@@ -513,15 +502,8 @@
                     return null;
                 }
 
-                // 鏍规嵁鏄惁鏈夐殰纰嶇墿璁剧疆涓嶅悓鐨勫畨鍏ㄨ窛绂�
-                double safetyDistance;
-                if (!obstacleList.isEmpty()) {
-                    // 鏈夐殰纰嶇墿鏃朵娇鐢ㄥ壊鑽夊搴︾殑涓�鍗� + 0.05绫抽澶栧畨鍏ㄨ窛绂�
-                    safetyDistance = widthMeters / 2.0 + 0.05;
-                } else {
-                    // 闅滅鐗╄В鏋愬け璐ヤ絾杈撳叆瀛樺湪锛屼娇鐢ㄨ緝灏忕殑瀹夊叏璺濈
-                    safetyDistance = 0.01;
-                }
+                // 鏈夐殰纰嶇墿鏃朵娇鐢ㄥ壊鑽夊搴︾殑涓�鍗� + 0.05绫抽澶栧畨鍏ㄨ窛绂�
+                double safetyDistance = widthMeters / 2.0 + 0.05;
 
                 ObstaclePathPlanner pathPlanner = new ObstaclePathPlanner(
                     polygon, widthMeters, mode, obstacleList, safetyDistance);
diff --git a/src/lujing/ObstaclePathPlanner.java b/src/lujing/ObstaclePathPlanner.java
index 8c89235..96f189a 100644
--- a/src/lujing/ObstaclePathPlanner.java
+++ b/src/lujing/ObstaclePathPlanner.java
@@ -533,4 +533,8 @@
             }
         }
     }
-}
\ No newline at end of file
+}
+
+
+
+
diff --git a/src/zhangaiwu/AddDikuai.java b/src/zhangaiwu/AddDikuai.java
index 02ac96d..b80b9ec 100644
--- a/src/zhangaiwu/AddDikuai.java
+++ b/src/zhangaiwu/AddDikuai.java
@@ -65,7 +65,9 @@
     private JTextField landNumberField;
     private JTextField areaNameField;
     private JComboBox<String> mowingPatternCombo;
-    private JSpinner mowingWidthSpinner;
+    private JTextField mowingWidthField; // 鍓茶崏鏈哄壊鍒�瀹藉害
+    private JTextField overlapDistanceField; // 鐩搁偦琛岄噸鍙犺窛绂�
+    private JLabel calculatedMowingWidthLabel; // 璁$畻鍚庣殑鍓茶崏瀹藉害鏄剧ず
     private JPanel previewPanel;
     private Map<String, JPanel> drawingOptionPanels = new HashMap<>();
     
@@ -768,7 +770,7 @@
             return false;
         }
         if (userTriggered && "handheld".equalsIgnoreCase(type) && !hasConfiguredHandheldMarker()) {
-            JOptionPane.showMessageDialog(this, "璇峰厛娣诲姞渚挎惡鎵撶偣鍣ㄧ紪鍙�", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
+            JOptionPane.showMessageDialog(this, "璇峰厛鍘荤郴缁熻缃坊鍔犱究鎼烘墦鐐瑰櫒缂栧彿", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
             return false;
         }
 
@@ -898,7 +900,7 @@
         settingsPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
         
         // 鍓茶崏妯″紡閫夋嫨
-        JPanel patternPanel = createFormGroup("鍓茶崏妯″紡", "閫夋嫨鍓茶崏璺緞鐨勭敓鎴愭ā寮�");
+        JPanel patternPanel = createFormGroupWithoutHint("鍓茶崏妯″紡");
         mowingPatternCombo = new JComboBox<>(new String[]{"骞宠绾�", "铻烘棆寮�"});
         mowingPatternCombo.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 16));
         mowingPatternCombo.setMaximumSize(new Dimension(Integer.MAX_VALUE, 48));
@@ -930,29 +932,27 @@
         
         patternPanel.add(mowingPatternCombo);
         settingsPanel.add(patternPanel);
-        settingsPanel.add(Box.createRigidArea(new Dimension(0, 20)));
+        settingsPanel.add(Box.createRigidArea(new Dimension(0, 10)));
         
-        // 鍓茶崏瀹藉害璁剧疆
-        JPanel widthPanel = createFormGroup("鍓茶崏瀹藉害", "璁剧疆鍓茶崏鏈哄崟娆″壊鑽夌殑瀹藉害");
+        // 鍓茶崏鏈哄壊鍒�瀹藉害璁剧疆
+        JPanel widthPanel = createFormGroupWithoutHint("鍓茶崏鏈哄壊鍒�瀹藉害");
         JPanel widthInputPanel = new JPanel(new BorderLayout());
         widthInputPanel.setBackground(WHITE);
         widthInputPanel.setMaximumSize(new Dimension(Integer.MAX_VALUE, 48));
         widthInputPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
         
-        SpinnerNumberModel widthModel = new SpinnerNumberModel(40, 20, 60, 1);
-        mowingWidthSpinner = new JSpinner(widthModel);
-        mowingWidthSpinner.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 16));
-        JSpinner.DefaultEditor editor = (JSpinner.DefaultEditor) mowingWidthSpinner.getEditor();
-        editor.getTextField().setBorder(BorderFactory.createCompoundBorder(
+        mowingWidthField = new JTextField("0.40");
+        mowingWidthField.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 16));
+        mowingWidthField.setBorder(BorderFactory.createCompoundBorder(
             BorderFactory.createLineBorder(BORDER_COLOR, 2),
             BorderFactory.createEmptyBorder(10, 12, 10, 12)
         ));
         
-        // 娣诲姞寰皟鍣ㄧ劍鐐规晥鏋�
-        mowingWidthSpinner.addFocusListener(new FocusAdapter() {
+        // 娣诲姞鏂囨湰妗嗙劍鐐规晥鏋滃拰鍙樺寲鐩戝惉
+        mowingWidthField.addFocusListener(new FocusAdapter() {
             @Override
             public void focusGained(FocusEvent e) {
-                editor.getTextField().setBorder(BorderFactory.createCompoundBorder(
+                mowingWidthField.setBorder(BorderFactory.createCompoundBorder(
                     BorderFactory.createLineBorder(PRIMARY_COLOR, 2),
                     BorderFactory.createEmptyBorder(10, 12, 10, 12)
                 ));
@@ -960,27 +960,97 @@
             
             @Override
             public void focusLost(FocusEvent e) {
-                editor.getTextField().setBorder(BorderFactory.createCompoundBorder(
+                mowingWidthField.setBorder(BorderFactory.createCompoundBorder(
                     BorderFactory.createLineBorder(BORDER_COLOR, 2),
                     BorderFactory.createEmptyBorder(10, 12, 10, 12)
                 ));
+                updateCalculatedMowingWidth();
             }
         });
         
-        JLabel unitLabel = new JLabel("鍘樼背");
+        JLabel unitLabel = new JLabel("绫�");
         unitLabel.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 14));
         unitLabel.setForeground(LIGHT_TEXT);
         unitLabel.setBorder(BorderFactory.createEmptyBorder(0, 15, 0, 0));
         
-        widthInputPanel.add(mowingWidthSpinner, BorderLayout.CENTER);
+        widthInputPanel.add(mowingWidthField, BorderLayout.CENTER);
         widthInputPanel.add(unitLabel, BorderLayout.EAST);
         
         widthPanel.add(widthInputPanel);
         settingsPanel.add(widthPanel);
+        settingsPanel.add(Box.createRigidArea(new Dimension(0, 10)));
+        
+        // 鐩搁偦琛岄噸鍙犺窛绂昏缃�
+        JPanel overlapPanel = createFormGroupWithoutHint("鐩搁偦琛岄噸鍙犺窛绂�");
+        JPanel overlapInputPanel = new JPanel(new BorderLayout());
+        overlapInputPanel.setBackground(WHITE);
+        overlapInputPanel.setMaximumSize(new Dimension(Integer.MAX_VALUE, 48));
+        overlapInputPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
+        
+        overlapDistanceField = new JTextField("0.06");
+        overlapDistanceField.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 16));
+        overlapDistanceField.setBorder(BorderFactory.createCompoundBorder(
+            BorderFactory.createLineBorder(BORDER_COLOR, 2),
+            BorderFactory.createEmptyBorder(10, 12, 10, 12)
+        ));
+        
+        // 娣诲姞鏂囨湰妗嗙劍鐐规晥鏋滃拰鍙樺寲鐩戝惉
+        overlapDistanceField.addFocusListener(new FocusAdapter() {
+            @Override
+            public void focusGained(FocusEvent e) {
+                overlapDistanceField.setBorder(BorderFactory.createCompoundBorder(
+                    BorderFactory.createLineBorder(PRIMARY_COLOR, 2),
+                    BorderFactory.createEmptyBorder(10, 12, 10, 12)
+                ));
+            }
+            
+            @Override
+            public void focusLost(FocusEvent e) {
+                overlapDistanceField.setBorder(BorderFactory.createCompoundBorder(
+                    BorderFactory.createLineBorder(BORDER_COLOR, 2),
+                    BorderFactory.createEmptyBorder(10, 12, 10, 12)
+                ));
+                updateCalculatedMowingWidth();
+            }
+        });
+        
+        JLabel overlapUnitLabel = new JLabel("绫�");
+        overlapUnitLabel.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 14));
+        overlapUnitLabel.setForeground(LIGHT_TEXT);
+        overlapUnitLabel.setBorder(BorderFactory.createEmptyBorder(0, 15, 0, 0));
+        
+        overlapInputPanel.add(overlapDistanceField, BorderLayout.CENTER);
+        overlapInputPanel.add(overlapUnitLabel, BorderLayout.EAST);
+        
+        overlapPanel.add(overlapInputPanel);
+        settingsPanel.add(overlapPanel);
+        settingsPanel.add(Box.createRigidArea(new Dimension(0, 10)));
+        
+        // 鍓茶崏瀹藉害鏄剧ず锛堣嚜鍔ㄨ绠楋紝涓嶅彲淇敼锛�
+        JPanel calculatedWidthPanel = createFormGroup("鍓茶崏瀹藉害", "鍓茶崏瀹藉害 = 鍓茶崏鏈哄壊鍒�瀹藉害 - 閲嶅彔璺濈锛堣嚜鍔ㄨ绠楋級");
+        JPanel calculatedWidthDisplayPanel = new JPanel(new BorderLayout());
+        calculatedWidthDisplayPanel.setBackground(LIGHT_GRAY);
+        calculatedWidthDisplayPanel.setMaximumSize(new Dimension(Integer.MAX_VALUE, 48));
+        calculatedWidthDisplayPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
+        calculatedWidthDisplayPanel.setBorder(BorderFactory.createCompoundBorder(
+            BorderFactory.createLineBorder(BORDER_COLOR, 2),
+            BorderFactory.createEmptyBorder(10, 12, 10, 12)
+        ));
+        
+        calculatedMowingWidthLabel = new JLabel("0.00 绫�");
+        calculatedMowingWidthLabel.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 16));
+        calculatedMowingWidthLabel.setForeground(TEXT_COLOR);
+        calculatedWidthDisplayPanel.add(calculatedMowingWidthLabel, BorderLayout.CENTER);
+        
+        calculatedWidthPanel.add(calculatedWidthDisplayPanel);
+        settingsPanel.add(calculatedWidthPanel);
         settingsPanel.add(Box.createRigidArea(new Dimension(0, 25)));
         
         stepPanel.add(settingsPanel);
         
+        // 鍒濆鍖栬绠楀悗鐨勫壊鑽夊搴�
+        updateCalculatedMowingWidth();
+        
         JButton generatePathButton = createPrimaryButton("鐢熸垚鍓茶崏璺緞", 16);
         generatePathButton.setAlignmentX(Component.LEFT_ALIGNMENT);
         generatePathButton.setMaximumSize(new Dimension(Integer.MAX_VALUE, 55));
@@ -1016,6 +1086,41 @@
         return stepPanel;
     }
     
+    /**
+     * 鏇存柊璁$畻鍚庣殑鍓茶崏瀹藉害鏄剧ず
+     */
+    private void updateCalculatedMowingWidth() {
+        if (calculatedMowingWidthLabel == null || mowingWidthField == null || overlapDistanceField == null) {
+            return;
+        }
+        
+        try {
+            String widthText = mowingWidthField.getText().trim();
+            String overlapText = overlapDistanceField.getText().trim();
+            
+            if (widthText.isEmpty() || overlapText.isEmpty()) {
+                calculatedMowingWidthLabel.setText("0.00 绫�");
+                return;
+            }
+            
+            double bladeWidthMeters = Double.parseDouble(widthText);
+            double overlapMeters = Double.parseDouble(overlapText);
+            double calculatedWidthMeters = bladeWidthMeters - overlapMeters;
+            
+            if (calculatedWidthMeters <= 0) {
+                calculatedMowingWidthLabel.setText("鏃犳晥锛堝壊鍒�瀹藉害闇�澶т簬閲嶅彔璺濈锛�");
+                calculatedMowingWidthLabel.setForeground(ERROR_COLOR);
+            } else {
+                calculatedMowingWidthLabel.setText(String.format(Locale.US, "%.2f 绫�", calculatedWidthMeters));
+                calculatedMowingWidthLabel.setForeground(TEXT_COLOR);
+            }
+        } catch (NumberFormatException e) {
+            calculatedMowingWidthLabel.setText("0.00 绫�");
+        } catch (Exception e) {
+            calculatedMowingWidthLabel.setText("0.00 绫�");
+        }
+    }
+    
     private JPanel createInstructionPanel(String text) {
         JPanel instructionPanel = new JPanel(new BorderLayout());
         instructionPanel.setBackground(PRIMARY_LIGHT);
@@ -1066,6 +1171,23 @@
         
         return formGroup;
     }
+    
+    private JPanel createFormGroupWithoutHint(String label) {
+        JPanel formGroup = new JPanel();
+        formGroup.setLayout(new BoxLayout(formGroup, BoxLayout.Y_AXIS));
+        formGroup.setBackground(WHITE);
+        formGroup.setAlignmentX(Component.LEFT_ALIGNMENT);
+        
+        JLabel nameLabel = new JLabel(label);
+        nameLabel.setFont(new Font("寰蒋闆呴粦", Font.BOLD, 16));
+        nameLabel.setForeground(TEXT_COLOR);
+        nameLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
+        
+        formGroup.add(nameLabel);
+        formGroup.add(Box.createRigidArea(new Dimension(0, 8)));
+        
+        return formGroup;
+    }
 
     private void generateMowingPath() {
         if (!dikuaiData.containsKey("boundaryDrawn")) {
@@ -1104,25 +1226,79 @@
         String patternDisplay = (String) mowingPatternCombo.getSelectedItem();
         dikuaiData.put("mowingPattern", patternDisplay);
 
-        Object widthObj = mowingWidthSpinner.getValue();
-        if (!(widthObj instanceof Number)) {
-            JOptionPane.showMessageDialog(this, "鍓茶崏瀹藉害杈撳叆鏃犳晥", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
+        String widthText = mowingWidthField.getText().trim();
+        if (widthText.isEmpty()) {
+            JOptionPane.showMessageDialog(this, "鍓茶崏鏈哄壊鍒�瀹藉害涓嶈兘涓虹┖", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
             dikuaiData.remove("plannedPath");
-            showPathGenerationMessage("鍓茶崏瀹藉害杈撳叆鏃犳晥锛岃閲嶆柊杈撳叆銆�", false);
+            showPathGenerationMessage("鍓茶崏鏈哄壊鍒�瀹藉害涓嶈兘涓虹┖锛岃閲嶆柊杈撳叆銆�", false);
             setPathAvailability(false);
             return;
         }
-        double widthCm = ((Number) widthObj).doubleValue();
-        if (widthCm <= 0) {
-            JOptionPane.showMessageDialog(this, "鍓茶崏瀹藉害蹇呴』澶т簬0", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
+        double bladeWidthMeters;
+        try {
+            bladeWidthMeters = Double.parseDouble(widthText);
+        } catch (NumberFormatException e) {
+            JOptionPane.showMessageDialog(this, "鍓茶崏鏈哄壊鍒�瀹藉害杈撳叆鏃犳晥", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
             dikuaiData.remove("plannedPath");
-            showPathGenerationMessage("鍓茶崏瀹藉害蹇呴』澶т簬0锛岃閲嶆柊璁剧疆銆�", false);
+            showPathGenerationMessage("鍓茶崏鏈哄壊鍒�瀹藉害杈撳叆鏃犳晥锛岃閲嶆柊杈撳叆銆�", false);
             setPathAvailability(false);
             return;
         }
-        dikuaiData.put("mowingWidth", widthObj.toString());
+        if (bladeWidthMeters <= 0) {
+            JOptionPane.showMessageDialog(this, "鍓茶崏鏈哄壊鍒�瀹藉害蹇呴』澶т簬0", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
+            dikuaiData.remove("plannedPath");
+            showPathGenerationMessage("鍓茶崏鏈哄壊鍒�瀹藉害蹇呴』澶т簬0锛岃閲嶆柊璁剧疆銆�", false);
+            setPathAvailability(false);
+            return;
+        }
+        // 淇濆瓨鍓茶崏鏈哄壊鍒�瀹藉害锛堢背锛�
+        dikuaiData.put("mowingBladeWidth", String.format(Locale.US, "%.2f", bladeWidthMeters));
+        
+        // 鑾峰彇閲嶅彔璺濈
+        String overlapText = overlapDistanceField.getText().trim();
+        if (overlapText.isEmpty()) {
+            JOptionPane.showMessageDialog(this, "鐩搁偦琛岄噸鍙犺窛绂讳笉鑳戒负绌�", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
+            dikuaiData.remove("plannedPath");
+            showPathGenerationMessage("鐩搁偦琛岄噸鍙犺窛绂讳笉鑳戒负绌猴紝璇烽噸鏂拌緭鍏ャ��", false);
+            setPathAvailability(false);
+            return;
+        }
+        double overlapMeters;
+        try {
+            overlapMeters = Double.parseDouble(overlapText);
+        } catch (NumberFormatException e) {
+            JOptionPane.showMessageDialog(this, "鐩搁偦琛岄噸鍙犺窛绂昏緭鍏ユ棤鏁�", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
+            dikuaiData.remove("plannedPath");
+            showPathGenerationMessage("鐩搁偦琛岄噸鍙犺窛绂昏緭鍏ユ棤鏁堬紝璇烽噸鏂拌緭鍏ャ��", false);
+            setPathAvailability(false);
+            return;
+        }
+        if (overlapMeters < 0) {
+            JOptionPane.showMessageDialog(this, "鐩搁偦琛岄噸鍙犺窛绂讳笉鑳戒负璐熸暟", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
+            dikuaiData.remove("plannedPath");
+            showPathGenerationMessage("鐩搁偦琛岄噸鍙犺窛绂讳笉鑳戒负璐熸暟锛岃閲嶆柊璁剧疆銆�", false);
+            setPathAvailability(false);
+            return;
+        }
+        
+        // 淇濆瓨閲嶅彔璺濈鍒板湴鍧楁暟鎹�
+        dikuaiData.put("mowingOverlapDistance", String.format(Locale.US, "%.2f", overlapMeters));
+        
+        // 璁$畻瀹為檯浣跨敤鐨勫壊鑽夊搴︼紙鍓插垁瀹藉害 - 閲嶅彔璺濈锛�
+        double calculatedWidthMeters = bladeWidthMeters - overlapMeters;
+        if (calculatedWidthMeters <= 0) {
+            JOptionPane.showMessageDialog(this, "璁$畻鍚庣殑鍓茶崏瀹藉害蹇呴』澶т簬0锛堝壊鍒�瀹藉害蹇呴』澶т簬閲嶅彔璺濈锛�", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
+            dikuaiData.remove("plannedPath");
+            showPathGenerationMessage("璁$畻鍚庣殑鍓茶崏瀹藉害蹇呴』澶т簬0锛岃璋冩暣鍓插垁瀹藉害鎴栭噸鍙犺窛绂汇��", false);
+            setPathAvailability(false);
+            return;
+        }
 
-        String widthMeters = String.format(Locale.US, "%.2f", widthCm / 100.0);
+        // 淇濆瓨鍓茶崏瀹藉害锛堣绠楀悗鐨勫�硷紝杞崲涓哄帢绫冲瓨鍌紝淇濇寔涓庡師鏈夋暟鎹牸寮忓吋瀹癸級
+        double calculatedWidthCm = calculatedWidthMeters * 100.0;
+        dikuaiData.put("mowingWidth", String.format(Locale.US, "%.0f", calculatedWidthCm));
+
+        String widthMeters = String.format(Locale.US, "%.2f", calculatedWidthMeters);
         String plannerMode = resolvePlannerMode(patternDisplay);
 
         try {
@@ -1245,13 +1421,51 @@
             }
         }
 
-        if (mowingWidthSpinner != null) {
-            Object widthValue = mowingWidthSpinner.getValue();
-            if (widthValue instanceof Number) {
-                int widthInt = ((Number) widthValue).intValue();
-                dikuaiData.put("mowingWidth", Integer.toString(widthInt));
-            } else if (widthValue != null) {
-                dikuaiData.put("mowingWidth", widthValue.toString());
+        // 淇濆瓨鍓茶崏鏈哄壊鍒�瀹藉害
+        if (mowingWidthField != null) {
+            String bladeWidthText = mowingWidthField.getText().trim();
+            if (!bladeWidthText.isEmpty()) {
+                try {
+                    double bladeWidthMeters = Double.parseDouble(bladeWidthText);
+                    dikuaiData.put("mowingBladeWidth", String.format(Locale.US, "%.2f", bladeWidthMeters));
+                } catch (NumberFormatException e) {
+                    // 濡傛灉瑙f瀽澶辫触锛岀洿鎺ヤ繚瀛樻枃鏈�
+                    dikuaiData.put("mowingBladeWidth", bladeWidthText);
+                }
+            }
+        }
+        
+        // 淇濆瓨鐩搁偦琛岄噸鍙犺窛绂�
+        if (overlapDistanceField != null) {
+            String overlapText = overlapDistanceField.getText().trim();
+            if (!overlapText.isEmpty()) {
+                try {
+                    double overlapMeters = Double.parseDouble(overlapText);
+                    dikuaiData.put("mowingOverlapDistance", String.format(Locale.US, "%.2f", overlapMeters));
+                } catch (NumberFormatException e) {
+                    // 濡傛灉瑙f瀽澶辫触锛岀洿鎺ヤ繚瀛樻枃鏈�
+                    dikuaiData.put("mowingOverlapDistance", overlapText);
+                }
+            }
+        }
+        
+        // 璁$畻骞朵繚瀛樺壊鑽夊搴︼紙鍓插垁瀹藉害 - 閲嶅彔璺濈锛�
+        if (mowingWidthField != null && overlapDistanceField != null) {
+            try {
+                String bladeWidthText = mowingWidthField.getText().trim();
+                String overlapText = overlapDistanceField.getText().trim();
+                if (!bladeWidthText.isEmpty() && !overlapText.isEmpty()) {
+                    double bladeWidthMeters = Double.parseDouble(bladeWidthText);
+                    double overlapMeters = Double.parseDouble(overlapText);
+                    double calculatedWidthMeters = bladeWidthMeters - overlapMeters;
+                    if (calculatedWidthMeters > 0) {
+                        // 杞崲涓哄帢绫冲瓨鍌紝淇濇寔涓庡師鏈夋暟鎹牸寮忓吋瀹�
+                        int widthCm = (int) Math.round(calculatedWidthMeters * 100.0);
+                        dikuaiData.put("mowingWidth", Integer.toString(widthCm));
+                    }
+                }
+            } catch (NumberFormatException e) {
+                // 濡傛灉璁$畻澶辫触锛屼笉淇濆瓨鍓茶崏瀹藉害
             }
         }
     }
@@ -1724,7 +1938,53 @@
 
             case 3:
                 dikuaiData.put("mowingPattern", (String) mowingPatternCombo.getSelectedItem());
-                dikuaiData.put("mowingWidth", mowingWidthSpinner.getValue().toString());
+                
+                // 淇濆瓨鍓茶崏鏈哄壊鍒�瀹藉害
+                if (mowingWidthField != null) {
+                    String bladeWidthText = mowingWidthField.getText().trim();
+                    if (!bladeWidthText.isEmpty()) {
+                        try {
+                            double bladeWidthMeters = Double.parseDouble(bladeWidthText);
+                            dikuaiData.put("mowingBladeWidth", String.format(Locale.US, "%.2f", bladeWidthMeters));
+                        } catch (NumberFormatException e) {
+                            dikuaiData.put("mowingBladeWidth", bladeWidthText);
+                        }
+                    }
+                }
+                
+                // 淇濆瓨鐩搁偦琛岄噸鍙犺窛绂�
+                if (overlapDistanceField != null) {
+                    String overlapText = overlapDistanceField.getText().trim();
+                    if (!overlapText.isEmpty()) {
+                        try {
+                            double overlapMeters = Double.parseDouble(overlapText);
+                            dikuaiData.put("mowingOverlapDistance", String.format(Locale.US, "%.2f", overlapMeters));
+                        } catch (NumberFormatException e) {
+                            dikuaiData.put("mowingOverlapDistance", overlapText);
+                        }
+                    }
+                }
+                
+                // 璁$畻骞朵繚瀛樺壊鑽夊搴︼紙鍓插垁瀹藉害 - 閲嶅彔璺濈锛�
+                if (mowingWidthField != null && overlapDistanceField != null) {
+                    try {
+                        String bladeWidthText = mowingWidthField.getText().trim();
+                        String overlapText = overlapDistanceField.getText().trim();
+                        if (!bladeWidthText.isEmpty() && !overlapText.isEmpty()) {
+                            double bladeWidthMeters = Double.parseDouble(bladeWidthText);
+                            double overlapMeters = Double.parseDouble(overlapText);
+                            double calculatedWidthMeters = bladeWidthMeters - overlapMeters;
+                            if (calculatedWidthMeters > 0) {
+                                // 杞崲涓哄帢绫冲瓨鍌紝淇濇寔涓庡師鏈夋暟鎹牸寮忓吋瀹�
+                                int widthCm = (int) Math.round(calculatedWidthMeters * 100.0);
+                                dikuaiData.put("mowingWidth", Integer.toString(widthCm));
+                            }
+                        }
+                    } catch (NumberFormatException e) {
+                        // 濡傛灉璁$畻澶辫触锛屼笉淇濆瓨鍓茶崏瀹藉害
+                    }
+                }
+                
                 if (!hasGeneratedPath()) {
                     JOptionPane.showMessageDialog(this, "璇峰厛鐢熸垚鍓茶崏璺緞", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
                     return false;
@@ -2005,21 +2265,51 @@
             }
         }
 
-        if (mowingWidthSpinner != null) {
-            String width = data.get("mowingWidth");
-            if (isMeaningfulValue(width)) {
+        // 鎭㈠鍓茶崏鏈哄壊鍒�瀹藉害锛堜紭鍏堜粠mowingBladeWidth鑾峰彇锛�
+        if (mowingWidthField != null) {
+            String bladeWidth = data.get("mowingBladeWidth");
+            if (isMeaningfulValue(bladeWidth)) {
                 try {
-                    double parsed = Double.parseDouble(width.trim());
-                    SpinnerNumberModel model = (SpinnerNumberModel) mowingWidthSpinner.getModel();
-                    int min = ((Number) model.getMinimum()).intValue();
-                    int max = ((Number) model.getMaximum()).intValue();
-                    int rounded = (int) Math.round(parsed);
-                    if (rounded < min) {
-                        rounded = min;
-                    } else if (rounded > max) {
-                        rounded = max;
+                    double bladeWidthMeters = Double.parseDouble(bladeWidth.trim());
+                    mowingWidthField.setText(String.format(Locale.US, "%.2f", bladeWidthMeters));
+                } catch (NumberFormatException ignored) {
+                    // 濡傛灉mowingBladeWidth涓嶅瓨鍦ㄦ垨瑙f瀽澶辫触锛屽皾璇曚粠mowingWidth鎭㈠
+                    String width = data.get("mowingWidth");
+                    if (isMeaningfulValue(width)) {
+                        try {
+                            // 濡傛灉瀛樺偍鐨勬槸鍘樼背锛岃浆鎹负绫虫樉绀�
+                            double parsed = Double.parseDouble(width.trim());
+                            // 鍋囪濡傛灉鍊煎ぇ浜�10锛屽垯鏄帢绫筹紝闇�瑕佽浆鎹负绫筹紱鍚﹀垯宸茬粡鏄背
+                            double widthMeters = parsed > 10 ? parsed / 100.0 : parsed;
+                            mowingWidthField.setText(String.format(Locale.US, "%.2f", widthMeters));
+                        } catch (NumberFormatException ignored2) {
+                            // 淇濇寔褰撳墠鍊�
+                        }
                     }
-                    mowingWidthSpinner.setValue(rounded);
+                }
+            } else {
+                // 濡傛灉mowingBladeWidth涓嶅瓨鍦紝灏濊瘯浠巑owingWidth鎭㈠
+                String width = data.get("mowingWidth");
+                if (isMeaningfulValue(width)) {
+                    try {
+                        // 濡傛灉瀛樺偍鐨勬槸鍘樼背锛岃浆鎹负绫虫樉绀�
+                        double parsed = Double.parseDouble(width.trim());
+                        // 鍋囪濡傛灉鍊煎ぇ浜�10锛屽垯鏄帢绫筹紝闇�瑕佽浆鎹负绫筹紱鍚﹀垯宸茬粡鏄背
+                        double widthMeters = parsed > 10 ? parsed / 100.0 : parsed;
+                        mowingWidthField.setText(String.format(Locale.US, "%.2f", widthMeters));
+                    } catch (NumberFormatException ignored) {
+                        // 淇濇寔褰撳墠鍊�
+                    }
+                }
+            }
+        }
+        
+        if (overlapDistanceField != null) {
+            String overlap = data.get("mowingOverlapDistance");
+            if (isMeaningfulValue(overlap)) {
+                try {
+                    double overlapMeters = Double.parseDouble(overlap.trim());
+                    overlapDistanceField.setText(String.format(Locale.US, "%.2f", overlapMeters));
                 } catch (NumberFormatException ignored) {
                     // 淇濇寔褰撳墠鍊�
                 }
@@ -2128,8 +2418,60 @@
         if (dikuaiData.containsKey("mowingPattern")) {
             dikuai.setMowingPattern(dikuaiData.get("mowingPattern"));
         }
+        
+        // 淇濆瓨鍓茶崏鏈哄壊鍒�瀹藉害锛堜紭鍏堜粠dikuaiData鑾峰彇锛屽惁鍒欎粠TextField鑾峰彇锛�
+        if (dikuaiData.containsKey("mowingBladeWidth")) {
+            dikuai.setMowingBladeWidth(dikuaiData.get("mowingBladeWidth"));
+        } else if (mowingWidthField != null) {
+            String bladeWidthText = mowingWidthField.getText().trim();
+            if (!bladeWidthText.isEmpty()) {
+                try {
+                    double bladeWidthMeters = Double.parseDouble(bladeWidthText);
+                    dikuai.setMowingBladeWidth(String.format(Locale.US, "%.2f", bladeWidthMeters));
+                } catch (NumberFormatException e) {
+                    dikuai.setMowingBladeWidth(bladeWidthText);
+                }
+            }
+        }
+        
+        // 淇濆瓨鐩搁偦琛岄噸鍙犺窛绂伙紙浼樺厛浠巇ikuaiData鑾峰彇锛屽惁鍒欎粠TextField鑾峰彇锛�
+        if (dikuaiData.containsKey("mowingOverlapDistance")) {
+            dikuai.setMowingOverlapDistance(dikuaiData.get("mowingOverlapDistance"));
+        } else if (overlapDistanceField != null) {
+            String overlapText = overlapDistanceField.getText().trim();
+            if (!overlapText.isEmpty()) {
+                try {
+                    double overlapMeters = Double.parseDouble(overlapText);
+                    dikuai.setMowingOverlapDistance(String.format(Locale.US, "%.2f", overlapMeters));
+                } catch (NumberFormatException e) {
+                    dikuai.setMowingOverlapDistance(overlapText);
+                }
+            }
+        }
+        
+        // 淇濆瓨鍓茶崏瀹藉害锛堣绠楀悗鐨勫�硷紝浼樺厛浠巇ikuaiData鑾峰彇锛�
         if (dikuaiData.containsKey("mowingWidth")) {
             dikuai.setMowingWidth(dikuaiData.get("mowingWidth"));
+        } else {
+            // 濡傛灉娌℃湁鍦╠ikuaiData涓紝鍒欎粠TextField璁$畻
+            if (mowingWidthField != null && overlapDistanceField != null) {
+                try {
+                    String bladeWidthText = mowingWidthField.getText().trim();
+                    String overlapText = overlapDistanceField.getText().trim();
+                    if (!bladeWidthText.isEmpty() && !overlapText.isEmpty()) {
+                        double bladeWidthMeters = Double.parseDouble(bladeWidthText);
+                        double overlapMeters = Double.parseDouble(overlapText);
+                        double calculatedWidthMeters = bladeWidthMeters - overlapMeters;
+                        if (calculatedWidthMeters > 0) {
+                            // 杞崲涓哄帢绫冲瓨鍌紝淇濇寔涓庡師鏈夋暟鎹牸寮忓吋瀹�
+                            int widthCm = (int) Math.round(calculatedWidthMeters * 100.0);
+                            dikuai.setMowingWidth(Integer.toString(widthCm));
+                        }
+                    }
+                } catch (NumberFormatException e) {
+                    // 濡傛灉璁$畻澶辫触锛屼繚鎸佸師鏈夊�兼垨浣跨敤榛樿鍊�
+                }
+            }
         }
 
         String plannedPath = dikuaiData.get("plannedPath");
diff --git a/src/zhuye/MapRenderer.java b/src/zhuye/MapRenderer.java
index 368e316..31b93b8 100644
--- a/src/zhuye/MapRenderer.java
+++ b/src/zhuye/MapRenderer.java
@@ -85,6 +85,7 @@
     private CircleCaptureOverlay circleCaptureOverlay;
     private final List<double[]> circleSampleMarkers = new ArrayList<>();
     private final List<Point2D.Double> realtimeMowingTrack = new ArrayList<>();
+    private final List<Point2D.Double> navigationPreviewTrack = new ArrayList<>(); // 瀵艰埅棰勮杞ㄨ抗
     private final Deque<tuowei.TrailSample> idleMowerTrail = new ArrayDeque<>();
     private final List<Point2D.Double> handheldBoundaryPreview = new ArrayList<>();
     private double boundaryPreviewMarkerScale = 1.0d;
@@ -417,9 +418,19 @@
         if (!realtimeMowingTrack.isEmpty()) {
             drawRealtimeMowingCoverage(g2d);
         }
+        
+        // 缁樺埗瀵艰埅棰勮宸插壊鍖哄煙
+        if (!navigationPreviewTrack.isEmpty()) {
+            drawNavigationPreviewCoverage(g2d);
+        }
 
         drawMower(g2d);
         
+        // 缁樺埗瀵艰埅棰勮閫熷害锛堝鏋滄鍦ㄥ鑸瑙堬級
+        if (navigationPreviewSpeed > 0 && mower != null && mower.hasValidPosition()) {
+            drawNavigationPreviewSpeed(g2d, scale);
+        }
+        
         // 缁樺埗娴嬮噺妯″紡锛堝鏋滄縺娲伙級
         if (measurementModeActive) {
             drawMeasurementMode(g2d, scale);
@@ -458,6 +469,60 @@
     private void drawMower(Graphics2D g2d) {
         mower.draw(g2d, scale);
     }
+    
+    /**
+     * 缁樺埗瀵艰埅棰勮閫熷害锛堝湪鍓茶崏鏈哄浘鏍囦笂鏂癸級
+     */
+    private void drawNavigationPreviewSpeed(Graphics2D g2d, double scale) {
+        if (mower == null || !mower.hasValidPosition()) {
+            return;
+        }
+        
+        Point2D.Double mowerPos = mower.getPosition();
+        if (mowerPos == null) {
+            return;
+        }
+        
+        // 灏嗛�熷害浠庣背/绉掕浆鎹负KM/h
+        double speedKmh = navigationPreviewSpeed * 3.6;
+        String speedText = String.format("%.1f km/h", speedKmh);
+        
+        // 淇濆瓨鍘熷鍙樻崲
+        AffineTransform originalTransform = g2d.getTransform();
+        
+        // 灏嗕笘鐣屽潗鏍囪浆鎹负灞忓箷鍧愭爣
+        Point2D.Double screenPos = worldToScreen(mowerPos);
+        
+        // 鎭㈠鍘熷鍙樻崲浠ョ粯鍒舵枃瀛楋紙鍥哄畾澶у皬锛屼笉闅忕缉鏀惧彉鍖栵級
+        g2d.setTransform(new AffineTransform());
+        
+        // 璁剧疆瀛椾綋锛堜笌缂╂斁鏂囧瓧澶у皬涓�鑷达紝11鍙峰瓧浣擄級
+        Font labelFont = new Font("寰蒋闆呴粦", Font.PLAIN, 11);
+        g2d.setFont(labelFont);
+        FontMetrics metrics = g2d.getFontMetrics(labelFont);
+        
+        // 璁$畻鏂囧瓧浣嶇疆锛堝湪鍓茶崏鏈哄浘鏍囦笂鏂癸級
+        int textWidth = metrics.stringWidth(speedText);
+        int textHeight = metrics.getHeight();
+        int textX = (int)Math.round(screenPos.x - textWidth / 2.0);
+        // 鍦ㄥ壊鑽夋満鍥炬爣涓婃柟锛岀暀鍑轰竴瀹氶棿璺�
+        // 鍥炬爣鍦ㄤ笘鐣屽潗鏍囩郴涓殑澶у皬绾︿负 48 * 0.8 / scale 绫�
+        // 杞崲涓哄睆骞曞儚绱狅細鍥炬爣楂樺害锛堝儚绱狅級= (48 * 0.8 / scale) * scale = 48 * 0.8 = 38.4 鍍忕礌
+        double iconSizePixels = 48.0 * 0.8; // 鍥炬爣鍦ㄥ睆骞曚笂鐨勫ぇ灏忥紙鍍忕礌锛�
+        int spacing = 8; // 闂磋窛锛堝儚绱狅級
+        int textY = (int)Math.round(screenPos.y - iconSizePixels / 2.0 - spacing - textHeight);
+        
+        // 缁樺埗鏂囧瓧鑳屾櫙锛堝崐閫忔槑鐧借壊锛屽寮哄彲璇绘�э級
+        g2d.setColor(new Color(255, 255, 255, 200));
+        g2d.fillRoundRect(textX - 4, textY - metrics.getAscent() - 2, textWidth + 8, textHeight + 4, 4, 4);
+        
+        // 缁樺埗鏂囧瓧
+        g2d.setColor(new Color(46, 139, 87)); // 浣跨敤涓婚缁胯壊
+        g2d.drawString(speedText, textX, textY);
+        
+        // 鎭㈠鍙樻崲
+        g2d.setTransform(originalTransform);
+    }
 
     private void drawRealtimeMowingCoverage(Graphics2D g2d) {
         if (realtimeMowingTrack == null || realtimeMowingTrack.size() < 2) {
@@ -468,6 +533,91 @@
         double effectiveWidth = getEffectiveMowerWidthMeters();
         gecaolunjing.draw(g2d, realtimeMowingTrack, effectiveWidth, boundaryPath);
     }
+    
+    /**
+     * 缁樺埗瀵艰埅棰勮宸插壊鍖哄煙
+     */
+    private void drawNavigationPreviewCoverage(Graphics2D g2d) {
+        if (navigationPreviewTrack == null || navigationPreviewTrack.size() < 2) {
+            return;
+        }
+        
+        Path2D.Double boundaryPath = currentBoundaryPath;
+        // 鑾峰彇瀵艰埅棰勮鐨勫壊鑽夊搴︼紙浠巇aohangyulan鑾峰彇锛�
+        double previewWidth = getNavigationPreviewWidth();
+        if (previewWidth <= 0) {
+            previewWidth = 0.5; // 榛樿50鍘樼背
+        }
+        gecaolunjing.draw(g2d, navigationPreviewTrack, previewWidth, boundaryPath);
+    }
+    
+    /**
+     * 璁剧疆瀵艰埅棰勮杞ㄨ抗
+     */
+    public void setNavigationPreviewTrack(List<Point2D.Double> track) {
+        if (track == null) {
+            navigationPreviewTrack.clear();
+        } else {
+            navigationPreviewTrack.clear();
+            navigationPreviewTrack.addAll(track);
+        }
+        if (visualizationPanel != null) {
+            visualizationPanel.repaint();
+        }
+    }
+    
+    /**
+     * 娣诲姞瀵艰埅棰勮杞ㄨ抗鐐�
+     */
+    public void addNavigationPreviewTrackPoint(Point2D.Double point) {
+        if (point != null && Double.isFinite(point.x) && Double.isFinite(point.y)) {
+            navigationPreviewTrack.add(new Point2D.Double(point.x, point.y));
+            if (visualizationPanel != null) {
+                visualizationPanel.repaint();
+            }
+        }
+    }
+    
+    /**
+     * 娓呴櫎瀵艰埅棰勮杞ㄨ抗
+     */
+    public void clearNavigationPreviewTrack() {
+        navigationPreviewTrack.clear();
+        if (visualizationPanel != null) {
+            visualizationPanel.repaint();
+        }
+    }
+    
+    private double navigationPreviewWidth = 0.5; // 瀵艰埅棰勮鐨勫壊鑽夊搴︼紙绫筹級
+    private double navigationPreviewSpeed = 0.0; // 瀵艰埅棰勮鐨勫壊鑽夋満閫熷害锛堢背/绉掞級
+    
+    /**
+     * 璁剧疆瀵艰埅棰勮鐨勫壊鑽夊搴�
+     */
+    public void setNavigationPreviewWidth(double widthMeters) {
+        navigationPreviewWidth = widthMeters > 0 ? widthMeters : 0.5;
+    }
+    
+    /**
+     * 鑾峰彇瀵艰埅棰勮鐨勫壊鑽夊搴�
+     */
+    private double getNavigationPreviewWidth() {
+        return navigationPreviewWidth;
+    }
+    
+    /**
+     * 璁剧疆瀵艰埅棰勮鐨勫壊鑽夋満閫熷害锛堢背/绉掞級
+     */
+    public void setNavigationPreviewSpeed(double speedMetersPerSecond) {
+        navigationPreviewSpeed = speedMetersPerSecond >= 0 ? speedMetersPerSecond : 0.0;
+    }
+    
+    /**
+     * 鑾峰彇瀵艰埅棰勮鐨勫壊鑽夋満閫熷害锛堢背/绉掞級
+     */
+    private double getNavigationPreviewSpeed() {
+        return navigationPreviewSpeed;
+    }
 
     private Path2D.Double getRealtimeBoundaryPath() {
         if (realtimeTrackLandNumber == null) {
@@ -1870,10 +2020,11 @@
             return;
         }
         
-        // 璁剧疆鐐圭殑澶у皬锛堜笌杈圭晫绾垮搴︿竴鑷达級
+        // 璁剧疆鐐圭殑澶у皬锛堣竟鐣岀嚎瀹藉害鐨�2鍊嶏級
         // 杈圭晫绾垮搴︼細3 / Math.max(0.5, scale)
         double scaleFactor = Math.max(0.5, scale);
-        double markerDiameter = 3.0 / scaleFactor;  // 涓庤竟鐣岀嚎瀹藉害涓�鑷�
+        double boundaryLineWidth = 3.0 / scaleFactor;  // 杈圭晫绾垮搴�
+        double markerDiameter = boundaryLineWidth * 2.0;  // 杈圭晫鐐圭洿寰� = 杈圭晫绾垮搴︾殑2鍊�
         double markerRadius = markerDiameter / 2.0;
         
         // 璁剧疆瀛椾綋锛堜笌闅滅鐗╁簭鍙蜂竴鑷达紝涓嶉殢缂╂斁鍙樺寲锛�
diff --git a/src/zhuye/Shouye.java b/src/zhuye/Shouye.java
index 30c1444..b588d83 100644
--- a/src/zhuye/Shouye.java
+++ b/src/zhuye/Shouye.java
@@ -80,6 +80,8 @@
 	private JLabel statusLabel;
 	private JLabel speedLabel;  // 閫熷害鏄剧ず鏍囩
 	private JLabel areaNameLabel;
+	private JLabel drawingBoundaryLabel;  // 姝e湪缁樺埗杈圭晫鐘舵�佹爣绛�
+	private JLabel navigationPreviewLabel;  // 瀵艰埅棰勮妯″紡鏍囩
 	
 	// 杈圭晫璀﹀憡鐩稿叧
 	private Timer boundaryWarningTimer;  // 杈圭晫璀﹀憡妫�鏌ュ畾鏃跺櫒
@@ -511,14 +513,28 @@
 
 		// 娣诲姞閫熷害鏄剧ず鏍囩
 		speedLabel = new JLabel("");
-		speedLabel.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 12));
-		speedLabel.setForeground(Color.GRAY);
-		speedLabel.setVisible(false);  // 榛樿闅愯棌
+	speedLabel.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 12));
+	speedLabel.setForeground(Color.GRAY);
+	speedLabel.setVisible(false);  // 榛樿闅愯棌
+
+	// 姝e湪缁樺埗杈圭晫鐘舵�佹爣绛�
+	drawingBoundaryLabel = new JLabel("姝e湪缁樺埗杈圭晫");
+	drawingBoundaryLabel.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 14));
+	drawingBoundaryLabel.setForeground(new Color(46, 139, 87));
+	drawingBoundaryLabel.setVisible(false);  // 榛樿闅愯棌
+
+	// 瀵艰埅棰勮妯″紡鏍囩
+	navigationPreviewLabel = new JLabel("褰撳墠瀵艰埅棰勮妯″紡");
+	navigationPreviewLabel.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 14));
+	navigationPreviewLabel.setForeground(new Color(46, 139, 87));
+	navigationPreviewLabel.setVisible(false);  // 榛樿闅愯棌
 
 	// 灏嗙姸鎬佷笌閫熷害鏀惧湪鍚屼竴琛岋紝鏄剧ず鍦ㄥ湴鍧楀悕绉颁笅闈竴琛�
 	JPanel statusRow = new JPanel(new FlowLayout(FlowLayout.LEFT, 8, 0));
 	statusRow.setOpaque(false);
 	statusRow.add(statusLabel);
+	statusRow.add(drawingBoundaryLabel);
+	statusRow.add(navigationPreviewLabel);
 	statusRow.add(speedLabel);
 
 	// 宸﹀榻愭爣绛句笌鐘舵�佽锛岀‘淇濆畠浠湪 BoxLayout 涓潬宸︽樉绀�
@@ -1154,7 +1170,7 @@
 			if (parentWindow != null) {
 				// 浣跨敤 yaokong 鍖呬腑鐨� RemoteControlDialog 瀹炵幇
 				remoteDialog = new yaokong.RemoteControlDialog(this, THEME_COLOR, speedLabel);
-			} else {
+			} else {/*  */
 				remoteDialog = new yaokong.RemoteControlDialog((JFrame) null, THEME_COLOR, speedLabel);
 			}
 		}
@@ -2793,6 +2809,11 @@
 		circleDialogMode = false;
 		hideCircleGuidancePanel();
 		enterDrawingControlMode();
+		
+		// 鏄剧ず"姝e湪缁樺埗杈圭晫"鎻愮ず
+		if (drawingBoundaryLabel != null) {
+			drawingBoundaryLabel.setVisible(true);
+		}
 
 		boolean enableCircleGuidance = drawingShape != null
 				&& "circle".equalsIgnoreCase(drawingShape.trim());
@@ -3497,6 +3518,12 @@
 			activeBoundaryMode = BoundaryCaptureMode.NONE;
 		}
 		endDrawingCallback = null;
+		
+		// 闅愯棌"姝e湪缁樺埗杈圭晫"鎻愮ず
+		if (drawingBoundaryLabel != null) {
+			drawingBoundaryLabel.setVisible(false);
+		}
+		
 		visualizationPanel.revalidate();
 		visualizationPanel.repaint();
 		setHandheldMowerIconActive(false);
@@ -3642,6 +3669,55 @@
 		return mapRenderer;
 	}
 
+	/**
+	 * 鑾峰彇鎺у埗闈㈡澘锛堢敤浜庡鑸瑙堟椂鏇挎崲鎸夐挳锛�
+	 * @return 鎺у埗闈㈡澘
+	 */
+	public JPanel getControlPanel() {
+		return controlPanel;
+	}
+
+	/**
+	 * 鑾峰彇寮�濮嬫寜閽紙鐢ㄤ簬瀵艰埅棰勮鏃堕殣钘忥級
+	 * @return 寮�濮嬫寜閽�
+	 */
+	public JButton getStartButton() {
+		return startBtn;
+	}
+
+	/**
+	 * 鑾峰彇缁撴潫鎸夐挳锛堢敤浜庡鑸瑙堟椂闅愯棌锛�
+	 * @return 缁撴潫鎸夐挳
+	 */
+	public JButton getStopButton() {
+		return stopBtn;
+	}
+
+	/**
+	 * 璁剧疆瀵艰埅棰勮妯″紡鏍囩鐨勬樉绀虹姸鎬�
+	 * @param visible 鏄惁鏄剧ず
+	 */
+	public void setNavigationPreviewLabelVisible(boolean visible) {
+		if (navigationPreviewLabel != null) {
+			navigationPreviewLabel.setVisible(visible);
+		}
+	}
+
+	/**
+	 * 鑾峰彇鍙鍖栭潰鏉垮疄渚�
+	 */
+	public JPanel getVisualizationPanel() {
+		return visualizationPanel;
+	}
+	
+	/**
+	 * 鑾峰彇涓诲唴瀹归潰鏉垮疄渚嬶紙鐢ㄤ簬娣诲姞娴姩鎸夐挳锛�
+	 */
+	public JPanel getMainContentPanel() {
+		return mainContentPanel;
+	}
+
+
 	public void updateCurrentAreaName(String areaName) {
 		if (areaNameLabel == null) {
 			return;
diff --git a/src/zhuye/adddikuaiyulan.java b/src/zhuye/adddikuaiyulan.java
index 3307106..4b382d2 100644
--- a/src/zhuye/adddikuaiyulan.java
+++ b/src/zhuye/adddikuaiyulan.java
@@ -38,37 +38,81 @@
             return;
         }
 
-        Path2D.Double path = new Path2D.Double();
-        boolean started = false;
+        // 杩囨护鏈夋晥鐐�
+        List<Point2D.Double> validPoints = new java.util.ArrayList<>();
         for (Point2D.Double point : previewPoints) {
-            if (point == null || !Double.isFinite(point.x) || !Double.isFinite(point.y)) {
-                continue;
-            }
-            if (!started) {
-                path.moveTo(point.x, point.y);
-                started = true;
-            } else {
-                path.lineTo(point.x, point.y);
+            if (point != null && Double.isFinite(point.x) && Double.isFinite(point.y)) {
+                validPoints.add(point);
             }
         }
 
-        if (!started) {
+        if (validPoints.isEmpty()) {
             return;
         }
 
         Stroke originalStroke = g2d.getStroke();
         Color originalColor = g2d.getColor();
 
-        if (previewPoints.size() >= 3) {
-            path.closePath();
+        // 鍒涘缓濉厖璺緞锛堝鏋滅偣鏁�>=3锛岄渶瑕侀棴鍚堜互濉厖锛�
+        Path2D.Double fillPath = new Path2D.Double();
+        if (validPoints.size() >= 3) {
+            fillPath.moveTo(validPoints.get(0).x, validPoints.get(0).y);
+            for (int i = 1; i < validPoints.size(); i++) {
+                fillPath.lineTo(validPoints.get(i).x, validPoints.get(i).y);
+            }
+            fillPath.closePath();
             g2d.setColor(HANDHELD_BOUNDARY_FILL);
-            g2d.fill(path);
+            g2d.fill(fillPath);
         }
 
         float outlineWidth = 0.1f;
-        g2d.setStroke(new BasicStroke(outlineWidth, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
-        g2d.setColor(HANDHELD_BOUNDARY_BORDER);
-        g2d.draw(path);
+        
+        if (validPoints.size() >= 3) {
+            // 鐐规暟>=3鏃讹紝闇�瑕佸垎鍒粯鍒跺疄绾垮拰铏氱嚎
+            // 缁樺埗瀹炵嚎閮ㄥ垎锛氫粠璧风偣渚濇杩炴帴鍒板悇涓偣锛堜笉闂悎锛屼笉鍖呮嫭璧风偣鍒扮粓鐐圭殑鐩存帴杩炵嚎锛�
+            Path2D.Double solidPath = new Path2D.Double();
+            solidPath.moveTo(validPoints.get(0).x, validPoints.get(0).y);
+            // 浠庣浜屼釜鐐瑰紑濮嬶紝渚濇杩炴帴鍒版渶鍚庝竴涓偣锛堝舰鎴愪笉闂悎鐨勮矾寰勶級
+            for (int i = 1; i < validPoints.size(); i++) {
+                solidPath.lineTo(validPoints.get(i).x, validPoints.get(i).y);
+            }
+            g2d.setStroke(new BasicStroke(outlineWidth, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
+            g2d.setColor(HANDHELD_BOUNDARY_BORDER);
+            g2d.draw(solidPath);
+            
+            // 鐢ㄨ櫄绾跨粯鍒惰捣鐐瑰埌缁堢偣鐨勮繛绾匡紙闂悎绾挎锛�
+            Point2D.Double startPoint = validPoints.get(0);
+            Point2D.Double endPoint = validPoints.get(validPoints.size() - 1);
+            
+            // 鍒涘缓铏氱嚎鏍峰紡锛堟牴鎹缉鏀捐皟鏁磋櫄绾挎ā寮忥級
+            double effectiveScale = Math.max(0.01d, scale);
+            float dashLength = (float) (0.05 / effectiveScale); // 铏氱嚎闀垮害闅忕缉鏀捐皟鏁�
+            float[] dashPattern = new float[]{dashLength, dashLength}; // 铏氱嚎妯″紡锛氬疄绾裤�佺┖鐧�
+            BasicStroke dashedStroke = new BasicStroke(
+                outlineWidth,
+                BasicStroke.CAP_ROUND,
+                BasicStroke.JOIN_ROUND,
+                1.0f,
+                dashPattern,
+                0.0f
+            );
+            
+            g2d.setStroke(dashedStroke);
+            g2d.setColor(HANDHELD_BOUNDARY_BORDER);
+            // 浣跨敤Path2D缁樺埗璧风偣鍒扮粓鐐圭殑铏氱嚎锛屼互渚挎敮鎸佹诞鐐瑰潗鏍�
+            Path2D.Double dashedLine = new Path2D.Double();
+            dashedLine.moveTo(startPoint.x, startPoint.y);
+            dashedLine.lineTo(endPoint.x, endPoint.y);
+            g2d.draw(dashedLine);
+        } else if (validPoints.size() == 2) {
+            // 濡傛灉鍙湁2涓偣锛岀洿鎺ョ粯鍒跺疄绾�
+            Path2D.Double simplePath = new Path2D.Double();
+            simplePath.moveTo(validPoints.get(0).x, validPoints.get(0).y);
+            simplePath.lineTo(validPoints.get(1).x, validPoints.get(1).y);
+            g2d.setStroke(new BasicStroke(outlineWidth, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
+            g2d.setColor(HANDHELD_BOUNDARY_BORDER);
+            g2d.draw(simplePath);
+        }
 
         if (cachedMarkerPixelDiameter <= 0.0d) {
             double previousPixelDiameter = Math.abs(BASE_WORLD_MARKER_SIZE * scale);
diff --git a/src/zhuye/bianjiedrwa.java b/src/zhuye/bianjiedrwa.java
index 1e3bb46..b40ee71 100644
--- a/src/zhuye/bianjiedrwa.java
+++ b/src/zhuye/bianjiedrwa.java
@@ -23,24 +23,42 @@
             return; // 鏃犳暟鎹繑鍥�
         } // if缁撴潫
 
-        Path2D path = new Path2D.Double(); // 鍒涘缓璺緞
+        float strokeWidth = (float) (3 / Math.max(0.5, scale)); // 璁$畻杈圭嚎瀹藉害
+        
+        // 濉厖鍖哄煙
+        Path2D fillPath = new Path2D.Double(); // 鍒涘缓濉厖璺緞
         boolean first = true; // 棣栫偣鏍囪
         for (Point2D.Double point : boundary) { // 閬嶅巻鐐�
             if (first) { // 棣栦釜鐐�
-                path.moveTo(point.x, point.y); // 绉诲姩鍒板紑濮嬬偣
+                fillPath.moveTo(point.x, point.y); // 绉诲姩鍒板紑濮嬬偣
                 first = false; // 鏇存柊鏍囪
             } else { // 鍏朵粬鐐�
-                path.lineTo(point.x, point.y); // 杩炵嚎鍒颁笅涓偣
+                fillPath.lineTo(point.x, point.y); // 杩炵嚎鍒颁笅涓偣
             } // if缁撴潫
         } // for缁撴潫
-        path.closePath(); // 闂悎璺緞
-
-        float strokeWidth = (float) (3 / Math.max(0.5, scale)); // 璁$畻杈圭嚎瀹藉害
-        g2d.setStroke(new BasicStroke(strokeWidth)); // 璁剧疆鎻忚竟
+        fillPath.closePath(); // 闂悎璺緞
+        
         g2d.setColor(fillColor); // 璁剧疆濉厖鑹�
-        g2d.fill(path); // 濉厖鍖哄煙
+        g2d.fill(fillPath); // 濉厖鍖哄煙
 
-        g2d.setColor(borderColor); // 璁剧疆杈圭嚎棰滆壊
-        g2d.draw(path); // 缁樺埗杈圭晫
+        // 缁樺埗杈圭晫绾匡紙鍖呮嫭璧风偣鍒扮粓鐐圭殑杩炴帴锛�- 瀹炵嚎
+        if (boundary.size() >= 2) {
+            Path2D.Double borderPath = new Path2D.Double(); // 鍒涘缓杈圭晫璺緞
+            Point2D.Double firstPoint = boundary.get(0);
+            borderPath.moveTo(firstPoint.x, firstPoint.y); // 绉诲姩鍒拌捣鐐�
+            for (int i = 1; i < boundary.size(); i++) { // 浠庣浜屼釜鐐瑰埌鏈�鍚庝竴涓偣
+                Point2D.Double point = boundary.get(i);
+                borderPath.lineTo(point.x, point.y); // 杩炵嚎
+            }
+            // 濡傛灉鏈�鍚庝竴涓偣涓嶆槸绗竴涓偣锛屽垯杩炴帴鍒拌捣鐐瑰舰鎴愰棴鍚�
+            Point2D.Double lastPoint = boundary.get(boundary.size() - 1);
+            if (!lastPoint.equals(firstPoint)) {
+                borderPath.lineTo(firstPoint.x, firstPoint.y); // 杩炴帴鍒拌捣鐐瑰舰鎴愰棴鍚�
+            }
+            
+            g2d.setStroke(new BasicStroke(strokeWidth, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); // 璁剧疆瀹炵嚎鎻忚竟
+            g2d.setColor(borderColor); // 璁剧疆杈圭嚎棰滆壊
+            g2d.draw(borderPath); // 缁樺埗瀹屾暣杈圭晫锛堝寘鎷捣鐐瑰埌缁堢偣鐨勮繛鎺ワ級
+        }
     } // 鏂规硶缁撴潫
 } // 绫荤粨鏉�
diff --git a/src/zhuye/celiangmoshi.java b/src/zhuye/celiangmoshi.java
index 0bf8154..992c3a7 100644
--- a/src/zhuye/celiangmoshi.java
+++ b/src/zhuye/celiangmoshi.java
@@ -81,3 +81,8 @@
         measurementPoints.clear();
     }
 }
+
+
+
+
+
diff --git a/src/zhuye/pointandnumber.java b/src/zhuye/pointandnumber.java
index c716159..582aca5 100644
--- a/src/zhuye/pointandnumber.java
+++ b/src/zhuye/pointandnumber.java
@@ -34,8 +34,14 @@
         }
 
     double scaleFactor = Math.max(0.5, scale); // 闃叉杩囧皬缂╂斁
-    // 杈圭晫鐐圭洿寰勪笌杈圭晫绾垮搴︿竴鑷达細3 / Math.max(0.5, scale)
-    double markerDiameter = 3.0 / scaleFactor; // 鎻忕偣鐩村緞锛堜笌杈圭晫绾垮搴︿竴鑷达級
+    // 杈圭晫绾垮搴︼細3 / Math.max(0.5, scale)
+    // 杈圭晫鐐圭洿寰� = 杈圭晫绾垮搴︾殑2鍊�
+    double boundaryLineWidth = 3.0 / scaleFactor; // 杈圭晫绾垮搴�
+    double markerDiameter = boundaryLineWidth * 2.0; // 鎻忕偣鐩村緞锛堣竟鐣岀嚎瀹藉害鐨�2鍊嶏級
+    // 搴旂敤鐩村緞缂╂斁鍥犲瓙
+    if (diameterScale > 0.0 && Double.isFinite(diameterScale)) {
+        markerDiameter *= diameterScale;
+    }
         double markerRadius = markerDiameter / 2.0; // 鍗婂緞
 
         for (int i = 0; i < effectiveCount; i++) { // 閬嶅巻鏈夋晥鐐�

--
Gitblit v1.10.0