From cbfd1df513c473dd5550d78740c92fc1677b6e9b Mon Sep 17 00:00:00 2001
From: 826220679@qq.com <826220679@qq.com>
Date: 星期六, 27 十二月 2025 13:40:42 +0800
Subject: [PATCH] 异形有障碍物路径规划没完成
---
shoudongbianjie.properties | 16
dikuai.properties | 42
src/lujing/MowingPathGenerationPage.java | 6
src/chuankou/dellmessage.java | 25
.classpath | 20
src/lujing/YixinglujingNoObstacle.java | 15
src/lujing/YixinglujingHaveObstacel.java | 1546 +++++++++++++++++--------------------------------
set.properties | 32
src/zhuye/Shouye.java | 51 +
src/chuankou/SerialPortService.java | 18
Obstacledge.properties | 6
src/denglu/Denglu.java | 42
12 files changed, 686 insertions(+), 1,133 deletions(-)
diff --git a/.classpath b/.classpath
index 835d2ed..b156962 100644
--- a/.classpath
+++ b/.classpath
@@ -6,15 +6,15 @@
<attribute name="module" value="true"/>
</attributes>
</classpathentry>
- <classpathentry kind="lib" path="E:/Users/hxzk/eclipse-workspace/GeCaoAPP/lib/jackson-annotations-2.15.2.jar"/>
- <classpathentry kind="lib" path="E:/Users/hxzk/eclipse-workspace/GeCaoAPP/lib/jackson-core-2.15.2.jar"/>
- <classpathentry kind="lib" path="E:/Users/hxzk/eclipse-workspace/GeCaoAPP/lib/jackson-databind-2.15.2.jar"/>
- <classpathentry kind="lib" path="E:/Users/hxzk/eclipse-workspace/GeCaoAPP/lib/jSerialComm-2.10.4.jar"/>
- <classpathentry kind="lib" path="E:/Users/hxzk/eclipse-workspace/GeCaoAPP/lib/jts-core-1.19.0.jar"/>
- <classpathentry kind="lib" path="E:/Users/hxzk/eclipse-workspace/GeCaoAPP/lib/lombok-1.18.36.jar"/>
- <classpathentry kind="lib" path="E:/Users/hxzk/eclipse-workspace/GeCaoAPP/lib/MQTT-1.0-SNAPSHOT.jar"/>
- <classpathentry kind="lib" path="E:/Users/hxzk/eclipse-workspace/GeCaoAPP/lib/org.eclipse.paho.client.mqttv3-1.2.2.jar"/>
- <classpathentry kind="lib" path="E:/Users/hxzk/eclipse-workspace/GeCaoAPP/lib/slf4j-api-1.7.30.jar"/>
- <classpathentry kind="lib" path="E:/Users/hxzk/eclipse-workspace/GeCaoAPP/lib/slf4j-simple-1.7.30.jar"/>
+ <classpathentry kind="lib" path="D:/eclipseworkspace/GIT/GeCaoAPP/lib/jackson-annotations-2.15.2.jar"/>
+ <classpathentry kind="lib" path="D:/eclipseworkspace/GIT/GeCaoAPP/lib/jackson-core-2.15.2.jar"/>
+ <classpathentry kind="lib" path="D:/eclipseworkspace/GIT/GeCaoAPP/lib/jackson-databind-2.15.2.jar"/>
+ <classpathentry kind="lib" path="D:/eclipseworkspace/GIT/GeCaoAPP/lib/jSerialComm-2.10.4.jar"/>
+ <classpathentry kind="lib" path="D:/eclipseworkspace/GIT/GeCaoAPP/lib/jts-core-1.19.0.jar"/>
+ <classpathentry kind="lib" path="D:/eclipseworkspace/GIT/GeCaoAPP/lib/lombok-1.18.36.jar"/>
+ <classpathentry kind="lib" path="D:/eclipseworkspace/GIT/GeCaoAPP/lib/MQTT-1.0-SNAPSHOT.jar"/>
+ <classpathentry kind="lib" path="D:/eclipseworkspace/GIT/GeCaoAPP/lib/org.eclipse.paho.client.mqttv3-1.2.2.jar"/>
+ <classpathentry kind="lib" path="D:/eclipseworkspace/GIT/GeCaoAPP/lib/slf4j-api-1.7.30.jar"/>
+ <classpathentry kind="lib" path="D:/eclipseworkspace/GIT/GeCaoAPP/lib/slf4j-simple-1.7.30.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>
diff --git a/Obstacledge.properties b/Obstacledge.properties
index e9b1439..52a4a75 100644
--- a/Obstacledge.properties
+++ b/Obstacledge.properties
@@ -1,5 +1,5 @@
# 鍓茶崏鏈哄湴鍧楅殰纰嶇墿閰嶇疆鏂囦欢
-# 鐢熸垚鏃堕棿锛�2025-12-26T19:43:09.374455600
+# 鐢熸垚鏃堕棿锛�2025-12-27T13:39:05.917584700
# 鍧愭爣绯伙細WGS84锛堝害鍒嗘牸寮忥級
# ============ 鍦板潡鍩哄噯绔欓厤缃� ============
@@ -14,6 +14,6 @@
# --- 鍦板潡LAND1鐨勯殰纰嶇墿 ---
plot.LAND1.obstacle.闅滅鐗�1.shape=1
-plot.LAND1.obstacle.闅滅鐗�1.originalCoords=0.000000,N;0.000000,E;0.000000,N;0.000000,E;0.000000,N;0.000000,E;0.000000,N;0.000000,E;0.000000,N;0.000000,E
-plot.LAND1.obstacle.闅滅鐗�1.xyCoords=25.17,9.94;17.74,67.19;113.88,72.00;120.00,19.12;74.99,-4.48
+plot.LAND1.obstacle.闅滅鐗�1.originalCoords=0.000000,N;0.000000,E;0.000000,N;0.000000,E;0.000000,N;0.000000,E;0.000000,N;0.000000,E
+plot.LAND1.obstacle.闅滅鐗�1.xyCoords=53.95,39.88;55.58,45.69;64.53,45.45;66.97,40.57
diff --git a/dikuai.properties b/dikuai.properties
index 6a1aad0..885dbb0 100644
--- a/dikuai.properties
+++ b/dikuai.properties
@@ -1,26 +1,26 @@
#Dikuai Properties
-#Fri Dec 26 19:43:09 CST 2025
-LAND1.angleThreshold=-1
-LAND1.baseStationCoordinates=3949.89151752,N,11616.79267501,E
-LAND1.boundaryCoordinates=4.30,87.65;-2.36,-65.51;44.25,-66.72;49.70,-14.05;98.13,-15.87;99.34,-69.75;137.48,-67.93;134.45,90.07;4.30,87.65
-LAND1.boundaryOriginalCoordinates=39.831522,116.279873,49.25;39.831524,116.279878,49.25;39.831525,116.279878,49.24;39.831524,116.279912,49.30;39.831524,116.279911,49.29;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
+#Sat Dec 27 13:39:05 GMT+08:00 2025
+LAND1.intelligentSceneAnalysis=-1
+LAND1.mowingSafetyDistance=0.53
+LAND1.landArea=577.12
+LAND1.returnPointCoordinates=-1
+LAND1.landNumber=LAND1
+LAND1.returnPathCoordinates=-1
+LAND1.mowingPattern=骞宠绾�
+LAND1.mowingOverlapDistance=0.06
+LAND1.returnPathRawCoordinates=-1
LAND1.boundaryOriginalXY=-1
+LAND1.mowingWidth=1.00
+LAND1.plannedPath=73.871028,49.873176;50.776259,50.037243;41.965934,22.443191;49.612130,19.993609;51.845415,34.259086;66.290000,36.696945;66.290000,21.401369;78.088741,24.750277;73.871028,49.873176;73.955072,49.372566;50.616974,49.538362;50.298405,48.540599;74.123160,48.371347;74.291248,47.370128;49.979836,47.542837;49.661267,46.545075;74.459336,46.368908;74.627423,45.367689;49.342698,45.547313;49.024129,44.549551;55.663908,44.502382;64.552007,44.439240;74.795511,44.366470;74.963599,43.365250;65.098159,43.435335;55.361561,43.504504;48.705560,43.551789;48.386992,42.554027;55.059215,42.506627;65.644310,42.431430;75.131687,42.364031;75.299775,41.362812;66.190462,41.427525;54.756869,41.508750;48.068423,41.556265;47.749854,40.558503;54.454523,40.510872;59.489469,40.475104;75.467863,40.361592;75.635951,39.360373;47.431285,39.560741;47.112716,38.562978;75.804039,38.359154;75.972127,37.357934;46.794147,37.565216;46.475578,36.567454;64.753396,36.437608;66.290000,36.426692;76.140215,36.356715;76.308303,35.355496;66.290000,35.426666;59.067471,35.477976;46.157009,35.569692;45.838440,34.571930;53.381545,34.518343;66.290000,34.426641;76.476391,34.354276;76.644478,33.353057;66.290000,33.426616;51.731282,33.530042;45.519871,33.574168;45.201302,32.576406;51.574900,32.531127;66.290000,32.426591;76.812566,32.351838;76.980654,31.350618;66.290000,31.426565;51.418519,31.532213;44.882733,31.578644;44.564164,30.580882;51.262137,30.533299;66.290000,30.426540;77.148742,30.349399;77.316830,29.348180;66.290000,29.426515;51.105755,29.534385;44.245595,29.583120;43.927026,28.585357;50.949373,28.535470;66.290000,28.426490;77.484918,28.346960;77.653006,27.345741;66.290000,27.426464;50.792992,27.536556;43.608458,27.587595;43.289889,26.589833;50.636610,26.537642;66.290000,26.426439;77.821094,26.344522;77.989182,25.343302;66.290000,25.426414;50.480228,25.538727;42.971320,25.592071;42.652751,24.594309;50.323846,24.539813;66.290000,24.426389;76.687398,24.352525;73.250178,23.376918;66.290000,23.426363;50.167465,23.540899;42.334182,23.596547;42.015613,22.598785;50.011083,22.541985;66.290000,22.426338;69.812957,22.401311;66.375737,21.425704;66.290000,21.426313;49.854701,21.543070;44.660415,21.579971;47.852711,20.557267;49.698319,20.544156
+LAND1.updateTime=2025-12-27 13\:39\:05
+LAND1.baseStationCoordinates=3949.89151752,N,11616.79267501,E
LAND1.boundaryPointInterval=-1
LAND1.createTime=2025-12-23 17\:08\:09
-LAND1.intelligentSceneAnalysis=-1
-LAND1.landArea=577.12
-LAND1.landName=123
-LAND1.landNumber=LAND1
-LAND1.mowingBladeWidth=0.51
-LAND1.mowingOverlapDistance=0.06
-LAND1.mowingPattern=骞宠绾�
-LAND1.mowingSafetyDistance=0.53
-LAND1.mowingTrack=-1
-LAND1.mowingWidth=0.50
-LAND1.obstacleCoordinates=(25.17,9.94;17.74,67.19;113.88,72.00;120.00,19.12;74.99,-4.48)
-LAND1.plannedPath=133.930254,89.530244;4.309853,87.120092;4.829500,87.626975;4.690221,87.491117;4.690221,87.127164;5.190221,87.136461;5.190221,-65.175826;4.690221,-65.162846;4.690221,84.423985;5.690221,87.145758;5.690221,-65.188806;6.190221,-65.201786;6.190221,87.155055;6.690221,87.164352;6.690221,-65.214766;7.190221,-65.227746;7.190221,87.173649;7.690221,87.182946;7.690221,-65.240726;8.190221,-65.253706;8.190221,87.192243;8.690221,87.201540;8.690221,-65.266686;9.190221,-65.279666;9.190221,87.210837;9.690221,87.220134;9.690221,-65.292646;10.190221,-65.305626;10.190221,87.229431;10.690221,87.238728;10.690221,-65.318606;11.190221,-65.331586;11.190221,87.248025;11.690221,87.257322;11.690221,-65.344567;12.190221,-65.357547;12.190221,87.266619;12.690221,87.275916;12.690221,-65.370527;13.190221,-65.383507;13.190221,87.285213;13.690221,87.294510;13.690221,-65.396487;14.190221,-65.409467;14.190221,87.303806;14.690221,87.313103;14.690221,-65.422447;15.190221,-65.435427;15.190221,87.322400;15.690221,87.331697;15.690221,-65.448407;16.190221,-65.461387;16.190221,87.340994;16.690221,87.350291;16.690221,-65.474367;17.190221,-65.487347;17.190221,67.308153;17.190221,67.693157;17.190221,87.359588;17.690221,87.368885;17.690221,67.718172;18.190221,67.743188;18.190221,87.378182;18.690221,87.387479;18.690221,67.768204;19.190221,67.793219;19.190221,87.396776;19.690221,87.406073;19.690221,67.818235;20.190221,67.843250;20.190221,87.415370;20.690221,87.424667;20.690221,67.868266;21.190221,67.893282;21.190221,87.433964;21.690221,87.443261;21.690221,67.918297;22.190221,67.943313;22.190221,87.452558;22.690221,87.461855;22.690221,67.968328;23.190221,67.993344;23.190221,87.471152;23.690221,87.480449;23.690221,68.018360;24.190221,68.043375;24.190221,87.489746;24.690221,87.499043;24.690221,68.068391;25.190221,68.093406;25.190221,87.508340;25.690221,87.517637;25.690221,68.118422;26.190221,68.143438;26.190221,87.526934;26.690221,87.536231;26.690221,68.168453;27.190221,68.193469;27.190221,87.545528;27.690221,87.554825;27.690221,68.218484;28.190221,68.243500;28.190221,87.564121;28.690221,87.573418;28.690221,68.268516;29.190221,68.293531;29.190221,87.582715;29.690221,87.592012;29.690221,68.318547;30.190221,68.343562;30.190221,87.601309;30.690221,87.610606;30.690221,68.368578;31.190221,68.393594;31.190221,87.619903;31.690221,87.629200;31.690221,68.418609;32.190221,68.443625;32.190221,87.638497;32.690221,87.647794;32.690221,68.468640;33.190221,68.493656;33.190221,87.657091;33.690221,87.666388;33.690221,68.518672;34.190221,68.543687;34.190221,87.675685;34.690221,87.684982;34.690221,68.568703;35.190221,68.593718;35.190221,87.694279;35.690221,87.703576;35.690221,68.618734;36.190221,68.643750;36.190221,87.712873;36.690221,87.722170;36.690221,68.668765;37.190221,68.693781;37.190221,87.731467;37.690221,87.740764;37.690221,68.718797;38.190221,68.743812;38.190221,87.750061;38.690221,87.759358;38.690221,68.768828;39.190221,68.793843;39.190221,87.768655;39.690221,87.777952;39.690221,68.818859;40.190221,68.843875;40.190221,87.787249;40.690221,87.796546;40.690221,68.868890;41.190221,68.893906;41.190221,87.805843;41.690221,87.815140;41.690221,68.918921;42.190221,68.943937;42.190221,87.824437;42.690221,87.833733;42.690221,68.968953;43.190221,68.993968;43.190221,87.843030;43.690221,87.852327;43.690221,69.018984;44.190221,69.043999;44.190221,87.861624;44.690221,87.870921;44.690221,69.069015;45.190221,69.094031;45.190221,87.880218;45.690221,87.889515;45.690221,69.119046;46.190221,69.144062;46.190221,87.898812;46.690221,87.908109;46.690221,69.169077;47.190221,69.194093;47.190221,87.917406;47.690221,87.926703;47.690221,69.219109;48.190221,69.244124;48.190221,87.936000;48.690221,87.945297;48.690221,69.269140;49.190221,69.294155;49.190221,87.954594;49.690221,87.963891;49.690221,69.319171;50.190221,69.344187;50.190221,87.973188;50.690221,87.982485;50.690221,69.369202;51.190221,69.394218;51.190221,87.991782;51.690221,88.001079;51.690221,69.419233;52.190221,69.444249;52.190221,88.010376;52.690221,88.019673;52.690221,69.469265;53.190221,69.494280;53.190221,88.028970;53.690221,88.038267;53.690221,69.519296;54.190221,69.544311;54.190221,88.047564;54.690221,88.056861;54.690221,69.569327;55.190221,69.594343;55.190221,88.066158;55.690221,88.075455;55.690221,69.619358;56.190221,69.644374;56.190221,88.084752;56.690221,88.094048;56.690221,69.669389;57.190221,69.694405;57.190221,88.103345;57.690221,88.112642;57.690221,69.719421;58.190221,69.744436;58.190221,88.121939;58.690221,88.131236;58.690221,69.769452;59.190221,69.794467;59.190221,88.140533;59.690221,88.149830;59.690221,69.819483;60.190221,69.844499;60.190221,88.159127;60.690221,88.168424;60.690221,69.869514;61.190221,69.894530;61.190221,88.177721;61.690221,88.187018;61.690221,69.919545;62.190221,69.944561;62.190221,88.196315;62.690221,88.205612;62.690221,69.969577;63.190221,69.994592;63.190221,88.214909;63.690221,88.224206;63.690221,70.019608;64.190221,70.044623;64.190221,88.233503;64.690221,88.242800;64.690221,70.069639;65.190221,70.094655;65.190221,88.252097;65.690221,88.261394;65.690221,70.119670;66.190221,70.144686;66.190221,88.270691;66.690221,88.279988;66.690221,70.169701;67.190221,70.194717;67.190221,88.289285;67.690221,88.298582;67.690221,70.219733;68.190221,70.244748;68.190221,88.307879;68.690221,88.317176;68.690221,70.269764;69.190221,70.294779;69.190221,88.326473;69.690221,88.335770;69.690221,70.319795;70.190221,70.344811;70.190221,88.345067;70.690221,88.354364;70.690221,70.369826;71.190221,70.394842;71.190221,88.363660;71.690221,88.372957;71.690221,70.419857;72.190221,70.444873;72.190221,88.382254;72.690221,88.391551;72.690221,70.469889;73.190221,70.494904;73.190221,88.400848;73.690221,88.410145;73.690221,70.519920;74.190221,70.544935;74.190221,88.419442;74.690221,88.428739;74.690221,70.569951;75.190221,70.594967;75.190221,88.438036;75.690221,88.447333;75.690221,70.619982;76.190221,70.644998;76.190221,88.456630;76.690221,88.465927;76.690221,70.670013;77.190221,70.695029;77.190221,88.475224;77.690221,88.484521;77.690221,70.720045;78.190221,70.745060;78.190221,88.493818;78.690221,88.503115;78.690221,70.770076;79.190221,70.795091;79.190221,88.512412;79.690221,88.521709;79.690221,70.820107;80.190221,70.845123;80.190221,88.531006;80.690221,88.540303;80.690221,70.870138;81.190221,70.895154;81.190221,88.549600;81.690221,88.558897;81.690221,70.920169;82.190221,70.945185;82.190221,88.568194;82.690221,88.577491;82.690221,70.970201;83.190221,70.995216;83.190221,88.586788;83.690221,88.596085;83.690221,71.020232;84.190221,71.045248;84.190221,88.605382;84.690221,88.614679;84.690221,71.070263;85.190221,71.095279;85.190221,88.623976;85.690221,88.633272;85.690221,71.120294;86.190221,71.145310;86.190221,88.642569;86.690221,88.651866;86.690221,71.170326;87.190221,71.195341;87.190221,88.661163;87.690221,88.670460;87.690221,71.220357;88.190221,71.245372;88.190221,88.679757;88.690221,88.689054;88.690221,71.270388;89.190221,71.295404;89.190221,88.698351;89.690221,88.707648;89.690221,71.320419;90.190221,71.345435;90.190221,88.716945;90.690221,88.726242;90.690221,71.370450;91.190221,71.395466;91.190221,88.735539;91.690221,88.744836;91.690221,71.420482;92.190221,71.445497;92.190221,88.754133;92.690221,88.763430;92.690221,71.470513;93.190221,71.495528;93.190221,88.772727;93.690221,88.782024;93.690221,71.520544;94.190221,71.545560;94.190221,88.791321;94.690221,88.800618;94.690221,71.570575;95.190221,71.595591;95.190221,88.809915;95.690221,88.819212;95.690221,71.620606;96.190221,71.645622;96.190221,88.828509;96.690221,88.837806;96.690221,71.670638;97.190221,71.695653;97.190221,88.847103;97.690221,88.856400;97.690221,71.720669;98.190221,71.745684;98.190221,88.865697;98.690221,88.874994;98.690221,71.770700;99.190221,71.795716;99.190221,88.884291;99.690221,88.893587;99.690221,71.820731;100.190221,71.845747;100.190221,88.902884;100.690221,88.912181;100.690221,71.870762;101.190221,71.895778;101.190221,88.921478;101.690221,88.930775;101.690221,71.920794;102.190221,71.945809;102.190221,88.940072;102.690221,88.949369;102.690221,71.970825;103.190221,71.995840;103.190221,88.958666;103.690221,88.967963;103.690221,72.020856;104.190221,72.045872;104.190221,88.977260;104.690221,88.986557;104.690221,72.070887;105.190221,72.095903;105.190221,88.995854;105.690221,89.005151;105.690221,72.120918;106.190221,72.145934;106.190221,89.014448;106.690221,89.023745;106.690221,72.170950;107.190221,72.195965;107.190221,89.033042;107.690221,89.042339;107.690221,72.220981;108.190221,72.245996;108.190221,89.051636;108.690221,89.060933;108.690221,72.271012;109.190221,72.296028;109.190221,89.070230;109.690221,89.079527;109.690221,72.321043;110.190221,72.346059;110.190221,89.088824;110.690221,89.098121;110.690221,72.371074;111.190221,72.396090;111.190221,89.107418;111.690221,89.116715;111.690221,72.421106;112.190221,72.446121;112.190221,89.126012;112.690221,89.135309;112.690221,72.471137;113.190221,72.496152;113.190221,89.144606;113.690221,89.153903;113.690221,72.521168;114.190221,72.546184;114.190221,89.163199;114.690221,89.172496;114.690221,69.609311;115.190221,65.289050;115.190221,89.181793;115.690221,89.191090;115.690221,60.968788;116.190221,56.648527;116.190221,89.200387;116.690221,89.209684;116.690221,52.328266;117.190221,48.008004;117.190221,89.218981;117.690221,89.228278;117.690221,43.687743;118.190221,39.367481;118.190221,89.237575;118.690221,89.246872;118.690221,35.047220;119.190221,30.726958;119.190221,89.256169;119.690221,89.265466;119.690221,26.406697;120.190221,22.086435;120.190221,89.274763;120.690221,89.284060;120.690221,-68.200587;121.190221,-68.176728;121.190221,89.293357;121.690221,89.302654;121.690221,-68.152868;122.190221,-68.129009;122.190221,89.311951;122.690221,89.321248;122.690221,-68.105149;123.190221,-68.081290;123.190221,89.330545;123.690221,89.339842;123.690221,-68.057430;124.190221,-68.033571;124.190221,89.349139;124.690221,89.358436;124.690221,-68.009711;125.190221,-67.985852;125.190221,89.367733;125.690221,89.377030;125.690221,-67.961993;126.190221,-67.938133;126.190221,89.386327;126.690221,89.395624;126.690221,-67.914274;127.190221,-67.890414;127.190221,89.404921;127.690221,89.414218;127.690221,-67.866555;128.190221,-67.842695;128.190221,89.423514;128.690221,89.432811;128.690221,-67.818836;129.190221,-67.794976;129.190221,89.442108;129.690221,89.451405;129.690221,-67.771117;130.190221,-67.747257;130.190221,89.460702;130.690221,89.469999;130.690221,-67.723398;131.190221,-67.699538;131.190221,89.479296;131.690221,89.488593;131.690221,-67.675679;132.190221,-67.651820;132.190221,89.497890;132.690221,89.507187;132.690221,-67.627960;133.190221,-67.604101;133.190221,89.516484;133.690221,89.525781;133.690221,-67.580241;134.190221,-67.556382;134.190221,75.974185;134.690221,49.901578;134.690221,-67.532522;135.190221,23.828971;119.690221,-68.248306;119.690221,18.359139;119.190221,18.096975;119.190221,-68.272166;118.690221,-68.296025;118.690221,17.834811;118.190221,17.572647;118.190221,-68.319885;117.690221,-68.343744;117.690221,17.310483;117.190221,17.048319;117.190221,-68.367603;116.690221,-68.391463;116.690221,16.786155;116.190221,16.523991;116.190221,-68.415322;115.690221,-68.439182;115.690221,16.261827;115.190221,15.999663;115.190221,-68.463041;114.690221,-68.486901;114.690221,15.737499;114.190221,15.475335;114.190221,-68.510760;113.690221,-68.534620;113.690221,15.213171;113.190221,14.951007;113.190221,-68.558479;112.690221,-68.582339;112.690221,14.688843;112.190221,14.426679;112.190221,-68.606198;111.690221,-68.630058;111.690221,14.164515;111.190221,13.902351;111.190221,-68.653917;110.690221,-68.677777;110.690221,13.640187;110.190221,13.378023;110.190221,-68.701636;109.690221,-68.725495;109.690221,13.115860;109.190221,12.853696;109.190221,-68.749355;108.690221,-68.773214;108.690221,12.591532;108.190221,12.329368;108.190221,-68.797074;107.690221,-68.820933;107.690221,12.067204;107.190221,11.805040;107.190221,-68.844793;106.690221,-68.868652;106.690221,11.542876;106.190221,11.280712;106.190221,-68.892512;105.690221,-68.916371;105.690221,11.018548;105.190221,10.756384;105.190221,-68.940231;104.690221,-68.964090;104.690221,10.494220;104.190221,10.232056;104.190221,-68.987950;103.690221,-69.011809;103.690221,9.969892;103.190221,9.707728;103.190221,-69.035668;102.690221,-69.059528;102.690221,9.445564;102.190221,9.183400;102.190221,-69.083387;101.690221,-69.107247;101.690221,8.921236;101.190221,8.659072;101.190221,-69.131106;100.690221,-69.154966;100.690221,8.396908;100.190221,8.134744;100.190221,-69.178825;99.690221,-61.738685;99.690221,7.872580;99.190221,7.610416;99.190221,-39.474222;98.690221,-17.209759;98.690221,7.348252;98.190221,7.086088;98.190221,-15.341889;97.690221,-15.323099;97.690221,6.823924;97.190221,6.561760;97.190221,-15.304309;96.690221,-15.285519;96.690221,6.299596;96.190221,6.037433;96.190221,-15.266729;95.690221,-15.247939;95.690221,5.775269;95.190221,5.513105;95.190221,-15.229149;94.690221,-15.210359;94.690221,5.250941;94.190221,4.988777;94.190221,-15.191569;93.690221,-15.172779;93.690221,4.726613;93.190221,4.464449;93.190221,-15.153989;92.690221,-15.135199;92.690221,4.202285;92.190221,3.940121;92.190221,-15.116409;91.690221,-15.097619;91.690221,3.677957;91.190221,3.415793;91.190221,-15.078829;90.690221,-15.060039;90.690221,3.153629;90.190221,2.891465;90.190221,-15.041249;89.690221,-15.022459;89.690221,2.629301;89.190221,2.367137;89.190221,-15.003669;88.690221,-14.984879;88.690221,2.104973;88.190221,1.842809;88.190221,-14.966089;87.690221,-14.947299;87.690221,1.580645;87.190221,1.318481;87.190221,-14.928509;86.690221,-14.909719;86.690221,1.056317;86.190221,0.794153;86.190221,-14.890929;85.690221,-14.872139;85.690221,0.531989;85.190221,0.269825;85.190221,-14.853349;84.690221,-14.834559;84.690221,0.007661;84.190221,-0.254503;84.190221,-14.815769;83.690221,-14.796979;83.690221,-0.516667;83.190221,-0.778831;83.190221,-14.778189;82.690221,-14.759399;82.690221,-1.040995;82.190221,-1.303158;82.190221,-14.740609;81.690221,-14.721819;81.690221,-1.565322;81.190221,-1.827486;81.190221,-14.703029;80.690221,-14.684239;80.690221,-2.089650;80.190221,-2.351814;80.190221,-14.665449;79.690221,-14.646659;79.690221,-2.613978;79.190221,-2.876142;79.190221,-14.627869;78.690221,-14.609079;78.690221,-3.138306;78.190221,-3.400470;78.190221,-14.590289;77.690221,-14.571499;77.690221,-3.662634;77.190221,-3.924798;77.190221,-14.552709;76.690221,-14.533919;76.690221,-4.186962;76.190221,-4.449126;76.190221,-14.515129;75.690221,-14.496339;75.690221,-4.711290;75.190221,-4.973454;75.190221,-14.477549;74.690221,-14.458759;74.690221,-4.944986;74.190221,-4.800265;74.190221,-14.439969;73.690221,-14.421179;73.690221,-4.655544;73.190221,-4.510823;73.190221,-14.402389;72.690221,-14.383599;72.690221,-4.366102;72.190221,-4.221381;72.190221,-14.364809;71.690221,-14.346019;71.690221,-4.076660;71.190221,-3.931939;71.190221,-14.327229;70.690221,-14.308439;70.690221,-3.787218;70.190221,-3.642497;70.190221,-14.289649;69.690221,-14.270859;69.690221,-3.497776;69.190221,-3.353055;69.190221,-14.252069;68.690221,-14.233279;68.690221,-3.208334;68.190221,-3.063613;68.190221,-14.214489;67.690221,-14.195699;67.690221,-2.918892;67.190221,-2.774171;67.190221,-14.176909;66.690221,-14.158119;66.690221,-2.629450;66.190221,-2.484729;66.190221,-14.139329;65.690221,-14.120539;65.690221,-2.340008;65.190221,-2.195287;65.190221,-14.101749;64.690221,-14.082959;64.690221,-2.050566;64.190221,-1.905845;64.190221,-14.064169;63.690221,-14.045379;63.690221,-1.761124;63.190221,-1.616403;63.190221,-14.026589;62.690221,-14.007799;62.690221,-1.471682;62.190221,-1.326961;62.190221,-13.989009;61.690221,-13.970219;61.690221,-1.182240;61.190221,-1.037519;61.190221,-13.951429;60.690221,-13.932639;60.690221,-0.892798;60.190221,-0.748077;60.190221,-13.913849;59.690221,-13.895059;59.690221,-0.603356;59.190221,-0.458635;59.190221,-13.876269;58.690221,-13.857479;58.690221,-0.313914;58.190221,-0.169193;58.190221,-13.838688;57.690221,-13.819898;57.690221,-0.024472;57.190221,0.120249;57.190221,-13.801108;56.690221,-13.782318;56.690221,0.264970;56.190221,0.409691;56.190221,-13.763528;55.690221,-13.744738;55.690221,0.554412;55.190221,0.699133;55.190221,-13.725948;54.690221,-13.707158;54.690221,0.843854;54.190221,0.988575;54.190221,-13.688368;53.690221,-13.669578;53.690221,1.133296;53.190221,1.278017;53.190221,-13.650788;52.690221,-13.631998;52.690221,1.422738;52.190221,1.567459;52.190221,-13.613208;51.690221,-13.594418;51.690221,1.712180;51.190221,1.856901;51.190221,-13.575628;50.690221,-13.556838;50.690221,2.001622;50.190221,2.146343;50.190221,-13.538048;49.690221,-13.519258;49.690221,2.291064;49.190221,2.435785;49.190221,-13.827232;48.690221,-18.659342;48.690221,2.580506;48.190221,2.725227;48.190221,-23.491452;47.690221,-28.323562;47.690221,2.869948;47.190221,3.014669;47.190221,-33.155672;46.690221,-37.987782;46.690221,3.159390;46.190221,3.304111;46.190221,-42.819892;45.690221,-47.652003;45.690221,3.448832;45.190221,3.593553;45.190221,-52.484113;44.690221,-57.316223;44.690221,3.738274;44.190221,3.882995;44.190221,-62.148333;43.690221,-66.175290;43.690221,4.027716;43.190221,4.172437;43.190221,-66.162309;42.690221,-66.149329;42.690221,4.317158;42.190221,4.461879;42.190221,-66.136349;41.690221,-66.123369;41.690221,4.606600;41.190221,4.751321;41.190221,-66.110389;40.690221,-66.097409;40.690221,4.896042;40.190221,5.040763;40.190221,-66.084429;39.690221,-66.071449;39.690221,5.185484;39.190221,5.330205;39.190221,-66.058469;38.690221,-66.045489;38.690221,5.474926;38.190221,5.619647;38.190221,-66.032509;37.690221,-66.019529;37.690221,5.764368;37.190221,5.909089;37.190221,-66.006549;36.690221,-65.993569;36.690221,6.053810;36.190221,6.198531;36.190221,-65.980589;35.690221,-65.967609;35.690221,6.343252;35.190221,6.487973;35.190221,-65.954629;34.690221,-65.941649;34.690221,6.632694;34.190221,6.777415;34.190221,-65.928669;33.690221,-65.915689;33.690221,6.922136;33.190221,7.066857;33.190221,-65.902709;32.690221,-65.889728;32.690221,7.211578;32.190221,7.356299;32.190221,-65.876748;31.690221,-65.863768;31.690221,7.501020;31.190221,7.645741;31.190221,-65.850788;30.690221,-65.837808;30.690221,7.790462;30.190221,7.935183;30.190221,-65.824828;29.690221,-65.811848;29.690221,8.079904;29.190221,8.224625;29.190221,-65.798868;28.690221,-65.785888;28.690221,8.369346;28.190221,8.514067;28.190221,-65.772908;27.690221,-65.759928;27.690221,8.658788;27.190221,8.803509;27.190221,-65.746948;26.690221,-65.733968;26.690221,8.948230;26.190221,9.092951;26.190221,-65.720988;25.690221,-65.708008;25.690221,9.237672;25.190221,9.382393;25.190221,-65.695028;24.690221,-65.682048;24.690221,9.527114;24.190221,13.371410;24.190221,-65.669068;23.690221,-65.656088;23.690221,17.224035;23.190221,21.076659;23.190221,-65.643108;22.690221,-65.630128;22.690221,24.929284;22.190221,28.781908;22.190221,-65.617147;21.690221,-65.604167;21.690221,32.634533;21.190221,36.487157;21.190221,-65.591187;20.690221,-65.578207;20.690221,40.339782;20.190221,44.192406;20.190221,-65.565227;19.690221,-65.552247;19.690221,48.045031;19.190221,51.897655;19.190221,-65.539267;18.690221,-65.526287;18.690221,55.750280;18.190221,59.602904;18.190221,-65.513307;3.690221,61.426988;3.190221,-65.123906;3.190221,49.928490;2.690221,38.429991;2.690221,-65.110926;2.190221,-65.097946;2.190221,26.931493;1.690221,15.432994;1.690221,-65.084966;1.190221,-65.071986;1.190221,3.934496;0.690221,-7.564003;0.690221,-65.059005;0.190221,-65.046025;0.190221,-19.062501;-0.309779,-30.561000;-0.309779,-65.033045;-0.809779,-65.020065;-0.809779,-42.059498;-1.309779,-53.557997;-1.309779,-65.007085;135.690221,-2.243636;136.190221,-67.460944;136.190221,-28.316244;136.690221,-54.388851;136.690221,-67.437084
-LAND1.returnPathCoordinates=-1
-LAND1.returnPathRawCoordinates=-1
-LAND1.returnPointCoordinates=-1
-LAND1.updateTime=2025-12-26 19\:43\:09
+LAND1.angleThreshold=-1
LAND1.userId=-1
+LAND1.landName=123
+LAND1.mowingTrack=-1
+LAND1.boundaryOriginalCoordinates=39.831522,116.279873,49.25;39.831524,116.279878,49.25;39.831525,116.279878,49.24;39.831524,116.279912,49.30;39.831524,116.279911,49.29;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
+LAND1.obstacleCoordinates=(53.95,39.88;55.58,45.69;64.53,45.45;66.97,40.57)
+LAND1.boundaryCoordinates=50.39,50.57;74.32,50.40;78.69,24.37;65.76,20.70;65.76,36.07;52.31,33.80;50.04,19.30;41.30,22.10
+LAND1.mowingBladeWidth=0.51
diff --git a/set.properties b/set.properties
index cc001f7..37fa8d3 100644
--- a/set.properties
+++ b/set.properties
@@ -1,19 +1,19 @@
#Mower Configuration Properties - Updated
-#Fri Dec 26 19:43:47 CST 2025
+#Sat Dec 27 13:39:12 GMT+08:00 2025
appVersion=-1
-boundaryLengthVisible=false
-currentWorkLandNumber=LAND1
-cuttingWidth=200
-firmwareVersion=-1
-handheldMarkerId=1872
-idleTrailDurationSeconds=60
-manualBoundaryDrawingMode=false
-mapScale=11.81
-measurementModeEnabled=false
-mowerId=6258
-serialAutoConnect=true
-serialBaudRate=115200
-serialPortName=COM15
simCardNumber=-1
-viewCenterX=-134.26
-viewCenterY=20.96
+currentWorkLandNumber=LAND1
+serialBaudRate=115200
+boundaryLengthVisible=false
+idleTrailDurationSeconds=60
+handheldMarkerId=1872
+viewCenterX=-60.00
+viewCenterY=-34.94
+manualBoundaryDrawingMode=false
+mowerId=6258
+serialPortName=COM15
+serialAutoConnect=true
+mapScale=10.32
+measurementModeEnabled=false
+firmwareVersion=-1
+cuttingWidth=200
diff --git a/shoudongbianjie.properties b/shoudongbianjie.properties
index 99426dd..e13b215 100644
--- a/shoudongbianjie.properties
+++ b/shoudongbianjie.properties
@@ -1,12 +1,12 @@
#\u624B\u52A8\u7ED8\u5236\u8FB9\u754C\u5750\u6807 - \u683C\u5F0F: x1,y1;x2,y2;...;xn,yn (\u5355\u4F4D:\u7C73,\u7CBE\u786E\u5230\u5C0F\u6570\u70B9\u540E2\u4F4D)
-#Fri Dec 26 15:33:26 CST 2025
-boundaryCoordinates=25.17,9.94;17.74,67.19;113.88,72.00;120.00,19.12;74.99,-4.48
-email=789
-language=zh
+#Sat Dec 27 13:37:22 GMT+08:00 2025
+registrationTime=-1
lastLoginTime=-1
password=123
-pointCount=5
-registrationTime=-1
-status=-1
-userId=-1
+pointCount=4
+boundaryCoordinates=53.95,39.88;55.58,45.69;64.53,45.45;66.97,40.57
+language=zh
userName=233
+userId=-1
+email=789
+status=-1
diff --git a/src/chuankou/SerialPortService.java b/src/chuankou/SerialPortService.java
index 53704fd..4895976 100644
--- a/src/chuankou/SerialPortService.java
+++ b/src/chuankou/SerialPortService.java
@@ -4,7 +4,7 @@
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
-import java.util.function.Consumer;
+// import java.util.function.Consumer;
import com.fazecast.jSerialComm.SerialPort;
@@ -18,12 +18,12 @@
private volatile boolean capturing = false;
private volatile boolean paused = true;
private Thread readerThread;
- private Consumer<byte[]> responseConsumer;
+ private DataListener<byte[]> responseConsumer;
// 浼樺寲锛氶噸鐢ㄧ紦鍐插尯锛屽噺灏戝唴瀛樺垎閰�
private byte[] readBuffer = new byte[200];
private ByteArrayOutputStream buffer = new ByteArrayOutputStream(1024);
- private Consumer<byte[]> dataReceivedCallback;
+ private DataListener<byte[]> dataReceivedCallback;
// 鏂板锛氭暟鎹潯鏁拌鏁板櫒
@@ -97,7 +97,7 @@
if (dataReceivedCallback != null) {
startCapture(dataReceivedCallback);
} else {
- System.err.println("No data received callback set. Please call startCapture(Consumer<byte[]> onReceived) first.");
+ System.err.println("No data received callback set. Please call startCapture(DataListener<byte[]> onReceived) first.");
}
}
@@ -115,7 +115,7 @@
return port.openPort();
}
- public void setResponseConsumer(Consumer<byte[]> consumer) {
+ public void setResponseConsumer(DataListener<byte[]> consumer) {
this.responseConsumer = consumer;
}
@@ -133,13 +133,15 @@
/**
* 鍚姩鏁版嵁鎺ユ敹绾跨▼
*/
- public void startCapture(Consumer<byte[]> onReceived) {
+ public void startCapture(DataListener<byte[]> onReceived) {
this.dataReceivedCallback = onReceived;
if (capturing || port == null || !port.isOpen()) return;
capturing = true;
paused = false;
- readerThread = new Thread(() -> {
+ readerThread = new Thread(new Runnable() {
+ @Override
+ public void run() {
buffer.reset();
long lastReceivedTime = 0;
@@ -189,7 +191,7 @@
responseConsumer.accept(data);
}
}
- });
+ } });
readerThread.setDaemon(true);
readerThread.start();
}
diff --git a/src/chuankou/dellmessage.java b/src/chuankou/dellmessage.java
index 0469572..0350928 100644
--- a/src/chuankou/dellmessage.java
+++ b/src/chuankou/dellmessage.java
@@ -5,7 +5,7 @@
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
-import java.util.function.Consumer;
+// import java.util.function.Consumer;
/**
* 涓插彛瀹炴椂鏁版嵁璋冨害涓績銆�
@@ -15,8 +15,8 @@
* GNGGA 鏁版嵁鐨勫唴缃В鏋愭敮鎸侊紝澶嶇敤 UDP 澶勭悊閫昏緫銆�
*/
public final class dellmessage {
- private static final CopyOnWriteArrayList<Consumer<byte[]>> RAW_CONSUMERS = new CopyOnWriteArrayList<>();
- private static final CopyOnWriteArrayList<Consumer<String>> LINE_CONSUMERS = new CopyOnWriteArrayList<>();
+ private static final CopyOnWriteArrayList<DataListener<byte[]>> RAW_CONSUMERS = new CopyOnWriteArrayList<>();
+ private static final CopyOnWriteArrayList<DataListener<String>> LINE_CONSUMERS = new CopyOnWriteArrayList<>();
private static final StringBuilder LINE_BUFFER = new StringBuilder(512);
private static final AtomicInteger LINE_COUNTER = new AtomicInteger(0);
private static final AtomicReference<String> LAST_LINE = new AtomicReference<>("");
@@ -30,7 +30,7 @@
*
* @param consumer 鎺ユ敹瀹屾暣鏁版嵁甯х殑鐩戝惉鍣�
*/
- public static void registerRawListener(Consumer<byte[]> consumer) {
+ public static void registerRawListener(DataListener<byte[]> consumer) {
// 鐢ㄦ硶锛氬湪闇�瑕佺洿鎺ュ鐞嗗師濮嬩覆鍙e瓧鑺傛祦鐨勬ā鍧楀惎鍔ㄦ椂璋冪敤锛屼紶鍏ュ洖璋冨鐞嗘暟鎹抚銆�
if (consumer != null) {
RAW_CONSUMERS.addIfAbsent(consumer);
@@ -40,7 +40,7 @@
/**
* 娉ㄩ攢鍘熷瀛楄妭鐩戝惉鍣ㄣ��
*/
- public static void unregisterRawListener(Consumer<byte[]> consumer) {
+ public static void unregisterRawListener(DataListener<byte[]> consumer) {
// 鐢ㄦ硶锛氭ā鍧楅攢姣佹垨涓嶅啀闇�瑕佹帴鏀跺師濮嬫暟鎹椂璋冪敤锛岄伩鍏嶅唴瀛樻硠婕忋��
if (consumer != null) {
RAW_CONSUMERS.remove(consumer);
@@ -52,7 +52,7 @@
* <p>
* 姣忎竴鏉$粡鐢辨崲琛岀鎴柇鐨勫畬鏁存枃鏈灏嗚Е鍙戜竴娆″洖璋冦��
*/
- public static void registerLineListener(Consumer<String> consumer) {
+ public static void registerLineListener(DataListener<String> consumer) {
// 鐢ㄦ硶锛氶渶瑕佹寜琛岃鍙栦覆鍙f枃鏈紙濡� NMEA 鎶ユ枃锛夋椂璋冪敤锛屽洖璋冩嬁鍒板畬鏁存枃鏈銆�
if (consumer != null) {
LINE_CONSUMERS.addIfAbsent(consumer);
@@ -62,7 +62,7 @@
/**
* 娉ㄩ攢鏂囨湰琛岀洃鍚櫒銆�
*/
- public static void unregisterLineListener(Consumer<String> consumer) {
+ public static void unregisterLineListener(DataListener<String> consumer) {
// 鐢ㄦ硶锛氬搴� registerLineListener 鐨勫弽娉ㄥ唽鎿嶄綔锛岄�氬父鍦ㄧ獥鍙e叧闂垨鏈嶅姟鍋滄鏃惰皟鐢ㄣ��
if (consumer != null) {
LINE_CONSUMERS.remove(consumer);
@@ -125,7 +125,7 @@
}
private static void notifyRawConsumers(byte[] data) {
- for (Consumer<byte[]> consumer : RAW_CONSUMERS) {
+ for (DataListener<byte[]> consumer : RAW_CONSUMERS) {
try {
consumer.accept(data);
} catch (Exception ex) {
@@ -220,9 +220,14 @@
}
LAST_LINE.set(line);
- LINE_COUNTER.updateAndGet(count -> count >= 10000 ? 1 : count + 1);
+ // LINE_COUNTER.updateAndGet(count -> count >= 10000 ? 1 : count + 1);
+ int current, next;
+ do {
+ current = LINE_COUNTER.get();
+ next = (current >= 10000) ? 1 : current + 1;
+ } while (!LINE_COUNTER.compareAndSet(current, next));
- for (Consumer<String> consumer : LINE_CONSUMERS) {
+ for (DataListener<String> consumer : LINE_CONSUMERS) {
try {
consumer.accept(line);
} catch (Exception ex) {
diff --git a/src/denglu/Denglu.java b/src/denglu/Denglu.java
index 4a756c3..31ab615 100644
--- a/src/denglu/Denglu.java
+++ b/src/denglu/Denglu.java
@@ -609,27 +609,33 @@
public static void launchMainApp() {
System.out.println("鍑嗗鎵撳紑涓诲簲鐢ㄧ▼搴�...");
- SwingUtilities.invokeLater(() -> {
- JFrame mainFrame = new JFrame("鏅鸿兘鍓茶崏绯荤粺");
- mainFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
+ SwingUtilities.invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ JFrame mainFrame = new JFrame("鏅鸿兘鍓茶崏绯荤粺");
+ mainFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
- Shouye homePanel = new Shouye();
- mainFrame.setContentPane(homePanel);
+ Shouye homePanel = new Shouye();
+ mainFrame.setContentPane(homePanel);
- // 璁剧疆涓庣櫥褰曢〉闈㈢浉鍚岀殑灏哄
- mainFrame.setSize(UIConfig.DIALOG_WIDTH, UIConfig.DIALOG_HEIGHT);
- mainFrame.setMinimumSize(new Dimension(UIConfig.DIALOG_WIDTH, UIConfig.DIALOG_HEIGHT));
- mainFrame.setResizable(true);
- mainFrame.setLocationRelativeTo(null);
- mainFrame.setVisible(true);
+ // 璁剧疆涓庣櫥褰曢〉闈㈢浉鍚岀殑灏哄
+ mainFrame.setSize(UIConfig.DIALOG_WIDTH, UIConfig.DIALOG_HEIGHT);
+ mainFrame.setMinimumSize(new Dimension(UIConfig.DIALOG_WIDTH, UIConfig.DIALOG_HEIGHT));
+ mainFrame.setResizable(true);
+ mainFrame.setLocationRelativeTo(null);
+ mainFrame.setVisible(true);
- System.out.println("涓诲簲鐢ㄧ▼搴忓凡鍚姩");
-
- // 鍚姩鍚庤繛鎺QTT
- new Thread(() -> {
- System.out.println("姝e湪杩炴帴MQTT鏈嶅姟鍣�...");
- Client.lianjiemqqt();
- }).start();
+ System.out.println("涓诲簲鐢ㄧ▼搴忓凡鍚姩");
+
+ // 鍚姩鍚庤繛鎺QTT
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ System.out.println("姝e湪杩炴帴MQTT鏈嶅姟鍣�...");
+ Client.lianjiemqqt();
+ }
+ }).start();
+ }
});
}
diff --git a/src/lujing/MowingPathGenerationPage.java b/src/lujing/MowingPathGenerationPage.java
index 78735ca..675d83f 100644
--- a/src/lujing/MowingPathGenerationPage.java
+++ b/src/lujing/MowingPathGenerationPage.java
@@ -609,12 +609,14 @@
// 鏃犻殰纰嶇墿鐨勬儏鍐�
if (grassType == 1) {
// 鍑稿舰鍦板潡锛屾棤闅滅鐗� -> 璋冪敤 AoxinglujingNoObstacle
+ System.out.println("璋冪敤绠楁硶: 鍑稿舰鏃犻殰纰嶇墿, 绫诲悕: AoxinglujingNoObstacle");
List<AoxinglujingNoObstacle.PathSegment> segments =
AoxinglujingNoObstacle.planPath(boundary, plannerWidth, safetyMarginStr);
generated = formatAoxingPathSegments(segments);
} else if (grassType == 2) {
// 寮傚舰鍦板潡锛屾棤闅滅鐗� -> 璋冪敤 YixinglujingNoObstacle
// 璋冪敤 YixinglujingNoObstacle.planPath 鑾峰彇璺緞娈靛垪琛�
+ System.out.println("璋冪敤绠楁硶: 寮傚舰鏃犻殰纰嶇墿, 绫诲悕: YixinglujingNoObstacle");
List<YixinglujingNoObstacle.PathSegment> segments =
YixinglujingNoObstacle.planPath(boundary, plannerWidth, safetyMarginStr);
// 鏍煎紡鍖栬矾寰勬鍒楄〃涓哄瓧绗︿覆
@@ -625,6 +627,7 @@
JOptionPane.showMessageDialog(parentComponent, "鏃犳硶鍒ゆ柇鍦板潡绫诲瀷锛屽皾璇曟寜鍑稿舰鍦板潡澶勭悊",
"鎻愮ず", JOptionPane.WARNING_MESSAGE);
}
+ System.out.println("璋冪敤绠楁硶: 鏃犳硶鍒ゆ柇绫诲瀷(榛樿鍑稿舰鏃犻殰纰嶇墿), 绫诲悕: AoxinglujingNoObstacle");
List<AoxinglujingNoObstacle.PathSegment> segments =
AoxinglujingNoObstacle.planPath(boundary, plannerWidth, safetyMarginStr);
generated = formatAoxingPathSegments(segments);
@@ -634,12 +637,14 @@
if (grassType == 1) {
// 鍑稿舰鍦板潡锛屾湁闅滅鐗� -> 璋冪敤 AoxinglujingHaveObstacel
// 浼犲叆鍙傛暟锛歜oundary(A), obstacles(B), plannerWidth(C), safetyMarginStr(D)
+ System.out.println("璋冪敤绠楁硶: 鍑稿舰鏈夐殰纰嶇墿, 绫诲悕: AoxinglujingHaveObstacel");
List<AoxinglujingHaveObstacel.PathSegment> segments =
AoxinglujingHaveObstacel.planPath(boundary, obstacles, plannerWidth, safetyMarginStr);
generated = formatAoxingHaveObstaclePathSegments(segments);
} else if (grassType == 2) {
// 寮傚舰鍦板潡锛屾湁闅滅鐗� -> 璋冪敤 YixinglujingHaveObstacel
// 浼犲叆鍙傛暟锛歜oundary(A), obstacles(B), plannerWidth(C), safetyMarginStr(D)
+ System.out.println("璋冪敤绠楁硶: 寮傚舰鏈夐殰纰嶇墿, 绫诲悕: YixinglujingHaveObstacel");
List<YixinglujingHaveObstacel.PathSegment> segments =
YixinglujingHaveObstacel.planPath(boundary, obstacles, plannerWidth, safetyMarginStr);
generated = formatYixingHaveObstaclePathSegments(segments);
@@ -649,6 +654,7 @@
JOptionPane.showMessageDialog(parentComponent, "鏃犳硶鍒ゆ柇鍦板潡绫诲瀷锛屽皾璇曟寜鍑稿舰鍦板潡澶勭悊",
"鎻愮ず", JOptionPane.WARNING_MESSAGE);
}
+ System.out.println("璋冪敤绠楁硶: 鏃犳硶鍒ゆ柇绫诲瀷(榛樿鍑稿舰鏈夐殰纰嶇墿), 绫诲悕: AoxinglujingHaveObstacel");
List<AoxinglujingHaveObstacel.PathSegment> segments =
AoxinglujingHaveObstacel.planPath(boundary, obstacles, plannerWidth, safetyMarginStr);
generated = formatAoxingHaveObstaclePathSegments(segments);
diff --git a/src/lujing/YixinglujingHaveObstacel.java b/src/lujing/YixinglujingHaveObstacel.java
index 08ba9ca..7d3cbce 100644
--- a/src/lujing/YixinglujingHaveObstacel.java
+++ b/src/lujing/YixinglujingHaveObstacel.java
@@ -1,1124 +1,634 @@
package lujing;
-
import java.util.*;
-import java.util.regex.*;
-import java.util.stream.Collectors;
+
/**
- * 寮傚舰鑽夊湴璺緞瑙勫垝 - 浼樺寲瀹屽杽鐗�
- * 閲囩敤鏇村畬鍠勭殑绠楁硶锛�
- * 1. 浣跨敤澶氳竟褰㈣鍓簱璁$畻鏇寸簿纭殑鍐呯缉杈圭晫
- * 2. 浣跨敤鎵弿绾垮~鍏呯畻娉曠敓鎴愭洿浼樺寲鐨勮矾寰�
- * 3. 浣跨敤鍙鍥剧畻娉曞鎵炬渶浼樼粫琛岃矾寰�
- * 4. 浣跨敤璺緞浼樺寲绠楁硶鍑忓皯绌鸿鍜岃浆寮�
+ * 寮傚舰鑽夊湴璺緞瑙勫垝 - 鍚殰纰嶇墿鐗�
+ * 鍔熻兘锛氬湪鍦板潡鍐呴儴閬垮紑闅滅鐗╋紝鐢熸垚杩炵画寮撳瓧褰㈠壊鑽夎矾寰�
*/
public class YixinglujingHaveObstacel {
-
- private static final double EPS = 1e-10;
- private static final double MIN_SEG_LEN = 0.01; // 蹇界暐灏忎簬1cm鐨勭绾�
- private static final double CORNER_THRESHOLD = Math.toRadians(30); // 30搴︿互涓嬬殑瑙掑害鍚堝苟
- public static List<PathSegment> planPath(String coordinates, String obstaclesStr, String widthStr, String marginStr) {
- try {
- // 瑙f瀽杈撳叆鍙傛暟
- double mowWidth = Double.parseDouble(widthStr);
- double safeMargin = Double.parseDouble(marginStr);
-
- // 瑙f瀽澶氳竟褰㈠拰闅滅鐗�
- List<Point> boundary = parseCoordinates(coordinates);
- if (boundary.size() < 3) {
- throw new IllegalArgumentException("鍦板潡杈圭晫鑷冲皯闇�瑕�3涓偣");
- }
-
- // 纭繚澶氳竟褰负閫嗘椂閽堟柟鍚�
- makeCCW(boundary);
-
- // 瑙f瀽闅滅鐗╁苟澶栨墿
- List<Obstacle> obstacles = parseAndExpandObstacles(obstaclesStr, safeMargin);
-
- // 鐢熸垚鍐呯缉浣滀笟杈圭晫锛堣�冭檻闅滅鐗╋級
- List<Point> workingArea = computeWorkingArea(boundary, obstacles, safeMargin);
- if (workingArea.isEmpty()) {
- return new ArrayList<>();
- }
-
- // 鐢熸垚瀹屾暣鐨勫叏瑕嗙洊璺緞锛堜笉鑰冭檻闅滅鐗╋級
- List<PathSegment> fullPath = generateCompleteCoverage(workingArea, mowWidth);
-
- // 鐢ㄩ殰纰嶇墿瑁佸壀璺緞
- List<PathSegment> clippedPath = clipPathWithObstacles(fullPath, obstacles);
-
- // 杩炴帴鍜屼紭鍖栬矾寰勶紙闄愬埗鍦ㄤ綔涓氳竟鐣屽唴锛�
- List<PathSegment> finalPath = connectAndOptimizePath(clippedPath, obstacles, mowWidth, workingArea);
-
- return finalPath;
-
- } catch (Exception e) {
- System.err.println("璺緞瑙勫垝閿欒: " + e.getMessage());
- e.printStackTrace();
- return new ArrayList<>();
+ public static List<PathSegment> planPath(String coordinates, String obstaclesStr,
+ String widthStr, String marginStr) {
+ // 1. 瑙f瀽鍙傛暟
+ List<Point> rawPoints = parseCoordinates(coordinates);
+ if (rawPoints.size() < 3) return new ArrayList<>();
+
+ double mowWidth = Double.parseDouble(widthStr);
+ double safeMargin = Double.parseDouble(marginStr);
+
+ // 瑙f瀽闅滅鐗�
+ List<Obstacle> obstacles = parseObstacles(obstaclesStr);
+
+ // 2. 棰勫鐞嗭細纭繚杈圭晫閫嗘椂閽�
+ ensureCounterClockwise(rawPoints);
+
+ // 3. 鐢熸垚鍐呯缉澶氳竟褰紙瀹夊叏杈圭晫锛�
+ List<Point> boundary = getInsetPolygon(rawPoints, safeMargin);
+ if (boundary.size() < 3) return new ArrayList<>();
+
+ // 4. 澶栨墿闅滅鐗╋紙瀹夊叏杈硅窛锛�
+ List<Obstacle> expandedObstacles = expandObstacles(obstacles, safeMargin);
+
+ // 5. 纭畾鏈�浼樹綔涓氳搴�
+ double bestAngle = findOptimalAngle(boundary);
+
+ // 6. 鑾峰彇棣栦釜浣滀笟鐐癸紝鐢ㄤ簬瀵归綈鍥磋竟璧风偣
+ Point firstScanStart = getFirstScanPoint(boundary, mowWidth, bestAngle);
+
+ // 7. 瀵归綈鍥磋竟
+ List<Point> alignedBoundary = alignBoundaryStart(boundary, firstScanStart);
+
+ // 8. 绗竴闃舵锛氬洿杈硅矾寰�
+ List<PathSegment> finalPath = new ArrayList<>();
+ for (int i = 0; i < alignedBoundary.size(); i++) {
+ Point pStart = alignedBoundary.get(i);
+ Point pEnd = alignedBoundary.get((i + 1) % alignedBoundary.size());
+ finalPath.add(new PathSegment(pStart, pEnd, true));
}
+
+ // 9. 绗簩闃舵锛氱敓鎴愬唴閮ㄦ壂鎻忚矾寰勶紙鑰冭檻闅滅鐗╋級
+ Point lastEdgePos = alignedBoundary.get(0);
+ List<PathSegment> scanPath = generateGlobalScanPathWithObstacles(
+ boundary, expandedObstacles, mowWidth, bestAngle, lastEdgePos);
+
+ finalPath.addAll(scanPath);
+
+ return finalPath;
}
/**
- * 璁$畻浣滀笟鍖哄煙锛堣�冭檻闅滅鐗╋級
+ * 鐢熸垚甯﹂殰纰嶇墿鐨勬壂鎻忚矾寰�
*/
- private static List<Point> computeWorkingArea(List<Point> boundary, List<Obstacle> obstacles, double margin) {
- // 棣栧厛鐢熸垚鍐呯缉杈圭晫
- List<Point> offsetBoundary = offsetPolygon(boundary, margin);
+ private static List<PathSegment> generateGlobalScanPathWithObstacles(
+ List<Point> polygon, List<Obstacle> obstacles,
+ double width, double angle, Point startPos) {
- if (obstacles.isEmpty()) {
- return offsetBoundary;
- }
+ // 1. 鐢熸垚鍘熷鎵弿绾匡紙鏃犻殰纰嶇墿锛�
+ List<PathSegment> originalSegments = generateGlobalScanPath(polygon, width, angle, startPos);
- // 濡傛灉瀛樺湪闅滅鐗╋紝浠庡唴缂╄竟鐣屼腑鍑忓幓闅滅鐗╁尯鍩�
- // 绠�鍖栧鐞嗭細宸ヤ綔鍖哄煙浠嶄互鍐呯缉杈圭晫涓轰富锛屽叿浣撹鍓湪璺緞灞傞潰瀹屾垚
- makeCCW(offsetBoundary);
- return offsetBoundary;
- }
-
- /**
- * 鐢熸垚瀹屾暣鐨勫叏瑕嗙洊璺緞
- */
- private static List<PathSegment> generateCompleteCoverage(List<Point> polygon, double width) {
- List<PathSegment> path = new ArrayList<>();
-
- // 1. 鐢熸垚杈圭晫璺緞
- List<PathSegment> borderPath = generateBorderPath(polygon, width);
- path.addAll(borderPath);
-
- // 2. 鐢熸垚鎵弿绾胯矾寰�
- List<PathSegment> scanLines = generateScanLines(polygon, width);
-
- // 3. 杩炴帴鎵弿绾�
- if (!scanLines.isEmpty()) {
- Point currentPos = path.isEmpty() ? scanLines.get(0).start :
- path.get(path.size() - 1).end;
-
- for (PathSegment scanLine : scanLines) {
- // 娣诲姞绌鸿杩炴帴
- if (distance(currentPos, scanLine.start) > MIN_SEG_LEN) {
- path.add(new PathSegment(currentPos, scanLine.start, false));
- }
- path.add(scanLine);
- currentPos = scanLine.end;
- }
-
- // 杩炴帴鍥炶捣鐐�
- if (distance(currentPos, path.get(0).start) > MIN_SEG_LEN) {
- path.add(new PathSegment(currentPos, path.get(0).start, false));
- }
- }
-
- return path;
- }
-
- /**
- * 鐢熸垚杈圭晫璺緞锛堜竴鍦堟垨澶氬湀锛�
- */
- private static List<PathSegment> generateBorderPath(List<Point> polygon, double width) {
- List<PathSegment> border = new ArrayList<>();
-
- // 鏍规嵁瀹藉害纭畾闇�瑕佸灏戝湀杈圭晫
- int borderPasses = 1; // 鑷冲皯涓�鍦�
- if (width < 0.3) {
- borderPasses = 2; // 瀹藉害杈冨皬锛屽鍔犺竟鐣屽湀鏁�
- }
-
- for (int pass = 0; pass < borderPasses; pass++) {
- double offset = pass * width;
- List<Point> offsetPoly = offsetPolygon(polygon, offset);
-
- if (offsetPoly.size() < 3) break;
-
- for (int i = 0; i < offsetPoly.size(); i++) {
- Point start = offsetPoly.get(i);
- Point end = offsetPoly.get((i + 1) % offsetPoly.size());
- border.add(new PathSegment(start, end, true));
- }
- }
-
- return border;
- }
-
- /**
- * 鐢熸垚鎵弿绾胯矾寰�
- */
- private static List<PathSegment> generateScanLines(List<Point> polygon, double width) {
- List<PathSegment> scanLines = new ArrayList<>();
-
- // 璁$畻鏈�浼樻壂鎻忔柟鍚�
- double optimalAngle = calculateOptimalScanAngle(polygon);
-
- // 鏃嬭浆澶氳竟褰㈠埌鎵弿鏂瑰悜
- List<Point> rotatedPoly = rotatePolygon(polygon, -optimalAngle);
-
- // 璁$畻鍖呭洿鐩�
- Bounds bounds = calculateBounds(rotatedPoly);
-
- // 鐢熸垚鎵弿绾�
- boolean leftToRight = true;
- for (double y = bounds.minY + width / 2; y <= bounds.maxY - width / 2 + EPS; y += width) {
- // 鑾峰彇姘村钩绾夸笌澶氳竟褰㈢殑浜ょ偣
- List<Double> intersections = getHorizontalIntersections(rotatedPoly, y);
-
- if (intersections.size() < 2) continue;
-
- // 浜ょ偣鎺掑簭骞舵垚瀵瑰鐞�
- Collections.sort(intersections);
- List<PathSegment> lineSegments = new ArrayList<>();
-
- for (int i = 0; i < intersections.size(); i += 2) {
- if (i + 1 >= intersections.size()) break;
-
- double x1 = intersections.get(i);
- double x2 = intersections.get(i + 1);
-
- if (x2 - x1 < MIN_SEG_LEN) continue;
-
- // 鏃嬭浆鍥炲師濮嬪潗鏍囩郴
- Point start = rotatePoint(new Point(x1, y), optimalAngle);
- Point end = rotatePoint(new Point(x2, y), optimalAngle);
-
- lineSegments.add(new PathSegment(start, end, true));
- }
-
- // 鏂瑰悜浜ゆ浛
- if (!leftToRight) {
- Collections.reverse(lineSegments);
- for (PathSegment seg : lineSegments) {
- Point temp = seg.start;
- seg.start = seg.end;
- seg.end = temp;
- }
- }
-
- scanLines.addAll(lineSegments);
- leftToRight = !leftToRight;
- }
-
- return scanLines;
- }
-
- /**
- * 鐢ㄩ殰纰嶇墿瑁佸壀璺緞
- */
- private static List<PathSegment> clipPathWithObstacles(List<PathSegment> path, List<Obstacle> obstacles) {
- if (obstacles.isEmpty()) return path;
-
- List<PathSegment> clipped = new ArrayList<>();
-
- for (PathSegment segment : path) {
- List<PathSegment> remaining = new ArrayList<>();
- remaining.add(segment);
-
- // 渚濇鐢ㄦ瘡涓殰纰嶇墿瑁佸壀
- for (Obstacle obstacle : obstacles) {
- List<PathSegment> temp = new ArrayList<>();
- for (PathSegment seg : remaining) {
- temp.addAll(obstacle.clipSegment(seg));
- }
- remaining = temp;
- }
-
- clipped.addAll(remaining);
- }
-
- return clipped;
- }
-
- /**
- * 杩炴帴鍜屼紭鍖栬矾寰�
- */
- private static List<PathSegment> connectAndOptimizePath(List<PathSegment> segments,
- List<Obstacle> obstacles,
- double width,
- List<Point> workingArea) {
- if (segments.isEmpty()) return new ArrayList<>();
-
- // 1. 鍏堟寜绫诲瀷鍒嗙粍锛氬壊鑽夋鍜岃繛鎺ユ
- List<PathSegment> mowingSegments = segments.stream()
- .filter(s -> s.isMowing)
- .collect(Collectors.toList());
-
- // 2. 浣跨敤鏃呰鍟嗛棶棰�(TSP)鐨勮繎浼肩畻娉曡繛鎺ュ壊鑽夋
- List<PathSegment> connectedPath = connectSegmentsTSP(mowingSegments, obstacles, workingArea);
-
- // 3. 浼樺寲璺緞锛氬悎骞跺皬娈点�佸钩婊戣浆瑙�
- connectedPath = optimizePath(connectedPath, width);
-
- return connectedPath;
- }
-
- /**
- * 浣跨敤鏃呰鍟嗛棶棰樿繎浼肩畻娉曡繛鎺ヨ矾寰勬
- */
- private static List<PathSegment> connectSegmentsTSP(List<PathSegment> segments, List<Obstacle> obstacles, List<Point> workingArea) {
- List<PathSegment> connected = new ArrayList<>();
-
- if (segments.isEmpty()) return connected;
-
- // 鏋勫缓鐐归泦锛堟墍鏈夌嚎娈电殑绔偣锛�
- List<Point> points = new ArrayList<>();
- for (PathSegment seg : segments) {
- points.add(seg.start);
- points.add(seg.end);
- }
-
- // 浣跨敤鏈�杩戦偦绠楁硶鏋勫缓璺緞
- boolean[] visited = new boolean[segments.size()];
- Point currentPos = segments.get(0).start;
-
- while (true) {
- int bestIdx = -1;
- double bestDist = Double.MAX_VALUE;
- boolean useStart = true;
-
- // 瀵绘壘鏈�杩戠殑鏈闂嚎娈�
- for (int i = 0; i < segments.size(); i++) {
- if (visited[i]) continue;
-
- PathSegment seg = segments.get(i);
- double distToStart = distance(currentPos, seg.start);
- double distToEnd = distance(currentPos, seg.end);
-
- if (distToStart < bestDist) {
- bestDist = distToStart;
- bestIdx = i;
- useStart = true;
- }
- if (distToEnd < bestDist) {
- bestDist = distToEnd;
- bestIdx = i;
- useStart = false;
- }
- }
-
- if (bestIdx == -1) break;
-
- // 娣诲姞杩炴帴璺緞
- PathSegment bestSeg = segments.get(bestIdx);
- Point targetPoint = useStart ? bestSeg.start : bestSeg.end;
-
- if (distance(currentPos, targetPoint) > MIN_SEG_LEN) {
- // 瀵绘壘瀹夊叏杩炴帴璺緞锛堝彈浣滀笟杈圭晫闄愬埗锛�
- List<PathSegment> detour = findSafePath(currentPos, targetPoint, obstacles, workingArea);
- connected.addAll(detour);
- }
-
- // 娣诲姞鍓茶崏绾挎锛堝彲鑳藉弽杞柟鍚戯級
- PathSegment toAdd = bestSeg;
- if (!useStart) {
- toAdd = new PathSegment(bestSeg.end, bestSeg.start, true);
- }
- connected.add(toAdd);
-
- currentPos = toAdd.end;
- visited[bestIdx] = true;
- }
-
- return connected;
- }
-
- /**
- * 瀵绘壘瀹夊叏璺緞锛圓*绠楁硶锛�
- */
- private static List<PathSegment> findSafePath(Point start, Point end, List<Obstacle> obstacles, List<Point> workingArea) {
- // 濡傛灉鐩寸嚎璺緞瀹夊叏锛岀洿鎺ヤ娇鐢�
- if (isLineSafe(start, end, obstacles, workingArea)) {
- List<PathSegment> direct = new ArrayList<>();
- direct.add(new PathSegment(start, end, false));
- return direct;
- }
-
- // 鍚﹀垯浣跨敤A*绠楁硶瀵绘壘缁曡璺緞
- return aStarPathFinding(start, end, obstacles, workingArea);
- }
-
- /**
- * A*绠楁硶璺緞瀵绘壘
- */
- private static List<PathSegment> aStarPathFinding(Point start, Point end, List<Obstacle> obstacles, List<Point> workingArea) {
- // 绠�鍖栫殑A*绠楁硶瀹炵幇
- // 杩欓噷鎴戜滑浣跨敤闅滅鐗╄竟鐣屼笂鐨勫叧閿偣浣滀负璺緞鑺傜偣
-
- List<Point> nodes = new ArrayList<>();
- nodes.add(start);
- nodes.add(end);
-
- // 娣诲姞闅滅鐗╃殑椤剁偣浣滀负鍊欓�夎妭鐐�
- for (Obstacle obs : obstacles) {
- nodes.addAll(obs.getKeyPoints());
- }
- // 娣诲姞浣滀笟杈圭晫椤剁偣锛屽厑璁歌创杈圭粫琛�
- if (workingArea != null && workingArea.size() >= 3) {
- nodes.addAll(workingArea);
- }
-
- // 鏋勫缓鍥�
- Map<Point, Map<Point, Double>> graph = new HashMap<>();
- for (Point p1 : nodes) {
- graph.put(p1, new HashMap<>());
- for (Point p2 : nodes) {
- if (p1 == p2) continue;
- if (isLineSafe(p1, p2, obstacles, workingArea)) {
- graph.get(p1).put(p2, distance(p1, p2));
- }
- }
- }
-
- // A*鎼滅储
- Map<Point, Double> gScore = new HashMap<>();
- Map<Point, Double> fScore = new HashMap<>();
- Map<Point, Point> cameFrom = new HashMap<>();
- PriorityQueue<Point> openSet = new PriorityQueue<>(
- Comparator.comparingDouble(p -> fScore.getOrDefault(p, Double.MAX_VALUE))
- );
-
- gScore.put(start, 0.0);
- fScore.put(start, heuristic(start, end));
- openSet.add(start);
-
- while (!openSet.isEmpty()) {
- Point current = openSet.poll();
-
- if (current.equals(end)) {
- return reconstructPath(cameFrom, current);
- }
-
- for (Map.Entry<Point, Double> neighborEntry : graph.getOrDefault(current, new HashMap<>()).entrySet()) {
- Point neighbor = neighborEntry.getKey();
- double tentativeGScore = gScore.get(current) + neighborEntry.getValue();
-
- if (tentativeGScore < gScore.getOrDefault(neighbor, Double.MAX_VALUE)) {
- cameFrom.put(neighbor, current);
- gScore.put(neighbor, tentativeGScore);
- fScore.put(neighbor, tentativeGScore + heuristic(neighbor, end));
-
- if (!openSet.contains(neighbor)) {
- openSet.add(neighbor);
- }
- }
- }
- }
-
- // 濡傛灉娌℃湁鎵惧埌璺緞锛屼笉鍋氫笉瀹夊叏鐨勮繛鎺�
- return new ArrayList<>();
- }
-
- /**
- * 閲嶆瀯璺緞
- */
- private static List<PathSegment> reconstructPath(Map<Point, Point> cameFrom, Point current) {
- List<Point> pathPoints = new ArrayList<>();
- while (current != null) {
- pathPoints.add(current);
- current = cameFrom.get(current);
- }
- Collections.reverse(pathPoints);
-
- List<PathSegment> path = new ArrayList<>();
- for (int i = 0; i < pathPoints.size() - 1; i++) {
- path.add(new PathSegment(pathPoints.get(i), pathPoints.get(i + 1), false));
- }
- return path;
- }
-
- /**
- * 鍚彂鍑芥暟
- */
- private static double heuristic(Point a, Point b) {
- return distance(a, b);
- }
-
- /**
- * 浼樺寲璺緞
- */
- private static List<PathSegment> optimizePath(List<PathSegment> path, double width) {
- if (path.size() <= 1) return path;
-
- List<PathSegment> optimized = new ArrayList<>();
- PathSegment current = path.get(0);
-
- for (int i = 1; i < path.size(); i++) {
- PathSegment next = path.get(i);
-
- // 妫�鏌ユ槸鍚﹀彲浠ュ悎骞跺綋鍓嶇嚎娈靛拰涓嬩竴绾挎
- if (canMergeSegments(current, next, width)) {
- // 鍚堝苟绾挎
- current = mergeSegments(current, next);
- } else {
- // 娣诲姞褰撳墠绾挎锛屽紑濮嬫柊鐨勫悎骞�
- optimized.add(current);
- current = next;
- }
- }
-
- optimized.add(current);
-
- // 骞虫粦杞
- optimized = smoothCorners(optimized, width);
-
- return optimized;
- }
-
- /**
- * 妫�鏌ユ槸鍚﹀彲浠ュ悎骞朵袱涓嚎娈�
- */
- private static boolean canMergeSegments(PathSegment a, PathSegment b, double width) {
- if (!a.isMowing || !b.isMowing) return false;
-
- // 妫�鏌ョ鐐规槸鍚﹂噸鍚�
- if (!a.end.equals(b.start) && !a.end.equals(b.end)) return false;
-
- // 妫�鏌ユ柟鍚戞槸鍚︿竴鑷�
- Point dir1 = new Point(a.end.x - a.start.x, a.end.y - a.start.y);
- Point dir2;
- if (a.end.equals(b.start)) {
- dir2 = new Point(b.end.x - b.start.x, b.end.y - b.start.y);
- } else {
- dir2 = new Point(b.start.x - b.end.x, b.start.y - b.end.y);
- }
-
- double angle = angleBetween(dir1, dir2);
- return angle < Math.toRadians(10); // 瑙掑害灏忎簬10搴﹀彲浠ュ悎骞�
- }
-
- /**
- * 鍚堝苟涓や釜绾挎
- */
- private static PathSegment mergeSegments(PathSegment a, PathSegment b) {
- Point newEnd = a.end.equals(b.start) ? b.end : b.start;
- return new PathSegment(a.start, newEnd, true);
- }
-
- /**
- * 骞虫粦杞
- */
- private static List<PathSegment> smoothCorners(List<PathSegment> path, double width) {
- if (path.size() < 3) return path;
-
- List<PathSegment> smoothed = new ArrayList<>();
- smoothed.add(path.get(0));
-
- for (int i = 1; i < path.size() - 1; i++) {
- PathSegment prev = path.get(i - 1);
- PathSegment curr = path.get(i);
- PathSegment next = path.get(i + 1);
-
- if (!prev.isMowing || !curr.isMowing || !next.isMowing) {
- smoothed.add(curr);
+ // 2. 绉婚櫎鍦ㄩ殰纰嶇墿鍐呴儴鐨勭嚎娈�
+ List<PathSegment> remainingSegments = new ArrayList<>();
+ for (PathSegment seg : originalSegments) {
+ if (!seg.isMowing) {
+ // 绌鸿蛋娈电洿鎺ヤ繚鐣�
+ remainingSegments.add(seg);
continue;
}
- // 璁$畻杞
- Point inVec = new Point(curr.start.x - prev.end.x, curr.start.y - prev.end.y);
- Point outVec = new Point(next.start.x - curr.end.x, next.start.y - curr.end.y);
+ // 灏嗗壊鑽夋涓庢墍鏈夐殰纰嶇墿杩涜瑁佸壀
+ List<PathSegment> clippedSegments = new ArrayList<>();
+ clippedSegments.add(seg);
- double angle = angleBetween(inVec, outVec);
+ for (Obstacle obs : obstacles) {
+ List<PathSegment> newSegments = new ArrayList<>();
+ for (PathSegment s : clippedSegments) {
+ newSegments.addAll(clipSegmentWithObstacle(s, obs));
+ }
+ clippedSegments = newSegments;
+ }
- if (angle < CORNER_THRESHOLD) {
- // 灏忚搴︼紝鍙互鐩存帴杩炴帴
- PathSegment direct = new PathSegment(prev.end, next.start, true);
- smoothed.remove(smoothed.size() - 1); // 绉婚櫎涓婁竴涓嚎娈�
- smoothed.add(direct);
- i++; // 璺宠繃涓嬩竴涓嚎娈�
+ remainingSegments.addAll(clippedSegments);
+ }
+
+ // 3. 閲嶆柊杩炴帴璺緞娈碉紙寮撳瓧褰㈣繛鎺ワ級
+ return reconnectSegments(remainingSegments);
+ }
+
+ /**
+ * 灏嗙嚎娈典笌闅滅鐗╄繘琛岃鍓�
+ * 杩斿洖涓嶅湪闅滅鐗╁唴閮ㄧ殑瀛愮嚎娈�
+ */
+ private static List<PathSegment> clipSegmentWithObstacle(PathSegment segment, Obstacle obstacle) {
+ List<PathSegment> result = new ArrayList<>();
+
+ // 妫�鏌ョ嚎娈垫槸鍚﹀畬鍏ㄥ湪闅滅鐗╁閮�
+ boolean startInside = obstacle.contains(segment.start);
+ boolean endInside = obstacle.contains(segment.end);
+
+ if (!startInside && !endInside) {
+ // 绾挎涓ょ閮藉湪澶栭儴锛屾鏌ユ槸鍚︾┛杩囬殰纰嶇墿
+ List<Point> intersections = obstacle.getIntersections(segment);
+ if (intersections.isEmpty()) {
+ // 瀹屽叏鍦ㄥ閮�
+ result.add(segment);
} else {
- smoothed.add(curr);
- }
- }
-
- if (path.size() > 1) {
- smoothed.add(path.get(path.size() - 1));
- }
-
- return smoothed;
- }
-
- // ==================== 鍑犱綍璁$畻宸ュ叿 ====================
-
- /**
- * 澶氳竟褰㈠亸绉荤畻娉�
- */
- private static List<Point> offsetPolygon(List<Point> polygon, double d) {
- // 鍩轰簬鈥滃亸绉昏竟鐩寸嚎浜ょ偣鈥濈殑杈冪ǔ鍋ュ疄鐜般�傜害瀹歱olygon涓篊CW锛屽乏娉曞悜閲忎负澶栦晶銆�
- if (polygon == null || polygon.size() < 3) return new ArrayList<>();
- List<Point> poly = new ArrayList<>(polygon);
- makeCCW(poly);
- int n = poly.size();
- List<Point> out = new ArrayList<>(n);
-
- for (int i = 0; i < n; i++) {
- Point A = poly.get((i - 1 + n) % n);
- Point B = poly.get(i);
- Point C = poly.get((i + 1) % n);
-
- Point e1 = normalize(subtract(B, A));
- Point e2 = normalize(subtract(C, B));
- Point n1 = new Point(-e1.y, e1.x);
- Point n2 = new Point(-e2.y, e2.x);
-
- Point p1 = add(B, multiply(n1, d));
- Point p2 = add(B, multiply(n2, d));
-
- Point dir1 = e1;
- Point dir2 = e2;
-
- Point inter = intersectLines(p1, dir1, p2, dir2);
- if (inter == null) {
- // 骞宠鎴栨暟鍊间笉绋冲畾鏃堕��鍖�
- Point avgN = add(n1, n2);
- if (magnitude(avgN) < EPS) avgN = n1;
- else avgN = normalize(avgN);
- inter = add(B, multiply(avgN, d));
- }
- out.add(inter);
- }
- return out;
- }
-
- // 璁$畻涓ゆ潯鍙傛暟鐩寸嚎鐨勪氦鐐� p=p0+t*v, q=q0+s*w
- private static Point intersectLines(Point p0, Point v, Point q0, Point w) {
- double det = v.x * w.y - v.y * w.x;
- if (Math.abs(det) < EPS) return null;
- double t = ((q0.x - p0.x) * w.y - (q0.y - p0.y) * w.x) / det;
- return new Point(p0.x + t * v.x, p0.y + t * v.y);
- }
-
- /**
- * 璁$畻鏈�浼樻壂鎻忚搴�
- */
- private static double calculateOptimalScanAngle(List<Point> polygon) {
- double bestAngle = 0;
- double minSpan = Double.MAX_VALUE;
-
- // 灏濊瘯澶氫釜瑙掑害
- for (int i = 0; i < 180; i += 5) {
- double angle = Math.toRadians(i);
- List<Point> rotated = rotatePolygon(polygon, angle);
-
- Bounds bounds = calculateBounds(rotated);
- double span = bounds.maxY - bounds.minY;
-
- if (span < minSpan) {
- minSpan = span;
- bestAngle = angle;
- }
- }
-
- return bestAngle;
- }
-
- /**
- * 鑾峰彇姘村钩绾夸笌澶氳竟褰㈢殑浜ょ偣
- */
- private static List<Double> getHorizontalIntersections(List<Point> polygon, double y) {
- List<Double> intersections = new ArrayList<>();
- int n = polygon.size();
-
- for (int i = 0; i < n; i++) {
- Point p1 = polygon.get(i);
- Point p2 = polygon.get((i + 1) % n);
-
- // 妫�鏌ヨ竟鏄惁涓庢按骞崇嚎鐩镐氦
- if ((p1.y <= y && p2.y >= y) || (p1.y >= y && p2.y <= y)) {
- if (Math.abs(p2.y - p1.y) < EPS) {
- // 姘村钩杈癸紝璺宠繃
- continue;
- }
+ // 绌胯繃闅滅鐗╋紝鍒嗗壊绾挎
+ intersections.sort(Comparator.comparingDouble(p ->
+ distance(segment.start, p)));
- double t = (y - p1.y) / (p2.y - p1.y);
- if (t >= -EPS && t <= 1 + EPS) {
- double x = p1.x + t * (p2.x - p1.x);
- intersections.add(x);
+ Point prevPoint = segment.start;
+ for (Point inter : intersections) {
+ result.add(new PathSegment(prevPoint, inter, true));
+ prevPoint = inter;
+ }
+ result.add(new PathSegment(prevPoint, segment.end, true));
+
+ // 绉婚櫎鍦ㄩ殰纰嶇墿鍐呴儴鐨勬锛堝鏁扮储寮曠殑娈碉級
+ List<PathSegment> filtered = new ArrayList<>();
+ for (int i = 0; i < result.size(); i++) {
+ PathSegment s = result.get(i);
+ Point midPoint = new Point(
+ (s.start.x + s.end.x) / 2,
+ (s.start.y + s.end.y) / 2
+ );
+ if (!obstacle.contains(midPoint)) {
+ filtered.add(s);
+ }
+ }
+ return filtered;
+ }
+ } else if (startInside && endInside) {
+ // 瀹屽叏鍦ㄥ唴閮紝涓㈠純
+ return result;
+ } else {
+ // 涓�绔湪鍐呴儴锛屼竴绔湪澶栭儴
+ Point insidePoint = startInside ? segment.start : segment.end;
+ Point outsidePoint = startInside ? segment.end : segment.start;
+
+ List<Point> intersections = obstacle.getIntersections(segment);
+ if (!intersections.isEmpty()) {
+ // 鍙栫澶栭儴鐐规渶杩戠殑浜ょ偣
+ intersections.sort(Comparator.comparingDouble(p ->
+ distance(outsidePoint, p)));
+ Point inter = intersections.get(0);
+
+ // 鍙繚鐣欏閮ㄩ儴鍒�
+ if (startInside) {
+ result.add(new PathSegment(inter, outsidePoint, true));
+ } else {
+ result.add(new PathSegment(outsidePoint, inter, true));
}
}
}
- // 鍘婚噸骞舵帓搴�
- intersections = intersections.stream()
- .distinct()
- .sorted()
- .collect(Collectors.toList());
-
- return intersections;
+ return result;
}
/**
- * 鍒ゆ柇鐩寸嚎鏄惁瀹夊叏
+ * 閲嶆柊杩炴帴璺緞娈碉紝褰㈡垚杩炵画寮撳瓧褰㈣矾寰�
*/
- private static boolean isLineSafe(Point p1, Point p2, List<Obstacle> obstacles, List<Point> workingArea) {
- // 蹇呴』瀹屽叏鍦ㄤ綔涓氬唴缂╄竟鐣屽唴
- if (workingArea != null && !isSegmentInsidePolygon(p1, p2, workingArea)) {
- return false;
- }
- for (Obstacle obs : obstacles) {
- if (obs.doesSegmentIntersect(p1, p2)) {
- return false;
- }
- }
- return true;
- }
-
- // 鍒ゆ柇绾挎鏄惁浣嶄簬澶氳竟褰㈠唴閮紙涓嶈秺鐣岋級
- private static boolean isSegmentInsidePolygon(Point a, Point b, List<Point> polygon) {
- if (polygon == null || polygon.size() < 3) return true;
- // 涓偣鍦ㄥ唴
- Point mid = new Point((a.x + b.x) / 2.0, (a.y + b.y) / 2.0);
- if (!pointInPolygon(mid, polygon)) return false;
- // 涓嶄笌杈圭晫鐩镐氦锛堝厑璁哥鐐规帴瑙︼級
- int n = polygon.size();
- for (int i = 0; i < n; i++) {
- Point p1 = polygon.get(i);
- Point p2 = polygon.get((i + 1) % n);
- if (lineSegmentIntersection(a, b, p1, p2)) {
- // 蹇界暐浠呭湪绔偣澶勭殑灏忔帴瑙�
- if (distance(a, p1) < EPS || distance(a, p2) < EPS || distance(b, p1) < EPS || distance(b, p2) < EPS) {
- continue;
+ private static List<PathSegment> reconnectSegments(List<PathSegment> segments) {
+ if (segments.isEmpty()) return new ArrayList<>();
+
+ List<PathSegment> reconnected = new ArrayList<>();
+ Point currentPos = segments.get(0).start;
+
+ for (PathSegment seg : segments) {
+ if (seg.isMowing) {
+ // 鍓茶崏娈碉細妫�鏌ユ槸鍚﹂渶瑕佹坊鍔犵┖璧版
+ if (distance(currentPos, seg.start) > 0.01) {
+ reconnected.add(new PathSegment(currentPos, seg.start, false));
}
- return false;
+ reconnected.add(seg);
+ currentPos = seg.end;
+ } else {
+ // 绌鸿蛋娈电洿鎺ユ坊鍔�
+ reconnected.add(seg);
+ currentPos = seg.end;
}
}
- return true;
- }
-
- private static boolean pointInPolygon(Point p, List<Point> poly) {
- boolean inside = false;
- for (int i = 0, j = poly.size() - 1; i < poly.size(); j = i++) {
- Point pi = poly.get(i), pj = poly.get(j);
- boolean intersect = ((pi.y > p.y) != (pj.y > p.y)) &&
- (p.x < (pj.x - pi.x) * (p.y - pi.y) / (pj.y - pi.y + EPS) + pi.x);
- if (intersect) inside = !inside;
- }
- return inside;
- }
-
- // ==================== 鍚戦噺杩愮畻宸ュ叿 ====================
-
- private static Point add(Point a, Point b) {
- return new Point(a.x + b.x, a.y + b.y);
- }
-
- private static Point subtract(Point a, Point b) {
- return new Point(a.x - b.x, a.y - b.y);
- }
-
- private static Point multiply(Point p, double scalar) {
- return new Point(p.x * scalar, p.y * scalar);
- }
-
- private static Point normalize(Point p) {
- double mag = magnitude(p);
- if (mag < EPS) return p;
- return new Point(p.x / mag, p.y / mag);
- }
-
- private static double magnitude(Point p) {
- return Math.sqrt(p.x * p.x + p.y * p.y);
- }
-
- private static double dot(Point a, Point b) {
- return a.x * b.x + a.y * b.y;
- }
-
- private static double angleBetween(Point a, Point b) {
- double dotProd = dot(a, b);
- double magA = magnitude(a);
- double magB = magnitude(b);
- if (magA < EPS || magB < EPS) return 0;
+ return reconnected;
+ }
+
+ /**
+ * 鐢熸垚鍘熷鎵弿璺緞锛堟棤闅滅鐗╃増鏈級
+ */
+ private static List<PathSegment> generateGlobalScanPath(
+ List<Point> polygon, double width, double angle, Point currentPos) {
- double cosAngle = dotProd / (magA * magB);
- cosAngle = Math.max(-1, Math.min(1, cosAngle));
- return Math.acos(cosAngle);
- }
-
- private static double distance(Point a, Point b) {
- return magnitude(subtract(a, b));
- }
-
- private static Point rotatePoint(Point p, double angle) {
- double cos = Math.cos(angle);
- double sin = Math.sin(angle);
- return new Point(p.x * cos - p.y * sin, p.x * sin + p.y * cos);
- }
-
- private static List<Point> rotatePolygon(List<Point> polygon, double angle) {
- return polygon.stream()
- .map(p -> rotatePoint(p, angle))
- .collect(Collectors.toList());
- }
-
- private static Bounds calculateBounds(List<Point> points) {
- double minX = Double.MAX_VALUE, maxX = -Double.MAX_VALUE;
+ List<PathSegment> segments = new ArrayList<>();
+ List<Point> rotatedPoly = new ArrayList<>();
+ for (Point p : polygon) rotatedPoly.add(rotatePoint(p, -angle));
+
double minY = Double.MAX_VALUE, maxY = -Double.MAX_VALUE;
-
- for (Point p : points) {
- minX = Math.min(minX, p.x);
- maxX = Math.max(maxX, p.x);
+ for (Point p : rotatedPoly) {
minY = Math.min(minY, p.y);
maxY = Math.max(maxY, p.y);
}
- return new Bounds(minX, maxX, minY, maxY);
- }
-
- private static void makeCCW(List<Point> polygon) {
- double area = 0;
- int n = polygon.size();
-
- for (int i = 0; i < n; i++) {
- Point p1 = polygon.get(i);
- Point p2 = polygon.get((i + 1) % n);
- area += (p2.x - p1.x) * (p2.y + p1.y);
+ boolean leftToRight = true;
+ for (double y = minY + width/2; y <= maxY - width/2; y += width) {
+ List<Double> xIntersections = getXIntersections(rotatedPoly, y);
+ if (xIntersections.size() < 2) continue;
+ Collections.sort(xIntersections);
+
+ List<PathSegment> lineSegmentsInRow = new ArrayList<>();
+ for (int i = 0; i < xIntersections.size() - 1; i += 2) {
+ Point pS = rotatePoint(new Point(xIntersections.get(i), y), angle);
+ Point pE = rotatePoint(new Point(xIntersections.get(i + 1), y), angle);
+ lineSegmentsInRow.add(new PathSegment(pS, pE, true));
+ }
+
+ if (!leftToRight) {
+ Collections.reverse(lineSegmentsInRow);
+ for (PathSegment s : lineSegmentsInRow) {
+ Point temp = s.start;
+ s.start = s.end;
+ s.end = temp;
+ }
+ }
+
+ for (PathSegment s : lineSegmentsInRow) {
+ if (distance(currentPos, s.start) > 0.01) {
+ segments.add(new PathSegment(currentPos, s.start, false));
+ }
+ segments.add(s);
+ currentPos = s.end;
+ }
+ leftToRight = !leftToRight;
}
- if (area > 0) {
- Collections.reverse(polygon);
- }
+ return segments;
}
- // ==================== 闅滅鐗╁鐞� ====================
-
- private static List<Obstacle> parseAndExpandObstacles(String obstaclesStr, double margin) {
+ /**
+ * 瑙f瀽闅滅鐗╁瓧绗︿覆
+ * 鏍煎紡锛�"(x1,y1;x2,y2)(x1,y1;x2,y2;x3,y3)"
+ */
+ private static List<Obstacle> parseObstacles(String obstaclesStr) {
List<Obstacle> obstacles = new ArrayList<>();
-
if (obstaclesStr == null || obstaclesStr.trim().isEmpty()) {
return obstacles;
}
- // 瑙f瀽闅滅鐗╁瓧绗︿覆
- Pattern pattern = Pattern.compile("\\(([^)]+)\\)");
- Matcher matcher = pattern.matcher(obstaclesStr);
+ String trimmed = obstaclesStr.trim();
+ List<String> obstacleStrs = new ArrayList<>();
- while (matcher.find()) {
- String coords = matcher.group(1);
- List<Point> points = parseCoordinates(coords);
+ // 鍒嗗壊姣忎釜闅滅鐗╋紙鐢ㄦ嫭鍙峰垎闅旓級
+ int start = trimmed.indexOf('(');
+ while (start != -1) {
+ int end = trimmed.indexOf(')', start);
+ if (end == -1) break;
+
+ String obsStr = trimmed.substring(start + 1, end);
+ obstacleStrs.add(obsStr);
+ start = trimmed.indexOf('(', end);
+ }
+
+ // 瑙f瀽姣忎釜闅滅鐗�
+ for (String obsStr : obstacleStrs) {
+ List<Point> points = new ArrayList<>();
+ String[] pairs = obsStr.split(";");
+
+ for (String pair : pairs) {
+ String[] xy = pair.split(",");
+ if (xy.length == 2) {
+ points.add(new Point(
+ Double.parseDouble(xy[0].trim()),
+ Double.parseDouble(xy[1].trim())
+ ));
+ }
+ }
if (points.size() == 2) {
- // 鍦嗗舰闅滅鐗�
+ // 鍦嗗舰闅滅鐗╋細绗竴涓偣涓哄渾蹇冿紝绗簩涓偣涓哄渾涓婁竴鐐�
Point center = points.get(0);
- double radius = distance(center, points.get(1)) + margin;
- obstacles.add(new CircularObstacle(center, radius));
- } else if (points.size() >= 3) {
+ Point onCircle = points.get(1);
+ double radius = distance(center, onCircle);
+ obstacles.add(new Obstacle(center, radius));
+ } else if (points.size() > 2) {
// 澶氳竟褰㈤殰纰嶇墿
- makeCCW(points);
- List<Point> expanded = offsetPolygon(points, -margin);
- obstacles.add(new PolygonalObstacle(expanded));
+ obstacles.add(new Obstacle(points));
}
}
return obstacles;
}
- private static List<Point> parseCoordinates(String str) {
- List<Point> points = new ArrayList<>();
+ /**
+ * 澶栨墿闅滅鐗╋紙澧炲姞瀹夊叏杈硅窛锛�
+ */
+ private static List<Obstacle> expandObstacles(List<Obstacle> obstacles, double margin) {
+ List<Obstacle> expanded = new ArrayList<>();
- if (str == null || str.trim().isEmpty()) {
- return points;
- }
-
- String[] tokens = str.split(";");
- for (String token : tokens) {
- token = token.trim();
- if (token.isEmpty()) continue;
-
- String[] xy = token.split(",");
- if (xy.length == 2) {
- try {
- double x = Double.parseDouble(xy[0].trim());
- double y = Double.parseDouble(xy[1].trim());
- points.add(new Point(x, y));
- } catch (NumberFormatException e) {
- System.err.println("鏃犳晥鍧愭爣: " + token);
- }
+ for (Obstacle obs : obstacles) {
+ if (obs.isCircle()) {
+ // 鍦嗗舰锛氬崐寰勫鍔犲畨鍏ㄨ竟璺�
+ expanded.add(new Obstacle(obs.center, obs.radius + margin));
+ } else {
+ // 澶氳竟褰細鍚戝鍋忕Щ锛堜笌杈圭晫鍐呯缉鏂瑰悜鐩稿弽锛�
+ List<Point> expandedPoints = getOutsetPolygon(obs.points, margin);
+ expanded.add(new Obstacle(expandedPoints));
}
}
- return points;
- }
-
- // ==================== 鍐呴儴绫诲畾涔� ====================
-
- /**
- * 闅滅鐗╁熀绫�
- */
- abstract static class Obstacle {
- abstract List<PathSegment> clipSegment(PathSegment seg);
- abstract boolean doesSegmentIntersect(Point p1, Point p2);
- abstract boolean containsPoint(Point p);
- abstract List<Point> getKeyPoints();
+ return expanded;
}
/**
- * 澶氳竟褰㈤殰纰嶇墿
+ * 澶氳竟褰㈠鎵╋紙涓庡唴缂╂柟鍚戠浉鍙嶏級
*/
- static class PolygonalObstacle extends Obstacle {
- List<Point> vertices;
+ private static List<Point> getOutsetPolygon(List<Point> points, double margin) {
+ // 杩欓噷浣跨敤绠�鍖栫殑澶栨墿鏂规硶锛氭部娉曠嚎鍚戝绉诲姩
+ List<Point> outset = new ArrayList<>();
+ int n = points.size();
- PolygonalObstacle(List<Point> vertices) {
- this.vertices = vertices;
- }
-
- @Override
- List<PathSegment> clipSegment(PathSegment seg) {
- List<Double> tValues = new ArrayList<>();
- tValues.add(0.0);
- tValues.add(1.0);
+ for (int i = 0; i < n; i++) {
+ Point pPrev = points.get((i - 1 + n) % n);
+ Point pCurr = points.get(i);
+ Point pNext = points.get((i + 1) % n);
- // 鏀堕泦鎵�鏈変氦鐐�
- for (int i = 0; i < vertices.size(); i++) {
- Point p1 = vertices.get(i);
- Point p2 = vertices.get((i + 1) % vertices.size());
-
- Double t = lineIntersection(seg.start, seg.end, p1, p2);
- if (t != null) {
- tValues.add(t);
- }
+ // 璁$畻涓や釜杈圭殑鍚戦噺
+ double v1x = pCurr.x - pPrev.x, v1y = pCurr.y - pPrev.y;
+ double v2x = pNext.x - pCurr.x, v2y = pNext.y - pCurr.y;
+
+ // 璁$畻娉曠嚎锛堢‘淇濆悜澶栵級
+ double nx1 = -v1y, ny1 = v1x;
+ double nx2 = -v2y, ny2 = v2x;
+
+ // 褰掍竴鍖�
+ double len1 = Math.hypot(nx1, ny1);
+ double len2 = Math.hypot(nx2, ny2);
+ if (len1 > 1e-6) { nx1 /= len1; ny1 /= len1; }
+ if (len2 > 1e-6) { nx2 /= len2; ny2 /= len2; }
+
+ // 璁$畻骞冲潎娉曠嚎鏂瑰悜
+ double nx = (nx1 + nx2) / 2;
+ double ny = (ny1 + ny2) / 2;
+ double len = Math.hypot(nx, ny);
+ if (len > 1e-6) {
+ nx /= len;
+ ny /= len;
}
- Collections.sort(tValues);
- List<PathSegment> result = new ArrayList<>();
-
- // 鐢熸垚涓嶅湪闅滅鐗╁唴閮ㄧ殑绾挎娈�
- for (int i = 0; i < tValues.size() - 1; i++) {
- double t1 = tValues.get(i);
- double t2 = tValues.get(i + 1);
- double tMid = (t1 + t2) / 2;
-
- Point midPoint = interpolate(seg.start, seg.end, tMid);
- if (!containsPoint(midPoint)) {
- Point start = interpolate(seg.start, seg.end, t1);
- Point end = interpolate(seg.start, seg.end, t2);
- result.add(new PathSegment(start, end, seg.isMowing));
- }
- }
-
- return result;
+ // 鍚戝绉诲姩
+ outset.add(new Point(
+ pCurr.x + nx * margin,
+ pCurr.y + ny * margin
+ ));
}
- @Override
- boolean doesSegmentIntersect(Point p1, Point p2) {
- for (int i = 0; i < vertices.size(); i++) {
- Point v1 = vertices.get(i);
- Point v2 = vertices.get((i + 1) % vertices.size());
-
- if (lineSegmentIntersection(p1, p2, v1, v2)) {
- return true;
- }
- }
- return false;
- }
-
- @Override
- boolean containsPoint(Point p) {
- int crossings = 0;
-
- for (int i = 0; i < vertices.size(); i++) {
- Point v1 = vertices.get(i);
- Point v2 = vertices.get((i + 1) % vertices.size());
-
- if (((v1.y <= p.y && p.y < v2.y) || (v2.y <= p.y && p.y < v1.y)) &&
- (p.x < (v2.x - v1.x) * (p.y - v1.y) / (v2.y - v1.y) + v1.x)) {
- crossings++;
- }
- }
-
- return (crossings % 2) == 1;
- }
-
- @Override
- List<Point> getKeyPoints() {
- return new ArrayList<>(vertices);
- }
+ return outset;
}
/**
- * 鍦嗗舰闅滅鐗�
+ * 闅滅鐗╃被
*/
- static class CircularObstacle extends Obstacle {
- Point center;
- double radius;
+ private static class Obstacle {
+ List<Point> points; // 澶氳竟褰㈤《鐐癸紙瀵瑰渾褰负绌猴級
+ Point center; // 鍦嗗績锛堜粎瀵瑰渾褰㈡湁鏁堬級
+ double radius; // 鍗婂緞锛堜粎瀵瑰渾褰㈡湁鏁堬級
+ boolean isCircle;
- CircularObstacle(Point center, double radius) {
- this.center = center;
+ // 澶氳竟褰㈡瀯閫犲嚱鏁�
+ Obstacle(List<Point> points) {
+ this.points = new ArrayList<>(points);
+ this.isCircle = false;
+ ensureCounterClockwise(this.points); // 纭繚椤烘椂閽堬紙瀵归殰纰嶇墿鏄唴閮ㄥ尯鍩燂級
+ }
+
+ // 鍦嗗舰鏋勯�犲嚱鏁�
+ Obstacle(Point center, double radius) {
+ this.center = new Point(center.x, center.y);
this.radius = radius;
+ this.isCircle = true;
+ this.points = new ArrayList<>();
}
- @Override
- List<PathSegment> clipSegment(PathSegment seg) {
- double dx = seg.end.x - seg.start.x;
- double dy = seg.end.y - seg.start.y;
- double fx = seg.start.x - center.x;
- double fy = seg.start.y - center.y;
-
- double a = dx * dx + dy * dy;
- double b = 2 * (fx * dx + fy * dy);
- double c = fx * fx + fy * fy - radius * radius;
-
- List<Double> tValues = new ArrayList<>();
- tValues.add(0.0);
- tValues.add(1.0);
-
- double discriminant = b * b - 4 * a * c;
- if (discriminant > 0) {
- double sqrtDisc = Math.sqrt(discriminant);
- double t1 = (-b - sqrtDisc) / (2 * a);
- double t2 = (-b + sqrtDisc) / (2 * a);
-
- if (t1 > EPS && t1 < 1 - EPS) tValues.add(t1);
- if (t2 > EPS && t2 < 1 - EPS) tValues.add(t2);
+ // 鍒ゆ柇鐐规槸鍚﹀湪闅滅鐗╁唴閮�
+ boolean contains(Point p) {
+ if (isCircle) {
+ return distance(p, center) <= radius;
+ } else {
+ return isPointInPolygon(p, points);
}
+ }
+
+ // 鑾峰彇绾挎涓庨殰纰嶇墿鐨勪氦鐐�
+ List<Point> getIntersections(PathSegment segment) {
+ List<Point> intersections = new ArrayList<>();
- Collections.sort(tValues);
- List<PathSegment> result = new ArrayList<>();
-
- for (int i = 0; i < tValues.size() - 1; i++) {
- double t1 = tValues.get(i);
- double t2 = tValues.get(i + 1);
- double tMid = (t1 + t2) / 2;
+ if (isCircle) {
+ // 绾挎涓庡渾鐨勪氦鐐�
+ double dx = segment.end.x - segment.start.x;
+ double dy = segment.end.y - segment.start.y;
+ double a = dx * dx + dy * dy;
+ double b = 2 * (dx * (segment.start.x - center.x) +
+ dy * (segment.start.y - center.y));
+ double c = (segment.start.x - center.x) * (segment.start.x - center.x) +
+ (segment.start.y - center.y) * (segment.start.y - center.y) -
+ radius * radius;
- Point midPoint = interpolate(seg.start, seg.end, tMid);
- if (!containsPoint(midPoint)) {
- Point start = interpolate(seg.start, seg.end, t1);
- Point end = interpolate(seg.start, seg.end, t2);
- result.add(new PathSegment(start, end, seg.isMowing));
+ double discriminant = b * b - 4 * a * c;
+ if (discriminant >= 0) {
+ discriminant = Math.sqrt(discriminant);
+ for (int sign = -1; sign <= 1; sign += 2) {
+ double t = (-b + sign * discriminant) / (2 * a);
+ if (t >= 0 && t <= 1) {
+ intersections.add(new Point(
+ segment.start.x + t * dx,
+ segment.start.y + t * dy
+ ));
+ }
+ }
+ }
+ } else {
+ // 绾挎涓庡杈瑰舰鐨勪氦鐐�
+ for (int i = 0; i < points.size(); i++) {
+ Point p1 = points.get(i);
+ Point p2 = points.get((i + 1) % points.size());
+
+ Point inter = getLineIntersection(
+ segment.start, segment.end, p1, p2);
+ if (inter != null) {
+ intersections.add(inter);
+ }
}
}
- return result;
+ return intersections;
}
- @Override
- boolean doesSegmentIntersect(Point p1, Point p2) {
- Point closest = closestPointOnSegment(center, p1, p2);
- // 灏嗕笌鍦嗙殑鐩稿垏涔熻涓虹浉浜わ紝閬垮厤璺緞鎿﹁竟
- return distance(center, closest) <= radius + EPS;
+ boolean isCircle() {
+ return isCircle;
}
-
- @Override
- boolean containsPoint(Point p) {
- return distance(center, p) < radius - EPS;
- }
-
- @Override
- List<Point> getKeyPoints() {
- List<Point> points = new ArrayList<>();
- int numPoints = 8; // 鍏竟褰㈣繎浼�
+ }
+
+ /**
+ * 鍒ゆ柇鐐规槸鍚﹀湪澶氳竟褰㈠唴閮紙灏勭嚎娉曪級
+ */
+ private static boolean isPointInPolygon(Point p, List<Point> polygon) {
+ boolean inside = false;
+ for (int i = 0, j = polygon.size() - 1; i < polygon.size(); j = i++) {
+ Point pi = polygon.get(i);
+ Point pj = polygon.get(j);
- for (int i = 0; i < numPoints; i++) {
- double angle = 2 * Math.PI * i / numPoints;
- points.add(new Point(
- center.x + radius * Math.cos(angle),
- center.y + radius * Math.sin(angle)
- ));
+ if (((pi.y > p.y) != (pj.y > p.y)) &&
+ (p.x < (pj.x - pi.x) * (p.y - pi.y) / (pj.y - pi.y) + pi.x)) {
+ inside = !inside;
}
-
- return points;
}
+ return inside;
}
/**
- * 璺緞娈�
+ * 璁$畻涓ゆ潯绾挎鐨勪氦鐐�
*/
- public static class PathSegment {
- public Point start, end;
- public boolean isMowing;
+ private static Point getLineIntersection(Point p1, Point p2, Point p3, Point p4) {
+ double denom = (p1.x - p2.x) * (p3.y - p4.y) - (p1.y - p2.y) * (p3.x - p4.x);
+ if (Math.abs(denom) < 1e-6) return null; // 骞宠
- public PathSegment(Point start, Point end, boolean isMowing) {
- this.start = start;
- this.end = end;
- this.isMowing = isMowing;
+ double t = ((p1.x - p3.x) * (p3.y - p4.y) - (p1.y - p3.y) * (p3.x - p4.x)) / denom;
+ double u = -((p1.x - p2.x) * (p1.y - p3.y) - (p1.y - p2.y) * (p1.x - p3.x)) / denom;
+
+ if (t >= 0 && t <= 1 && u >= 0 && u <= 1) {
+ return new Point(
+ p1.x + t * (p2.x - p1.x),
+ p1.y + t * (p2.y - p1.y)
+ );
}
-
- @Override
- public String toString() {
- return String.format("%s -> %s [%s]", start, end, isMowing ? "MOW" : "MOVE");
- }
- }
-
- /**
- * 鐐圭被
- */
- public static class Point {
- public double x, y;
-
- public Point(double x, double y) {
- this.x = x;
- this.y = y;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) return true;
- if (!(obj instanceof Point)) return false;
- Point other = (Point) obj;
- return Math.abs(x - other.x) < EPS && Math.abs(y - other.y) < EPS;
- }
-
- @Override
- public int hashCode() {
- return Double.hashCode(x) * 31 + Double.hashCode(y);
- }
-
- @Override
- public String toString() {
- return String.format("(%.2f, %.2f)", x, y);
- }
- }
-
- /**
- * 杈圭晫妗�
- */
- private static class Bounds {
- double minX, maxX, minY, maxY;
-
- Bounds(double minX, double maxX, double minY, double maxY) {
- this.minX = minX;
- this.maxX = maxX;
- this.minY = minY;
- this.maxY = maxY;
- }
- }
-
- // ==================== 鍑犱綍宸ュ叿鍑芥暟 ====================
-
- private static Double lineIntersection(Point a1, Point a2, Point b1, Point b2) {
- double det = (a2.x - a1.x) * (b2.y - b1.y) - (a2.y - a1.y) * (b2.x - b1.x);
-
- if (Math.abs(det) < EPS) return null;
-
- double t = ((b1.x - a1.x) * (b2.y - b1.y) - (b1.y - a1.y) * (b2.x - b1.x)) / det;
- double u = ((a1.x - b1.x) * (a2.y - a1.y) - (a1.y - b1.y) * (a2.x - a1.x)) / (-det);
-
- if (t >= -EPS && t <= 1 + EPS && u >= -EPS && u <= 1 + EPS) {
- return Math.max(0, Math.min(1, t));
- }
-
return null;
}
- private static boolean lineSegmentIntersection(Point a1, Point a2, Point b1, Point b2) {
- Double t = lineIntersection(a1, a2, b1, b2);
- return t != null;
+ /**
+ * 璁$畻涓ょ偣璺濈
+ */
+ private static double distance(Point p1, Point p2) {
+ return Math.hypot(p1.x - p2.x, p1.y - p2.y);
}
- private static Point interpolate(Point a, Point b, double t) {
- return new Point(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t);
+ // ============ 浠ヤ笅鏄粠A浠g爜澶嶇敤鐨勬柟娉� ============
+
+ private static Point getFirstScanPoint(List<Point> polygon, double width, double angle) {
+ List<Point> rotatedPoly = new ArrayList<>();
+ for (Point p : polygon) rotatedPoly.add(rotatePoint(p, -angle));
+ double minY = Double.MAX_VALUE;
+ for (Point p : rotatedPoly) minY = Math.min(minY, p.y);
+
+ double firstY = minY + width/2;
+ List<Double> xInter = getXIntersections(rotatedPoly, firstY);
+ if (xInter.isEmpty()) return polygon.get(0);
+ Collections.sort(xInter);
+ return rotatePoint(new Point(xInter.get(0), firstY), angle);
}
- private static Point closestPointOnSegment(Point p, Point a, Point b) {
- double ax = b.x - a.x;
- double ay = b.y - a.y;
- double bx = p.x - a.x;
- double by = p.y - a.y;
-
- double dot = ax * bx + ay * by;
- double lenSq = ax * ax + ay * ay;
-
- double t = (lenSq > EPS) ? Math.max(0, Math.min(1, dot / lenSq)) : 0;
-
- return new Point(a.x + t * ax, a.y + t * ay);
- }
-
-}
\ No newline at end of file
+ private static List<Point> alignBoundaryStart(List<Point> boundary, Point targetStart) {
+ int bestIdx = 0;
+ double minDist = Double.MAX_VALUE;
+ for (int i = 0; i < boundary.size(); i++) {
+ double d = Math.hypot(boundary.get(i).x - targetStart.x, boundary.get(i).y - targetStart.y);
+ if (d < minDist) { minDist = d; bestIdx = i; }
+ }
+ List<Point> aligned = new ArrayList<>();
+ for (int i = 0; i < boundary.size(); i++) {
+ aligned.add(boundary.get((bestIdx + i) % boundary.size()));
+ }
+ return aligned;
+ }
+
+ private static List<Double> getXIntersections(List<Point> rotatedPoly, double y) {
+ List<Double> xIntersections = new ArrayList<>();
+ for (int i = 0; i < rotatedPoly.size(); i++) {
+ Point p1 = rotatedPoly.get(i);
+ Point p2 = rotatedPoly.get((i + 1) % rotatedPoly.size());
+ if ((p1.y <= y && p2.y > y) || (p2.y <= y && p1.y > y)) {
+ double x = p1.x + (y - p1.y) * (p2.x - p1.x) / (p2.y - p1.y);
+ xIntersections.add(x);
+ }
+ }
+ return xIntersections;
+ }
+
+ private static double findOptimalAngle(List<Point> polygon) {
+ double bestAngle = 0;
+ double minHeight = Double.MAX_VALUE;
+ for (int i = 0; i < polygon.size(); i++) {
+ Point p1 = polygon.get(i), p2 = polygon.get((i + 1) % polygon.size());
+ double angle = Math.atan2(p2.y - p1.y, p2.x - p1.x);
+ double h = calculateHeightAtAngle(polygon, angle);
+ if (h < minHeight) { minHeight = h; bestAngle = angle; }
+ }
+ return bestAngle;
+ }
+
+ private static double calculateHeightAtAngle(List<Point> poly, double angle) {
+ double minY = Double.MAX_VALUE, maxY = -Double.MAX_VALUE;
+ for (Point p : poly) {
+ Point rp = rotatePoint(p, -angle);
+ minY = Math.min(minY, rp.y); maxY = Math.max(maxY, rp.y);
+ }
+ return maxY - minY;
+ }
+
+ private static List<Point> getInsetPolygon(List<Point> points, double margin) {
+ List<Point> result = new ArrayList<>();
+ int n = points.size();
+ for (int i = 0; i < n; i++) {
+ Point pPrev = points.get((i - 1 + n) % n);
+ Point pCurr = points.get(i);
+ Point pNext = points.get((i + 1) % n);
+
+ double d1x = pCurr.x - pPrev.x, d1y = pCurr.y - pPrev.y;
+ double l1 = Math.hypot(d1x, d1y);
+ double d2x = pNext.x - pCurr.x, d2y = pNext.y - pCurr.y;
+ double l2 = Math.hypot(d2x, d2y);
+
+ if (l1 < 1e-6 || l2 < 1e-6) continue;
+
+ double n1x = -d1y / l1, n1y = d1x / l1;
+ double n2x = -d2y / l2, n2y = d2x / l2;
+
+ double bisectorX = n1x + n2x, bisectorY = n1y + n2y;
+ double bLen = Math.hypot(bisectorX, bisectorY);
+ if (bLen < 1e-6) { bisectorX = n1x; bisectorY = n1y; }
+ else { bisectorX /= bLen; bisectorY /= bLen; }
+
+ double cosHalfAngle = n1x * bisectorX + n1y * bisectorY;
+ double dist = margin / Math.max(cosHalfAngle, 0.1);
+
+ dist = Math.min(dist, margin * 5);
+
+ result.add(new Point(pCurr.x + bisectorX * dist, pCurr.y + bisectorY * dist));
+ }
+ return result;
+ }
+
+ private static Point rotatePoint(Point p, double angle) {
+ double cos = Math.cos(angle), sin = Math.sin(angle);
+ return new Point(p.x * cos - p.y * sin, p.x * sin + p.y * cos);
+ }
+
+ private static void ensureCounterClockwise(List<Point> points) {
+ double sum = 0;
+ for (int i = 0; i < points.size(); i++) {
+ Point p1 = points.get(i), p2 = points.get((i + 1) % points.size());
+ sum += (p2.x - p1.x) * (p2.y + p1.y);
+ }
+ if (sum > 0) Collections.reverse(points);
+ }
+
+ private static List<Point> parseCoordinates(String coordinates) {
+ List<Point> points = new ArrayList<>();
+ String[] pairs = coordinates.split(";");
+ for (String pair : pairs) {
+ String[] xy = pair.split(",");
+ if (xy.length == 2) points.add(new Point(Double.parseDouble(xy[0]), Double.parseDouble(xy[1])));
+ }
+ if (points.size() > 1 && points.get(0).equals(points.get(points.size()-1))) points.remove(points.size()-1);
+ return points;
+ }
+
+ public static class Point {
+ public double x, y;
+ public Point(double x, double y) { this.x = x; this.y = y; }
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof Point)) return false;
+ Point p = (Point) o;
+ return Math.abs(x - p.x) < 1e-4 && Math.abs(y - p.y) < 1e-4;
+ }
+ }
+
+ public static class PathSegment {
+ public Point start, end;
+ public boolean isMowing;
+ public PathSegment(Point s, Point e, boolean m) {
+ this.start = s;
+ this.end = e;
+ this.isMowing = m;
+ }
+ }
+}
+
diff --git a/src/lujing/YixinglujingNoObstacle.java b/src/lujing/YixinglujingNoObstacle.java
index 1672ccc..c38d7c1 100644
--- a/src/lujing/YixinglujingNoObstacle.java
+++ b/src/lujing/YixinglujingNoObstacle.java
@@ -7,7 +7,20 @@
* 淇锛氳В鍐冲嚬澶氳竟褰㈡壂鎻忕嚎璺ㄨ秺杈圭晫鐨勯棶棰橈紝浼樺寲璺緞瀵归綈
*/
public class YixinglujingNoObstacle {
-
+ // 鐢ㄦ硶璇存槑锛堟棤闅滅鐗╄矾寰勮鍒掞級锛�
+ // - 鏂规硶鐢ㄩ�旓細鏍规嵁鍦板潡杈圭晫銆佸壊鑽夊搴︿笌瀹夊叏杈硅窛锛岀敓鎴愯鐩栧叏鍖哄煙鐨勫壊鑽夎矾寰勩��
+ // - 鍙傛暟锛�
+ // coordinates锛氬湴鍧楄竟鐣屽潗鏍囧瓧绗︿覆锛屾牸寮� "x1,y1;x2,y2;..."锛岃嚦灏�3涓偣锛屽崟浣嶄负绫炽��
+ // widthStr锛氬壊鑽夊搴︼紙瀛楃涓诧紝鍗曚綅绫筹級锛岀敤浜庣‘瀹氭壂鎻忕嚎闂磋窛銆�
+ // marginStr锛氬畨鍏ㄨ竟璺濓紙瀛楃涓诧紝鍗曚綅绫筹級锛岀敤浜庡皢鍦板潡杈圭晫鍚戝唴鏀剁缉锛岄伩鍏嶈创杈逛綔涓氥��
+ // - 杩斿洖鍊硷細List<PathSegment>锛屽叾涓� PathSegment.start/end 涓哄潗鏍囩偣锛宨sMowing 涓� true 琛ㄧず鍓茶崏娈碉紝false 琛ㄧず绌鸿蛋娈点��
+ // - 澶辫触鎯呭喌锛氬綋杈圭晫鐐逛笉瓒虫垨鍐呯缉鍚庡尯鍩熻繃灏忥紝杩斿洖绌哄垪琛ㄣ��
+ // - 浣跨敤绀轰緥锛�
+ // String boundary = "0,0;20,0;20,15;0,15";
+ // String width = "0.3";
+ // String margin = "0.5";
+ // List<YixinglujingNoObstacle.PathSegment> path =
+ // YixinglujingNoObstacle.planPath(boundary, width, margin);
public static List<PathSegment> planPath(String coordinates, String widthStr, String marginStr) {
List<Point> rawPoints = parseCoordinates(coordinates);
if (rawPoints.size() < 3) return new ArrayList<>();
diff --git a/src/zhuye/Shouye.java b/src/zhuye/Shouye.java
index dd3dfbf..cd33de7 100644
--- a/src/zhuye/Shouye.java
+++ b/src/zhuye/Shouye.java
@@ -31,7 +31,8 @@
import java.util.Map;
import java.util.Locale;
import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.function.Consumer;
+// import java.util.function.Consumer;
+import chuankou.DataListener;
import java.awt.geom.Point2D;
import publicway.Gpstoxuzuobiao;
@@ -110,19 +111,25 @@
private boolean pathPreviewActive;
- private final Consumer<String> serialLineListener = line -> {
- SwingUtilities.invokeLater(() -> {
- updateDataPacketCountLabel();
- // 濡傛灉鏀跺埌GGA鏁版嵁锛岀珛鍗虫洿鏂版嫋灏�
- if (line != null) {
- String trimmed = line.trim();
- if (trimmed.startsWith("$GNGGA") || trimmed.startsWith("$GPGGA") || trimmed.startsWith("$GBGGA")) {
- if (mapRenderer != null && !pathPreviewActive) {
- mapRenderer.forceUpdateIdleMowerTrail();
+ private final DataListener<String> serialLineListener = new DataListener<String>() {
+ @Override
+ public void accept(final String line) {
+ SwingUtilities.invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ updateDataPacketCountLabel();
+ // 濡傛灉鏀跺埌GGA鏁版嵁锛岀珛鍗虫洿鏂版嫋灏�
+ if (line != null) {
+ String trimmed = line.trim();
+ if (trimmed.startsWith("$GNGGA") || trimmed.startsWith("$GPGGA") || trimmed.startsWith("$GBGGA")) {
+ if (mapRenderer != null && !pathPreviewActive) {
+ mapRenderer.forceUpdateIdleMowerTrail();
+ }
+ }
}
}
- }
- });
+ });
+ }
};
private static final int FLOAT_ICON_SIZE = 32;
private JButton endDrawingButton;
@@ -193,6 +200,10 @@
scheduleIdentifierCheck();
}
+ private static boolean isFinite(double d) {
+ return !Double.isNaN(d) && !Double.isInfinite(d);
+ }
+
public static Shouye getInstance() {
return instance;
}
@@ -2555,7 +2566,7 @@
double lat = parseDMToDecimal(latest.getLatitude(), latest.getLatDirection());
double lon = parseDMToDecimal(latest.getLongitude(), latest.getLonDirection());
- if (!Double.isFinite(lat) || !Double.isFinite(lon)) {
+ if (!isFinite(lat) || !isFinite(lon)) {
discardLatestCoordinate(latest);
lastMowerCoordinate = latest;
return;
@@ -2563,7 +2574,7 @@
double[] local = convertLatLonToLocal(lat, lon, base[0], base[1]);
Point2D.Double candidate = new Point2D.Double(local[0], local[1]);
- if (!Double.isFinite(candidate.x) || !Double.isFinite(candidate.y)) {
+ if (!isFinite(candidate.x) || !isFinite(candidate.y)) {
discardLatestCoordinate(latest);
lastMowerCoordinate = latest;
return;
@@ -2661,7 +2672,7 @@
double x = parseMetersValue(device.getRealtimeX());
double y = parseMetersValue(device.getRealtimeY());
- if (!Double.isFinite(x) || !Double.isFinite(y)) {
+ if (!isFinite(x) || !isFinite(y)) {
JOptionPane.showMessageDialog(this, "褰撳墠瀹氫綅鏁版嵁鏃犳晥锛岃绋嶅悗鍐嶈瘯銆�", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
return -1;
}
@@ -2739,7 +2750,7 @@
}
double x = parseMetersValue(device.getRealtimeX());
double y = parseMetersValue(device.getRealtimeY());
- if (!Double.isFinite(x) || !Double.isFinite(y)) {
+ if (!isFinite(x) || !isFinite(y)) {
return false;
}
return isDuplicateHandheldPoint(x, y);
@@ -2752,7 +2763,7 @@
}
double x = parseMetersValue(device.getRealtimeX());
double y = parseMetersValue(device.getRealtimeY());
- return Double.isFinite(x) && Double.isFinite(y);
+ return isFinite(x) && isFinite(y);
}
private boolean isDuplicateHandheldPoint(double x, double y) {
@@ -3560,7 +3571,7 @@
double lat = parseDMToDecimal(latest.getLatitude(), latest.getLatDirection());
double lon = parseDMToDecimal(latest.getLongitude(), latest.getLonDirection());
- if (!Double.isFinite(lat) || !Double.isFinite(lon)) {
+ if (!isFinite(lat) || !isFinite(lon)) {
JOptionPane.showMessageDialog(this, "閲囬泦鐐瑰潗鏍囨棤鏁堬紝璇烽噸鏂伴噰闆嗐��", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
return false;
}
@@ -3717,7 +3728,7 @@
}
double baseLat = parseDMToDecimal(parts[0], parts[1]);
double baseLon = parseDMToDecimal(parts[2], parts[3]);
- if (!Double.isFinite(baseLat) || !Double.isFinite(baseLon)) {
+ if (!isFinite(baseLat) || !isFinite(baseLon)) {
return null;
}
return new double[]{baseLat, baseLon};
@@ -3783,7 +3794,7 @@
double centerX = (x1Sq * (y2 - y3) + x2Sq * (y3 - y1) + x3Sq * (y1 - y2)) / d;
double centerY = (x1Sq * (x3 - x2) + x2Sq * (x1 - x3) + x3Sq * (x2 - x1)) / d;
double radius = Math.hypot(centerX - x1, centerY - y1);
- if (!Double.isFinite(centerX) || !Double.isFinite(centerY) || !Double.isFinite(radius)) {
+ if (!isFinite(centerX) || !isFinite(centerY) || !isFinite(radius)) {
return null;
}
if (radius < 0.05) {
--
Gitblit v1.10.0