From 1175f5fbe8fd832943880bfc37c0e2a451a0688a Mon Sep 17 00:00:00 2001
From: 张世豪 <979909237@qq.com>
Date: 星期四, 25 十二月 2025 19:34:38 +0800
Subject: [PATCH] 删除了几个类优化了路径生成的逻辑
---
shoudongbianjie.properties | 6
/dev/null | 408 ------------------------
dikuai.properties | 10
src/dikuai/daohangyulan.java | 69 ---
src/lujing/MowingPathGenerationPage.java | 193 ++++------
src/zhangaiwu/AddDikuai.java | 15
set.properties | 8
src/gecaoji/lujingdraw.java | 197 +++--------
Obstacledge.properties | 2
src/dikuai/Dikuaiguanli.java | 108 +----
10 files changed, 176 insertions(+), 840 deletions(-)
diff --git a/Obstacledge.properties b/Obstacledge.properties
index 1209c73..6940857 100644
--- a/Obstacledge.properties
+++ b/Obstacledge.properties
@@ -1,5 +1,5 @@
# 鍓茶崏鏈哄湴鍧楅殰纰嶇墿閰嶇疆鏂囦欢
-# 鐢熸垚鏃堕棿锛�2025-12-25T16:37:39.564155300
+# 鐢熸垚鏃堕棿锛�2025-12-25T19:02:14.286913600
# 鍧愭爣绯伙細WGS84锛堝害鍒嗘牸寮忥級
# ============ 鍦板潡鍩哄噯绔欓厤缃� ============
diff --git a/dikuai.properties b/dikuai.properties
index 4958dad..2e6a691 100644
--- a/dikuai.properties
+++ b/dikuai.properties
@@ -1,8 +1,8 @@
#Dikuai Properties
-#Thu Dec 25 16:37:39 CST 2025
+#Thu Dec 25 19:02:14 CST 2025
LAND1.angleThreshold=-1
LAND1.baseStationCoordinates=3949.89151752,N,11616.79267501,E
-LAND1.boundaryCoordinates=-58.32,-476.37;85.99,-289.22;354.31,-329.80;293.43,-559.79
+LAND1.boundaryCoordinates=121.86,-611.32;130.67,-577.12;173.17,-587.48;167.47,-621.17
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.boundaryOriginalXY=-1
LAND1.boundaryPointInterval=-1
@@ -16,11 +16,11 @@
LAND1.mowingPattern=骞宠绾�
LAND1.mowingSafetyDistance=0.53
LAND1.mowingTrack=-1
-LAND1.mowingWidth=500
+LAND1.mowingWidth=50
LAND1.obstacleCoordinates=-1
-LAND1.plannedPath=353.646421,-330.235669;86.219211,-289.790692;-57.399120,-476.043693;293.049800,-559.155132;353.646421,-330.235669;352.359360,-335.097876;82.727142,-294.319420;79.235073,-298.848147;351.072299,-339.960083;349.785238,-344.822290;75.743005,-303.376874;72.250936,-307.905602;348.498177,-349.684497;347.211116,-354.546703;68.758867,-312.434329;65.266799,-316.963057;345.924055,-359.408910;344.636994,-364.271117;61.774730,-321.491784;58.282661,-326.020511;343.349933,-369.133324;342.062872,-373.995531;54.790593,-330.549239;51.298524,-335.077966;340.775811,-378.857738;339.488750,-383.719945;47.806455,-339.606694;44.314387,-344.135421;338.201689,-388.582152;336.914628,-393.444358;40.822318,-348.664148;37.330249,-353.192876;335.627567,-398.306565;334.340506,-403.168772;33.838181,-357.721603;30.346112,-362.250331;333.053445,-408.030979;331.766384,-412.893186;26.854043,-366.779058;23.361975,-371.307785;330.479324,-417.755393;329.192263,-422.617600;19.869906,-375.836513;16.377837,-380.365240;327.905202,-427.479807;326.618141,-432.342013;12.885769,-384.893968;9.393700,-389.422695;325.331080,-437.204220;324.044019,-442.066427;5.901631,-393.951422;2.409563,-398.480150;322.756958,-446.928634;321.469897,-451.790841;-1.082506,-403.008877;-4.574575,-407.537605;320.182836,-456.653048;318.895775,-461.515255;-8.066643,-412.066332;-11.558712,-416.595059;317.608714,-466.377461;316.321653,-471.239668;-15.050781,-421.123787;-18.542849,-425.652514;315.034592,-476.101875;313.747531,-480.964082;-22.034918,-430.181242;-25.526987,-434.709969;312.460470,-485.826289;311.173409,-490.688496;-29.019055,-439.238696;-32.511124,-443.767424;309.886348,-495.550703;308.599287,-500.412910;-36.003193,-448.296151;-39.495261,-452.824879;307.312226,-505.275116;306.025165,-510.137323;-42.987330,-457.353606;-46.479399,-461.882333;304.738104,-514.999530;303.451043,-519.861737;-49.971467,-466.411061;-53.463536,-470.939788;302.163982,-524.723944;300.876921,-529.586151;-56.955605,-475.468516;-6.018549,-488.228958;299.589860,-534.448358;298.302799,-539.310565;52.837057,-502.186981;111.692662,-516.145005;297.015738,-544.172771;295.728677,-549.034978;170.548268,-530.103028;229.403874,-544.061051;294.441616,-553.897185
+LAND1.plannedPath=122.510775,-610.918324;167.039920,-620.534901;172.565118,-587.878071;131.052742,-577.758818;122.510775,-610.918324;122.635602,-610.433754;167.123414,-620.041405;167.206909,-619.547910;122.760428,-609.949185;122.885254,-609.464616;167.290403,-619.054415;167.373897,-618.560919;123.010080,-608.980047;123.134906,-608.495477;167.457392,-618.067424;167.540886,-617.573928;123.259733,-608.010908;123.384559,-607.526339;167.624380,-617.080433;167.707875,-616.586937;123.509385,-607.041769;123.634211,-606.557200;167.791369,-616.093442;167.874863,-615.599947;123.759037,-606.072631;123.883864,-605.588061;167.958358,-615.106451;168.041852,-614.612956;124.008690,-605.103492;124.133516,-604.618923;168.125346,-614.119460;168.208841,-613.625965;124.258342,-604.134353;124.383168,-603.649784;168.292335,-613.132470;168.375829,-612.638974;124.507994,-603.165215;124.632821,-602.680645;168.459324,-612.145479;168.542818,-611.651983;124.757647,-602.196076;124.882473,-601.711507;168.626312,-611.158488;168.709807,-610.664993;125.007299,-601.226937;125.132125,-600.742368;168.793301,-610.171497;168.876795,-609.678002;125.256952,-600.257799;125.381778,-599.773229;168.960290,-609.184506;169.043784,-608.691011;125.506604,-599.288660;125.631430,-598.804091;169.127278,-608.197516;169.210773,-607.704020;125.756256,-598.319521;125.881083,-597.834952;169.294267,-607.210525;169.377761,-606.717029;126.005909,-597.350383;126.130735,-596.865813;169.461256,-606.223534;169.544750,-605.730038;126.255561,-596.381244;126.380387,-595.896675;169.628244,-605.236543;169.711739,-604.743048;126.505214,-595.412106;126.630040,-594.927536;169.795233,-604.249552;169.878727,-603.756057;126.754866,-594.442967;126.879692,-593.958398;169.962221,-603.262561;170.045716,-602.769066;127.004518,-593.473828;127.129344,-592.989259;170.129210,-602.275571;170.212704,-601.782075;127.254171,-592.504690;127.378997,-592.020120;170.296199,-601.288580;170.379693,-600.795084;127.503823,-591.535551;127.628649,-591.050982;170.463187,-600.301589;170.546682,-599.808094;127.753475,-590.566412;127.878302,-590.081843;170.630176,-599.314598;170.713670,-598.821103;128.003128,-589.597274;128.127954,-589.112704;170.797165,-598.327607;170.880659,-597.834112;128.252780,-588.628135;128.377606,-588.143566;170.964153,-597.340617;171.047648,-596.847121;128.502433,-587.658996;128.627259,-587.174427;171.131142,-596.353626;171.214636,-595.860130;128.752085,-586.689858;128.876911,-586.205288;171.298131,-595.366635;171.381625,-594.873139;129.001737,-585.720719;129.126564,-585.236150;171.465119,-594.379644;171.548614,-593.886149;129.251390,-584.751580;129.376216,-584.267011;171.632108,-593.392653;171.715602,-592.899158;129.501042,-583.782442;129.625868,-583.297872;171.799097,-592.405662;171.882591,-591.912167;129.750694,-582.813303;129.875521,-582.328734;171.966085,-591.418672;172.049580,-590.925176;130.000347,-581.844165;130.125173,-581.359595;172.133074,-590.431681;172.216568,-589.938185;130.249999,-580.875026;130.374825,-580.390457;172.300063,-589.444690;172.383557,-588.951195;130.499652,-579.905887;130.624478,-579.421318;172.467051,-588.457699;172.550546,-587.964204;130.749304,-578.936749;130.874130,-578.452179;157.378188,-584.176033
LAND1.returnPathCoordinates=-1
LAND1.returnPathRawCoordinates=-1
LAND1.returnPointCoordinates=-1
-LAND1.updateTime=2025-12-25 16\:37\:39
+LAND1.updateTime=2025-12-25 19\:02\:14
LAND1.userId=-1
diff --git a/set.properties b/set.properties
index 6ff9c73..ebc5f88 100644
--- a/set.properties
+++ b/set.properties
@@ -1,5 +1,5 @@
#Mower Configuration Properties - Updated
-#Thu Dec 25 16:37:55 CST 2025
+#Thu Dec 25 19:34:03 CST 2025
appVersion=-1
boundaryLengthVisible=false
currentWorkLandNumber=LAND1
@@ -8,12 +8,12 @@
handheldMarkerId=1872
idleTrailDurationSeconds=60
manualBoundaryDrawingMode=false
-mapScale=11.95
+mapScale=5.20
measurementModeEnabled=false
mowerId=6288
serialAutoConnect=true
serialBaudRate=115200
serialPortName=COM15
simCardNumber=-1
-viewCenterX=-148.00
-viewCenterY=424.51
+viewCenterX=-141.32
+viewCenterY=608.58
diff --git a/shoudongbianjie.properties b/shoudongbianjie.properties
index 1161d79..34d23f2 100644
--- a/shoudongbianjie.properties
+++ b/shoudongbianjie.properties
@@ -1,11 +1,11 @@
#\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)
-#Tue Dec 23 17:49:02 CST 2025
-boundaryCoordinates=-99.64,193.56;185.77,182.30;61.84,424.89;237.59,415.88;235.34,539.80;-26.03,544.31
+#Thu Dec 25 19:00:22 CST 2025
+boundaryCoordinates=121.86,-611.32;130.67,-577.12;173.17,-587.48;167.47,-621.17
email=789
language=zh
lastLoginTime=-1
password=123
-pointCount=6
+pointCount=4
registrationTime=-1
status=-1
userId=-1
diff --git a/src/dikuai/Dikuaiguanli.java b/src/dikuai/Dikuaiguanli.java
index a9b2a9a..b61db27 100644
--- a/src/dikuai/Dikuaiguanli.java
+++ b/src/dikuai/Dikuaiguanli.java
@@ -1,5 +1,4 @@
package dikuai;
-
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
@@ -21,8 +20,6 @@
import java.util.Objects;
import java.util.Properties;
import java.util.Locale;
-
-import lujing.Lunjingguihua;
import lujing.MowingPathGenerationPage;
import publicway.Fuzhibutton;
import publicway.Lookbutton;
@@ -1277,6 +1274,11 @@
public boolean savePlannedPath(Dikuai dikuai, String value) {
return saveFieldAndRefresh(dikuai, "plannedPath", value);
}
+
+ @Override
+ public boolean saveMowingSafetyDistance(Dikuai dikuai, String value) {
+ return saveFieldAndRefresh(dikuai, "mowingSafetyDistance", value);
+ }
};
// 鏄剧ず璺緞瑙勫垝椤甸潰
@@ -1319,14 +1321,8 @@
}
}
String modeValue = sanitizeValueOrNull(dikuai.getMowingPattern());
- String initialGenerated = attemptMowingPathPreview(
- boundaryValue,
- obstacleValue,
- widthValue,
- modeValue,
- this,
- false
- );
+ // 涓嶅啀棰勫厛鐢熸垚璺緞锛岀敱璺緞瑙勫垝椤甸潰澶勭悊
+ String initialGenerated = null;
showMowingPathDialog(dikuai, baseStationValue, boundaryValue, obstacleValue, widthValue, modeValue, initialGenerated);
}
@@ -1366,6 +1362,11 @@
public boolean savePlannedPath(Dikuai dikuai, String value) {
return saveFieldAndRefresh(dikuai, "plannedPath", value);
}
+
+ @Override
+ public boolean saveMowingSafetyDistance(Dikuai dikuai, String value) {
+ return saveFieldAndRefresh(dikuai, "mowingSafetyDistance", value);
+ }
};
// 浣跨敤鏂扮殑鐙珛椤甸潰绫�
@@ -1384,78 +1385,19 @@
dialog.setVisible(true);
}
- private String attemptMowingPathPreview(
- String boundaryInput,
- String obstacleInput,
- String widthCmInput,
- String modeInput,
- Component parentComponent,
- boolean showMessages) {
- String boundary = sanitizeValueOrNull(boundaryInput);
- if (boundary == null) {
- if (showMessages) {
- JOptionPane.showMessageDialog(parentComponent, "褰撳墠鍦板潡鏈缃竟鐣屽潗鏍囷紝鏃犳硶鐢熸垚璺緞", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
- }
- return null;
- }
- String rawWidth = widthCmInput != null ? widthCmInput.trim() : "";
- String widthStr = sanitizeWidthString(widthCmInput);
- if (widthStr == null) {
- if (showMessages) {
- String message = rawWidth.isEmpty() ? "璇峰厛璁剧疆鍓茶崏瀹藉害(鍘樼背)" : "鍓茶崏瀹藉害鏍煎紡涓嶆纭�";
- JOptionPane.showMessageDialog(parentComponent, message, "鎻愮ず", JOptionPane.WARNING_MESSAGE);
- }
- return null;
- }
- double widthCm;
- try {
- widthCm = Double.parseDouble(widthStr);
- } catch (NumberFormatException ex) {
- if (showMessages) {
- JOptionPane.showMessageDialog(parentComponent, "鍓茶崏瀹藉害鏍煎紡涓嶆纭�", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
- }
- return null;
- }
- if (widthCm <= 0) {
- if (showMessages) {
- JOptionPane.showMessageDialog(parentComponent, "鍓茶崏瀹藉害蹇呴』澶т簬0", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
- }
- return null;
- }
- double widthMeters = widthCm / 100.0d;
- String plannerWidth = BigDecimal.valueOf(widthMeters)
- .setScale(3, RoundingMode.HALF_UP)
- .stripTrailingZeros()
- .toPlainString();
- String obstacles = sanitizeValueOrNull(obstacleInput);
- if (obstacles != null) {
- obstacles = obstacles.replace("\r\n", " ").replace('\r', ' ').replace('\n', ' ');
- }
- String mode = normalizeExistingMowingPattern(modeInput);
- try {
- String generated = Lunjingguihua.generatePathFromStrings(boundary, obstacles, plannerWidth, mode);
- String trimmed = generated != null ? generated.trim() : "";
- if (trimmed.isEmpty()) {
- if (showMessages) {
- JOptionPane.showMessageDialog(parentComponent, "鏈敓鎴愭湁鏁堢殑鍓茶崏璺緞锛岃妫�鏌ュ湴鍧楁暟鎹�", "鎻愮ず", JOptionPane.INFORMATION_MESSAGE);
- }
- return null;
- }
- if (showMessages) {
- JOptionPane.showMessageDialog(parentComponent, "鍓茶崏璺緞宸茬敓鎴�", "鎴愬姛", JOptionPane.INFORMATION_MESSAGE);
- }
- return trimmed;
- } catch (IllegalArgumentException ex) {
- if (showMessages) {
- JOptionPane.showMessageDialog(parentComponent, "鐢熸垚鍓茶崏璺緞澶辫触: " + ex.getMessage(), "閿欒", JOptionPane.ERROR_MESSAGE);
- }
- } catch (Exception ex) {
- if (showMessages) {
- JOptionPane.showMessageDialog(parentComponent, "鐢熸垚鍓茶崏璺緞鏃跺彂鐢熷紓甯�: " + ex.getMessage(), "閿欒", JOptionPane.ERROR_MESSAGE);
- }
- }
- return null;
- }
+ /**
+ * 灏濊瘯鐢熸垚鍓茶崏璺緞棰勮
+ * 鐢ㄤ簬鍦ㄥ璇濇涓疄鏃堕瑙堟垨鐢熸垚璺緞锛屽寘鍚弬鏁版牎楠屽拰閿欒鎻愮ず閫昏緫
+ *
+ * @param boundaryInput 鍦板潡杈圭晫鍧愭爣瀛楃涓�
+ * @param obstacleInput 闅滅鐗╁潗鏍囧瓧绗︿覆
+ * @param widthCmInput 鍓茶崏瀹藉害锛堝帢绫筹級
+ * @param modeInput 鍓茶崏妯″紡锛堝钩琛�/铻烘棆锛�
+ * @param parentComponent 鐢ㄤ簬鏄剧ず鎻愮ず妗嗙殑鐖剁粍浠�
+ * @param showMessages 鏄惁鏄剧ず鎴愬姛/澶辫触鐨勬彁绀烘
+ * @return 鐢熸垚鐨勮矾寰勫瓧绗︿覆锛屽鏋滅敓鎴愬け璐ユ垨鏍¢獙鏈�氳繃鍒欒繑鍥� null
+ */
+
private JTextArea createInfoTextArea(String text, boolean editable, int rows) {
JTextArea area = new JTextArea(text);
diff --git a/src/dikuai/daohangyulan.java b/src/dikuai/daohangyulan.java
index 8d3bfaf..d7a3ffd 100644
--- a/src/dikuai/daohangyulan.java
+++ b/src/dikuai/daohangyulan.java
@@ -9,7 +9,6 @@
import java.util.ArrayList;
import zhuye.Shouye;
import zhuye.MapRenderer;
-import gecaoji.Device;
import gecaoji.Gecaoji;
import gecaoji.lujingdraw;
import publicway.buttonset;
@@ -90,73 +89,9 @@
return;
}
- // 2. 灏濊瘯閲嶆柊鐢熸垚瀹屾暣璺緞娈碉紙鍖呭惈鍥磋竟鍜屼綔涓氳矾寰勶級
- // 杩欐牱鍙互纭繚瀵艰埅棰勮鏃讹紝鍓茶崏鏈哄厛娌跨潃鍐呯缉杈圭晫璧颁竴鍦堬紝鍐嶈蛋鍓茶崏璺緞
- List<lujing.Lunjingguihua.PathSegment> segments = null;
- String boundaryCoords = dikuai.getBoundaryCoordinates();
- String mowingWidth = dikuai.getMowingBladeWidth(); // 娉ㄦ剰锛氳繖閲屽簲璇ョ敤鍓茶崏瀹藉害锛岃�屼笉鏄壊鍒�瀹藉害锛岄�氬父鏄竴鏍风殑
- // 濡傛灉娌℃湁鍓茶崏瀹藉害锛屽皾璇曚粠Device鑾峰彇
- if (mowingWidth == null || mowingWidth.trim().isEmpty() || "-1".equals(mowingWidth.trim())) {
- Device device = Device.getActiveDevice();
- if (device != null) {
- mowingWidth = device.getMowingWidth();
- }
- }
- // 濡傛灉杩樻槸娌℃湁锛屼娇鐢ㄩ粯璁ゅ��
- if (mowingWidth == null || mowingWidth.trim().isEmpty() || "-1".equals(mowingWidth.trim())) {
- mowingWidth = "0.34";
- }
-
- String safetyDistance = dikuai.getMowingSafetyDistance();
- String obstaclesCoords = dikuai.getObstacleCoordinates();
- String mowingPattern = dikuai.getMowingPattern();
-
- if (boundaryCoords != null && !boundaryCoords.trim().isEmpty() && !"-1".equals(boundaryCoords.trim())) {
- try {
- // 瑙f瀽鍓茶崏妯″紡
- String mode = "parallel"; // 榛樿骞宠妯″紡
- if (mowingPattern != null && !mowingPattern.trim().isEmpty()) {
- String pattern = mowingPattern.trim().toLowerCase();
- if ("1".equals(pattern) || "spiral".equals(pattern) || "铻烘棆寮�".equals(pattern) || "铻烘棆".equals(pattern)) {
- mode = "spiral";
- } else if ("parallel".equals(pattern) || "骞宠绾�".equals(pattern) || "骞宠".equals(pattern)) {
- mode = "parallel";
- }
- }
-
- // 璋冪敤璺緞瑙勫垝鐢熸垚瀹屾暣璺緞娈�
- segments = lujing.Lunjingguihua.generatePathSegments(
- boundaryCoords,
- obstaclesCoords != null ? obstaclesCoords : "",
- mowingWidth,
- safetyDistance,
- mode
- );
- } catch (Exception e) {
- // 濡傛灉閲嶆柊鐢熸垚澶辫触锛宻egments 涓� null
- System.err.println("瀵艰埅棰勮閲嶆柊鐢熸垚璺緞澶辫触: " + e.getMessage());
- }
- }
-
// 3. 鏋勫缓鏈�缁堝鑸矾寰勭偣鍒楄〃
- pathPoints = new ArrayList<>();
- if (segments != null && !segments.isEmpty()) {
- // 濡傛灉鎴愬姛鐢熸垚浜嗚矾寰勬锛屼娇鐢ㄨ矾寰勬鏋勫缓鐐瑰垪琛�
- // 杩欐牱鍖呭惈浜嗗洿杈硅矾寰勫拰浣滀笟璺緞锛屼互鍙婂畠浠箣闂寸殑杩炴帴
- lujing.Lunjingguihua.PathSegment firstSeg = segments.get(0);
- pathPoints.add(new Point2D.Double(firstSeg.start.x, firstSeg.start.y));
-
- for (lujing.Lunjingguihua.PathSegment seg : segments) {
- // 娣诲姞缁堢偣锛堣捣鐐瑰凡缁忓湪涓婁竴娆″惊鐜垨鍒濆鍖栨椂娣诲姞浜嗭級
- // 娉ㄦ剰锛氳繖閲屽亣璁捐矾寰勬鏄繛缁殑锛屾垨鑰呮垜浠彧鍏冲績绔偣
- // 濡傛灉娈典箣闂翠笉杩炵画锛堟湁绌鸿蛋锛夛紝generatePathSegments 搴旇宸茬粡鐢熸垚浜嗚繛鎺ユ锛坕sMowing=false锛�
- pathPoints.add(new Point2D.Double(seg.end.x, seg.end.y));
- }
- } else {
- // 濡傛灉鐢熸垚澶辫触锛屽洖閫�鍒颁娇鐢ㄥ師濮嬭В鏋愮殑璺緞鐐�
- // 杩欓�氬父鍙寘鍚綔涓氳矾寰勶紝鍙兘娌℃湁鍥磋竟
- pathPoints = rawPathPoints;
- }
+ // 鐩存帴浣跨敤瑙f瀽鍑烘潵鐨勮矾寰勭偣
+ pathPoints = rawPathPoints;
if (pathPoints == null || pathPoints.size() < 2) {
JOptionPane.showMessageDialog(null, "鏃犳硶鏋勫缓鏈夋晥鐨勫鑸矾寰�", "閿欒", JOptionPane.ERROR_MESSAGE);
diff --git a/src/gecaoji/lujingdraw.java b/src/gecaoji/lujingdraw.java
index 95ed85a..5d54008 100644
--- a/src/gecaoji/lujingdraw.java
+++ b/src/gecaoji/lujingdraw.java
@@ -1,5 +1,4 @@
package gecaoji; // 鍖呭0鏄�
-
import java.awt.BasicStroke; // 寮曞叆鍩虹鎻忚竟绫�
import java.awt.Color; // 寮曞叆棰滆壊绫�
import java.awt.Graphics2D; // 寮曞叆2D鍥惧舰涓婁笅鏂�
@@ -8,7 +7,6 @@
import java.awt.geom.Point2D; // 寮曞叆浜岀淮鐐圭被
import java.util.ArrayList; // 寮曞叆鍔ㄦ�佹暟缁�
import java.util.List; // 寮曞叆鍒楄〃鎺ュ彛
-import lujing.Lunjingguihua; // 寮曞叆璺緞瑙勫垝绫�
import org.locationtech.jts.geom.Coordinate; // 寮曞叆鍧愭爣绫�
import org.locationtech.jts.geom.GeometryFactory; // 寮曞叆鍑犱綍宸ュ巶绫�
import org.locationtech.jts.geom.Polygon; // 寮曞叆澶氳竟褰㈢被
@@ -24,7 +22,7 @@
// 钃濊壊 - 鐢ㄤ簬闈炰綔涓氱Щ鍔ㄨ矾寰�
private static final Color TRAVEL_PATH_COLOR = new Color(0, 0, 255);
// 铏氱嚎鏍峰紡 - 鐢ㄤ簬闈炰綔涓氱Щ鍔ㄨ矾寰�
- private static final float[] DASH_PATTERN = {10.0f, 5.0f};
+ private static final float[] DASH_PATTERN = {5.0f, 5.0f};
private static final Color START_POINT_COLOR = new Color(0, 0, 0, 220); // 璧风偣绠ご棰滆壊
private static final Color END_POINT_COLOR = new Color(0, 0, 0, 220); // 缁堢偣绠ご棰滆壊
@@ -107,62 +105,29 @@
drawInnerBoundary(g2d, boundaryCoords, safetyDistance, scale);
}
- // 2. 灏濊瘯閲嶆柊鐢熸垚璺緞娈典互鍖哄垎浣滀笟璺緞鍜岀Щ鍔ㄨ矾寰�
- List<Lunjingguihua.PathSegment> segments = null;
- if (boundaryCoords != null && mowingWidth != null) {
- try {
- // 瑙f瀽鍓茶崏妯″紡
- String mode = "parallel"; // 榛樿骞宠妯″紡
- if (mowingPattern != null && !mowingPattern.trim().isEmpty()) {
- String pattern = mowingPattern.trim().toLowerCase();
- if ("1".equals(pattern) || "spiral".equals(pattern) || "铻烘棆寮�".equals(pattern) || "铻烘棆".equals(pattern)) {
- mode = "spiral";
- } else if ("parallel".equals(pattern) || "骞宠绾�".equals(pattern) || "骞宠".equals(pattern)) {
- mode = "parallel";
- }
- }
- segments = Lunjingguihua.generatePathSegments(
- boundaryCoords,
- obstaclesCoords != null ? obstaclesCoords : "",
- mowingWidth,
- safetyDistance,
- mode
- );
- } catch (Exception e) {
- // 濡傛灉閲嶆柊鐢熸垚澶辫触锛屼娇鐢ㄧ畝鍗曠粯鍒舵柟寮�
- segments = null;
- }
- }
+ // 2. 鐩存帴缁樺埗璺緞锛堜笉鍐嶉噸鏂扮敓鎴愶級
+ Path2D polyline = new Path2D.Double(); // 鍒涘缓鎶樼嚎
+ boolean move = true; // 棣栨鏍囪
+ for (Point2D.Double point : path) { // 閬嶅巻鐐归泦
+ if (move) { // 绗竴娈�
+ polyline.moveTo(point.x, point.y); // 绉诲姩鍒伴鐐�
+ move = false; // 鏇存柊鏍囪
+ } else { // 鍚庣画娈�
+ polyline.lineTo(point.x, point.y); // 杩炵嚎鍒颁笅涓�鐐�
+ } // if缁撴潫
+ } // for缁撴潫
- // 3. 鏍规嵁鏄惁鏈夋淇℃伅閫夋嫨涓嶅悓鐨勭粯鍒舵柟寮�
- if (segments != null && !segments.isEmpty()) {
- // 鏈夋淇℃伅锛氬垎鍒粯鍒朵綔涓氳矾寰勫拰绉诲姩璺緞
- drawPathSegments(g2d, segments, scale, arrowScale);
- } else {
- // 鏃犳淇℃伅锛氫娇鐢ㄧ畝鍗曠粯鍒舵柟寮忥紙鎵�鏈夎矾寰勪娇鐢ㄤ綔涓氳矾寰勯鑹诧級
- Path2D polyline = new Path2D.Double(); // 鍒涘缓鎶樼嚎
- boolean move = true; // 棣栨鏍囪
- for (Point2D.Double point : path) { // 閬嶅巻鐐归泦
- if (move) { // 绗竴娈�
- polyline.moveTo(point.x, point.y); // 绉诲姩鍒伴鐐�
- move = false; // 鏇存柊鏍囪
- } else { // 鍚庣画娈�
- polyline.lineTo(point.x, point.y); // 杩炵嚎鍒颁笅涓�鐐�
- } // if缁撴潫
- } // for缁撴潫
-
- g2d.setStroke(new BasicStroke(strokeWidth, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); // 璁剧疆鍦嗗ご鍦嗚鎻忚竟
- g2d.setColor(MOWING_PATH_COLOR); // 璁剧疆浣滀笟璺緞棰滆壊锛堟彁棣欑孩70%閫忔槑搴︼級
- g2d.draw(polyline); // 缁樺埗鎶樼嚎
-
- Point2D.Double start = path.get(0); // 璧风偣
- Point2D.Double second = path.get(1); // 绗簩涓偣
- Point2D.Double end = path.get(path.size() - 1); // 缁堢偣
- Point2D.Double prev = path.get(path.size() - 2); // 鍊掓暟绗簩涓偣
+ g2d.setStroke(new BasicStroke(strokeWidth, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); // 璁剧疆鍦嗗ご鍦嗚鎻忚竟
+ g2d.setColor(MOWING_PATH_COLOR); // 璁剧疆浣滀笟璺緞棰滆壊锛堟彁棣欑孩70%閫忔槑搴︼級
+ g2d.draw(polyline); // 缁樺埗鎶樼嚎
+
+ Point2D.Double start = path.get(0); // 璧风偣
+ Point2D.Double second = path.get(1); // 绗簩涓偣
+ Point2D.Double end = path.get(path.size() - 1); // 缁堢偣
+ Point2D.Double prev = path.get(path.size() - 2); // 鍊掓暟绗簩涓偣
- drawArrowMarker(g2d, start, second, START_POINT_COLOR, scale, arrowScale); // 缁樺埗璧风偣绠ご
- drawArrowMarker(g2d, prev, end, END_POINT_COLOR, scale, arrowScale); // 缁樺埗缁堢偣绠ご
- }
+ drawArrowMarker(g2d, start, second, START_POINT_COLOR, scale, arrowScale); // 缁樺埗璧风偣绠ご
+ drawArrowMarker(g2d, prev, end, END_POINT_COLOR, scale, arrowScale); // 缁樺埗缁堢偣绠ご
g2d.setStroke(previous); // 鎭㈠鍘熸弿杈�
} // 鏂规硶缁撴潫
@@ -172,7 +137,7 @@
*/ // 鏂囨。娉ㄩ噴缁撴潫
private static void drawInnerBoundary(Graphics2D g2d, String boundaryCoords, String safetyDistanceStr, double scale) {
try {
- List<Coordinate> boundary = Lunjingguihua.parseCoordinates(boundaryCoords);
+ List<Coordinate> boundary = parseCoordinates(boundaryCoords);
if (boundary.size() < 4) {
return; // 杈圭晫鐐逛笉瓒�
}
@@ -258,89 +223,7 @@
}
} // 鏂规硶缁撴潫
- /** // 鏂囨。娉ㄩ噴寮�濮�
- * 缁樺埗璺緞娈碉紙鍖哄垎浣滀笟璺緞鍜岀Щ鍔ㄨ矾寰勶級
- */ // 鏂囨。娉ㄩ噴缁撴潫
- private static void drawPathSegments(Graphics2D g2d, List<Lunjingguihua.PathSegment> segments, double scale, double arrowScale) {
- if (segments == null || segments.isEmpty()) {
- return;
- }
-
- float strokeWidth = (float) (2.5 / Math.max(0.5, scale));
- Stroke previous = g2d.getStroke();
-
- // 鍒嗗埆缁樺埗浣滀笟璺緞鍜岀Щ鍔ㄨ矾寰�
- Path2D.Double mowingPath = new Path2D.Double();
- Path2D.Double travelPath = new Path2D.Double();
- boolean mowingStarted = false;
- boolean travelStarted = false;
-
- Coordinate lastMowingEnd = null;
- Coordinate lastTravelEnd = null;
-
- for (Lunjingguihua.PathSegment seg : segments) {
- if (seg == null || seg.start == null || seg.end == null) {
- continue;
- }
-
- if (seg.isMowing) {
- // 浣滀笟璺緞 - 鎻愰绾�70%閫忔槑搴�
- if (!mowingStarted || lastMowingEnd == null || !equals2D(lastMowingEnd, seg.start)) {
- mowingPath.moveTo(seg.start.x, seg.start.y);
- mowingStarted = true;
- }
- mowingPath.lineTo(seg.end.x, seg.end.y);
- lastMowingEnd = seg.end;
- } else {
- // 绉诲姩璺緞 - 钃濊壊铏氱嚎
- if (!travelStarted || lastTravelEnd == null || !equals2D(lastTravelEnd, seg.start)) {
- travelPath.moveTo(seg.start.x, seg.start.y);
- travelStarted = true;
- }
- travelPath.lineTo(seg.end.x, seg.end.y);
- lastTravelEnd = seg.end;
- }
- }
-
- // 缁樺埗浣滀笟璺緞
- if (mowingStarted) {
- g2d.setColor(MOWING_PATH_COLOR); // 鎻愰绾�70%閫忔槑搴�
- g2d.setStroke(new BasicStroke(strokeWidth, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
- g2d.draw(mowingPath);
- }
-
- // 缁樺埗绉诲姩璺緞锛堣櫄绾匡級
- if (travelStarted) {
- g2d.setColor(TRAVEL_PATH_COLOR); // 钃濊壊
- g2d.setStroke(new BasicStroke(strokeWidth, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 0, DASH_PATTERN, 0));
- g2d.draw(travelPath);
- }
-
- // 缁樺埗璧风偣鍜岀粓鐐圭澶�
- if (!segments.isEmpty()) {
- Lunjingguihua.PathSegment firstSeg = segments.get(0);
- if (firstSeg != null && firstSeg.start != null && segments.size() > 1) {
- Lunjingguihua.PathSegment secondSeg = segments.get(1);
- if (secondSeg != null && secondSeg.start != null) {
- Point2D.Double start = new Point2D.Double(firstSeg.start.x, firstSeg.start.y);
- Point2D.Double second = new Point2D.Double(secondSeg.start.x, secondSeg.start.y);
- drawArrowMarker(g2d, start, second, START_POINT_COLOR, scale, arrowScale);
- }
- }
-
- Lunjingguihua.PathSegment lastSeg = segments.get(segments.size() - 1);
- if (lastSeg != null && lastSeg.end != null && segments.size() > 1) {
- Lunjingguihua.PathSegment prevSeg = segments.get(segments.size() - 2);
- if (prevSeg != null && prevSeg.end != null) {
- Point2D.Double prev = new Point2D.Double(prevSeg.end.x, prevSeg.end.y);
- Point2D.Double end = new Point2D.Double(lastSeg.end.x, lastSeg.end.y);
- drawArrowMarker(g2d, prev, end, END_POINT_COLOR, scale, arrowScale);
- }
- }
- }
-
- g2d.setStroke(previous);
- } // 鏂规硶缁撴潫
+
/** // 鏂囨。娉ㄩ噴寮�濮�
* 姣旇緝涓や釜鍧愭爣鏄惁鐩稿悓锛堝宸級
@@ -392,4 +275,36 @@
g2d.setColor(color); // 璁剧疆棰滆壊
g2d.fill(arrow); // 濉厖绠ご
} // 鏂规硶缁撴潫
+
+ /**
+ * 瑙f瀽鍧愭爣瀛楃涓�
+ */
+ private static List<Coordinate> parseCoordinates(String s) {
+ List<Coordinate> list = new ArrayList<>();
+ if (s == null || s.trim().isEmpty()) return list;
+ // 澧炲己姝e垯锛氬鐞嗗彲鑳藉瓨鍦ㄧ殑澶氱鍒嗛殧绗�
+ String[] pts = s.split("[;\\s]+");
+ for (String p : pts) {
+ String trimmed = p.trim().replace("(", "").replace(")", "");
+ if (trimmed.isEmpty()) continue;
+ String[] xy = trimmed.split("[,锛孿\s]+");
+ if (xy.length >= 2) {
+ try {
+ double x = Double.parseDouble(xy[0].trim());
+ double y = Double.parseDouble(xy[1].trim());
+ // 杩囨护鏃犳晥鍧愭爣
+ if (!Double.isNaN(x) && !Double.isNaN(y) && !Double.isInfinite(x) && !Double.isInfinite(y)) {
+ list.add(new Coordinate(x, y));
+ }
+ } catch (NumberFormatException ex) {
+ // 蹇界暐瑙f瀽閿欒鐨勭偣
+ }
+ }
+ }
+ // 纭繚澶氳竟褰㈤棴鍚�
+ if (list.size() > 2 && !list.get(0).equals2D(list.get(list.size() - 1))) {
+ list.add(new Coordinate(list.get(0)));
+ }
+ return list;
+ }
} // 绫荤粨鏉�
diff --git a/src/lujing/Lunjingguihua.java b/src/lujing/Lunjingguihua.java
deleted file mode 100644
index e9329c1..0000000
--- a/src/lujing/Lunjingguihua.java
+++ /dev/null
@@ -1,417 +0,0 @@
-package lujing;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import org.locationtech.jts.geom.Coordinate;
-import org.locationtech.jts.geom.Envelope;
-import org.locationtech.jts.geom.Geometry;
-import org.locationtech.jts.geom.GeometryFactory;
-import org.locationtech.jts.geom.LineString;
-import org.locationtech.jts.geom.MultiLineString;
-import org.locationtech.jts.geom.Polygon;
-import org.locationtech.jts.geom.MultiPolygon;
-
-/**
- * 浼樺寲鍚庣殑鍓茶崏璺緞瑙勫垝绫�
- * 淇锛氳В鍐宠矾寰勮秴鍑哄湴鍧楄竟鐣岀殑闂锛屽鍔犲畨鍏ㄨ竟璺濊绠楃殑鍋ュ.鎬с��
- */
-public final class Lunjingguihua {
-
- private Lunjingguihua() {
- throw new IllegalStateException("Utility class");
- }
-
- /**
- * 鐢熸垚鍓茶崏璺緞娈靛垪琛紙5鍙傛暟鐗堟湰锛�
- * 鏍规嵁缁欏畾鐨勫杈瑰舰杈圭晫銆侀殰纰嶇墿銆佸壊鑽夊搴︺�佸畨鍏ㄨ窛绂诲拰妯″紡锛岀敓鎴愬畬鏁寸殑鍓茶崏璺緞瑙勫垝
- *
- * @param polygonCoords 澶氳竟褰㈣竟鐣屽潗鏍囧瓧绗︿覆锛屾牸寮忥細"x1,y1;x2,y2;x3,y3;..." 鎴� "(x1,y1);(x2,y2);..."
- * 鏀寔鍒嗗彿銆佺┖鏍笺�侀�楀彿绛夊绉嶅垎闅旂锛屼細鑷姩闂悎澶氳竟褰�
- * @param obstaclesCoords 闅滅鐗╁潗鏍囧瓧绗︿覆锛屾牸寮忥細"(x1,y1;x2,y2;...)" 澶氫釜闅滅鐗╃敤鎷彿鍒嗛殧
- * 濡傛灉涓虹┖鎴杗ull锛屽垯瑙嗕负鏃犻殰纰嶇墿
- * @param mowingWidth 鍓茶崏瀹藉害锛堢背锛夛紝瀛楃涓叉牸寮忥紝濡� "0.34" 琛ㄧず34鍘樼背
- * 濡傛灉涓虹┖鎴栨棤娉曡В鏋愶紝榛樿浣跨敤0.34绫�
- * @param safetyDistStr 瀹夊叏杈硅窛锛堢背锛夛紝瀛楃涓叉牸寮忥紝鐢ㄤ簬鍐呯缉杈圭晫鍜岄殰纰嶇墿澶栨墿
- * 濡傛灉涓虹┖鎴杗ull锛屽皢鑷姩璁$畻涓� width/2 + 0.2绫筹紝纭繚鍓茶崏鏈哄疄浣撳畬鍏ㄥ湪鐣屽唴
- * @param modeStr 璺緞妯″紡瀛楃涓诧紝"1" 鎴� "spiral" 琛ㄧず铻烘棆妯″紡锛屽叾浠栧�艰〃绀哄钩琛屾ā寮忥紙榛樿锛�
- * @return 璺緞娈靛垪琛紝姣忎釜PathSegment鍖呭惈璧风偣銆佺粓鐐瑰拰鏄惁涓哄壊鑽夋鐨勬爣蹇�
- * 濡傛灉澶氳竟褰㈠潗鏍囦笉瓒�4涓偣锛屽皢鎶涘嚭IllegalArgumentException寮傚父
- */
- public static List<PathSegment> generatePathSegments(String polygonCoords,
- String obstaclesCoords,
- String mowingWidth,
- String safetyDistStr,
- String modeStr) {
- List<Coordinate> polygon = parseCoordinates(polygonCoords);
- if (polygon.size() < 4) {
- throw new IllegalArgumentException("澶氳竟褰㈠潗鏍囨暟閲忎笉瓒�");
- }
-
- double width = parseDoubleOrDefault(mowingWidth, 0.34);
- // 濡傛灉浼犲叆绌猴紝璁句负 NaN锛屽湪 PlannerCore 涓繘琛屾櫤鑳借绠�
- double safetyDistance = parseDoubleOrDefault(safetyDistStr, Double.NaN);
-
- List<List<Coordinate>> obstacles = parseObstacles(obstaclesCoords);
- String mode = normalizeMode(modeStr);
-
- PlannerCore planner = new PlannerCore(polygon, width, safetyDistance, mode, obstacles);
- return planner.generate();
- }
-
- /**
- * 鐢熸垚鍓茶崏璺緞娈靛垪琛紙4鍙傛暟鐗堟湰锛�
- * 杩欐槸5鍙傛暟鐗堟湰鐨勯噸杞芥柟娉曪紝瀹夊叏璺濈鍙傛暟鑷姩璁句负null锛岀郴缁熷皢浣跨敤榛樿璁$畻鍊�
- * 涓昏鐢ㄤ簬閫傞厤 AddDikuai.java 绛変笉闇�瑕佹寚瀹氬畨鍏ㄨ窛绂荤殑鍦烘櫙
- *
- * @param polygonCoords 澶氳竟褰㈣竟鐣屽潗鏍囧瓧绗︿覆锛屾牸寮忥細"x1,y1;x2,y2;x3,y3;..."
- * @param obstaclesCoords 闅滅鐗╁潗鏍囧瓧绗︿覆锛屾牸寮忥細"(x1,y1;x2,y2;...)"锛屽彲涓虹┖
- * @param mowingWidth 鍓茶崏瀹藉害锛堢背锛夛紝瀛楃涓叉牸寮忥紝濡� "0.34"
- * @param modeStr 璺緞妯″紡瀛楃涓诧紝"1" 鎴� "spiral" 琛ㄧず铻烘棆妯″紡锛屽叾浠栧�艰〃绀哄钩琛屾ā寮�
- * @return 璺緞娈靛垪琛紝姣忎釜PathSegment鍖呭惈璧风偣銆佺粓鐐瑰拰鏄惁涓哄壊鑽夋鐨勬爣蹇�
- * 瀹夊叏璺濈灏嗚嚜鍔ㄨ绠椾负 width/2 + 0.2绫�
- */
- public static List<PathSegment> generatePathSegments(String polygonCoords,
- String obstaclesCoords,
- String mowingWidth,
- String modeStr) {
- return generatePathSegments(polygonCoords, obstaclesCoords, mowingWidth, null, modeStr);
- }
-
- // 5鍙傛暟璺緞瀛楃涓茬敓鎴�
- public static String generatePathFromStrings(String polygonCoords,
- String obstaclesCoords,
- String mowingWidth,
- String safetyDistStr,
- String modeStr) {
- List<PathSegment> segments = generatePathSegments(polygonCoords, obstaclesCoords, mowingWidth, safetyDistStr, modeStr);
- return formatPathSegments(segments);
- }
-
- // 4鍙傛暟璺緞瀛楃涓茬敓鎴愰噸杞�
- public static String generatePathFromStrings(String polygonCoords,
- String obstaclesCoords,
- String mowingWidth,
- String modeStr) {
- return generatePathFromStrings(polygonCoords, obstaclesCoords, mowingWidth, null, modeStr);
- }
-
- public static String formatPathSegments(List<PathSegment> path) {
- if (path == null || path.isEmpty()) return "";
- StringBuilder sb = new StringBuilder();
- Coordinate last = null;
- for (PathSegment segment : path) {
- if (last == null || !equals2D(last, segment.start)) {
- appendPoint(sb, segment.start);
- }
- appendPoint(sb, segment.end);
- last = segment.end;
- }
- return sb.toString();
- }
-
- public static List<Coordinate> parseCoordinates(String s) {
- List<Coordinate> list = new ArrayList<>();
- if (s == null || s.trim().isEmpty()) return list;
- // 澧炲己姝e垯锛氬鐞嗗彲鑳藉瓨鍦ㄧ殑澶氱鍒嗛殧绗�
- String[] pts = s.split("[;\\s]+");
- for (String p : pts) {
- String trimmed = p.trim().replace("(", "").replace(")", "");
- if (trimmed.isEmpty()) continue;
- String[] xy = trimmed.split("[,锛孿\s]+");
- if (xy.length >= 2) {
- try {
- double x = Double.parseDouble(xy[0].trim());
- double y = Double.parseDouble(xy[1].trim());
- // 杩囨护鏃犳晥鍧愭爣
- if (!Double.isNaN(x) && !Double.isNaN(y) && !Double.isInfinite(x) && !Double.isInfinite(y)) {
- list.add(new Coordinate(x, y));
- }
- } catch (NumberFormatException ex) {
- // 蹇界暐瑙f瀽閿欒鐨勭偣
- }
- }
- }
- // 纭繚澶氳竟褰㈤棴鍚�
- if (list.size() > 2 && !list.get(0).equals2D(list.get(list.size() - 1))) {
- list.add(new Coordinate(list.get(0)));
- }
- return list;
- }
-
- public static List<List<Coordinate>> parseObstacles(String str) {
- List<List<Coordinate>> obs = new ArrayList<>();
- if (str == null || str.trim().isEmpty()) return obs;
- java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("\\(([^)]+)\\)");
- java.util.regex.Matcher matcher = pattern.matcher(str);
- while (matcher.find()) {
- List<Coordinate> coords = parseCoordinates(matcher.group(1));
- if (coords.size() >= 3) obs.add(coords);
- }
- if (obs.isEmpty()) {
- List<Coordinate> coords = parseCoordinates(str);
- if (coords.size() >= 3) obs.add(coords);
- }
- return obs;
- }
-
- private static double parseDoubleOrDefault(String value, double defaultValue) {
- if (value == null || value.trim().isEmpty()) return defaultValue;
- try {
- return Double.parseDouble(value.trim());
- } catch (NumberFormatException ex) {
- return defaultValue;
- }
- }
-
- private static String normalizeMode(String modeStr) {
- return (modeStr != null && (modeStr.equals("1") || modeStr.equalsIgnoreCase("spiral"))) ? "spiral" : "parallel";
- }
-
- private static boolean equals2D(Coordinate a, Coordinate b) {
- if (a == b) return true;
- if (a == null || b == null) return false;
- return a.distance(b) < 1e-4;
- }
-
- private static void appendPoint(StringBuilder sb, Coordinate point) {
- if (sb.length() > 0) sb.append(";");
- sb.append(String.format("%.3f,%.3f", point.x, point.y));
- }
-
- public static final class PathSegment {
- public Coordinate start, end;
- public boolean isMowing;
- public boolean isStartPoint, isEndPoint;
-
- public PathSegment(Coordinate start, Coordinate end, boolean isMowing) {
- this.start = start;
- this.end = end;
- this.isMowing = isMowing;
- }
-
- public void setAsStartPoint() { this.isStartPoint = true; }
- public void setAsEndPoint() { this.isEndPoint = true; }
- }
-
- public static final class PlannerCore {
- private final List<Coordinate> polygon;
- private final double width;
- private final double safetyDistance;
- private final String mode;
- private final List<List<Coordinate>> obstacles;
- private final GeometryFactory gf = new GeometryFactory();
-
- // 1. 鍏ㄥ弬鏁版瀯閫犲嚱鏁�
- public PlannerCore(List<Coordinate> polygon, double width, double safetyDistance, String mode, List<List<Coordinate>> obstacles) {
- this.polygon = polygon;
- this.width = width;
- this.mode = mode;
- this.obstacles = obstacles != null ? obstacles : new ArrayList<>();
-
- // FIX: 澧炲姞榛樿瀹夊叏杈硅窛銆傚師閫昏緫涓� width/2 + 0.05锛屽鏄撻�犳垚璇樊鍑虹晫銆�
- // 鐜版敼涓� width/2 + 0.2 (20cm浣欓噺)锛岀‘淇濆壊鑽夋満瀹炰綋瀹屽叏鍦ㄧ晫鍐呫��
- if (Double.isNaN(safetyDistance) || safetyDistance <= 0) {
- this.safetyDistance = (width / 2.0) + 0.20;
- } else {
- this.safetyDistance = safetyDistance;
- }
- }
-
- // 2. 4鍙傛暟鏋勯�犲嚱鏁�
- public PlannerCore(List<Coordinate> polygon, double width, String mode, List<List<Coordinate>> obstacles) {
- this(polygon, width, Double.NaN, mode, obstacles);
- }
-
- public List<PathSegment> generate() {
- if ("spiral".equals(mode)) return generateSpiralPath();
- return generateDividedParallelPath();
- }
-
- public List<PathSegment> generateParallelPath() {
- return generateDividedParallelPath();
- }
-
- private List<PathSegment> generateDividedParallelPath() {
- List<PathSegment> totalPath = new ArrayList<>();
- Geometry safeArea = buildSafeArea();
-
- if (safeArea == null || safeArea.isEmpty()) return totalPath;
-
- List<Polygon> subRegions = new ArrayList<>();
- if (safeArea instanceof Polygon) subRegions.add((Polygon) safeArea);
- else if (safeArea instanceof MultiPolygon) {
- for (int i = 0; i < safeArea.getNumGeometries(); i++) {
- subRegions.add((Polygon) safeArea.getGeometryN(i));
- }
- }
-
- for (Polygon region : subRegions) {
- if (region.isEmpty()) continue;
-
- Vector2D baseDir = calculateMainDirection(region);
- Vector2D perp = baseDir.rotate90CCW();
- Envelope env = region.getEnvelopeInternal();
-
- double minProj = Double.MAX_VALUE, maxProj = -Double.MAX_VALUE;
- Coordinate[] coords = region.getCoordinates();
- for (Coordinate c : coords) {
- double p = perp.dot(new Vector2D(c));
- minProj = Math.min(minProj, p);
- maxProj = Math.max(maxProj, p);
- }
-
- int lineIdx = 0;
- // 浠� minProj + width/2 寮�濮嬶紝纭繚绗竴鏉$嚎鍦ㄥ畨鍏ㄥ尯鍩熷唴渚�
- for (double d = minProj + width / 2.0; d <= maxProj; d += width) {
- LineString scanLine = createScanLine(d, perp, baseDir, env);
-
- try {
- Geometry intersections = region.intersection(scanLine);
- if (intersections.isEmpty()) continue;
-
- List<LineString> parts = extractLineStrings(intersections);
-
- // 鎸夌収鎵弿鏂瑰悜鎺掑簭锛屽鐞嗗嚬澶氳竟褰㈡垨闅滅鐗�
- parts.sort((a, b) -> Double.compare(
- baseDir.dot(new Vector2D(a.getCoordinateN(0))),
- baseDir.dot(new Vector2D(b.getCoordinateN(0)))
- ));
-
- // 铔囧舰璺緞锛氬鏁拌鍙嶈浆
- if (lineIdx % 2 != 0) Collections.reverse(parts);
-
- for (LineString part : parts) {
- Coordinate[] cs = part.getCoordinates();
- if (cs.length < 2) continue;
-
- if (lineIdx % 2 != 0) reverseArray(cs);
-
- // 纭繚鐐瑰潗鏍囨湁鏁�
- totalPath.add(new PathSegment(cs[0], cs[cs.length - 1], true));
- }
- lineIdx++;
- } catch (Exception e) {
- // 蹇界暐鏋佸叾缃曡鐨勬嫇鎵戝紓甯革紝闃叉宕╂簝
- }
- }
- }
- return markStartEnd(totalPath);
- }
-
- private Geometry buildSafeArea() {
- try {
- Polygon poly = gf.createPolygon(gf.createLinearRing(polygon.toArray(new Coordinate[0])));
-
- // 1. 鍒濆淇锛氬鐞嗚嚜鐩镐氦
- if (!poly.isValid()) poly = (Polygon) poly.buffer(0);
-
- // 2. 鍐呯缉鐢熸垚瀹夊叏鍖哄煙
- Geometry safe = poly.buffer(-safetyDistance);
-
- // 3. 浜屾淇锛氳礋缂撳啿鍚庡彲鑳戒骇鐢熶笉瑙勮寖鍑犱綍浣�
- if (!safe.isValid()) safe = safe.buffer(0);
-
- // 4. 澶勭悊闅滅鐗�
- for (List<Coordinate> obsCoords : obstacles) {
- if (obsCoords.size() < 3) continue;
- try {
- Polygon obs = gf.createPolygon(gf.createLinearRing(obsCoords.toArray(new Coordinate[0])));
- if (!obs.isValid()) obs = (Polygon) obs.buffer(0);
- // 闅滅鐗╁鎵╁畨鍏ㄨ窛绂�
- safe = safe.difference(obs.buffer(safetyDistance));
- } catch (Exception e) {
- // 蹇界暐閿欒鐨勯殰纰嶇墿鏁版嵁
- }
- }
-
- // 5. 鏈�缁堟竻鐞�
- if (!safe.isValid()) safe = safe.buffer(0);
- return safe;
- } catch (Exception e) {
- // 濡傛灉鍑犱綍鏋勫缓瀹屽叏澶辫触锛岃繑鍥炵┖
- return gf.createPolygon();
- }
- }
-
- private Vector2D calculateMainDirection(Polygon region) {
- Coordinate[] coords = region.getExteriorRing().getCoordinates();
- double maxLen = -1;
- Vector2D bestDir = new Vector2D(1, 0);
-
- // 瀵绘壘鏈�闀胯竟浣滀负涓绘柟鍚戯紝鍑忓皯杞集娆℃暟
- for (int i = 0; i < coords.length - 1; i++) {
- double d = coords[i].distance(coords[i+1]);
- if (d > maxLen && d > 1e-4) {
- maxLen = d;
- bestDir = new Vector2D(coords[i+1].x - coords[i].x, coords[i+1].y - coords[i].y).normalize();
- }
- }
- return bestDir;
- }
-
- private List<LineString> extractLineStrings(Geometry geom) {
- List<LineString> list = new ArrayList<>();
- if (geom instanceof LineString) list.add((LineString) geom);
- else if (geom instanceof MultiLineString) {
- for (int i = 0; i < geom.getNumGeometries(); i++) list.add((LineString) geom.getGeometryN(i));
- } else if (geom instanceof org.locationtech.jts.geom.GeometryCollection) {
- for (int i = 0; i < geom.getNumGeometries(); i++) {
- if (geom.getGeometryN(i) instanceof LineString) {
- list.add((LineString) geom.getGeometryN(i));
- }
- }
- }
- return list;
- }
-
- private LineString createScanLine(double dist, Vector2D perp, Vector2D baseDir, Envelope env) {
- // 鎵╁ぇ鎵弿绾块暱搴︼紝纭繚瑕嗙洊鏃嬭浆鍚庣殑澶氳竟褰�
- double size = Math.max(env.getWidth(), env.getHeight());
- // 澶勭悊閫�鍖栧寘鍥寸洅
- if (size < 1.0) size = 1000.0;
-
- double len = size * 3.0; // 3鍊嶅昂瀵哥‘淇濊冻澶熼暱
-
- // 涓績鐐硅绠楋細鍦ㄥ瀭鐩存柟鍚戜笂璺濈鍘熺偣 dist 鐨勪綅缃�
- Vector2D center = perp.mul(dist);
-
- return gf.createLineString(new Coordinate[]{
- new Coordinate(center.x + baseDir.x * len, center.y + baseDir.y * len),
- new Coordinate(center.x - baseDir.x * len, center.y - baseDir.y * len)
- });
- }
-
- private List<PathSegment> markStartEnd(List<PathSegment> path) {
- if (!path.isEmpty()) {
- path.get(0).setAsStartPoint();
- path.get(path.size() - 1).setAsEndPoint();
- }
- return path;
- }
-
- private void reverseArray(Coordinate[] arr) {
- for (int i = 0; i < arr.length / 2; i++) {
- Coordinate t = arr[i];
- arr[i] = arr[arr.length - 1 - i];
- arr[arr.length - 1 - i] = t;
- }
- }
-
- List<PathSegment> generateSpiralPath() { return new ArrayList<>(); }
- }
-
- private static final class Vector2D {
- final double x, y;
- Vector2D(double x, double y) { this.x = x; this.y = y; }
- Vector2D(Coordinate c) { this.x = c.x; this.y = c.y; }
-
- Vector2D normalize() {
- double len = Math.hypot(x, y);
- return len < 1e-9 ? new Vector2D(1, 0) : new Vector2D(x / len, y / len);
- }
- Vector2D rotate90CCW() { return new Vector2D(-y, x); }
- double dot(Vector2D v) { return x * v.x + y * v.y; }
- Vector2D mul(double k) { return new Vector2D(x * k, y * k); }
- }
-}
\ No newline at end of file
diff --git a/src/lujing/MowingPathGenerationPage.java b/src/lujing/MowingPathGenerationPage.java
index 853c9ce..8bd2ba9 100644
--- a/src/lujing/MowingPathGenerationPage.java
+++ b/src/lujing/MowingPathGenerationPage.java
@@ -1,25 +1,12 @@
package lujing;
-
import javax.swing.*;
import javax.swing.SwingUtilities;
import java.awt.*;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
import java.math.BigDecimal;
import java.math.RoundingMode;
-import java.util.ArrayList;
import java.util.List;
-
import dikuai.Dikuai;
-import lujing.Lunjingguihua;
-import lujing.ObstaclePathPlanner;
-import lujing.Qufenxingzhuang;
-import lujing.AoxinglujingNoObstacle;
-import lujing.YixinglujingNoObstacle;
import publicway.Fuzhibutton;
-import lujing.AoxinglujingHaveObstacel;
-import lujing.YixinglujingHaveObstacel;
-import org.locationtech.jts.geom.Coordinate;
import gecaoji.Device;
import java.util.Locale;
@@ -49,6 +36,7 @@
boolean saveObstacleCoordinates(Dikuai dikuai, String baseStationValue, String obstacleValue);
boolean saveMowingWidth(Dikuai dikuai, String value);
boolean savePlannedPath(Dikuai dikuai, String value);
+ boolean saveMowingSafetyDistance(Dikuai dikuai, String value);
}
private final Dikuai dikuai;
@@ -262,30 +250,35 @@
* 棰勮璺緞
*/
private void previewPath() {
- // 鍏堜繚瀛樺綋鍓嶈矾寰勫埌鍦板潡锛堜复鏃朵繚瀛橈紝鐢ㄤ簬棰勮锛�
- String pathNormalized = normalizeCoordinateInput(pathArea.getText());
+ // 鐩存帴浠庢枃鏈煙鑾峰彇璺緞鏁版嵁
+ String rawPath = pathArea.getText();
+ String pathNormalized = normalizeCoordinateInput(rawPath);
+
if (!"-1".equals(pathNormalized)) {
+ // 瑙勮寖鍖栬矾寰勬暟鎹細鏀寔鎹㈣銆佺┖鏍肩瓑鍒嗛殧绗�
pathNormalized = pathNormalized
.replace("\r\n", ";")
.replace('\r', ';')
.replace('\n', ';')
- .replaceAll(";+", ";")
- .replaceAll("\\s*;\\s*", ";")
- .trim();
+ .replaceAll("\\s+", ";") // 灏嗘墍鏈夌┖鐧藉瓧绗︽浛鎹负鍒嗗彿
+ .replaceAll(";+", ";"); // 鍚堝苟杩炵画鍒嗗彿
+
+ // 鍘婚櫎棣栧熬鍒嗗彿
+ if (pathNormalized.startsWith(";")) pathNormalized = pathNormalized.substring(1);
+ if (pathNormalized.endsWith(";")) pathNormalized = pathNormalized.substring(0, pathNormalized.length() - 1);
+
if (pathNormalized.isEmpty()) {
pathNormalized = "-1";
}
}
if ("-1".equals(pathNormalized)) {
- JOptionPane.showMessageDialog(this, "璇峰厛鐢熸垚鍓茶崏璺緞", "鎻愮ず", JOptionPane.INFORMATION_MESSAGE);
+ JOptionPane.showMessageDialog(this, "璇峰厛鐢熸垚鍓茶崏璺緞鎴栧湪鏂囨湰妗嗕腑杈撳叆鏈夋晥鍧愭爣", "鎻愮ず", JOptionPane.INFORMATION_MESSAGE);
return;
}
- // 涓存椂淇濆瓨璺緞鍒板湴鍧楀璞★紙涓嶆寔涔呭寲锛�
- if (saveCallback != null) {
- saveCallback.savePlannedPath(dikuai, pathNormalized);
- }
+ // 娉ㄦ剰锛氶瑙堟椂涓嶈嚜鍔ㄤ繚瀛樿矾寰勫埌鍦板潡锛屼粎浣跨敤鏂囨湰鍩熶腑鐨勬暟鎹繘琛岄瑙�
+ // 鍙湁鐐瑰嚮"淇濆瓨璺緞"鎸夐挳鏃舵墠鎸佷箙鍖栨暟鎹�
// 淇濆瓨褰撳墠椤甸潰鐘舵�侊紝鐢ㄤ簬杩斿洖鏃舵仮澶�
String currentBaseStation = baseStationField.getText();
@@ -302,12 +295,16 @@
String boundaryInput = normalizeCoordinateInput(boundaryArea.getText());
final String boundary;
if (!"-1".equals(boundaryInput)) {
- String processed = boundaryInput.replace("\r\n", ";")
+ String processed = boundaryInput
+ .replace("\r\n", ";")
.replace('\r', ';')
.replace('\n', ';')
- .replaceAll(";+", ";")
- .replaceAll("\\s*;\\s*", ";")
- .trim();
+ .replaceAll("\\s+", ";")
+ .replaceAll(";+", ";");
+
+ if (processed.startsWith(";")) processed = processed.substring(1);
+ if (processed.endsWith(";")) processed = processed.substring(0, processed.length() - 1);
+
if (processed.isEmpty()) {
boundary = dikuai.getBoundaryCoordinates();
} else {
@@ -457,6 +454,12 @@
dikuai.setMowingWidth(widthNormalized);
dikuai.setPlannedPath(pathNormalized);
dikuai.setObstacleCoordinates(obstacleNormalized);
+
+ // 鑾峰彇骞舵洿鏂板畨鍏ㄨ窛绂�
+ String safetyDistance = getSafetyDistanceString();
+ if (safetyDistance != null) {
+ dikuai.setMowingSafetyDistance(safetyDistance);
+ }
}
// 璋冪敤鍥炶皟淇濆瓨鏁版嵁
@@ -481,6 +484,15 @@
JOptionPane.showMessageDialog(this, "鏃犳硶淇濆瓨鍓茶崏璺緞", "閿欒", JOptionPane.ERROR_MESSAGE);
return;
}
+
+ // 淇濆瓨瀹夊叏璺濈
+ String safetyDistance = getSafetyDistanceString();
+ if (safetyDistance != null) {
+ if (!saveCallback.saveMowingSafetyDistance(dikuai, safetyDistance)) {
+ JOptionPane.showMessageDialog(this, "鏃犳硶淇濆瓨鍓茶崏瀹夊叏璺濈", "閿欒", JOptionPane.ERROR_MESSAGE);
+ return;
+ }
+ }
}
JOptionPane.showMessageDialog(this, "鍓茶崏璺緞宸蹭繚瀛�", "鎴愬姛", JOptionPane.INFORMATION_MESSAGE);
@@ -543,7 +555,20 @@
String obstacles = sanitizeValueOrNull(obstacleInput);
if (obstacles != null) {
- obstacles = obstacles.replace("\r\n", " ").replace('\r', ' ').replace('\n', ' ');
+ // 鎸夌収鐢ㄦ埛瑕佹眰锛屽涓殰纰嶇墿涔嬮棿鐢� $ 绗﹀彿鍒嗛殧
+ // 濡傛灉杈撳叆涓寘鍚� $锛屽垯淇濈暀 $锛屽惁鍒欏皢鎹㈣绗︽浛鎹负 $
+ if (obstacles.contains("$")) {
+ // 宸茬粡鏄� $ 鍒嗛殧鐨勬牸寮忥紝鍙渶娓呯悊鎹㈣绗�
+ obstacles = obstacles.replace("\r\n", "").replace('\r', ' ').replace('\n', ' ');
+ } else {
+ // 灏濊瘯灏嗘崲琛岀杞崲涓� $锛屾垨鑰呭鏋滄槸涓�琛屽垯淇濇寔鍘熸牱
+ // 杩欓噷鍋囪鐢ㄦ埛鍙兘鐢ㄦ崲琛屽垎闅斿涓殰纰嶇墿
+ // 浣嗘牴鎹渶姹傛弿杩帮紝浼间箮杈撳叆鏈韩灏卞簲璇ユ槸 $ 鍒嗛殧鐨勶紝鎴栬�呮垜浠渶瑕佸鐞嗘垚 $ 鍒嗛殧
+ // 涓轰簡鍏煎鎬э紝濡傛灉鐢ㄦ埛杈撳叆鐨勬槸鎹㈣鍒嗛殧鐨勫涓殰纰嶇墿锛屾垜浠皢鍏惰浆鎹负 $ 鍒嗛殧
+ // 浣嗛�氬父闅滅鐗╁潗鏍囨槸涓�涓插潗鏍囩偣锛屽鏋滅敤鎴锋病鏈夋樉寮忕敤 $ 鍒嗛殧锛屾垜浠緢闅惧尯鍒嗘槸鍚屼竴涓殰纰嶇墿鐨勭偣杩樻槸澶氫釜闅滅鐗�
+ // 鍥犳锛岃繖閲屼富瑕佸鐞嗘竻鐞嗗伐浣滐紝鍏蜂綋鐨勮В鏋愰�昏緫鍦ㄥ悇瀹炵幇绫讳腑澶勭悊
+ obstacles = obstacles.replace("\r\n", " ").replace('\r', ' ').replace('\n', ' ');
+ }
}
// 鑾峰彇瀹夊叏璺濈
@@ -564,19 +589,10 @@
int grassType = shapeJudger.judgeGrassType(boundary);
// grassType: 0=鏃犳硶鍒ゆ柇, 1=鍑稿舰, 2=寮傚舰
- // 瑙f瀽闅滅鐗╁垪琛�
- List<List<Coordinate>> obstacleList = Lunjingguihua.parseObstacles(obstacles);
- if (obstacleList == null) {
- obstacleList = new ArrayList<>();
- }
-
- // 鍒ゆ柇鏄惁鏈夋湁鏁堢殑闅滅鐗╋細鍙湁褰撹В鏋愭垚鍔熶笖鍒楄〃涓嶄负绌烘椂锛屾墠璁や负鏈夐殰纰嶇墿
- boolean hasValidObstacles = !obstacleList.isEmpty();
-
String generated = null;
// 2. 鏍规嵁鍦板潡绫诲瀷鍜屾槸鍚︽湁闅滅鐗╋紝璋冪敤涓嶅悓鐨勮矾寰勭敓鎴愮被
- if (!hasValidObstacles) {
+ if (!hasObstacleInput) {
// 鏃犻殰纰嶇墿鐨勬儏鍐�
if (grassType == 1) {
// 鍑稿舰鍦板潡锛屾棤闅滅鐗� -> 璋冪敤 AoxinglujingNoObstacle
@@ -585,100 +601,43 @@
generated = formatAoxingPathSegments(segments);
} else if (grassType == 2) {
// 寮傚舰鍦板潡锛屾棤闅滅鐗� -> 璋冪敤 YixinglujingNoObstacle
- // 娉ㄦ剰锛氬鏋滆绫昏繕娌℃湁瀹炵幇锛岃繖閲屼細鎶涘嚭寮傚父鎴栬繑鍥瀗ull
- try {
- // 璋冪敤 YixinglujingNoObstacle.planPath 鑾峰彇璺緞娈靛垪琛�
- List<YixinglujingNoObstacle.PathSegment> segments =
- YixinglujingNoObstacle.planPath(boundary, plannerWidth, safetyMarginStr);
- // 鏍煎紡鍖栬矾寰勬鍒楄〃涓哄瓧绗︿覆
- generated = formatYixingPathSegments(segments);
- } catch (Exception e) {
- // 濡傛灉绫昏繕娌℃湁瀹炵幇锛屼娇鐢ㄥ師鏉ョ殑鏂规硶浣滀负鍚庡
- if (showMessages) {
- System.err.println("YixinglujingNoObstacle 灏氭湭瀹炵幇锛屼娇鐢ㄩ粯璁ゆ柟娉�: " + e.getMessage());
- }
- generated = Lunjingguihua.generatePathFromStrings(
- boundary, obstacles != null ? obstacles : "", plannerWidth, safetyMarginStr, mode);
- }
+ // 璋冪敤 YixinglujingNoObstacle.planPath 鑾峰彇璺緞娈靛垪琛�
+ List<YixinglujingNoObstacle.PathSegment> segments =
+ YixinglujingNoObstacle.planPath(boundary, plannerWidth, safetyMarginStr);
+ // 鏍煎紡鍖栬矾寰勬鍒楄〃涓哄瓧绗︿覆
+ generated = formatYixingPathSegments(segments);
} else {
- // 鏃犳硶鍒ゆ柇鍦板潡绫诲瀷锛屼娇鐢ㄥ師鏉ョ殑鏂规硶浣滀负鍚庡
+ // 鏃犳硶鍒ゆ柇鍦板潡绫诲瀷锛岄粯璁ゆ寜鍑稿舰澶勭悊鎴栨彁绀�
if (showMessages) {
- JOptionPane.showMessageDialog(parentComponent, "鏃犳硶鍒ゆ柇鍦板潡绫诲瀷锛屼娇鐢ㄩ粯璁よ矾寰勭敓鎴愭柟娉�",
+ JOptionPane.showMessageDialog(parentComponent, "鏃犳硶鍒ゆ柇鍦板潡绫诲瀷锛屽皾璇曟寜鍑稿舰鍦板潡澶勭悊",
"鎻愮ず", JOptionPane.WARNING_MESSAGE);
}
- generated = Lunjingguihua.generatePathFromStrings(
- boundary, obstacles != null ? obstacles : "", plannerWidth, safetyMarginStr, mode);
+ List<AoxinglujingNoObstacle.PathSegment> segments =
+ AoxinglujingNoObstacle.planPath(boundary, plannerWidth, safetyMarginStr);
+ generated = formatAoxingPathSegments(segments);
}
} else {
// 鏈夐殰纰嶇墿鐨勬儏鍐�
if (grassType == 1) {
// 鍑稿舰鍦板潡锛屾湁闅滅鐗� -> 璋冪敤 AoxinglujingHaveObstacel
- try {
- // 鍋囪 AoxinglujingHaveObstacel 鏈夌被浼肩殑鏂规硶绛惧悕
- List<AoxinglujingHaveObstacel.PathSegment> segments = AoxinglujingHaveObstacel.planPath(boundary, obstacles, plannerWidth, safetyMarginStr);
- generated = formatAoxingHaveObstaclePathSegments(segments);
- } catch (Exception e) {
- // 濡傛灉绫昏繕娌℃湁瀹炵幇锛屼娇鐢ㄥ師鏉ョ殑鏂规硶浣滀负鍚庡
- if (showMessages) {
- System.err.println("AoxinglujingHaveObstacel 灏氭湭瀹炵幇锛屼娇鐢ㄩ粯璁ゆ柟娉�: " + e.getMessage());
- }
- List<Coordinate> polygon = Lunjingguihua.parseCoordinates(boundary);
- if (polygon.size() < 4) {
- if (showMessages) {
- JOptionPane.showMessageDialog(parentComponent, "澶氳竟褰㈠潗鏍囨暟閲忎笉瓒筹紝鑷冲皯闇�瑕佷笁涓偣",
- "閿欒", JOptionPane.ERROR_MESSAGE);
- }
- return null;
- }
- double safetyDistance = Double.parseDouble(safetyMarginStr);
- ObstaclePathPlanner pathPlanner = new ObstaclePathPlanner(
- polygon, widthMeters, mode, obstacleList, safetyDistance);
- List<Lunjingguihua.PathSegment> segments = pathPlanner.generate();
- generated = Lunjingguihua.formatPathSegments(segments);
- }
+ // 浼犲叆鍙傛暟锛歜oundary(A), obstacles(B), plannerWidth(C), safetyMarginStr(D)
+ List<AoxinglujingHaveObstacel.PathSegment> segments =
+ AoxinglujingHaveObstacel.planPath(boundary, obstacles, plannerWidth, safetyMarginStr);
+ generated = formatAoxingHaveObstaclePathSegments(segments);
} else if (grassType == 2) {
// 寮傚舰鍦板潡锛屾湁闅滅鐗� -> 璋冪敤 YixinglujingHaveObstacel
- try {
- // 鍋囪 YixinglujingHaveObstacel 鏈夌被浼肩殑鏂规硶绛惧悕
- generated = YixinglujingHaveObstacel.planPath(boundary, obstacles, plannerWidth, safetyMarginStr);
- } catch (Exception e) {
- // 濡傛灉绫昏繕娌℃湁瀹炵幇锛屼娇鐢ㄥ師鏉ョ殑鏂规硶浣滀负鍚庡
- if (showMessages) {
- System.err.println("YixinglujingHaveObstacel 灏氭湭瀹炵幇锛屼娇鐢ㄩ粯璁ゆ柟娉�: " + e.getMessage());
- }
- List<Coordinate> polygon = Lunjingguihua.parseCoordinates(boundary);
- if (polygon.size() < 4) {
- if (showMessages) {
- JOptionPane.showMessageDialog(parentComponent, "澶氳竟褰㈠潗鏍囨暟閲忎笉瓒筹紝鑷冲皯闇�瑕佷笁涓偣",
- "閿欒", JOptionPane.ERROR_MESSAGE);
- }
- return null;
- }
- double safetyDistance = Double.parseDouble(safetyMarginStr);
- ObstaclePathPlanner pathPlanner = new ObstaclePathPlanner(
- polygon, widthMeters, mode, obstacleList, safetyDistance);
- List<Lunjingguihua.PathSegment> segments = pathPlanner.generate();
- generated = Lunjingguihua.formatPathSegments(segments);
- }
+ // 浼犲叆鍙傛暟锛歜oundary(A), obstacles(B), plannerWidth(C), safetyMarginStr(D)
+ // 娉ㄦ剰锛歒ixinglujingHaveObstacel.planPath 杩斿洖 String
+ generated = YixinglujingHaveObstacel.planPath(boundary, obstacles, plannerWidth, safetyMarginStr);
} else {
- // 鏃犳硶鍒ゆ柇鍦板潡绫诲瀷锛屼娇鐢ㄥ師鏉ョ殑鏂规硶浣滀负鍚庡
+ // 鏃犳硶鍒ゆ柇鍦板潡绫诲瀷锛岄粯璁ゆ寜鍑稿舰澶勭悊鎴栨彁绀�
if (showMessages) {
- JOptionPane.showMessageDialog(parentComponent, "鏃犳硶鍒ゆ柇鍦板潡绫诲瀷锛屼娇鐢ㄩ粯璁よ矾寰勭敓鎴愭柟娉�",
+ JOptionPane.showMessageDialog(parentComponent, "鏃犳硶鍒ゆ柇鍦板潡绫诲瀷锛屽皾璇曟寜鍑稿舰鍦板潡澶勭悊",
"鎻愮ず", JOptionPane.WARNING_MESSAGE);
}
- List<Coordinate> polygon = Lunjingguihua.parseCoordinates(boundary);
- if (polygon.size() < 4) {
- if (showMessages) {
- JOptionPane.showMessageDialog(parentComponent, "澶氳竟褰㈠潗鏍囨暟閲忎笉瓒筹紝鑷冲皯闇�瑕佷笁涓偣",
- "閿欒", JOptionPane.ERROR_MESSAGE);
- }
- return null;
- }
- double safetyDistance = Double.parseDouble(safetyMarginStr);
- ObstaclePathPlanner pathPlanner = new ObstaclePathPlanner(
- polygon, widthMeters, mode, obstacleList, safetyDistance);
- List<Lunjingguihua.PathSegment> segments = pathPlanner.generate();
- generated = Lunjingguihua.formatPathSegments(segments);
+ List<AoxinglujingHaveObstacel.PathSegment> segments =
+ AoxinglujingHaveObstacel.planPath(boundary, obstacles, plannerWidth, safetyMarginStr);
+ generated = formatAoxingHaveObstaclePathSegments(segments);
}
}
diff --git a/src/lujing/ObstaclePathPlanner.java b/src/lujing/ObstaclePathPlanner.java
deleted file mode 100644
index bc93f34..0000000
--- a/src/lujing/ObstaclePathPlanner.java
+++ /dev/null
@@ -1,546 +0,0 @@
-package lujing;
-
-import org.locationtech.jts.algorithm.Angle;
-import org.locationtech.jts.geom.*;
-import org.locationtech.jts.operation.distance.DistanceOp;
-import org.locationtech.jts.operation.union.CascadedPolygonUnion;
-
-import java.util.*;
-import java.util.stream.Collectors;
-
-/**
- * 闅滅鐗╄矾寰勮鍒掑櫒
- * * 浼樺寲鏂规锛�
- * 1. 棰勮鍒掞細鍏堜笉鑰冭檻闅滅鐗╋紝瑙勫垝鍑鸿鐩栧叏鍥剧殑骞宠绾胯矾寰勶紙寮撳瓧褰級銆�
- * 2. 鍑犱綍鍒囧壊锛氭牴鎹殰纰嶇墿鐨勫鎵╋紙瀹夊叏璺濈锛夊嚑浣曚綋锛屽皢璺緞鍒囨柇锛岀Щ闄よ惤鍦ㄩ殰纰嶇墿鍐呯殑閮ㄥ垎銆�
- * 3. 鍖哄煙閲嶇粍锛氬皢鍓╀綑鐨勮矾寰勬鎸夎繛閫氭�ц仛绫讳负鑻ュ共涓�滆繛缁尯鍩熲�濓紝姣忎釜鍖哄煙鍐呴儴閫氳繃寮撳瓧褰㈣繛鎺ャ��
- * 4. 鍏ㄥ眬杩炴帴锛氫娇鐢ㄩ伩闅滅畻娉曪紙A*鍙鍥撅級灏嗚繖浜涘绔嬬殑鍖哄煙涓茶仈璧锋潵銆�
- * * * 淇闂锛�
- * 1. 淇璺緞绌胯秺闅滅鐗╃殑闂锛堥�氳繃鏇翠弗鏍肩殑 Interior Intersection 妫�鏌ワ級銆�
- * 2. 淇璺緞瓒呭嚭鍦板潡杈圭晫鐨勯棶棰橈紙閫氳繃鍔犲叆 Boundary Covers 绾︽潫锛夈��
- * 3. [鏈淇] 淇 IntersectionMatrix 绫诲瀷鎶ラ敊锛屼娇鐢ㄦ纭殑鐭╅樀鍗曞厓鏍兼鏌ユ浛浠d笉瀛樺湪鐨勬柟娉曘��
- * * * 浜屾浼樺寲锛堥拡瀵圭敤鎴峰弽棣堬級锛�
- * 1. 寮曞叆 Tolerance Buffer (鍐呯缉) 鐢ㄤ簬鐩镐氦妫�娴嬶紝瑙e喅鈥滄帴瑙﹀嵆鐩镐氦鈥濆鑷寸殑鍚堟硶杈圭紭璺緞琚鍒ら棶棰樸��
- * 2. 澧炲己 isLineSafe 鐨勮竟鐣岀害鏉燂紝纭繚璺緞涓ユ牸鍦� Boundary 鍐呴儴銆�
- * 3. 浼樺寲 findSafePath锛屽鍔犵偣浣嶆牎楠屼笌鍚搁檮锛圫nap锛夛紝闃叉鍥犳诞鐐硅宸鑷寸殑瀵昏矾澶辫触鑰屽洖閫�鍒扮洿绾裤��
- */
-public class ObstaclePathPlanner {
- private final List<Coordinate> polygon; // 鍓茶崏鍖哄煙杈圭晫鐐归泦
- private final double width; // 鍓茶崏瀹藉害
- private final String mode; // 妯″紡
- private final List<List<Coordinate>> obstacles; // 闅滅鐗╁垪琛�
- private final double safetyDistance; // 瀹夊叏璺濈
- private final GeometryFactory gf = new GeometryFactory();
-
- // 淇濆瓨鍦板潡鐨勫嚑浣曞舰鐘讹紝鐢ㄤ簬杈圭晫绾︽潫妫�鏌�
- private Geometry boundaryGeom;
- // 鐢ㄤ簬妫�娴嬬殑闅滅鐗╁嚑浣曚綋锛堝彲鑳界粡杩囧井璋冿級
- private Geometry checkObstacleGeom;
-
- public ObstaclePathPlanner(List<Coordinate> polygon, double width, String mode,
- List<List<Coordinate>> obstacles, double safetyDistance) {
- this.polygon = polygon;
- this.width = width;
- this.mode = mode;
- this.obstacles = obstacles != null ? obstacles : new ArrayList<>();
- this.safetyDistance = safetyDistance;
-
- initBoundaryGeom();
- }
-
- /**
- * 鍒濆鍖栬竟鐣屽嚑浣曚綋锛岀敤浜庡悗缁殑绾︽潫妫�鏌�
- */
- private void initBoundaryGeom() {
- if (polygon == null || polygon.size() < 3) {
- this.boundaryGeom = gf.createPolygon();
- return;
- }
- List<Coordinate> closed = new ArrayList<>(polygon);
- if (!closed.get(0).equals2D(closed.get(closed.size() - 1))) {
- closed.add(new Coordinate(closed.get(0)));
- }
- LinearRing ring = gf.createLinearRing(closed.toArray(new Coordinate[0]));
- Polygon poly = gf.createPolygon(ring);
- // 纭繚鍑犱綍鏈夋晥鎬�
- this.boundaryGeom = poly.isValid() ? poly : poly.buffer(0);
- }
-
- /**
- * 鐢熸垚璺緞鐨勪富鍏ュ彛
- */
- public List<Lunjingguihua.PathSegment> generate() {
- // 1. 鐢熸垚鍒濆鐨勫畬鏁村钩琛岀嚎璺緞锛堝拷鐣ラ殰纰嶇墿锛�
- List<Lunjingguihua.PathSegment> fullPath = generateFullPathWithoutObstacles();
- if (fullPath.isEmpty()) return fullPath;
-
- // 2. 鏋勫缓闅滅鐗╃殑澶栨墿瀹夊叏鍖哄煙 (Buffer)
- Geometry obstacleBuffer = createObstacleBuffer();
-
- // 鍒濆鍖栫敤浜庢娴嬬殑鍑犱綍浣擄紙鍐呯缉涓�鐐圭偣锛屽厑璁歌矾寰勮创杈癸級
- if (!obstacleBuffer.isEmpty()) {
- this.checkObstacleGeom = obstacleBuffer.buffer(-0.01); // 鍐呯缉1cm锛屽蹇嶆诞鐐硅宸�
- } else {
- this.checkObstacleGeom = obstacleBuffer;
- }
-
- if (obstacleBuffer.isEmpty()) return fullPath;
-
- // 3. 鍒囧壊璺緞锛氱Щ闄や笌闅滅鐗╅噸鍙犵殑閮ㄥ垎
- List<Lunjingguihua.PathSegment> clippedSegments = clipPathWithObstacles(fullPath, obstacleBuffer);
- if (clippedSegments.isEmpty()) return new ArrayList<>();
-
- // 4. 閲嶆柊瑙勫垝锛氬皢纰庣墖鍖栫殑绾挎閲嶇粍鎴愯繛缁殑寮撳瓧褰㈣矾寰勶紝骞惰繘琛岄伩闅滆繛鎺�
- List<Lunjingguihua.PathSegment> finalPath = reorganizeAndConnectPath(clippedSegments, obstacleBuffer);
-
- // 5. 鍚庡鐞嗭紙鏍囪璧风粓鐐圭瓑锛�
- postProcessPath(finalPath);
-
- return finalPath;
- }
-
- /**
- * 姝ラ1锛氳皟鐢ㄦ牳蹇冨簱鐢熸垚鏃犻殰纰嶇殑骞宠绾胯矾寰�
- */
- private List<Lunjingguihua.PathSegment> generateFullPathWithoutObstacles() {
- Lunjingguihua.PlannerCore tempPlanner = new Lunjingguihua.PlannerCore(
- polygon, width, mode, new ArrayList<>());
- return tempPlanner.generateParallelPath();
- }
-
- /**
- * 姝ラ2锛氬垱寤烘墍鏈夐殰纰嶇墿鐨勫苟闆� + 瀹夊叏璺濈澶栨墿
- */
- private Geometry createObstacleBuffer() {
- if (obstacles.isEmpty()) return gf.createPolygon();
-
- List<Geometry> geoms = new ArrayList<>();
- for (List<Coordinate> obs : obstacles) {
- if (obs == null || obs.size() < 3) continue;
- List<Coordinate> closed = new ArrayList<>(obs);
- if (!closed.get(0).equals2D(closed.get(closed.size() - 1))) {
- closed.add(new Coordinate(closed.get(0)));
- }
- LinearRing ring = gf.createLinearRing(closed.toArray(new Coordinate[0]));
- Polygon poly = gf.createPolygon(ring);
- if (!poly.isValid()) poly = (Polygon) poly.buffer(0);
- geoms.add(poly);
- }
-
- if (geoms.isEmpty()) return gf.createPolygon();
-
- Geometry union = CascadedPolygonUnion.union(geoms);
- // 瀵瑰悎骞跺悗鐨勯殰纰嶇墿杩涜澶栨墿锛圔uffer锛�
- Geometry buffered = union.buffer(safetyDistance, 8);
- return buffered.isValid() ? buffered : buffered.buffer(0);
- }
-
- /**
- * 姝ラ3锛氱敤闅滅鐗╁嚑浣曚綋鍒囧壊璺緞
- */
- private List<Lunjingguihua.PathSegment> clipPathWithObstacles(List<Lunjingguihua.PathSegment> fullPath, Geometry obstacleBuffer) {
- List<Lunjingguihua.PathSegment> validSegments = new ArrayList<>();
-
- for (Lunjingguihua.PathSegment seg : fullPath) {
- if (!seg.isMowing) continue;
-
- LineString line = gf.createLineString(new Coordinate[]{seg.start, seg.end});
- Geometry diff;
- try {
- diff = line.difference(obstacleBuffer);
- } catch (Exception e) {
- continue;
- }
-
- if (diff.isEmpty()) continue;
-
- for (int i = 0; i < diff.getNumGeometries(); i++) {
- Geometry g = diff.getGeometryN(i);
- if (g instanceof LineString) {
- Coordinate[] coords = g.getCoordinates();
- for (int k = 0; k < coords.length - 1; k++) {
- Coordinate p1 = coords[k];
- Coordinate p2 = coords[k+1];
- if (p1.distance(p2) > 0.1) {
- validSegments.add(new Lunjingguihua.PathSegment(p1, p2, true));
- }
- }
- }
- }
- }
- return validSegments;
- }
-
- /**
- * 姝ラ4锛氭牳蹇冮噸缁勯�昏緫
- */
- private List<Lunjingguihua.PathSegment> reorganizeAndConnectPath(List<Lunjingguihua.PathSegment> segments, Geometry obstacleBuffer) {
- if (segments.isEmpty()) return new ArrayList<>();
-
- // --- A. 鍒嗘瀽鎵弿绾挎柟鍚� ---
- Lunjingguihua.PathSegment firstSeg = segments.get(0);
- double angle = Math.atan2(firstSeg.end.y - firstSeg.start.y, firstSeg.end.x - firstSeg.start.x);
- double sin = Math.sin(angle);
- double cos = Math.cos(angle);
-
- // --- B. 缁欐瘡涓嚎娈靛垎閰嶆壂鎻忕嚎绱㈠紩 (Grid Index) ---
- double gridStep = width;
-
- class IndexedSegment {
- final Lunjingguihua.PathSegment segment;
- final int gridIndex;
- final double projectVal;
-
- IndexedSegment(Lunjingguihua.PathSegment s) {
- this.segment = s;
- double cx = (s.start.x + s.end.x) / 2;
- double cy = (s.start.y + s.end.y) / 2;
- double perpDist = -cx * sin + cy * cos;
- this.gridIndex = (int) Math.floor(perpDist / gridStep);
- this.projectVal = cx * cos + cy * sin;
- }
- }
-
- List<IndexedSegment> indexedSegments = segments.stream()
- .map(IndexedSegment::new)
- .sorted(Comparator.comparingInt((IndexedSegment s) -> s.gridIndex)
- .thenComparingDouble(s -> s.projectVal))
- .collect(Collectors.toList());
-
- // --- C. 鏋勫缓鈥滃尯鍩熼摼鈥� (Zones) ---
- List<List<Lunjingguihua.PathSegment>> zones = new ArrayList<>();
- Set<IndexedSegment> visited = new HashSet<>();
-
- while (visited.size() < indexedSegments.size()) {
- IndexedSegment startNode = null;
- for (IndexedSegment is : indexedSegments) {
- if (!visited.contains(is)) {
- startNode = is;
- break;
- }
- }
- if (startNode == null) break;
-
- List<Lunjingguihua.PathSegment> zone = new ArrayList<>();
- zone.add(startNode.segment);
- visited.add(startNode);
-
- IndexedSegment current = startNode;
- boolean lookingForNext = true;
-
- while (lookingForNext) {
- IndexedSegment bestNext = null;
- double minDistance = Double.MAX_VALUE;
-
- // 鎼滅储鏈�浣冲悗缁嚎娈�
- for (int i = 0; i < indexedSegments.size(); i++) {
- IndexedSegment candidate = indexedSegments.get(i);
- if (visited.contains(candidate)) continue;
-
- if (Math.abs(candidate.gridIndex - current.gridIndex) > 1) continue;
-
- double d = current.segment.end.distance(candidate.segment.start);
-
- if (d > width * 3.0) continue;
-
- if (d < minDistance) {
- // 浣跨敤 checkObstacleGeom 杩涜妫�娴�
- if (isLineSafe(current.segment.end, candidate.segment.start)) {
- minDistance = d;
- bestNext = candidate;
- }
- }
- }
-
- if (bestNext != null) {
- zone.add(bestNext.segment);
- visited.add(bestNext);
- current = bestNext;
- } else {
- lookingForNext = false;
- }
- }
- zones.add(zone);
- }
-
- // --- D. 杩炴帴鎵�鏈� Zones ---
- List<Lunjingguihua.PathSegment> resultPath = new ArrayList<>();
-
- List<List<Lunjingguihua.PathSegment>> remainingZones = new ArrayList<>(zones);
- List<Lunjingguihua.PathSegment> currentProcessingZone = remainingZones.remove(0);
-
- addZoneToPath(resultPath, currentProcessingZone, obstacleBuffer, false);
-
- while (!remainingZones.isEmpty()) {
- Lunjingguihua.PathSegment lastSeg = resultPath.get(resultPath.size() - 1);
- Coordinate currentPos = lastSeg.end;
-
- int bestZoneIdx = -1;
- double minDist = Double.MAX_VALUE;
-
- for (int i = 0; i < remainingZones.size(); i++) {
- List<Lunjingguihua.PathSegment> z = remainingZones.get(i);
- if (z.isEmpty()) continue;
- double d = currentPos.distance(z.get(0).start);
- if (d < minDist) {
- minDist = d;
- bestZoneIdx = i;
- }
- }
-
- if (bestZoneIdx != -1) {
- List<Lunjingguihua.PathSegment> nextZone = remainingZones.remove(bestZoneIdx);
- addZoneToPath(resultPath, nextZone, obstacleBuffer, true);
- } else {
- break;
- }
- }
-
- return resultPath;
- }
-
- /**
- * 灏嗕竴涓� Zone 娣诲姞鍒扮粨鏋滆矾寰勪腑
- */
- private void addZoneToPath(List<Lunjingguihua.PathSegment> path,
- List<Lunjingguihua.PathSegment> zone,
- Geometry obstacleBuffer,
- boolean needConnectToZoneStart) {
- if (zone.isEmpty()) return;
-
- // 1. 杩炴帴鍒� Zone 鐨勮捣鐐�
- if (needConnectToZoneStart && !path.isEmpty()) {
- Coordinate from = path.get(path.size() - 1).end;
- Coordinate to = zone.get(0).start;
- List<Coordinate> travel = findSafePath(from, to, obstacleBuffer);
- if (travel.size() > 1) {
- for (int i = 0; i < travel.size() - 1; i++) {
- path.add(new Lunjingguihua.PathSegment(travel.get(i), travel.get(i+1), false));
- }
- }
- }
-
- // 2. 澶勭悊 Zone 鍐呴儴
- for (int i = 0; i < zone.size(); i++) {
- Lunjingguihua.PathSegment seg = zone.get(i);
-
- if (i > 0) {
- Coordinate prevEnd = zone.get(i-1).end;
- Coordinate currStart = seg.start;
- if (!prevEnd.equals2D(currStart)) {
- if (isLineSafe(prevEnd, currStart)) {
- path.add(new Lunjingguihua.PathSegment(prevEnd, currStart, false));
- } else {
- List<Coordinate> detour = findSafePath(prevEnd, currStart, obstacleBuffer);
- if (detour.size() > 1) {
- for (int k = 0; k < detour.size() - 1; k++) {
- path.add(new Lunjingguihua.PathSegment(detour.get(k), detour.get(k+1), false));
- }
- }
- }
- }
- }
- path.add(seg);
- }
- }
-
- /**
- * 妫�鏌ヤ袱鐐硅繛绾挎槸鍚﹀畨鍏�
- * 淇敼鐐癸細
- * 1. 涓ユ牸妫�鏌� Boundary (Covers)
- * 2. 浣跨敤 checkObstacleGeom (鍐呯缉鐗�) 妫�鏌ラ殰纰嶇墿锛屽厑璁歌创杈�
- * 3. [Fix] 浣跨敤 matrix.get() 浠f浛涓嶅瓨鍦ㄧ殑 isIntersects(int)
- */
- private boolean isLineSafe(Coordinate p1, Coordinate p2) {
- if (p1.equals2D(p2)) return true;
- LineString line = gf.createLineString(new Coordinate[]{p1, p2});
-
- // 1. 杈圭晫绾︽潫锛氱嚎娈靛繀椤诲畬鍏ㄥ湪鍦板潡鍐呴儴
- if (boundaryGeom != null && !boundaryGeom.covers(line)) {
- return false;
- }
-
- // 2. 閬块殰绾︽潫锛氫娇鐢ㄥ唴缂╁悗鐨� buffer 妫�鏌�
- // 濡傛灉 checkObstacleGeom 涓虹┖锛堟棤闅滅锛夛紝鍒欏畨鍏�
- if (checkObstacleGeom == null || checkObstacleGeom.isEmpty()) return true;
-
- IntersectionMatrix matrix = line.relate(checkObstacleGeom);
-
- // 鎴戜滑瑕佹鏌ワ細绾挎鐨勪换浣曢儴鍒嗭紙Interior锛夋槸鍚︾┛杩囬殰纰嶇墿鍐呴儴锛圛nterior锛�
- // 鎴栬�� 绾挎鐨勭鐐癸紙Boundary锛夋槸鍚﹀湪闅滅鐗╁唴閮紙Interior锛�
- // 濡傛灉涓よ�呴兘鏄� Dimension.FALSE (-1)锛屽垯璇存槑娌℃湁绌胯繃鍐呴儴
-
- boolean interiorIntersects = matrix.get(Location.INTERIOR, Location.INTERIOR) != Dimension.FALSE;
- boolean boundaryIntersects = matrix.get(Location.BOUNDARY, Location.INTERIOR) != Dimension.FALSE;
-
- return !interiorIntersects && !boundaryIntersects;
- }
-
- /**
- * 瀵绘壘涓ょ偣闂寸殑瀹夊叏璺緞
- * 淇敼鐐癸細
- * 1. 澧炲姞鐐逛綅鏍¢獙涓庡惛闄勶紙Snap锛夛紝纭繚璧风偣缁堢偣鏈夋晥
- * 2. 绉婚櫎鐩寸嚎寮哄埗鍥為��锛岃嫢瀵昏矾澶辫触鍒欒繑鍥炵┖锛堟垨淇濈暀璧风偣锛夛紝閬垮厤绌垮
- */
- private List<Coordinate> findSafePath(Coordinate start, Coordinate end, Geometry obstacleBuffer) {
- // 0. 鏁版嵁娓呮礂锛氬惛闄勮捣鐐圭粓鐐瑰埌鍚堟硶鍖哄煙
- Coordinate safeStart = snapPointToValid(start);
- Coordinate safeEnd = snapPointToValid(end);
-
- List<Coordinate> path = new ArrayList<>();
-
- // 1. 灏濊瘯鐩磋繛
- if (isLineSafe(safeStart, safeEnd)) {
- path.add(safeStart);
- path.add(safeEnd);
- return path;
- }
-
- // 2. 鏋勫缓鍙鍥�
- Set<Coordinate> nodes = new HashSet<>();
- nodes.add(safeStart);
- nodes.add(safeEnd);
-
- // 鎻愬彇闅滅鐗╅《鐐�
- addPolygonVertices(obstacleBuffer, nodes);
- // 鎻愬彇杈圭晫椤剁偣锛堝叧閿細澶勭悊鍑瑰舰杈圭晫锛�
- addPolygonVertices(boundaryGeom, nodes);
-
- List<Coordinate> nodeList = new ArrayList<>(nodes);
-
- // 鏋勫缓閭绘帴琛�
- Map<Coordinate, List<Coordinate>> graph = new HashMap<>();
- for (Coordinate c1 : nodeList) {
- for (Coordinate c2 : nodeList) {
- if (c1 == c2) continue;
- if (isLineSafe(c1, c2)) {
- graph.computeIfAbsent(c1, k -> new ArrayList<>()).add(c2);
- }
- }
- }
-
- // Dijkstra 瀵昏矾
- Map<Coordinate, Double> dist = new HashMap<>();
- Map<Coordinate, Coordinate> prev = new HashMap<>();
- PriorityQueue<Coordinate> pq = new PriorityQueue<>(Comparator.comparingDouble(dist::get));
-
- for (Coordinate n : nodeList) dist.put(n, Double.MAX_VALUE);
- dist.put(safeStart, 0.0);
- pq.add(safeStart);
-
- while (!pq.isEmpty()) {
- Coordinate u = pq.poll();
- if (u.equals2D(safeEnd)) break;
- if (dist.get(u) == Double.MAX_VALUE) break;
-
- if (graph.containsKey(u)) {
- for (Coordinate v : graph.get(u)) {
- double alt = dist.get(u) + u.distance(v);
- if (alt < dist.get(v)) {
- dist.put(v, alt);
- prev.put(v, u);
- pq.add(v);
- }
- }
- }
- }
-
- // 閲嶆瀯璺緞
- if (prev.containsKey(safeEnd)) {
- LinkedList<Coordinate> p = new LinkedList<>();
- Coordinate curr = safeEnd;
- while (curr != null) {
- p.addFirst(curr);
- curr = prev.get(curr);
- }
- return p;
- }
-
- // 瀵昏矾澶辫触锛岃繑鍥炵┖锛堥伩鍏嶉敊璇殑鐩寸嚎绌胯秺锛�
- return path;
- }
-
- // 杈呭姪锛氶獙璇佸苟鍚搁檮鐐瑰埌鍚堟硶鍖哄煙
- private Coordinate snapPointToValid(Coordinate p) {
- Point point = gf.createPoint(p);
- boolean inBoundary = (boundaryGeom == null) || boundaryGeom.covers(point);
- boolean outObstacle = (checkObstacleGeom == null) || !checkObstacleGeom.contains(point); // 浣跨敤 contains 鑰屼笉鏄� intersects interior锛岀◢寰弗鏍肩偣
-
- if (inBoundary && outObstacle) return p;
-
- // 濡傛灉鐐规棤鏁堬紝灏濊瘯鎵炬渶杩戠殑鏈夋晥鐐癸紙杈圭晫鎴栭殰纰嶇墿杈圭紭锛�
- // 杩欓噷绠�鍖栧鐞嗭細濡傛灉鍦ㄩ殰纰嶇墿鍐咃紝鍚搁檮鍒伴殰纰嶇墿杈圭晫锛涘鏋滃湪杈圭晫澶栵紝鍚搁檮鍒拌竟鐣�
- // 瀹為檯涓� JTS DistanceOp.nearestPoints 鍙互鍋氳繖涓�
-
- Geometry target = boundaryGeom;
- if (!outObstacle && checkObstacleGeom != null) {
- // 鍦ㄩ殰纰嶇墿鍐咃紝浼樺厛鍚搁檮鍑洪殰纰嶇墿
- Coordinate[] nearest = DistanceOp.nearestPoints(point, checkObstacleGeom.getBoundary());
- return nearest[1];
- }
-
- if (!inBoundary && boundaryGeom != null) {
- Coordinate[] nearest = DistanceOp.nearestPoints(point, boundaryGeom);
- return nearest[1];
- }
-
- return p;
- }
-
- private void addPolygonVertices(Geometry geom, Set<Coordinate> nodes) {
- if (geom == null) return;
- if (geom instanceof Polygon) {
- Collections.addAll(nodes, ((Polygon) geom).getExteriorRing().getCoordinates());
- for(int i=0; i<((Polygon)geom).getNumInteriorRing(); i++) {
- Collections.addAll(nodes, ((Polygon)geom).getInteriorRingN(i).getCoordinates());
- }
- } else if (geom instanceof MultiPolygon) {
- MultiPolygon mp = (MultiPolygon) geom;
- for (int i = 0; i < mp.getNumGeometries(); i++) {
- addPolygonVertices(mp.getGeometryN(i), nodes);
- }
- } else if (geom instanceof GeometryCollection) {
- GeometryCollection gc = (GeometryCollection) geom;
- for (int i = 0; i < gc.getNumGeometries(); i++) {
- addPolygonVertices(gc.getGeometryN(i), nodes);
- }
- }
- }
-
- /**
- * 鍚庡鐞嗭細绉婚櫎鐭嚎娈碉紝鏍囪璧风粓鐐�
- */
- private void postProcessPath(List<Lunjingguihua.PathSegment> path) {
- if (path.isEmpty()) return;
- path.removeIf(seg -> seg.start.distance(seg.end) < 0.05);
- for (Lunjingguihua.PathSegment seg : path) {
- seg.isStartPoint = false;
- seg.isEndPoint = false;
- }
- boolean startFound = false;
- for (Lunjingguihua.PathSegment seg : path) {
- if (seg.isMowing) {
- seg.setAsStartPoint();
- startFound = true;
- break;
- }
- }
- for (int i = path.size() - 1; i >= 0; i--) {
- Lunjingguihua.PathSegment seg = path.get(i);
- if (seg.isMowing) {
- seg.setAsEndPoint();
- break;
- }
- }
- }
-}
-
-
-
-
-
-
-
-
-
-
diff --git a/src/lujing/luoxuan.java b/src/lujing/luoxuan.java
deleted file mode 100644
index c660e05..0000000
--- a/src/lujing/luoxuan.java
+++ /dev/null
@@ -1,408 +0,0 @@
-package lujing;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-
-import org.locationtech.jts.geom.Coordinate;
-import org.locationtech.jts.geom.Geometry;
-import org.locationtech.jts.geom.LinearRing;
-import org.locationtech.jts.geom.Polygon;
-import org.locationtech.jts.geom.TopologyException;
-import org.locationtech.jts.operation.buffer.BufferParameters;
-
-import lujing.Lunjingguihua.PathSegment;
-
-/**
- * Utility class that produces spiral mowing paths by iteratively offsetting a safe area polygon.
- * 浼樺寲鐗堬細鏀硅繘璺緞鐢熸垚閫昏緫锛屽噺灏戠┖椹惰窛绂伙紝浼樺寲璺緞杩炵画鎬�
- */
-public final class luoxuan {
-
- private static final int MAX_ITERATIONS = 512;
- private static final double AREA_EPSILON = 1e-2;
- private static final double LENGTH_EPSILON = 1e-6;
- private static final double MIN_BUFFER_RATIO = 0.6; // 鏈�灏忕紦鍐叉瘮渚�
-
- private luoxuan() {
- }
-
- /**
- * Generate optimized spiral mowing paths with improved continuity
- */
- public static List<PathSegment> generateOptimizedSpiralPath(Geometry safeArea, double laneWidth) {
- if (safeArea == null || safeArea.isEmpty() || !Double.isFinite(laneWidth) || laneWidth <= 0) {
- return Collections.emptyList();
- }
-
- // 1. 娓呯悊鍑犱綍浣擄紝纭繚鏈夋晥鎬�
- Geometry working = cleanGeometry(safeArea);
- if (working.isEmpty()) {
- return Collections.emptyList();
- }
-
- // 2. 鎻愬彇涓诲杈瑰舰锛堥�夋嫨闈㈢Н鏈�澶х殑锛�
- Polygon mainPolygon = extractMainPolygon(working);
- if (mainPolygon == null) {
- return Collections.emptyList();
- }
-
- // 3. 璁$畻铻烘棆璺緞
- List<PathSegment> segments = new ArrayList<>();
- Coordinate cursor = clone(findOptimalStartPoint(mainPolygon));
- Geometry currentLayer = mainPolygon; // start from the outer boundaryand peel inwards
-
- for (int iteration = 0; iteration < MAX_ITERATIONS; iteration++) {
- Geometry layerGeometry = cleanGeometry(currentLayer);
- if (layerGeometry == null || layerGeometry.isEmpty()) {
- break;
- }
-
- List<Polygon> polygons = extractPolygons(layerGeometry);
- if (polygons.isEmpty()) {
- break;
- }
- polygons.sort(Comparator.comparingDouble(Polygon::getArea).reversed());
-
- try {
- for (Polygon polygon : polygons) {
- LinearRing outer = polygon.getExteriorRing();
- if (outer == null || outer.getNumPoints() < 4) {
- continue;
- }
-
- cursor = processRing(outer.getCoordinates(), true, cursor, segments);
-
- for (int holeIndex = 0; holeIndex < polygon.getNumInteriorRing(); holeIndex++) {
- LinearRing hole = polygon.getInteriorRingN(holeIndex);
- if (hole == null || hole.getNumPoints() < 4) {
- continue;
- }
- cursor = processRing(hole.getCoordinates(), false, cursor, segments);
- }
- }
- } catch (TopologyException ex) {
- break;
- }
-
- if (!canShrinkFurther(polygons, laneWidth)) {
- break;
- }
-
- Geometry nextLayer;
- try {
- nextLayer = layerGeometry.buffer(
- -laneWidth,
- BufferParameters.DEFAULT_QUADRANT_SEGMENTS,
- BufferParameters.CAP_FLAT
- );
- } catch (TopologyException ex) {
- break;
- }
-
- if (nextLayer.isEmpty() || nextLayer.getArea() < AREA_EPSILON) {
- break;
- }
-
- double areaDelta = Math.abs(layerGeometry.getArea() - nextLayer.getArea());
- if (areaDelta <= AREA_EPSILON) {
- break;
- }
-
- currentLayer = nextLayer;
- }
-
- // 4. 浼樺寲璺緞杩炴帴
- optimizePathConnections(segments);
-
- // 5. 鏍囪绔偣
- markEndpoints(segments);
-
- return segments;
- }
-
- /**
- * Backward compatible entry that delegates to the optimized implementation.
- */
- public static List<PathSegment> generateSpiralPath(Geometry safeArea, double laneWidth) {
- return generateOptimizedSpiralPath(safeArea, laneWidth);
- }
-
- /**
- * 娓呯悊鍑犱綍浣擄紝纭繚鏈夋晥鎬�
- */
- private static Geometry cleanGeometry(Geometry geometry) {
- if (geometry == null) return null;
- try {
- return geometry.buffer(0.0);
- } catch (Exception e) {
- return geometry;
- }
- }
-
- /**
- * 鎻愬彇涓诲杈瑰舰锛堥潰绉渶澶х殑锛�
- */
- private static Polygon extractMainPolygon(Geometry geometry) {
- List<Polygon> polygons = extractPolygons(geometry);
- if (polygons.isEmpty()) return null;
-
- // 鎸夐潰绉帓搴忥紝閫夋嫨鏈�澶х殑
- polygons.sort((p1, p2) -> Double.compare(p2.getArea(), p1.getArea()));
- return polygons.get(0);
- }
-
- /**
- * 瀵绘壘鏈�浼樿捣鐐癸紙绂诲杈瑰舰涓績鏈�杩戠殑鐐癸級
- */
- private static Coordinate findOptimalStartPoint(Polygon polygon) {
- if (polygon == null) return null;
-
- Coordinate center = polygon.getCentroid().getCoordinate();
- LinearRing ring = polygon.getExteriorRing();
- Coordinate[] coords = ring.getCoordinates();
-
- Coordinate nearest = coords[0];
- double minDist = Double.MAX_VALUE;
-
- for (Coordinate coord : coords) {
- double dist = coord.distance(center);
- if (dist < minDist) {
- minDist = dist;
- nearest = coord;
- }
- }
-
- return nearest;
- }
-
- /**
- * 浼樺寲璺緞杩炴帴锛屽噺灏戠┖椹惰窛绂�
- */
- private static void optimizePathConnections(List<PathSegment> segments) {
- if (segments == null || segments.size() < 2) {
- return;
- }
-
- List<PathSegment> optimized = new ArrayList<>(segments.size());
- PathSegment previous = null;
-
- for (PathSegment segment : segments) {
- if (segment == null || segment.start == null || segment.end == null) {
- continue;
- }
- if (isDegenerate(segment)) {
- continue;
- }
-
- if (previous != null
- && previous.isMowing == segment.isMowing
- && equals2D(previous.start, segment.start)
- && equals2D(previous.end, segment.end)) {
- continue; // 璺宠繃閲嶅娈�
- }
-
- optimized.add(segment);
- previous = segment;
- }
-
- segments.clear();
- segments.addAll(optimized);
- }
-
- /**
- * 妫�鏌ユ槸鍚﹀彲浠ョ户缁紦鍐�
- */
- private static boolean canShrinkFurther(List<Polygon> polygons, double bufferDistance) {
- if (polygons == null || polygons.isEmpty()) {
- return false;
- }
-
- for (Polygon polygon : polygons) {
- if (polygon == null || polygon.isEmpty()) {
- continue;
- }
-
- double width = polygon.getEnvelopeInternal().getWidth();
- double height = polygon.getEnvelopeInternal().getHeight();
- double minDimension = Math.min(width, height);
-
- if (minDimension <= bufferDistance * 2 * MIN_BUFFER_RATIO) {
- return false;
- }
- }
-
- return true;
- }
-
- /**
- * 鏍囪璧风偣鍜岀粓鐐�
- */
- private static void markEndpoints(List<PathSegment> segments) {
- if (segments == null || segments.isEmpty()) {
- return;
- }
-
- // 瀵绘壘绗竴涓壊鑽夋浣滀负璧风偣
- PathSegment firstMowing = null;
- for (PathSegment seg : segments) {
- if (seg != null && seg.isMowing) {
- firstMowing = seg;
- break;
- }
- }
-
- // 瀵绘壘鏈�鍚庝竴涓壊鑽夋浣滀负缁堢偣
- PathSegment lastMowing = null;
- for (int i = segments.size() - 1; i >= 0; i--) {
- PathSegment seg = segments.get(i);
- if (seg != null && seg.isMowing) {
- lastMowing = seg;
- break;
- }
- }
-
- if (firstMowing != null) {
- firstMowing.setAsStartPoint();
- }
- if (lastMowing != null && lastMowing != firstMowing) {
- lastMowing.setAsEndPoint();
- }
- }
-
- /**
- * 妫�鏌ョ嚎娈垫槸鍚﹂��鍖栵紙闀垮害杩囧皬锛�
- */
- private static boolean isDegenerate(PathSegment segment) {
- if (segment == null || segment.start == null || segment.end == null) {
- return true;
- }
- double dx = segment.start.x - segment.end.x;
- double dy = segment.start.y - segment.end.y;
- return Math.hypot(dx, dy) <= LENGTH_EPSILON;
- }
-
- /**
- * 鎻愬彇澶氳竟褰紙涓庡師鏂规硶鐩稿悓锛�
- */
- private static List<Polygon> extractPolygons(Geometry geometry) {
- if (geometry == null || geometry.isEmpty()) {
- return Collections.emptyList();
- }
-
- List<Polygon> result = new ArrayList<>();
-
- if (geometry instanceof Polygon) {
- result.add((Polygon) geometry);
- } else if (geometry instanceof org.locationtech.jts.geom.MultiPolygon) {
- org.locationtech.jts.geom.MultiPolygon mp = (org.locationtech.jts.geom.MultiPolygon) geometry;
- for (int i = 0; i < mp.getNumGeometries(); i++) {
- Geometry g = mp.getGeometryN(i);
- if (g instanceof Polygon) {
- result.add((Polygon) g);
- }
- }
- } else if (geometry instanceof org.locationtech.jts.geom.GeometryCollection) {
- org.locationtech.jts.geom.GeometryCollection gc = (org.locationtech.jts.geom.GeometryCollection) geometry;
- for (int i = 0; i < gc.getNumGeometries(); i++) {
- Geometry child = gc.getGeometryN(i);
- result.addAll(extractPolygons(child));
- }
- }
-
- return result;
- }
-
- /**
- * 澶嶅埗鍧愭爣
- */
- private static Coordinate clone(Coordinate source) {
- return source == null ? null : new Coordinate(source.x, source.y);
- }
-
- /**
- * 姣旇緝涓や釜鍧愭爣鏄惁鐩稿悓锛�2D锛�
- */
- private static boolean equals2D(Coordinate a, Coordinate b) {
- if (a == b) return true;
- if (a == null || b == null) return false;
- return a.distance(b) <= LENGTH_EPSILON;
- }
-
- private static Coordinate processRing(Coordinate[] coords,
- boolean forward,
- Coordinate cursor,
- List<PathSegment> segments) {
- if (coords == null || coords.length < 4) {
- return cursor;
- }
-
- List<Coordinate> base = new ArrayList<>(coords.length - 1);
- for (int i = 0; i < coords.length - 1; i++) {
- Coordinate cloned = clone(coords[i]);
- if (cloned != null) {
- base.add(cloned);
- }
- }
-
- if (base.size() < 2) {
- return cursor;
- }
-
- if (!forward) {
- Collections.reverse(base);
- }
-
- int startIndex = 0;
- if (cursor != null) {
- startIndex = findNearestIndex(base, cursor);
- }
-
- List<Coordinate> ordered = new ArrayList<>(base.size());
- for (int i = 0; i < base.size(); i++) {
- int index = (startIndex + i) % base.size();
- ordered.add(clone(base.get(index)));
- }
-
- Coordinate firstCoord = ordered.get(0);
- if (cursor != null && !equals2D(cursor, firstCoord)) {
- PathSegment transfer = new PathSegment(clone(cursor), clone(firstCoord), false);
- if (!isDegenerate(transfer)) {
- segments.add(transfer);
- }
- }
-
- for (int i = 0; i < ordered.size(); i++) {
- Coordinate start = ordered.get(i);
- Coordinate end = ordered.get((i + 1) % ordered.size());
- if (equals2D(start, end)) {
- continue;
- }
- PathSegment mowing = new PathSegment(clone(start), clone(end), true);
- segments.add(mowing);
- }
-
- return clone(firstCoord);
- }
-
- private static int findNearestIndex(List<Coordinate> coordinates, Coordinate reference) {
- if (coordinates == null || coordinates.isEmpty() || reference == null) {
- return 0;
- }
- double bestDistance = Double.MAX_VALUE;
- int bestIndex = 0;
- for (int i = 0; i < coordinates.size(); i++) {
- Coordinate candidate = coordinates.get(i);
- if (candidate == null) {
- continue;
- }
- double distance = reference.distance(candidate);
- if (distance < bestDistance) {
- bestDistance = distance;
- bestIndex = i;
- }
- }
- return bestIndex;
- }
-}
\ No newline at end of file
diff --git a/src/zhangaiwu/AddDikuai.java b/src/zhangaiwu/AddDikuai.java
index 8d6764a..24452c3 100644
--- a/src/zhangaiwu/AddDikuai.java
+++ b/src/zhangaiwu/AddDikuai.java
@@ -23,7 +23,7 @@
import dikuai.Gecaokuanjisuan;
import dikuai.Gecaoanquanjuli;
import bianjie.Bianjieyouhuatoxy;
-import lujing.Lunjingguihua;
+
import lujing.Qufenxingzhuang;
import lujing.AoxinglujingNoObstacle;
import lujing.YixinglujingNoObstacle;
@@ -1469,17 +1469,10 @@
YixinglujingNoObstacle.planPath(boundaryCoords, widthMetersStr, safetyDistanceMetersStr);
plannedPath = formatYixingPathSegments(segments);
} else {
- // 鏃犳硶鍒ゆ柇鍦板潡绫诲瀷锛屼娇鐢ㄩ粯璁ゆ柟娉曚綔涓哄悗澶�
- JOptionPane.showMessageDialog(this, "鏃犳硶鍒ゆ柇鍦板潡绫诲瀷锛屼娇鐢ㄩ粯璁よ矾寰勭敓鎴愭柟娉�",
+ // 鏃犳硶鍒ゆ柇鍦板潡绫诲瀷
+ JOptionPane.showMessageDialog(this, "鏃犳硶鍒ゆ柇鍦板潡绫诲瀷锛屾棤娉曠敓鎴愯矾寰�",
"鎻愮ず", JOptionPane.WARNING_MESSAGE);
- String plannerMode = resolvePlannerMode(patternDisplay);
- plannedPath = Lunjingguihua.generatePathFromStrings(
- boundaryCoords,
- obstacleCoords != null ? obstacleCoords : "",
- widthMetersStr,
- safetyDistanceMetersStr,
- plannerMode
- );
+ plannedPath = "";
}
if (!isMeaningfulValue(plannedPath)) {
--
Gitblit v1.10.0